diff --git a/application/src/main/data/json/system/scada_symbols/left-analog-water-level-meter.svg b/application/src/main/data/json/system/scada_symbols/left-analog-water-level-meter.svg index ae02548602..c2b2a32a2d 100644 --- a/application/src/main/data/json/system/scada_symbols/left-analog-water-level-meter.svg +++ b/application/src/main/data/json/system/scada_symbols/left-analog-water-level-meter.svg @@ -1,5 +1,4 @@ - -{ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:tb="https://thingsboard.io/svg" width="200" height="200" fill="none" version="1.1" viewBox="0 0 200 200"><tb:metadata xmlns=""><![CDATA[{ "title": "Left analog water level meter", "description": "Left analog water level meter", "searchTags": [ @@ -38,18 +37,22 @@ }, { "tag": "icon", - "stateRenderFunction": "var icon = ctx.properties.icon;\nif (icon) {\n element.show();\n} else {\n element.hide()\n}", + "stateRenderFunction": "var showIcon = ctx.properties.showIcon;\nif (showIcon) {\n element.show();\n var icon = ctx.properties.icon;\n var iconSize = ctx.properties.iconSize;\n var iconColor = ctx.properties.iconColor;\n ctx.api.icon(element, icon, iconSize, iconColor, true);\n} else {\n element.hide()\n}", "actions": null }, { "tag": "label", - "stateRenderFunction": "var label = ctx.properties.label;\nif (label) {\n var icon = ctx.properties.icon;\n var labelTextFont = ctx.properties.labelTextFont;\n var labelTextColor = ctx.properties.labelTextColor;\n ctx.api.font(element, labelTextFont, labelTextColor);\n ctx.api.text(element, ctx.properties.labelText);\n if (!icon) {\n element.transform({translateX: 10});\n }\n element.show();\n} else {\n element.hide();\n}", + "stateRenderFunction": "var label = ctx.properties.label;\nif (label) {\n var showIcon = ctx.properties.showIcon;\n var labelTextFont = ctx.properties.labelTextFont;\n var labelTextColor = ctx.properties.labelTextColor;\n ctx.api.font(element, labelTextFont, labelTextColor);\n ctx.api.text(element, ctx.properties.labelText);\n if (!showIcon) {\n element.transform({translateX: 10});\n }\n element.show();\n} else {\n element.hide();\n}", "actions": null }, { "tag": "pointer", "stateRenderFunction": "var valueSet = element.remember('valueSet');\nif (!valueSet) {\n element.remember('valueSet', true);\n element.transform({\n rotate: 0\n });\n}\n\nvar value = ctx.values.value;\nvar fullValue = ctx.values.fullValue;\n\nvar degrees = Math.max(0, Math.min(1, value/fullValue))*179.99;\nvar rotate = element.remember('rotate');\nif (degrees !== rotate) {\n element.remember('rotate', degrees);\n ctx.api.animate(element, 1000).ease('-').transform({rotate: degrees});\n}", - "actions": null + "actions": { + "click": { + "actionFunction": "ctx.api.callAction(event, 'displayClick');" + } + } } ], "behavior": [ @@ -354,7 +357,7 @@ "step": null }, { - "id": "icon", + "id": "showIcon", "name": "{i18n:scada.symbol.icon}", "type": "switch", "default": true, @@ -369,6 +372,54 @@ "max": null, "step": null }, + { + "id": "iconSize", + "name": "{i18n:scada.symbol.icon}", + "type": "number", + "default": 14, + "required": null, + "subLabel": null, + "divider": null, + "fieldSuffix": "px", + "disableOnProperty": "showIcon", + "rowClass": "", + "fieldClass": "", + "min": 0, + "max": null, + "step": null + }, + { + "id": "icon", + "name": "{i18n:scada.symbol.icon}", + "type": "icon", + "default": "water", + "required": null, + "subLabel": null, + "divider": null, + "fieldSuffix": null, + "disableOnProperty": "showIcon", + "rowClass": "", + "fieldClass": "", + "min": null, + "max": null, + "step": null + }, + { + "id": "iconColor", + "name": "{i18n:scada.symbol.icon}", + "type": "color", + "default": "#0000008A", + "required": null, + "subLabel": null, + "divider": null, + "fieldSuffix": null, + "disableOnProperty": "showIcon", + "rowClass": "", + "fieldClass": "", + "min": null, + "max": null, + "step": null + }, { "id": "defaultBorderColor", "name": "{i18n:scada.symbol.default-border-color}", @@ -610,9 +661,12 @@ "step": null } ] -} +}]]> + - Water + Water + + diff --git a/application/src/main/data/json/system/scada_symbols/right-analog-water-level-meter.svg b/application/src/main/data/json/system/scada_symbols/right-analog-water-level-meter.svg index 8658a6dc3e..739505d421 100644 --- a/application/src/main/data/json/system/scada_symbols/right-analog-water-level-meter.svg +++ b/application/src/main/data/json/system/scada_symbols/right-analog-water-level-meter.svg @@ -1,6 +1,5 @@ - -{ - "title": "Rigth analog water level meter", +<svg xmlns="http://www.w3.org/2000/svg" xmlns:tb="https://thingsboard.io/svg" width="200" height="200" fill="none" version="1.1" viewBox="0 0 200 200"><tb:metadata xmlns=""><![CDATA[{ + "title": "Right analog water level meter", "description": "Right analog water level meter", "searchTags": [ "water meter" @@ -38,18 +37,22 @@ }, { "tag": "icon", - "stateRenderFunction": "var icon = ctx.properties.icon;\nif (icon) {\n element.show();\n} else {\n element.hide()\n}", + "stateRenderFunction": "var showIcon = ctx.properties.showIcon;\nif (showIcon) {\n element.show();\n var icon = ctx.properties.icon;\n var iconSize = ctx.properties.iconSize;\n var iconColor = ctx.properties.iconColor;\n ctx.api.icon(element, icon, iconSize, iconColor, true);\n} else {\n element.hide()\n}", "actions": null }, { "tag": "label", - "stateRenderFunction": "var label = ctx.properties.label;\nif (label) {\n var icon = ctx.properties.icon;\n var labelTextFont = ctx.properties.labelTextFont;\n var labelTextColor = ctx.properties.labelTextColor;\n ctx.api.font(element, labelTextFont, labelTextColor);\n ctx.api.text(element, ctx.properties.labelText);\n if (!icon) {\n element.transform({translateX: 10});\n }\n element.show();\n} else {\n element.hide();\n}", + "stateRenderFunction": "var label = ctx.properties.label;\nif (label) {\n var showIcon = ctx.properties.showIcon;\n var labelTextFont = ctx.properties.labelTextFont;\n var labelTextColor = ctx.properties.labelTextColor;\n ctx.api.font(element, labelTextFont, labelTextColor);\n ctx.api.text(element, ctx.properties.labelText);\n if (!showIcon) {\n element.transform({translateX: 10});\n }\n element.show();\n} else {\n element.hide();\n}", "actions": null }, { "tag": "pointer", "stateRenderFunction": "var valueSet = element.remember('valueSet');\nif (!valueSet) {\n element.remember('valueSet', true);\n element.transform({\n rotate: 0\n });\n}\n\nvar value = ctx.values.value;\nvar fullValue = ctx.values.fullValue;\n\nvar degrees = Math.max(0, Math.min(1, value/fullValue))*179.99;\nvar rotate = element.remember('rotate');\nif (degrees !== rotate) {\n element.remember('rotate', degrees);\n ctx.api.animate(element, 1000).ease('-').transform({rotate: degrees});\n}", - "actions": null + "actions": { + "click": { + "actionFunction": "ctx.api.callAction(event, 'displayClick');" + } + } } ], "behavior": [ @@ -354,7 +357,7 @@ "step": null }, { - "id": "icon", + "id": "showIcon", "name": "{i18n:scada.symbol.icon}", "type": "switch", "default": true, @@ -369,6 +372,54 @@ "max": null, "step": null }, + { + "id": "iconSize", + "name": "{i18n:scada.symbol.icon}", + "type": "number", + "default": 14, + "required": null, + "subLabel": null, + "divider": null, + "fieldSuffix": "px", + "disableOnProperty": "showIcon", + "rowClass": "", + "fieldClass": "", + "min": 0, + "max": null, + "step": null + }, + { + "id": "icon", + "name": "{i18n:scada.symbol.icon}", + "type": "icon", + "default": "water", + "required": null, + "subLabel": null, + "divider": null, + "fieldSuffix": null, + "disableOnProperty": "showIcon", + "rowClass": "", + "fieldClass": "", + "min": null, + "max": null, + "step": null + }, + { + "id": "iconColor", + "name": "{i18n:scada.symbol.icon}", + "type": "color", + "default": "#0000008A", + "required": null, + "subLabel": null, + "divider": null, + "fieldSuffix": null, + "disableOnProperty": "showIcon", + "rowClass": "", + "fieldClass": "", + "min": null, + "max": null, + "step": null + }, { "id": "defaultBorderColor", "name": "{i18n:scada.symbol.default-border-color}", @@ -610,9 +661,12 @@ "step": null } ] -} +}]]> + - Water + Water + + diff --git a/application/src/main/data/json/system/scada_symbols/stand-filter.svg b/application/src/main/data/json/system/scada_symbols/sand-filter.svg similarity index 99% rename from application/src/main/data/json/system/scada_symbols/stand-filter.svg rename to application/src/main/data/json/system/scada_symbols/sand-filter.svg index ebd1e28edd..1f9c0293d9 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-filter.svg +++ b/application/src/main/data/json/system/scada_symbols/sand-filter.svg @@ -1,9 +1,10 @@ { - "title": "Stand filter", - "description": "Stand filter with configurable filtration mode option and various states.", + "title": "Sand filter", + "description": "Sand filter with configurable filtration mode option and various states.", "searchTags": [ - "filter" + "filter", + "sand" ], "widgetSizeX": 3, "widgetSizeY": 5, diff --git a/application/src/main/data/json/system/scada_symbols/vertical-ball-valve.svg b/application/src/main/data/json/system/scada_symbols/vertical-ball-valve.svg index 3aee266486..f284c7f86d 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-ball-valve.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-ball-valve.svg @@ -93,7 +93,7 @@ }, "valueToData": { "type": "CONSTANT", - "constantValue": false, + "constantValue": true, "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;" } }, @@ -127,7 +127,7 @@ }, "valueToData": { "type": "CONSTANT", - "constantValue": true, + "constantValue": false, "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;" } }, diff --git a/application/src/main/data/json/system/widget_bundles/scada_fluid_system.json b/application/src/main/data/json/system/widget_bundles/scada_fluid_system.json new file mode 100644 index 0000000000..bcb92dce1d --- /dev/null +++ b/application/src/main/data/json/system/widget_bundles/scada_fluid_system.json @@ -0,0 +1,74 @@ +{ + "widgetsBundle": { + "alias": "scada_fluid_system", + "title": "SCADA fluid system", + "image": "tb-image:c2NhZGFfZmx1aWRfc3lzdGVtX2J1bmRsZV9pbWFnZV8oMSkucG5n:IlNDQURBIGZsdWlkIHN5c3RlbSIgc3lzdGVtIGJ1bmRsZSBpbWFnZQ==:SU1BR0U=;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAChCAMAAAC1fQA+AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAJcEhZcwAACxMAAAsTAQCanBgAAALxUExURUdwTIuLi4uKi4qKi319fnNzc21ubnJxcW1vbnFvb5WUlHRzc7S0tI6NjY2NjcfHx4iIiJKSko+Pj5SUlKSkpIGAgIGAgBZ0MZOTk4yMjIyMjF9gYYyMjGxub3FxcV9uZqurq5aVlYqKipOTk25ubm5vcHBycm9zcEGFU3BwcaioqKurq66urjdjQZ+enhNkKmlrbo+Pj7OysnBvcKCgoHR0dKenp8LCwoCAgUyAWxFjKUGEUxJiKlB/XRZxL76+vrS0tBJjKs7OzsrKyhVxMBRiKhVuMOrq6r+/v83Nzenp6bOzs5+env///5iYmKysrL6+vtbW1qenp9fX17u7u6Kiora2tqGhobCwsM7Oztzc3OLi4tHR0d7e3uDg4Ofn58nJyevr6+bm5qampu3t7cXFxYyMjK2trdTU1Lq6uqmpqdra2pqamr29vaioqIPU7oDR67Kyspubm7e3t7W1taOjo6urq6SkpITW8HPF3tLS0q+vr6aqrYjZ84ze+MbGxoSIi7i4uNjY2MHBwWSrwoKBgX5+fuTk5FurxcLCwp2dnXB4e9DQ0MTExIqKisjIyJaVlVSkvnfH4WiaqsvLy4iIiJOSknDB22etxHZ6fTWeU32Agy2XS4aFhfv7+zCbTnZ3d5De966ytCWGQMDAwIuPkn/H3RyEOme20JCPj3/N5nnK43XB2np5eS+LSZWYm3S81Izc9nFydGKmu+/v72ahtJygo2y71J6ipCaRRKfVtPH482uToCSAPiWLQnGwxJeanZWzvYbK32Gcr3/A1VenwHnE3HC1zIbQ6G1vcWqovDqSU0CgXHSrvYrW7/T09HCZpo/U6iqSRzeHTZ26pVKguY6Rlfn5+W2AhoaptZuutJLa8VmWa3ejsX61x1CWY2KxyqWwsxp9NkiMXGeieK6trYKwjnp9gFmTpY3O45G0m36bpX2kiLzPwbGwsFKta16KcEubtUukZLbJu2eJlK3Gs3GWe5SmrMXWysnTy6iuquih9iMAAABHdFJOUwDfYEAQn0DfIJ/fgGCAvyFwn7/vYCBg/r9QkF8wMGCA3GDPIFCw73DewLaXRxB4ZN2v78/FkO+67aM974C/sN96UNWaz4CQZ2JzjQAAIb5JREFUeNrVnXlAk1e2wFEREIeplqkV6zau1S7TbdrpzJt93jQIhgCRJRikUiBAgIQtJAhpAohBlhRCQIUBCw1bpAmUSZ2HMkUEBKUidBzrWhVbrVKntvPmvb/eufd+XxYS9gz4jpJ8+fLlS34559x7v3PPPXFwGFeeGF8c/h/Ixud/89zv3/j171TBu33lsdzQkNzcvXv37NmzA/727s3NDQnlxPIk+arfvfHG73/z/OrHksFx0XPbX5ExFBFFKs98Cc8/llMQzY5jsVgMRm1WVm0tg8FixbGzgETuK9kdrAqTKlhJ65/z2Ph4UXi89nq6V4CMDSBhFEhW2Kc2pMgMhBEnS/JK3f6jx4bF0S0vPCYqiIBIaY1k7b1oQ8LMQGrjogO8gqJi1r/4eKCsdg0U+RGQOHON5OJP/mm+XCqXMj4NNQfJp0BkGMRP5LroceBw9zaB1NIakdMgF6XSYGlSfqjcGoTBjqZAAhN/PO8cT7kmjgNCmVbojlD5jvyLcrkRhEeDGDUS6O3+1HyDLGQaQZJkbAAJUwVbgFj7iBGEbQLhr5pvkJeZlhqhfEQe68vm8Xi+FsLjqSRGkAgTSEpgXuKG+Qb5IQFJRSDR5hrhcENyoSt86623sbz1FvSKuSFcGqTIQiN5fNf5BlnJsIvErZ93jTSo1UomH9SSIoqP8RkZ9UoOkEWzWbWKAmlRmArE09Mz2NMTbYUVSQsUtay46KjUGL/UER/QBbIqJlOpbljwmJgWdvbouLGmtcPctDx9wzx5cWwFT1haWlmZ44VNKz0qJhxo+AseGx8ZHQsSavSRd+AfgMh3M9jcWH9fXkxkZGFh6QgCEab7PGYgIxYgvhYgFs5OgZSWjrDYsmRh0OMEsmsMyG4jyA5KIyaQWGiUMUglpZGoxwokfnyQt8c2v/60RgAk2WsGGnn+xefWr3/llfXbt7+4aA5BrDQiMQeZto88/9wr0XFx7OhoWVJystBn/fKN/x6QAksQytnfMYHId++mTCtqBiCL3ojLgvYbOLyCkr28hKPpIyI7oUwMQkzLpBGOuWmxpgviuD1OkcVAHLLk5PhUoTAofcQnNSbwRTuDyKJZ4/gIpREVKylWGlFky7SYUwB5/tcKmkOWHp6XSnHE+6W4brSzRlhZBRP5CCdYxY319aVNy1wjzMLXXGyOSVdtpx36B9EFNEdSQHJ8vJEjXJTivtqOIMkm0+JRMZQxprU3N5TL8UXNL/SHpWYg3nnMUvlaFxvya6ZqFdn6DVthxgHuQXGEA0dgoHKRnTWimAwkVkKBmDQCHyQRQA7+3Ya8z1RVRoIUKoEjzsQB31lAFMWxK9DbO2/WOqFB0jHIFDSCnd0MJBVAvBFIq0F3w4CkHv505QZDV0d9fRJTxUwGEcoUCna0D+aI5vk+GL53Z/gRRzGKOUAheYmuT9kFBA17k9i0j4wHEgIayd9tATICILsCkWl1NDY2FTdpmhq78U13U6NGUxzNVMXLQaIVilqv0UDgYHEeXL9ZV3fvSt3NE7cfFcUDB19Zyeczf2gnjQi9ZBOC7KBAJBJe/BiN7MIauZaWkTGQQclAArllM1VeEA7Lr1XUMpJiYqJlnv+6frPm5PHjw9ePnzxZd/P2/6QHejMjG/hwKbDCPj4iTJ4UhMOVcjly/zEg8TRIrz5Drz86qEcy2Ku/3KvXZwBI0sWLHyVl1TLi2KAP3j3AuFBRUXXnelVFxYWTdUPfs/MSQR9KpXKB46xBwuN90m2A7B0DolKwoR+RmkCSwLR8aJAOgUDQKGhshFt809skEGjAtFK5XAXuzoHDd/gWYFQdPnz4/nW4qao4XnNr2ItwqBuWzRYErg2tQDg2QPZyOdCP8GiQuGgEYtRIX1mZtsegKyszaLvqywxlZWVd5QYZU5UYx/YiwxKZdLjm0XWEUVV1u78KbVTcflTzIAVzqBs2zN60YqYGEkL6EZNpeY2aQL5rbz/f3o5uzp8nW1+3t0PzW6gMjCPdeQBvqObsveuAUVVxa6gCkVwZ7q8bUiEMdUNDodPsQAJTwo0gEQgEIqbjgpg7OwyZRk0+snipDXmFqfrh0vUUh+ftuuMVZ+/3V1XUnAA5WVF16/7ZipN1d2IwR2TkT2cFkmcOQmlkAhC5LwUCnQKAGDXCsPl1rndnrHB4heoGfW+erDh8uP9h84kaJCdODD0EK7tw8kQY4SicjW09ybcAiSiaRCNyk0bAR0ymtWCNzdO7OK5xWJ1EOAru1V0Aa6rCHM0nTwIKegwqeaTEHIU5jnYCgWC8VOVpDvKWNchu3uclSJBpmYFMMOpNIsMSyfUa+OBVFcDR3Nw81NwMJNCCVV2ouz/agAfUOWvsAQLTIywACfMcVyOxiixsWp+fPv3ee+/5WGpk/Ld4kRom5p5AllV1/ARw9Pef7W8+iUEOX6jpz8IclTmb7GlaRpDcsRrxjZPy2NEKyeeI4z2TaQVODPIcTGyNRAlHOdhFKsCkmvvPfvstkNScOIlta0gaWdjQkFOZs9ZOGiFTiOOC5JJWS/J5KwFhT00jzyV5pcd7j6bz7n0/fP+fD09gkG++QSA1Qw//eX/4+ysRhaWRldU5dgWx1IitVkvy+WfvtZpMy29SkOTkFL5f+giPaKTGWiMnIsA/qqtz9tsBJIhy9ilp5PR7nwEIC4Pg6ZGJfSQZRxl8uOY+cra/H7wdN1vgIywUg83J2b/JHiBGjZDZ6fFAkEawjxCNRMVM6iM/GsUcqTxotQ4bW61+s1brdjjhOOY0axB6UtcmyNtmIHKikdPmrdYkIKtTyVUt+46pH2lGGFQ/crxuWI059lfboR8JGjPNbksjoXIeVw6RYcq00Oz0VEzL8XUqyvAv7CSHHw6Rnr0G9+yo0VIRjv2vOtgPpMga5B0cDsL9iJRDTOsANi1oVoOQs08C4vAaFS3xvA4qOXv/VsUFPNaqqahAY63jMNYiHMeWzBbEz8y0VOObViwHJt0LpADSSvsINRc6MciyVBL1iZfXnDw7jEa/FRVD/RVo+Auj35ohKcVR7TRLEJFNkLHTI9hHODBEkXyOLGsaII6vU1Gf6HtDj66Q65Fb16nrkQc3HzUQjmPODg4ey1+0eXnlst1t1WQg3hYgYdYg5s7OMbVaqeypgjgsJ1GfQO+ie1eoK8QrV/AV4oWaK3fSEQZwVEMvspwh3G7rDG4q5iSzlE8m2gKR29DIHqKR3dBqZZNWyzTNPgnIRm/CkZcnvXOz5jigVN2+DQYG1+wn7iURdRw71gL3DQxhYrWZHKLuc1RMEdlqeXWx0xRAjIkP1rPTO/D0iJzHQz07gKSagfAnif2u2oU4vJl8fsTwUB1EUS7cv33h+MmauusPUnL2V+YARnW1MsrHh88Q/ne9rry+vt6A/wzlN+rrr2XXn1cx99XfgCduiHtKDm52mYpGgifQCICQfqSvFUxr6iCOriiamBgJUYbA2OEhiGvduV1Xd/P69xENoI/C/S3AcQzOvDucIfy8GIJixU0QHdNqihu1sNnZ3X1VxfxCi6JlZZ3i+hvtzi4TgVhP6lr4CJpViKBBwN2nYVowMcL0zlNH5uAoQ4zn/3x/5879O8M8GXHz6jNnwHi474CkAwiExAbSQDLgH5GM3ksAkgBbg41pArGhp/3VCUAsU1FsasSfjRMfEEjrez7miQ+TTiss4yfy1UoSLWmIVKfExPMjqW4QvKO6+oznn5B4MYRfdGbqMzMzL2fAjf5oZ2bmIDxEIBloV0bGYKO45/Tfl06kEeQjk2RwyCOgHyn44osv9u2jMzjCpwTi4KaExAIlFWVAl8qVRg5wkDPCXCw+oBEBLQmN6EbQCbcIpLEXHmsaB/QCTX3bFquW0dxHppqK4jk2p4bPnDxu4KY25yg14wB95BUQCQRnRxExgxZuyzQ9ECvDd8hH0P6eMg0ENDVlhr+Pbbpe8FixYsVCJD9G8iNKfjCe0Afgo/HrFq5AMoXh3s8iTRyF6v37TRwt6ry8PG8kSgBpK2m7eqqtre1q2znYgg24a4dWC/Zfgh09CfoMQVf71nmbCHepbChtoO0qp7L6GM3RUr3/2ObFRBYwhK6LlyxesgS2l4DgG7jboGK+Dg9g58EbhqaExvqSJfMGsrVUDTN0hZHErND1IOZo2c/MU1fShrKc8cprNtuKCHeqZz9oaErLbCw7P38g2wAkXihS5xjdHIaJ1TnxXvEAQscYXZzW2JyLdHRyoVgP3mi6qxeUzZ9GXI6Vqr3jveKKpF5+StyV5zR4J6nCWBhky5TPc1DXKMgUaOZLI45PbN1fqk4MH2VHBPtz93x08U8XP30nl+sfLGUHifgNldWbnpri1eHBa90ZmYKe9sXzwvGEPydMGobz2FACG2SwQSYhXGCmp4bDRKo6shRszXmKIDeKM/Rd82Vaz3ND0XhTArmQEVksKoyE+h+Y3oksrERxh+ozU9Ks08G2c9e6Ovq+2+w0LxrJhyz0ooIsEq8gSR8UA3b5FpApgWxXGYUxhySOa9e9+ea6TdAOPf8DUz9K96FrkTxjlCl9LqfKQqOsmSsMp182D926cuXWUPMvN9nrnCtMia2ypXPU3P6y+TbjnZ0guQ8eNr/pYq/TOrf1dHd29bQ5u8wRx7O3GDuN8uD6s/Z6X+c+8eDRtOI+57niuPLOTjN554q9SJyzxY0ZaU0dcwQyhgOTONoH5JomITOha6oaWeb002m97wqPZebf+LpmxHHxox1/grtP374It5yhdeYaW7rCY1qf382J8m3nNl1C5qA2e2ogLoxI1bSa6fUihpu5YX2MtPBRiOQjwNkh90eP7v3C7KtxY4jWT6sFVEUyXCjTKuuFK6uJQRy3bnYmAiBbnKch4SLGz8weYoXsfDtY+unOnX+KlYbixmvI7Iw/Y4hE0zm/M4CQjZZz2qY0gaZnAhDHpVu+Kykvb+1ozW4DkFMd51rLy8uz4a+vHG129KHt8mtt6C4bbrJhTzY8lZ2dvU/EOA/PlBN5+E/iGBct7m5fKe+DYzvQ8ecZon3ZHeRM6A3wuTta8avRe+HT9+Fj0ZtklwBIW+u58r7s1p7egcsCcd+2cTnWOH+XbdBotWKNTtsDIOeaOrXa4u7iYl1xcXGnFv508ADfiYvFxd30HnhJsfgLEeOquFOHj+8S3xreufMvY2TnzuFbTV1wLH7RVYboCy0cDy+FE4jFjV1aMT4TfgPqNFq82aiDp84BSI+2q7hYXCbQZzQWG87/dPyepqS13gBBi7SEhLtdAHJNkDbQhaJKCWkooiRAUSVBwkAnPN2YgESQQAR2CQDkEw0cn4CPH4Iu5C//hUXIIPcAUjBEveBuQsIlhuj9zrS0uxp0fAJ5FQicfLAxAU5jIbDrGoDAh2kcTNDo9RDZOnBw3NZ8c/sNXVOnPg2SrTIzOwGkK/MobB0dRDEmPYSUyKOBTFPUaeAoPLqMHvUCyCXqGX1mb3OYEYTBNIKENfdCiEqPTwMgX2SQ4wfwmeBt9NTbGd9Wr4cnyV4E0on26NMyOjW6G9+NO4pfAxf1xQK9vlvQC9831gj5znvpr34A6QEpoxftFVC70ZeYMKhBIMbjE8w0smePEYSBNYJOP9CJQAT4WAE5E/y/K0DPkO00i7dNu9sBILq72AwEhvrW9vEHKD89byhuzNA3lonBOrGP9InF3bpugxikSycWa9GdFj0Sa3U6dNcND7vBpXq02jLsI2Kxjhxhw0ceIB8pQ6cpRqdBPgKPug34TBodbJfBCcvwy4t1WrS72Pi2YjHxEZ1GXKbVGA58N8FAa1ufVnB5oLenFTdRqNUqgQajDVqNc63QfHWcgjYE2iuQvmzcTrWhZ69CE4cPQq1WditpldqyH97eaUNuP2w91wYNFHo5arVa+9Cx8AbQMLXCzlb8TDY0m+Q05fhtW/HbnkKtVnYbtGt95/++ZekEnbVzDyi1SXuuxdiPTKuZF1n0I1uGONSHL/KRhtCDlCHnmfcjW4z9yKuL1zpOPBbTavS9YqrDhJ49Yno9++vmPbvjL+5Rnz5EKvuI2rz3rF169knHYq3awcwEXRvVYa5wml6m5CaPFRZjLaNKjBLbbDHWWrZpemOtZVP9QM59XTCo1Fyz0+j42evWo9+5GXc7dzQlZDSKs+0E8u+7HplcI8UJRwfEdrvwgivERyYORv9ccaBL4a7ObjteCrssab7+KBdRcANuDb3pODccS82W3S6z10nXvDnUPHTl+lDzL345ZyEoJxwoSo1Et3Z8U0enrevWbXWaiTaeWrRw4TK3ZQs9Fk3r1W4QuVME7JFlwf0yh3kWx4WrNrjDjCMlSveVq6ZOs+nE0K3Rt5NuDZ1wmmcKt5WwmJtfWlkIs3F5DTCJkpPIZzLVTy6cGsvP6473j76VDDlHLvOJsQhRJCbCZGIiBOmVgZUwL9cCqQawMoPpvnwqa35+Alnr6blCAPnJfGIABUyKBgbuShGJRIG7RKUo+yQFp38Ai3IKKL8CEB/u/wLIH+cLYzXBwBDhfn7xMSClaGYLMr3QwripofwBQGJ8wwHkV/PEAQkFGEMkQgypqT4+qalRkSibAIDi/URocRxUM3BdOOFZXngaQMKDPwaQp+cFY+MGjJEiCkcUUSPp6UFBUVGjkWjGdCQKSjNA6hqFsnwir/85gFwQSUUI5IV54FjoTqpOAIZP1EhQ0KgwPd1rdDQZtVrH8JreqFQKBZQygXn9BED6WfLoswDy8/kwKz6og2CkBwm9vJKFynAZiBrNY8MCAS9YR4oqZoCveCfy3cdfRvofT9f1f//t4dsPKuqenvtmyw3MCpzDD2wqfVTolZwkgzogkHgvi1MiEABKgmRujAJKAfNSLpwA5P63h7+58O2deQBxQ2UnUpA6RoK8ILdHxoYKZVCfjM3OUkJywX5qXSygGCuYjEsCIHeOf3P427rv657+z3nigGI5o14BkDUGFFkKhaKgtjaCibIksmCtMpuNtQJKiQ/HJB7jgvyz4ptv7hwennOQZbgMSHgMWvacDNqIQxQREVJpUVFYGL8UljFEFChQWRmMAgnThGScRcoAMjR8+HjF9/1zbVoblXzMgRYLQ4kchFEghdwCSC6ARNE8GI3nQHpBBKqQgwoToAl6Mrvt6jhuq3Xv3jBqtX47lxxPuVIp7ZgDVfoBXSCI9GSo8hPsDSvIK1GqBKBk1SKlGEmYT9o6328BpOrst2er5rr5XY4WphKOJKhYBOvpEYanZ1hAVhY7Kx+D4MpFgKLIYqGkPeMiIlvXGy4Y5BsMMpcd4kKlWVkASKkswBjBwfm7IU8aJBCB7M4PDvZEFZigQgGlE7zUw2aVNRPIH+ZSIa4kMx9x4Ep+wIExYLEjjwe5lbsg5a4U0oHzg7FSCrLMM0KZL9se/VIgv5rjltd8FQ7mIBi+/v6wYjgFgUDuNxRUREqRRlAkUGgCGZeNHv6PRpCfzKWno5Y33rSYE3EgDF9/KEoAVYpiRZDOWSqHuksSST5FwiILa3G28Uob3m4E+fmcdiF47Qqp0oBW1yIOHixVk8fGxnJA9n399dfvxsqhGAAPlOKJrYtFlnaNo5IXYNUQtFoVJ2/Ooa+7UivQcTZ7AaUPpI7YWH9FGBeKA3xy4PTpU5zYWKwUQoKrKuLCBqASqyb4x0KTrJizJosoBCqyyEgOOOZA6uBwuMG+HH9OyCcdBw6c4nI4JpKiCAU2LqIS5dhecZHaGH1xnzyMssbJyWmRUeDBzAIWeA1OvE8QLsiCF0Bijli0LCo0JCSEy8395D0ACeWiBHBYI4yqEaqkKH0NJREiL2G6jW0+JHJaYieNa7mcOXTk3Q8+/Hjf++/v+/OHH7x75NDmGbm6EjdZWCHGXHZ/rA7AIJWGPzlw4MapkFBUjiUWk1DJ7HgpEajEyt1d1m5pv3ru2tWr7VvWTho/cmoZC/LqTC0L1TEBDwGFYMPC/sHBBZOhVDIk5wNI66ncEFSiAawLG1dYUQFUg4ViE5CUD+5u1SmiGavMBG3rFKLxm6xAXpoJyMvIstC6QcpDKMPCHKjsMwVyoA0q5BhJSPFRqP/hle6D3N16nOLcqkuD7KFzUwB5xgpky0zbLLAs6EPisgrIEmFfigNRhMDqCAxyao+RxFgyGcpmgG2hpUTLrUDOaRL0CcVTyedaZwVyZoYuAkX8YNV2NIteEUXqASAOTpYEKQWBlOzBJJRKcMOVFYc6RdxuuVqbljjt8l0xbVprHGw3Xmtc1tgCcXF0mV7Op6OTB3YR6ESSaMsyU8gO0IhcwqE0Qhbc4fpLtG1FBwhR5rCNBhhSBcG0xOUExFG2gGHzk4W7M9YusQHymqvMbTogS4XLofwHbnyhzSqQktWPVKGfPaQwekjuDsq0jCox2RY4CeoTE5ljrxSdy3WNCcWG1i143cZmmGffRq3hoBZz4M3FQqZ820vWIJtfFzE2LCYLPKhjlyym/5Gz4NOQ/7C5gfEyPw+69SjU+GbRlhVLVZrA9d1huSCAZGONGJegI9uinYR4+9gwxOarGpQ/1HG+pP1qyfl2AGkvOV9CyXnYU4L/AKTykDVIQ7yI0Y4PoI4vaSd3SOi9JeSM+Kh2xgI+8vUocJG4sYsGMcUOJEgjV/GOPci2cLsFTlJQi4rkQIkyG83W0naDtlGf0dlV1tNVVlaOc1G6DChDRAzlgMSwuKmss8dgAJDEUmuQUR+cr9WDc0dQYgksixJ3dxnwQqlr+A5VE+rWGcjCqbKrjAVUo4V8fWxNRcKRu3cH7SOmImXYSQqyyCjFVt++puWGoRNWL4mhElOTQIfztQS9GkEvLtGECzWhAk0AMqK0BmGnQ3YQHNzVBIf1kopO8JpBjUDQ2dh7Vwev7kWn6cWngmVslxju0K/7mYPwjCBIJJIduWY+Au5uBkKaLQJi1f5u+ypb19R4OQFSogaOonytawOoUFYmur2sH8QP9BkAws6zBvEUQuIZPkKPDjwKmVzk0WX8kNo9oCfFt2DrEqMBgaSOeFmAcI0aCeZyJXIEkn1qB+UkXFMZayOIjY5kzZa2+rKmhLTGy1CqTIPztQaghllGbwas0MwYTMgY1GRkCAAkmW8NEjwKGsHHZgym4ZJnsLyzE+4ud5K9l3tJITR4XgCP7mKQXX62TQs7idFHaI3YBMmzBnHYevCzG4ZuWCCraWy6BiAdTU2wYLYYbqGWHNps0nRrAUT0gTUIawR8BB1fDIfBgdom/MJuctfUjU7QBImK8BT8L26CnEZ3/oQ+AiTQfH3SR/sIXRDWyrRsLHPf5PwdFPuqr+/R1SNnb6unljHf0PWUo7XM9V3Z9QDScMQaJDAG8rXg0B54gaG8vqu8vgMd31ePRZcNNz31XR03dLAWWncNDrpKtVoYBDe/BIRrphELHzE5O2q1JnB2Mgbe1nKQCIDQmxYCIMdarEH2Q97vEdNRhyzubMkRxg+p5hcNteBihG5+cYEGohECUm7qRzj0GAU1v8lB44waaRgsTgCyyVYlTADZutkaxAkysVe5TENWMV5GPTvpEGsLqAINxqEW7hH3mPsIVd2AZxo14uGvzUiK+VBo5dLtNi/7nnN7zcXWWGvVqpXTWuzisX2ZaYgCYy1yNUJsC6lkjydnD2yQQSM83Dt2+IuGKH4pNoYo05DFaPYVJmbC42EyDE+2ls4gYrGavq6CCIrxcsQ0ipdIONSgsY1SCNd4QQKX7TI0aESjX/UsggYvCsfK+hlkmzgqjT1iXBZVaoIa/u4lpgWXJPQwnr4ewS4iNfq6jWvdaclLLdVH3v3bhx+H7/srsqzqlmdmcpaVeIwCQS10yV5koZK91DCFvrDKRZGI2Fh8rauyHDPO6scpth069O67H/513773P/7z3z5499DMCrOsIk4CthVtLAhAqYQ4POUjbXsxB/YQcl2lgDCKEIdRJvP1SWSzOUgkjIZnBLKISQYp2LYKUMk400U7CqKQa3YYxtMcRoXUUoEtuK5yn1VkbQkC+asZyMxWBKK+XUQCplR8TiIhYRRAgaBWaOhe7CMhoSYOT/QzGyhoGuQzzgBl2iAm0/qyZWYBOjdkW34oHiSLIwUi8yVUQIgbG6CAEF0I9hEulwRNwbCMCsHRILAsj1mBrAOQQqNGjnzZMrOExdXUpAJWCerdjSSAIo/NV+WHEhDMwaM4SBQ7CLdZibP81ZN1Fho58uWZGZ5nJZ+oRGge/CXRXxyL55AgNsIgHHTRDFQL1m+i8ckU5ZlDX5p8ZBYgi3CJ3hgf0y+GwDQPNT0C8wr+/pxPyk8fOCUnEyTBVDAe/VYTqsSNFPLUbEEsNfLSTE+0kknPvMmowuIw8UZmevxxIPrSZ6ARX18yZYUm3xRZdDGslHFGvtMGMWnkyIxBFlnX6FXRU4i+vrsl/pdOg0Z4eBKRcNQa644Gzl4hDk4HLTRyZNtsZ6cDG9Q+Mjw5XUTPhhYUwOfnAchnpyT0tG4EyhqQiRoaUkgd7oWznaFZc9BSIzMHcXRH/u5dOBpeOYpJIqj56bAohZSlkADI6VPBwcHURDtKGfApFYpycO7DytlyOLi00CB/xj6yeean8kCZKOpCHisyPADlodA/cQQsIPmXoLLaV57U7xxlMeKiZQHqSE5yZOJ40+wzAPnQCHJkNnUkVgGJMofH2O8HKTWQM5CFUXCZC2mRJwIpwcUu6GQUYWAOx6s0cJzEh+nKmS8tNDKbCtCOkMzoXenLaIiCzDmU41SLs2qAJQyyObBGpDinBsq1www7JDpFcoRM4LDLb7JZmtaRdbNKD4LsB6UvyzsmCmrwo5/QwnlOBZBbAzwYhM5yQrlB0IEoOULgWGkPDoeX6CGKHUAQidqXleeHEuiQUtAvfMLPeypQ7tnXUFrtq1oGxqBT6JRcYSJ/g32WcbxkaVrPzO5sq10bfFmJKPcMUhrRD5uhXMDUZMiaY3z92WeflbCpTMBR+IUmuLhWc4X8BXb61cJXTSAfAMhsa2xsXODLYlJZjYCCWUbjR2KEbATyFfV7JSg3Mx4yGhu4wg32Wlaz2QLk0KwXOGzyZSlRErYfzpcdRfmyAQFJkOCIQahsWR+S+JsHIHZbHrTOAqRl1lkfTr4sNUnEBhSUhx00imi8vDCI8bdjSNZvJFdot+SLF5zNevYv1znYAUQZiHKx6ZxySMceGUn1Cfr6H//4x1fol2Ni/DAGZJR7F9oRxMFlGz3W+uBndigGByCpEuhQCIrIzy8GpflDO/Z1G4DgyrQkMZ6vdA9R2xPEwWHthr8ByF/dV9mj/XDyjUsNXbHQFf0uI1l3IQoP9wPlYI3AootdZNUFc+XG5W/bGQQmyj0WLlxtH7cjIJDV4UqvhAnkN6SIUlLaEUggpkAYEPtBIKMOj6c4PuGhCoiRrUTrKRYtV6O1SQCTqGxQemMQQuHuBlHeJ37/6wjmbp+NTz2WIL+LVUXH8KEyK279HD2WuzJhuVgiEqjB1aCGSq6uq0gg7gdSiTxMFsMs3fo4grwRF5UXub/F7LOt9nB7eaUr5DOq3V03LF/mYWbAb7BTEyP3n7GslP9/K5/YJIXJyFEAAAAASUVORK5CYII=", + "scada": true, + "description": "Bundle with SCADA symbols for fluid system", + "order": 9300, + "name": "SCADA fluid system" + }, + "widgetTypeFqns": [ + "horizontal_pipe", + "long_horizontal_pipe", + "vertical_pipe", + "long_vertical_pipe", + "left_bottom_elbow_pipe", + "bottom_right_elbow_pipe", + "top_right_elbow_pipe", + "left_top_elbow_pipe", + "cross_pipe", + "left_tee_pipe", + "bottom_tee_pipe", + "right_tee_pipe", + "top_tee_pipe", + "right_elbow_drain_pipe", + "left_elbow_drain_pipe", + "left_drain_pipe", + "right_drain_pipe", + "short_left_drain_pipe", + "short_right_drain_pipe", + "top_flow_meter", + "right_flow_meter", + "bottom_flow_meter", + "left_flow_meter", + "horizontal_inline_flow_meter", + "vertical_inline_flow_meter", + "left_analog_water_level_meter", + "right_analog_water_level_meter", + "leak_sensor", + "centrifugal_pump", + "small_right_motor_pump", + "small_left_motor_pump", + "right_motor_pump", + "left_motor_pump", + "right_heat_pump", + "left_heat_pump", + "short_bottom_filter", + "long_bottom_filter", + "short_top_filter", + "long_top_filter", + "sand_filter", + "horizontal_wheel_valve", + "vertical_wheel_valve", + "horizontal_ball_valve", + "vertical_ball_valve", + "water_stop", + "vertical_tank", + "stand_vertical_tank", + "cylindrical_tank", + "stand_cylindrical_tank", + "vertical_short_tank", + "stand_vertical_short_tank", + "large_cylindrical_tank", + "large_stand_cylindrical_tank", + "large_vertical_tank", + "large_stand_vertical_tank", + "horizontal_tank", + "stand_horizontal_tank", + "spherical_tank", + "small_spherical_tank", + "elevated_tank", + "pool" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/scada_symbols.json b/application/src/main/data/json/system/widget_bundles/scada_symbols.json index f1fbfbc297..4de61d2b05 100644 --- a/application/src/main/data/json/system/widget_bundles/scada_symbols.json +++ b/application/src/main/data/json/system/widget_bundles/scada_symbols.json @@ -3,7 +3,7 @@ "alias": "scada_symbols", "title": "SCADA symbols", "scada": true, - "image": null, + "image": "tb-image:c2NhZGFfc3ltYm9sc19zeXN0ZW1fYnVuZGxlX2ltYWdlXygxKS5zdmc=:IlNDQURBIHN5bWJvbHMiIHN5c3RlbSBidW5kbGUgaW1hZ2U=:SU1BR0U=;data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE2MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMTI2LjA0MiAzNS42NjY2LTIyLjkxNy0xMy4yNWMtMS45MTctMS4xMjUtNC4zMzMzLTEuMTI1LTYuMjUgMGwtMjIuOTE2NyAxMy4yNWMtMS45MTY2IDEuMTI1LTMuMTI1IDMuMTY2Ny0zLjEyNSA1LjQxNjd2MjYuNDU4M2MwIDIuMjUgMS4yMDg0IDQuMjkxNiAzLjEyNSA1LjQxNjZsMjIuOTE2NyAxMy4yNWMxLjkxNjcgMS4xMjUgNC4zMzMgMS4xMjUgNi4yNSAwbDIyLjkxNy0xMy4yNWMxLjkxNi0xLjEyNSAzLjEyNS0zLjE2NjYgMy4xMjUtNS40MTY2VjQxLjA4MzNjMC0yLjI1LTEuMjA5LTQuMjkxNy0zLjEyNS01LjQxNjdaTTc5LjE2NjcgNjYuMzMzM3YtMTkuMjVsMTYuNjY2NiA5LjY2NjZ2MTkuMjA4NGwtMTYuNjY2Ni05LjYyNVpNMTAwIDQ5LjU0MTZsLTE2LjY2NjctOS42NjY3TDEwMCAzMC4yNDk5bDE2LjY2NyA5LjYyNUwxMDAgNDkuNTQxNlptNC4xNjcgMjYuNDE2N1Y1Ni43NDk5bDE2LjY2Ni05LjY2NjZ2MTkuMjVsLTE2LjY2NiA5LjYyNVptLTI1LjAwMDMtNjMuNjI1SDY0LjU4MzNjLTMuNDU4MyAwLTYuMjUgMi43OTE2LTYuMjUgNi4yNXYxNC41ODMzaDguMzMzNHYtMTIuNWgxMi41di04LjMzMzNabTQxLjY2NjMgMGgxNC41ODRjMy40NTggMCA2LjI1IDIuNzkxNiA2LjI1IDYuMjV2MTQuNTgzM2gtOC4zMzR2LTEyLjVoLTEyLjV2LTguMzMzM1pNNzkuMTY2NyA5NS42NjY2SDY0LjU4MzNjLTMuNDU4MyAwLTYuMjUtMi43OTE3LTYuMjUtNi4yNVY3NC44MzMyaDguMzMzNHYxMi41MDAxaDEyLjV2OC4zMzMzWm00MS42NjYzIDBoMTQuNTg0YzMuNDU4IDAgNi4yNS0yLjc5MTcgNi4yNS02LjI1Vjc0LjgzMzJoLTguMzM0djEyLjUwMDFoLTEyLjV2OC4zMzMzWiIgZmlsbD0iIzMwNTY4MCIgZmlsbC1vcGFjaXR5PSIuNiIvPjxwYXRoIGQ9Ik02Mi41ODI4IDEyMS42MjVoNC4wMjM1Yy44NjQ1IDAgMS42MDE1LjEzIDIuMjEwOS4zOTEuNjA5NC4yNiAxLjA3NTUuNjQ1IDEuMzk4NCAxLjE1Ni4zMjgyLjUwNS40OTIyIDEuMTMuNDkyMiAxLjg3NSAwIC41NjgtLjEwNDIgMS4wNjgtLjMxMjUgMS41LS4yMDgzLjQzMi0uNTAyNi43OTctLjg4MjggMS4wOTQtLjM4MDIuMjkxLS44MzMzLjUxOC0xLjM1OTQuNjc5bC0uNTkzNy4yODloLTMuNjE3MmwtLjAxNTYtMS41NTRoMi43MTA5Yy40Njg4IDAgLjg1OTQtLjA4NCAxLjE3MTktLjI1LjMxMjUtLjE2Ny41NDY5LS4zOTQuNzAzMS0uNjguMTYxNS0uMjkyLjI0MjItLjYyLjI0MjItLjk4NCAwLS4zOTYtLjA3ODEtLjc0LS4yMzQ0LTEuMDMyLS4xNTEtLjI5Ny0uMzg1NC0uNTIzLS43MDMxLS42NzktLjMxNzctLjE2Mi0uNzIxNC0uMjQyLTEuMjEwOS0uMjQyaC0yLjA2MjVWMTMzaC0xLjk2MXYtMTEuMzc1Wk02OS4wNzUgMTMzbC0yLjY3MTktNS4xMDkgMi4wNTQ3LS4wMDggMi43MTEgNS4wMTVWMTMzSDY5LjA3NVptNy4zMjUuMTU2Yy0uNjI1IDAtMS4xOTAxLS4xMDEtMS42OTUzLS4zMDQtLjUtLjIwOS0uOTI3MS0uNDk4LTEuMjgxMy0uODY4LS4zNDg5LS4zNjktLjYxNzEtLjgwNC0uODA0Ni0xLjMwNHMtLjI4MTMtMS4wMzktLjI4MTMtMS42MTh2LS4zMTJjMC0uNjYxLjA5NjQtMS4yNi4yODkxLTEuNzk3LjE5MjctLjUzNi40NjA5LS45OTUuODA0Ny0xLjM3NS4zNDM3LS4zODUuNzUtLjY4IDEuMjE4Ny0uODgzLjQ2ODgtLjIwMy45NzY2LS4zMDQgMS41MjM0LS4zMDQuNjA0MiAwIDEuMTMyOS4xMDEgMS41ODYuMzA0LjQ1MzEuMjAzLjgyODEuNDkgMS4xMjUuODYuMzAyMS4zNjQuNTI2Ljc5OS42NzE5IDEuMzA0LjE1MS41MDYuMjI2NSAxLjA2My4yMjY1IDEuNjcydi44MDVoLTYuNTMxMnYtMS4zNTJoNC42NzE4di0uMTQ4Yy0uMDEwNC0uMzM5LS4wNzgxLS42NTYtLjIwMzEtLjk1My0uMTE5OC0uMjk3LS4zMDQ3LS41MzctLjU1NDctLjcxOS0uMjUtLjE4Mi0uNTgzMy0uMjczLTEtLjI3My0uMzEyNSAwLS41OTExLjA2Ny0uODM1OS4yMDMtLjIzOTYuMTMtLjQ0MDEuMzItLjYwMTYuNTctLjE2MTQuMjUtLjI4NjQuNTUyLS4zNzUuOTA2LS4wODMzLjM0OS0uMTI1Ljc0Mi0uMTI1IDEuMTh2LjMxMmMwIC4zNy4wNDk1LjcxNC4xNDg1IDEuMDMyLjEwNDEuMzEyLjI1NTIuNTg2LjQ1MzEuODIuMTk3OS4yMzQuNDM3NS40MTkuNzE4Ny41NTUuMjgxMy4xMy42MDE2LjE5NS45NjEuMTk1LjQ1MzEgMCAuODU2Ny0uMDkxIDEuMjEwOS0uMjczLjM1NDItLjE4My42NjE1LS40NC45MjE5LS43NzRsLjk5MjIuOTYxYy0uMTgyMy4yNjYtLjQxOTMuNTIxLS43MTEuNzY2LS4yOTE2LjIzOS0uNjQ4NC40MzUtMS4wNzAzLjU4Ni0uNDE2Ni4xNTEtLjkwMS4yMjYtMS40NTMxLjIyNlptOS43OTM3LTIuNDQ1YzAtLjE4OC0uMDQ2OC0uMzU3LS4xNDA2LS41MDgtLjA5MzctLjE1Ni0uMjczNC0uMjk3LS41MzktLjQyMi0uMjYwNS0uMTI1LS42NDU5LS4yMzktMS4xNTYzLS4zNDMtLjQ0NzktLjA5OS0uODU5NC0uMjE3LTEuMjM0NC0uMzUyLS4zNjk4LS4xNDEtLjY4NzUtLjMxLS45NTMxLS41MDgtLjI2NTYtLjE5OC0uNDcxMy0uNDMyLS42MTcyLS43MDMtLjE0NTgtLjI3MS0uMjE4Ny0uNTgzLS4yMTg3LS45MzcgMC0uMzQ0LjA3NTUtLjY3LjIyNjUtLjk3Ny4xNTExLS4zMDcuMzY3Mi0uNTc4LjY0ODUtLjgxMy4yODEyLS4yMzQuNjIyNC0uNDE5IDEuMDIzNC0uNTU0LjQwNjMtLjEzNi44NTk0LS4yMDMgMS4zNTk0LS4yMDMuNzA4MyAwIDEuMzE1MS4xMTkgMS44MjAzLjM1OS41MTA0LjIzNC45MDEuNTU1IDEuMTcxOS45NjEuMjcwOC40MDEuNDA2Mi44NTQuNDA2MiAxLjM1OWgtMS44ODI4YzAtLjIyNC0uMDU3My0uNDMyLS4xNzE5LS42MjUtLjEwOTMtLjE5OC0uMjc2LS4zNTYtLjUtLjQ3Ni0uMjIzOS0uMTI1LS41MDUyLS4xODgtLjg0MzctLjE4OC0uMzIyOSAwLS41OTEyLjA1Mi0uODA0Ny4xNTctLjIwODMuMDk4LS4zNjQ2LjIyOS0uNDY4OC4zOWExIDEgMCAwIDAtLjE0ODQuNTMxYzAgLjE0MS4wMjYxLjI2OS4wNzgxLjM4My4wNTczLjExLjE1MTEuMjExLjI4MTMuMzA1LjEzMDIuMDg4LjMwNzMuMTcyLjUzMTIuMjUuMjI5Mi4wNzguNTE1Ny4xNTQuODU5NC4yMjYuNjQ1OC4xMzYgMS4yMDA1LjMxIDEuNjY0MS41MjQuNDY4Ny4yMDguODI4MS40NzkgMS4wNzgxLjgxMi4yNS4zMjkuMzc1Ljc0NS4zNzUgMS4yNSAwIC4zNzUtLjA4MDcuNzE5LS4yNDIyIDEuMDMyLS4xNTYyLjMwNy0uMzg1NC41NzUtLjY4NzUuODA0LS4zMDIxLjIyNC0uNjY0MS4zOTktMS4wODU5LjUyNC0uNDE2Ny4xMjUtLjg4NTQuMTg3LTEuNDA2My4xODctLjc2NTYgMC0xLjQxNC0uMTM1LTEuOTQ1My0uNDA2LS41MzEyLS4yNzYtLjkzNDktLjYyOC0xLjIxMDktMS4wNTUtLjI3MDktLjQzMi0uNDA2My0uODgtLjQwNjMtMS4zNDNoMS44MjAzYy4wMjA5LjM0OS4xMTcyLjYyNy4yODkxLjgzNi4xNzcxLjIwMy4zOTU4LjM1MS42NTYyLjQ0NS4yNjU3LjA4OC41MzkxLjEzMy44MjA0LjEzMy4zMzg1IDAgLjYyMjQtLjA0NS44NTE1LS4xMzMuMjI5Mi0uMDk0LjQwMzctLjIxOS41MjM1LS4zNzUuMTE5OC0uMTYyLjE3OTYtLjM0NC4xNzk2LS41NDdabTMuMzMyOS0xLjg0NHYtLjE3OWMwLS42MS4wODg1LTEuMTc1LjI2NTYtMS42OTYuMTc3MS0uNTI2LjQzMjMtLjk4Mi43NjU2LTEuMzY3LjMzODYtLjM5MS43NS0uNjkzIDEuMjM0NC0uOTA2LjQ4OTYtLjIxOSAxLjA0MTctLjMyOCAxLjY1NjItLjMyOC42MTk4IDAgMS4xNzE5LjEwOSAxLjY1NjMuMzI4LjQ4OTYuMjEzLjkwMzYuNTE1IDEuMjQyMi45MDYuMzM4NS4zODUuNTk2My44NDEuNzczNCAxLjM2Ny4xNzcxLjUyMS4yNjU2IDEuMDg2LjI2NTYgMS42OTZ2LjE3OWMwIC42MS0uMDg4NSAxLjE3NS0uMjY1NiAxLjY5NS0uMTc3MS41MjEtLjQzNDkuOTc3LS43NzM0IDEuMzY4LS4zMzg2LjM4NS0uNzUuNjg3LTEuMjM0NC45MDYtLjQ4NDQuMjEzLTEuMDMzOS4zMi0xLjY0ODQuMzItLjYxOTggMC0xLjE3NDUtLjEwNy0xLjY2NDEtLjMyLS40ODQ0LS4yMTktLjg5NTgtLjUyMS0xLjIzNDQtLjkwNi0uMzM4NS0uMzkxLS41OTYzLS44NDctLjc3MzQtMS4zNjgtLjE3NzEtLjUyLS4yNjU2LTEuMDg1LS4yNjU2LTEuNjk1Wm0xLjg4MjgtLjE3OXYuMTc5YzAgLjM4LjAzOS43NC4xMTcyIDEuMDc4LjA3ODEuMzM5LjIwMDUuNjM2LjM2NzIuODkxLjE2NjYuMjU1LjM4MDIuNDU2LjY0MDYuNjAyLjI2MDQuMTQ1LjU3MDMuMjE4LjkyOTcuMjE4LjM0ODkgMCAuNjUxLS4wNzMuOTA2Mi0uMjE4LjI2MDQtLjE0Ni40NzQtLjM0Ny42NDA2LS42MDIuMTY2Ny0uMjU1LjI4OTEtLjU1Mi4zNjcyLS44OTEuMDgzNC0uMzM4LjEyNS0uNjk4LjEyNS0xLjA3OHYtLjE3OWMwLS4zNzYtLjA0MTYtLjczLS4xMjUtMS4wNjMtLjA3ODEtLjMzOS0uMjAzMS0uNjM4LS4zNzUtLjg5OC0uMTY2Ni0uMjYxLS4zODAyLS40NjQtLjY0MDYtLjYxLS4yNTUyLS4xNTEtLjU1OTktLjIyNi0uOTE0MS0uMjI2LS4zNTQxIDAtLjY2MTQuMDc1LS45MjE4LjIyNi0uMjU1Mi4xNDYtLjQ2NjIuMzQ5LS42MzI4LjYxLS4xNjY3LjI2LS4yODkxLjU1OS0uMzY3Mi44OTgtLjA3ODIuMzMzLS4xMTcyLjY4Ny0uMTE3MiAxLjA2M1ptMTIuODQwNiAyLjMydi02LjQ2MWgxLjg5MVYxMzNoLTEuNzgybC0uMTA5LTEuOTkyWm0uMjY2LTEuNzU4LjYzMi0uMDE2YzAgLjU2OC0uMDYyIDEuMDkyLS4xODcgMS41NzEtLjEyNS40NzQtLjMxOC44ODgtLjU3OCAxLjI0Mi0uMjYxLjM0OS0uNTk0LjYyMi0xIC44Mi0uNDA2LjE5My0uODkzLjI4OS0xLjQ2MS4yODktLjQxMiAwLS43ODktLjA2LTEuMTMzLS4xNzktLjM0NC0uMTItLjY0MS0uMzA1LS44OTA2LS41NTUtLjI0NDgtLjI1LS40MzQ5LS41NzYtLjU3MDMtLjk3Ny0uMTM1NC0uNDAxLS4yMDMxLS44OC0uMjAzMS0xLjQzN3YtNS40NjFoMS44ODN2NS40NzZjMCAuMzA4LjAzNi41NjYuMTA5Ljc3NC4wNzMuMjAzLjE3Mi4zNjcuMjk3LjQ5MnMuMjcxLjIxNC40MzguMjY2Yy4xNjYuMDUyLjM0My4wNzguNTMxLjA3OC41MzYgMCAuOTU4LS4xMDQgMS4yNjUtLjMxMy4zMTMtLjIxMy41MzQtLjUuNjY0LS44NTkuMTM2LS4zNTkuMjA0LS43NjMuMjA0LTEuMjExWm01LjY0NS0zLjA5NFYxMzNoLTEuODgzdi04LjQ1M2gxLjc5N2wuMDg2IDEuNjA5Wm0yLjU4Ni0xLjY2NC0uMDE2IDEuNzVhMy43NTc0IDMuNzU3NCAwIDAgMC0uMzc1LS4wNDdjLS4xMy0uMDEtLjI2LS4wMTUtLjM5LS4wMTUtLjMyMyAwLS42MDcuMDQ3LS44NTIuMTQtLjI0NS4wODktLjQ1LjIxOS0uNjE3LjM5MS0uMTYyLjE2Ny0uMjg3LjM3LS4zNzUuNjA5LS4wODkuMjQtLjE0MS41MDgtLjE1Ni44MDVsLS40My4wMzFjMC0uNTMxLjA1Mi0xLjAyMy4xNTYtMS40NzYuMTA0LS40NTMuMjYxLS44NTIuNDY5LTEuMTk2LjIxMy0uMzQzLjQ3OS0uNjEyLjc5Ny0uODA0LjMyMy0uMTkzLjY5NS0uMjg5IDEuMTE3LS4yODkuMTE1IDAgLjIzNy4wMS4zNjcuMDMxLjEzNi4wMjEuMjM3LjA0NC4zMDUuMDdabTQuNjc2IDcuMTY0Yy4zMDggMCAuNTg0LS4wNi44MjktLjE3OS4yNS0uMTI1LjQ1LS4yOTcuNjAxLS41MTYuMTU2LS4yMTkuMjQyLS40NzEuMjU4LS43NThoMS43NzNjLS4wMS41NDctLjE3MSAxLjA0NC0uNDg0IDEuNDkyLS4zMTIuNDQ4LS43MjcuODA1LTEuMjQyIDEuMDcxLS41MTYuMjYtMS4wODYuMzktMS43MTEuMzktLjY0NiAwLTEuMjA4LS4xMDktMS42ODgtLjMyOC0uNDc5LS4yMjQtLjg3Ny0uNTMxLTEuMTk1LS45MjItLjMxOC0uMzktLjU1Ny0uODQxLS43MTktMS4zNTEtLjE1Ni0uNTExLS4yMzQtMS4wNTgtLjIzNC0xLjY0MXYtLjI3M2MwLS41ODQuMDc4LTEuMTMxLjIzNC0xLjY0MS4xNjItLjUxNi40MDEtLjk2OS43MTktMS4zNTkuMzE4LS4zOTEuNzE2LS42OTYgMS4xOTUtLjkxNC40OC0uMjI0IDEuMDM5LS4zMzYgMS42OC0uMzM2LjY3NyAwIDEuMjcxLjEzNSAxLjc4MS40MDYuNTExLjI2NS45MTIuNjM4IDEuMjAzIDEuMTE3LjI5Ny40NzQuNDUxIDEuMDI2LjQ2MSAxLjY1NmgtMS43NzNjLS4wMTYtLjMxMi0uMDk0LS41OTMtLjIzNC0uODQzLS4xMzYtLjI1Ni0uMzI5LS40NTktLjU3OS0uNjEtLjI0NC0uMTUxLS41MzktLjIyNi0uODgyLS4yMjYtLjM4MSAwLS42OTYuMDc4LS45NDYuMjM0LS4yNS4xNTEtLjQ0NS4zNTktLjU4Ni42MjUtLjE0LjI2LS4yNDIuNTU1LS4zMDQuODgzLS4wNTguMzIzLS4wODYuNjU5LS4wODYgMS4wMDh2LjI3M2MwIC4zNDkuMDI4LjY4OC4wODYgMS4wMTYuMDU3LjMyOC4xNTYuNjIyLjI5Ny44ODIuMTQ1LjI1Ni4zNDMuNDYxLjU5My42MTguMjUuMTUxLjU2OC4yMjYuOTUzLjIyNlptOC44MzMgMS41Yy0uNjI1IDAtMS4xOS0uMTAxLTEuNjk1LS4zMDQtLjUtLjIwOS0uOTI3LS40OTgtMS4yODEtLjg2OC0uMzQ5LS4zNjktLjYxNy0uODA0LS44MDUtMS4zMDQtLjE4Ny0uNS0uMjgxLTEuMDM5LS4yODEtMS42MTh2LS4zMTJjMC0uNjYxLjA5Ni0xLjI2LjI4OS0xLjc5Ny4xOTMtLjUzNi40NjEtLjk5NS44MDUtMS4zNzUuMzQzLS4zODUuNzUtLjY4IDEuMjE4LS44ODMuNDY5LS4yMDMuOTc3LS4zMDQgMS41MjQtLjMwNC42MDQgMCAxLjEzMy4xMDEgMS41ODYuMzA0LjQ1My4yMDMuODI4LjQ5IDEuMTI1Ljg2LjMwMi4zNjQuNTI2Ljc5OS42NzIgMS4zMDQuMTUxLjUwNi4yMjYgMS4wNjMuMjI2IDEuNjcydi44MDVoLTYuNTMxdi0xLjM1Mmg0LjY3MnYtLjE0OGMtLjAxMS0uMzM5LS4wNzgtLjY1Ni0uMjAzLS45NTMtLjEyLS4yOTctLjMwNS0uNTM3LS41NTUtLjcxOS0uMjUtLjE4Mi0uNTgzLS4yNzMtMS0uMjczLS4zMTMgMC0uNTkxLjA2Ny0uODM2LjIwMy0uMjQuMTMtLjQ0LjMyLS42MDIuNTctLjE2MS4yNS0uMjg2LjU1Mi0uMzc1LjkwNi0uMDgzLjM0OS0uMTI1Ljc0Mi0uMTI1IDEuMTh2LjMxMmMwIC4zNy4wNS43MTQuMTQ5IDEuMDMyLjEwNC4zMTIuMjU1LjU4Ni40NTMuODIuMTk4LjIzNC40MzcuNDE5LjcxOS41NTUuMjgxLjEzLjYwMS4xOTUuOTYxLjE5NS40NTMgMCAuODU2LS4wOTEgMS4yMTEtLjI3My4zNTQtLjE4My42NjEtLjQ0LjkyMS0uNzc0bC45OTMuOTYxYy0uMTgzLjI2Ni0uNDIuNTIxLS43MTEuNzY2LS4yOTIuMjM5LS42NDkuNDM1LTEuMDcxLjU4Ni0uNDE2LjE1MS0uOTAxLjIyNi0xLjQ1My4yMjZabTkuNzk0LTIuNDQ1YzAtLjE4OC0uMDQ3LS4zNTctLjE0MS0uNTA4LS4wOTMtLjE1Ni0uMjczLS4yOTctLjUzOS0uNDIyLS4yNi0uMTI1LS42NDYtLjIzOS0xLjE1Ni0uMzQzLS40NDgtLjA5OS0uODU5LS4yMTctMS4yMzQtLjM1Mi0uMzctLjE0MS0uNjg4LS4zMS0uOTUzLS41MDgtLjI2Ni0uMTk4LS40NzItLjQzMi0uNjE4LS43MDMtLjE0NS0uMjcxLS4yMTgtLjU4My0uMjE4LS45MzcgMC0uMzQ0LjA3NS0uNjcuMjI2LS45NzcuMTUxLS4zMDcuMzY3LS41NzguNjQ5LS44MTMuMjgxLS4yMzQuNjIyLS40MTkgMS4wMjMtLjU1NC40MDYtLjEzNi44NTktLjIwMyAxLjM1OS0uMjAzLjcwOSAwIDEuMzE2LjExOSAxLjgyMS4zNTkuNTEuMjM0LjkwMS41NTUgMS4xNzIuOTYxLjI3LjQwMS40MDYuODU0LjQwNiAxLjM1OWgtMS44ODNjMC0uMjI0LS4wNTctLjQzMi0uMTcyLS42MjUtLjEwOS0uMTk4LS4yNzYtLjM1Ni0uNS0uNDc2LS4yMjQtLjEyNS0uNTA1LS4xODgtLjg0NC0uMTg4LS4zMjIgMC0uNTkxLjA1Mi0uODA0LjE1Ny0uMjA5LjA5OC0uMzY1LjIyOS0uNDY5LjM5LS4wOTkuMTYyLS4xNDguMzM5LS4xNDguNTMxIDAgLjE0MS4wMjYuMjY5LjA3OC4zODMuMDU3LjExLjE1MS4yMTEuMjgxLjMwNS4xMy4wODguMzA3LjE3Mi41MzEuMjUuMjI5LjA3OC41MTYuMTU0Ljg2LjIyNi42NDUuMTM2IDEuMi4zMSAxLjY2NC41MjQuNDY4LjIwOC44MjguNDc5IDEuMDc4LjgxMi4yNS4zMjkuMzc1Ljc0NS4zNzUgMS4yNSAwIC4zNzUtLjA4MS43MTktLjI0MiAxLjAzMi0uMTU3LjMwNy0uMzg2LjU3NS0uNjg4LjgwNC0uMzAyLjIyNC0uNjY0LjM5OS0xLjA4Ni41MjQtLjQxNy4xMjUtLjg4NS4xODctMS40MDYuMTg3LS43NjYgMC0xLjQxNC0uMTM1LTEuOTQ1LS40MDYtLjUzMi0uMjc2LS45MzUtLjYyOC0xLjIxMS0xLjA1NS0uMjcxLS40MzItLjQwNy0uODgtLjQwNy0xLjM0M2gxLjgyMWMuMDIxLjM0OS4xMTcuNjI3LjI4OS44MzYuMTc3LjIwMy4zOTYuMzUxLjY1Ni40NDUuMjY2LjA4OC41MzkuMTMzLjgyLjEzMy4zMzkgMCAuNjIzLS4wNDUuODUyLS4xMzMuMjI5LS4wOTQuNDA0LS4yMTkuNTIzLS4zNzUuMTItLjE2Mi4xOC0uMzQ0LjE4LS41NDdaTTYxLjEyNDIgMTQ5Ljg0NGMwLS4xOTktLjAzMTItLjM3NS0uMDkzNy0uNTI4LS4wNTg2LS4xNTYtLjE2NDEtLjI5Ni0uMzE2NC0uNDIxLS4xNDg1LS4xMjUtLjM1NTUtLjI0NS0uNjIxMS0uMzU4LS4yNjE4LS4xMTMtLjU5MzgtLjIyOC0uOTk2MS0uMzQ2LS40MjE5LS4xMjUtLjgwMjgtLjI2My0xLjE0MjYtLjQxNi0uMzM5OC0uMTU2LS42MzA5LS4zMzQtLjg3MzEtLjUzMy0uMjQyMS0uMTk5LS40Mjc3LS40MjgtLjU1NjYtLjY4NS0uMTI4OS0uMjU4LS4xOTM0LS41NTMtLjE5MzQtLjg4NSAwLS4zMzIuMDY4NC0uNjM5LjIwNTEtLjkycy4zMzIxLS41MjUuNTg2LS43MzJjLjI1NzgtLjIxMS41NjQ0LS4zNzUuOTE5OS0uNDkzLjM1NTUtLjExNy43NTE5LS4xNzUgMS4xODk0LS4xNzUuNjQwNyAwIDEuMTgzNi4xMjMgMS42Mjg5LjM2OS40NDkzLjI0Mi43OTExLjU2IDEuMDI1NC45NTUuMjM0NC4zOS4zNTE2LjgwOC4zNTE2IDEuMjU0aC0xLjEyNWMwLS4zMjEtLjA2ODQtLjYwNC0uMjA1MS0uODUtLjEzNjctLjI1LS4zNDM3LS40NDUtLjYyMTEtLjU4Ni0uMjc3My0uMTQ0LS42Mjg5LS4yMTctMS4wNTQ3LS4yMTctLjQwMjMgMC0uNzM0My4wNjEtLjk5NjEuMTgyLS4yNjE3LjEyMS0uNDU3LjI4NS0uNTg1OS40OTItLjEyNS4yMDctLjE4NzUuNDQ0LS4xODc1LjcwOSAwIC4xOC4wMzcxLjM0NC4xMTEzLjQ5Mi4wNzgyLjE0NS4xOTczLjI4LjM1NzUuNDA1LjE2NC4xMjUuMzcxMS4yNC42MjExLjM0NS4yNTM5LjEwNi41NTY2LjIwNy45MDgyLjMwNS40ODQzLjEzNy45MDIzLjI4OSAxLjI1MzkuNDU3LjM1MTUuMTY4LjY0MDYuMzU3Ljg2NzEuNTY4LjIzMDUuMjA3LjQwMDQuNDQ0LjUwOTguNzA5LjExMzMuMjYyLjE2OTkuNTU5LjE2OTkuODkxIDAgLjM0OC0uMDcwMy42NjItLjIxMDkuOTQzLS4xNDA2LjI4Mi0uMzQxOC41MjItLjYwMzUuNzIxLS4yNjE3LjE5OS0uNTc2Mi4zNTQtLjk0MzQuNDYzLS4zNjMzLjEwNS0uNzY5NS4xNTgtMS4yMTg3LjE1OGE0LjIzOCA0LjIzOCAwIDAgMS0xLjE2Ni0uMTY0Yy0uMzc4OS0uMTA5LS43MjQ3LS4yNzMtMS4wMzcyLS40OTItLjMwODUtLjIxOS0uNTU2Ni0uNDg4LS43NDQxLS44MDktLjE4MzYtLjMyNC0uMjc1NC0uNjk5LS4yNzU0LTEuMTI1aDEuMTI1YzAgLjI5My4wNTY3LjU0NS4xNjk5Ljc1Ni4xMTMzLjIwNy4yNjc2LjM3OS40NjI5LjUxNi4xOTkyLjEzNy40MjM5LjIzOC42NzM5LjMwNS4yNTM5LjA2Mi41MTc1LjA5My43OTEuMDkzLjM5NDUgMCAuNzI4NS0uMDU0IDEuMDAxOS0uMTY0LjI3MzUtLjEwOS40ODA1LS4yNjUuNjIxMS0uNDY5LjE0NDYtLjIwMy4yMTY4LS40NDMuMjE2OC0uNzJabTcuOTI4NS0uNTU3aDEuMTI1Yy0uMDU4Ni41MzktLjIxMjkgMS4wMjItLjQ2MjkgMS40NDctLjI1LjQyNi0uNjAzNS43NjQtMS4wNjA1IDEuMDE0LS40NTcuMjQ2LTEuMDI3My4zNjktMS43MTA5LjM2OS0uNSAwLS45NTUxLS4wOTQtMS4zNjUzLS4yODFhMy4wMzc3IDMuMDM3NyAwIDAgMS0xLjA0ODgtLjc5N2MtLjI5My0uMzQ4LS41MTk1LS43NjQtLjY3OTctMS4yNDgtLjE1NjItLjQ4OC0uMjM0NC0xLjAzMS0uMjM0NC0xLjYyOXYtLjg1YzAtLjU5Ny4wNzgyLTEuMTM4LjIzNDQtMS42MjMuMTYwMi0uNDg4LjM4ODctLjkwNi42ODU2LTEuMjUzYTMuMDQ4NiAzLjA0ODYgMCAwIDEgMS4wODM5LS44MDNjLjQyMTktLjE4OC44OTY1LS4yODEgMS40MjM5LS4yODEuNjQ0NSAwIDEuMTg5NC4xMjEgMS42MzQ3LjM2My40NDUzLjI0Mi43OTExLjU3OCAxLjAzNzEgMS4wMDguMjUuNDI1LjQwNDMuOTIuNDYyOSAxLjQ4MmgtMS4xMjVjLS4wNTQ3LS4zOTgtLjE1NjItLjc0LS4zMDQ3LTEuMDI1LS4xNDg0LS4yODktLjM1OTMtLjUxMi0uNjMyOC0uNjY4LS4yNzM0LS4xNTctLjYzMDgtLjIzNS0xLjA3MjItLjIzNS0uMzc4OSAwLS43MTI5LjA3My0xLjAwMi4yMTctLjI4NTEuMTQ1LS41MjU0LjM1LS43MjA3LjYxNS0uMTkxNC4yNjYtLjMzNTkuNTg0LS40MzM2Ljk1NS0uMDk3Ni4zNzItLjE0NjUuNzg0LS4xNDY1IDEuMjM3di44NjFjMCAuNDE4LjA0My44MTEuMTI4OSAxLjE3OC4wODk5LjM2Ny4yMjQ3LjY4OS40MDQzLjk2Ny4xNzk3LjI3Ny40MDgyLjQ5Ni42ODU2LjY1Ni4yNzczLjE1Ni42MDU1LjIzNC45ODQ0LjIzNC40ODA0IDAgLjg2MzItLjA3NiAxLjE0ODQtLjIyOC4yODUyLS4xNTMuNS0uMzcxLjY0NDUtLjY1Ny4xNDg1LS4yODUuMjUzOS0uNjI2LjMxNjQtMS4wMjVabTYuMDI0My01LjA2Mkw3Mi4yNTI3IDE1MmgtMS4xNTQzbDMuMjUyLTguNTMxaC43NDQxbC0uMDE3NS43NTZaTTc3LjQ0NDEgMTUybC0yLjgzLTcuNzc1LS4wMTc2LS43NTZoLjc0NDFMNzguNjA0MyAxNTJoLTEuMTYwMlptLS4xNDY0LTMuMTU4di45MjZoLTQuNzkzdi0uOTI2aDQuNzkzWk04Mi4yNTU1IDE1MmgtMS43ODEzbC4wMTE3LS45MmgxLjc2OTZjLjYwOTMgMCAxLjExNzItLjEyNyAxLjUyMzQtLjM4MS40MDYzLS4yNTguNzEwOS0uNjE3LjkxNDEtMS4wNzguMjA3LS40NjUuMzEwNS0xLjAwOC4zMTA1LTEuNjI5di0uNTIxYzAtLjQ4OS0uMDU4Ni0uOTIyLS4xNzU4LTEuMzAxLS4xMTcyLS4zODMtLjI4OS0uNzA1LS41MTU2LS45NjctLjIyNjYtLjI2NS0uNTAzOS0uNDY3LS44MzItLjYwMy0uMzI0Mi0uMTM3LS42OTczLS4yMDUtMS4xMTkyLS4yMDVoLTEuOTIxOHYtLjkyNmgxLjkyMThjLjU1ODYgMCAxLjA2ODQuMDkzIDEuNTI5My4yODEuNDYxLjE4NC44NTc1LjQ1MSAxLjE4OTUuODAzLjMzNTkuMzQ3LjU5MzcuNzY5Ljc3MzQgMS4yNjUuMTc5Ny40OTMuMjY5NiAxLjA0Ny4yNjk2IDEuNjY0di41MWMwIC42MTctLjA4OTkgMS4xNzQtLjI2OTYgMS42Ny0uMTc5Ny40OTItLjQzOTQuOTEyLS43NzkzIDEuMjYtLjMzNTkuMzQ4LS43NDIyLjYxNS0xLjIxODcuODAzLS40NzI3LjE4My0xLjAwNTkuMjc1LTEuNTk5Ni4yNzVabS0xLjE3NzgtOC41MzFWMTUyaC0xLjEzMDh2LTguNTMxaDEuMTMwOFptOS45NzM1Ljc1Nkw4OC4yMjcgMTUyaC0xLjE1NDNsMy4yNTE5LTguNTMxaC43NDQxbC0uMDE3NS43NTZaTTkzLjQxODQgMTUybC0yLjgzMDEtNy43NzUtLjAxNzYtLjc1NmguNzQ0MUw5NC41Nzg1IDE1MmgtMS4xNjAxWm0tLjE0NjUtMy4xNTh2LjkyNmgtNC43OTN2LS45MjZoNC43OTNabTkuMzUzMSAxLjQ3NmMwLS4xNTYtLjAzNS0uMy0uMTA1LS40MzMtLjA2Ny0uMTM3LS4yMDYtLjI2LS40MTYtLjM2OS0uMjA4LS4xMTQtLjUyLS4yMTEtLjkzOC0uMjkzLS4zNTItLjA3NS0uNjctLjE2Mi0uOTU1LS4yNjQtLjI4MTMtLjEwMi0uNTIxNS0uMjI1LS43MjA4LS4zNjktLjE5NTMtLjE0NS0uMzQ1Ny0uMzE1LS40NTExLS41MS0uMTA1NS0uMTk1LS4xNTgyLS40MjQtLjE1ODItLjY4NSAwLS4yNS4wNTQ2LS40ODcuMTY0LS43MDkuMTEzMy0uMjIzLjI3MTUtLjQyLjQ3NDYtLjU5Mi4yMDcxLS4xNzIuNDU1MS0uMzA3Ljc0NDUtLjQwNS4yODktLjA5Ny42MTEtLjE0Ni45NjYtLjE0Ni41MDggMCAuOTQyLjA5IDEuMzAxLjI2OS4zNi4xOC42MzUuNDIuODI2LjcyMS4xOTIuMjk3LjI4OC42MjcuMjg4Ljk5aC0xLjA4NGMwLS4xNzUtLjA1My0uMzQ1LS4xNTktLjUwOS0uMTAxLS4xNjgtLjI1Mi0uMzA3LS40NTEtLjQxNi0uMTk1LS4xMS0uNDM1LS4xNjQtLjcyMS0uMTY0LS4zIDAtLjU0NC4wNDYtLjczMi4xNC0uMTg0LjA5LS4zMTguMjA1LS40MDQuMzQ2LS4wODIuMTQxLS4xMjMzLjI4OS0uMTIzMy40NDUgMCAuMTE3LjAxOTUuMjIzLjA1ODMuMzE3LjA0My4wODkuMTE3LjE3My4yMjMuMjUyLjEwNS4wNzQuMjU0LjE0NC40NDUuMjExLjE5Mi4wNjYuNDM2LjEzMi43MzMuMTk5LjUxOS4xMTcuOTQ3LjI1OCAxLjI4My40MjIuMzM2LjE2NC41ODYuMzY1Ljc1LjYwMy4xNjQuMjM4LjI0Ni41MjcuMjQ2Ljg2NyAwIC4yNzgtLjA1OS41MzItLjE3Ni43NjItLjExMy4yMzEtLjI3OS40My0uNDk4LjU5OC0uMjE1LjE2NC0uNDczLjI5My0uNzczLjM4Ni0uMjk3LjA5LS42MzEuMTM1LTEuMDAyLjEzNS0uNTU5IDAtMS4wMzEtLjA5OS0xLjQxODItLjI5OS0uMzg2Ny0uMTk5LS42Nzk3LS40NTctLjg3ODktLjc3My0uMTk5Mi0uMzE2LS4yOTg4LS42NS0uMjk4OC0xLjAwMmgxLjA4OThjLjAxNTYuMjk3LjEwMTYuNTMzLjI1ODEuNzA5LjE1Ni4xNzIuMzQ3LjI5NS41NzQuMzY5LjIyNi4wNy40NTEuMTA2LjY3NC4xMDYuMjk3IDAgLjU0NS0uMDM5Ljc0NC0uMTE4LjIwMy0uMDc4LjM1Ny0uMTg1LjQ2My0uMzIyLjEwNS0uMTM3LjE1OC0uMjkzLjE1OC0uNDY5Wm00LjQ4OSAxLjAyNiAxLjc2NC01LjY4NGgxLjE2bC0yLjU0MyA3LjMxOWMtLjA1OS4xNTYtLjEzNy4zMjQtLjIzNC41MDMtLjA5NC4xODQtLjIxNS4zNTgtLjM2NC41MjItLjE0OC4xNjQtLjMyOC4yOTctLjUzOS4zOTgtLjIwNy4xMDYtLjQ1NS4xNTktLjc0NC4xNTktLjA4NiAwLS4xOTUtLjAxMi0uMzI4LS4wMzYtLjEzMy0uMDIzLS4yMjctLjA0My0uMjgxLS4wNThsLS4wMDYtLjg3OWMuMDMxLjAwNC4wOC4wMDguMTQ2LjAxMi4wNzEuMDA3LjExOS4wMTEuMTQ3LjAxMS4yNDYgMCAuNDU1LS4wMzMuNjI3LS4wOTkuMTcyLS4wNjMuMzE2LS4xNy40MzMtLjMyMy4xMjEtLjE0OC4yMjUtLjM1My4zMTEtLjYxNWwuNDUxLTEuMjNabS0xLjI5NS01LjY4NCAxLjY0NyA0LjkyMi4yODEgMS4xNDMtLjc3OS4zOTgtMi4zMzItNi40NjNoMS4xODNabTYuNDc2IDEuMjZWMTUyaC0xLjA5di02LjM0aDEuMDMxbC4wNTkgMS4yNlptLS4yMjMgMS42Ny0uNTA0LS4wMThjLjAwNC0uNDMzLjA2MS0uODM0LjE3LTEuMjAxLjEwOS0uMzcxLjI3MS0uNjkzLjQ4Ni0uOTY3LjIxNS0uMjczLjQ4My0uNDg0LjgwMy0uNjMzLjMyLS4xNTIuNjkxLS4yMjggMS4xMTMtLjIyOC4yOTcgMCAuNTcxLjA0My44MjEuMTI5LjI1LjA4Mi40NjYuMjEzLjY1LjM5Mi4xODQuMTguMzI2LjQxMS40MjguNjkyLjEwMS4yODEuMTUyLjYyMS4xNTIgMS4wMTlWMTUyaC0xLjA4NHYtNC4xNzJjMC0uMzMyLS4wNTctLjU5OC0uMTctLjc5Ny0uMTA5LS4xOTktLjI2Ni0uMzQzLS40NjktLjQzMy0uMjAzLS4wOTQtLjQ0MS0uMTQxLS43MTQtLjE0MS0uMzIxIDAtLjU4OC4wNTctLjgwMy4xNy0uMjE1LjExMy0uMzg3LjI2OS0uNTE2LjQ2OS0uMTI5LjE5OS0uMjIzLjQyNy0uMjgxLjY4NS0uMDU1LjI1NC0uMDgyLjUyNC0uMDgyLjgwOVptNC4xMDctLjU5OC0uNzI2LjIyM2MuMDA0LS4zNDguMDYtLjY4Mi4xNy0xLjAwMi4xMTMtLjMyLjI3NS0uNjA2LjQ4Ni0uODU2LjIxNS0uMjUuNDc4LS40NDcuNzkxLS41OTEuMzEyLS4xNDkuNjctLjIyMyAxLjA3Mi0uMjIzLjM0IDAgLjY0MS4wNDUuOTAzLjEzNS4yNjUuMDkuNDg4LjIyOC42NjguNDE2LjE4My4xODMuMzIyLjQyLjQxNi43MDkuMDkzLjI4OS4xNC42MzMuMTQgMS4wMzFWMTUyaC0xLjA5di00LjE3OGMwLS4zNTUtLjA1Ni0uNjMxLS4xNy0uODI2LS4xMDktLjE5OS0uMjY1LS4zMzgtLjQ2OC0uNDE2LS4yLS4wODItLjQzOC0uMTIzLS43MTUtLjEyMy0uMjM4IDAtLjQ0OS4wNDEtLjYzMy4xMjMtLjE4NC4wODItLjMzOC4xOTUtLjQ2My4zNGExLjQ4NSAxLjQ4NSAwIDAgMC0uMjg3LjQ4NmMtLjA2Mi4xODQtLjA5NC4zNzktLjA5NC41ODZabTUuNzU1LTQuOTkyaDEuMDl2Ny43N2wtLjA5NCAxLjIzaC0uOTk2di05Wm01LjM3MyA1Ljc3N3YuMTIzYzAgLjQ2MS0uMDU1Ljg4OS0uMTY0IDEuMjg0LS4xMDkuMzktLjI3LjczLS40OCAxLjAxOS0uMjExLjI4OS0uNDY5LjUxNC0uNzc0LjY3NC0uMzA1LjE2LS42NTQuMjQtMS4wNDkuMjQtLjQwMiAwLS43NTYtLjA2OC0xLjA2LS4yMDVhMi4wOTM0IDIuMDkzNCAwIDAgMS0uNzYyLS42MDNjLS4yMDctLjI2Mi0uMzczLS41NzktLjQ5OC0uOTUtLjEyMS0uMzcxLS4yMDUtLjc4OS0uMjUyLTEuMjU0di0uNTM5Yy4wNDctLjQ2OC4xMzEtLjg4OC4yNTItMS4yNTkuMTI1LS4zNzEuMjkxLS42ODguNDk4LS45NS4yMDctLjI2NS40NjEtLjQ2Ni43NjItLjYwMy4zLS4xNDEuNjUtLjIxMSAxLjA0OS0uMjExLjM5OCAwIC43NTEuMDc4IDEuMDYuMjM0LjMwOS4xNTMuNTY2LjM3MS43NzQuNjU3LjIxLjI4NS4zNzEuNjI3LjQ4IDEuMDI1LjEwOS4zOTUuMTY0LjgzNC4xNjQgMS4zMThabS0xLjA5LjEyM3YtLjEyM2MwLS4zMTYtLjAyOS0uNjEzLS4wODgtLjg5LS4wNTgtLjI4Mi0uMTUyLS41MjgtLjI4MS0uNzM5LS4xMjktLjIxNC0uMjk5LS4zODItLjUxLS41MDMtLjIxMS0uMTI1LS40Ny0uMTg4LS43NzktLjE4OC0uMjczIDAtLjUxMi4wNDctLjcxNS4xNDEtLjE5OS4wOTMtLjM2OS4yMi0uNTEuMzgxLS4xNC4xNTYtLjI1NS4zMzUtLjM0NS41MzktLjA4Ni4xOTktLjE1MS40MDYtLjE5NC42MjF2MS40MTJjLjA2My4yNzMuMTY0LjUzNy4zMDUuNzkxLjE0NS4yNS4zMzYuNDU1LjU3NC42MTUuMjQyLjE2LjU0MS4yNC44OTcuMjQuMjkzIDAgLjU0My0uMDU4Ljc1LS4xNzYuMjExLS4xMjEuMzgxLS4yODcuNTA5LS40OTguMTMzLS4yMTEuMjMxLS40NTUuMjkzLS43MzIuMDYzLS4yNzcuMDk0LS41NzQuMDk0LS44OTFabTIuMzc0IDB2LS4xMzRjMC0uNDU3LjA2Ni0uODgxLjE5OS0xLjI3Mi4xMzMtLjM5NC4zMjQtLjczNi41NzQtMS4wMjUuMjUtLjI5My41NTMtLjUyLjkwOS0uNjguMzU1LS4xNjQuNzU0LS4yNDYgMS4xOTUtLjI0Ni40NDUgMCAuODQ2LjA4MiAxLjIwMS4yNDYuMzYuMTYuNjY0LjM4Ny45MTQuNjguMjU0LjI4OS40NDcuNjMxLjU4IDEuMDI1LjEzMy4zOTEuMi44MTUuMiAxLjI3MnYuMTM0YzAgLjQ1Ny0uMDY3Ljg4MS0uMiAxLjI3Mi0uMTMzLjM5LS4zMjYuNzMyLS41OCAxLjAyNS0uMjUuMjg5LS41NTMuNTE2LS45MDguNjgtLjM1Mi4xNi0uNzUuMjQtMS4xOTUuMjQtLjQ0NiAwLS44NDYtLjA4LTEuMjAxLS4yNC0uMzU2LS4xNjQtLjY2MS0uMzkxLS45MTUtLjY4LS4yNS0uMjkzLS40NDEtLjYzNS0uNTc0LTEuMDI1LS4xMzMtLjM5MS0uMTk5LS44MTUtLjE5OS0xLjI3MlptMS4wODQtLjEzNHYuMTM0YzAgLjMxNy4wMzcuNjE2LjExMS44OTcuMDc1LjI3Ny4xODYuNTIzLjMzNC43MzguMTUzLjIxNS4zNDIuMzg1LjU2OS41MS4yMjYuMTIxLjQ5LjE4Mi43OTEuMTgyLjI5NyAwIC41NTYtLjA2MS43NzktLjE4Mi4yMjctLjEyNS40MTQtLjI5NS41NjItLjUxLjE0OS0uMjE1LjI2LS40NjEuMzM0LS43MzguMDc5LS4yODEuMTE4LS41OC4xMTgtLjg5N3YtLjEzNGMwLS4zMTMtLjAzOS0uNjA4LS4xMTgtLjg4NS0uMDc0LS4yODEtLjE4Ny0uNTI5LS4zMzktLjc0NC0uMTQ5LS4yMTktLjMzNi0uMzkxLS41NjMtLjUxNi0uMjIzLS4xMjUtLjQ4NC0uMTg3LS43ODUtLjE4Ny0uMjk3IDAtLjU1OS4wNjItLjc4NS4xODctLjIyMy4xMjUtLjQxLjI5Ny0uNTYzLjUxNi0uMTQ4LjIxNS0uMjU5LjQ2My0uMzM0Ljc0NC0uMDc0LjI3Ny0uMTExLjU3Mi0uMTExLjg4NVpNMTM3LjEgMTQzdjloLTEuMDl2LTloMS4wOVptNS42MzEgNy4zMThjMC0uMTU2LS4wMzUtLjMtLjEwNS0uNDMzLS4wNjctLjEzNy0uMjA1LS4yNi0uNDE2LS4zNjktLjIwNy0uMTE0LS41Mi0uMjExLS45MzgtLjI5My0uMzUxLS4wNzUtLjY3LS4xNjItLjk1NS0uMjY0LS4yODEtLjEwMi0uNTIxLS4yMjUtLjcyMS0uMzY5LS4xOTUtLjE0NS0uMzQ1LS4zMTUtLjQ1MS0uNTEtLjEwNS0uMTk1LS4xNTgtLjQyNC0uMTU4LS42ODUgMC0uMjUuMDU1LS40ODcuMTY0LS43MDkuMTEzLS4yMjMuMjcyLS40Mi40NzUtLjU5Mi4yMDctLjE3Mi40NTUtLjMwNy43NDQtLjQwNS4yODktLjA5Ny42MTEtLjE0Ni45NjctLjE0Ni41MDggMCAuOTQxLjA5IDEuMy4yNjkuMzYuMTguNjM1LjQyLjgyNy43MjEuMTkxLjI5Ny4yODcuNjI3LjI4Ny45OWgtMS4wODRjMC0uMTc1LS4wNTMtLjM0NS0uMTU4LS41MDktLjEwMi0uMTY4LS4yNTItLjMwNy0uNDUyLS40MTYtLjE5NS0uMTEtLjQzNS0uMTY0LS43Mi0uMTY0LS4zMDEgMC0uNTQ1LjA0Ni0uNzMzLjE0LS4xODMuMDktLjMxOC4yMDUtLjQwNC4zNDYtLjA4Mi4xNDEtLjEyMy4yODktLjEyMy40NDUgMCAuMTE3LjAxOS4yMjMuMDU5LjMxNy4wNDMuMDg5LjExNy4xNzMuMjIyLjI1Mi4xMDYuMDc0LjI1NC4xNDQuNDQ2LjIxMS4xOTEuMDY2LjQzNS4xMzIuNzMyLjE5OS41MTkuMTE3Ljk0Ny4yNTggMS4yODMuNDIyLjMzNi4xNjQuNTg2LjM2NS43NS42MDMuMTY0LjIzOC4yNDYuNTI3LjI0Ni44NjcgMCAuMjc4LS4wNTguNTMyLS4xNzYuNzYyLS4xMTMuMjMxLS4yNzkuNDMtLjQ5OC41OTgtLjIxNC4xNjQtLjQ3Mi4yOTMtLjc3My4zODYtLjI5Ny4wOS0uNjMxLjEzNS0xLjAwMi4xMzUtLjU1OSAwLTEuMDMxLS4wOTktMS40MTgtLjI5OS0uMzg3LS4xOTktLjY4LS40NTctLjg3OS0uNzczLS4xOTktLjMxNi0uMjk5LS42NS0uMjk5LTEuMDAyaDEuMDljLjAxNi4yOTcuMTAyLjUzMy4yNTguNzA5LjE1Ni4xNzIuMzQ4LjI5NS41NzQuMzY5LjIyNy4wNy40NTEuMTA2LjY3NC4xMDYuMjk3IDAgLjU0NS0uMDM5Ljc0NC0uMTE4LjIwMy0uMDc4LjM1OC0uMTg1LjQ2My0uMzIyLjEwNi0uMTM3LjE1OC0uMjkzLjE1OC0uNDY5WiIgZmlsbD0iIzMwNTY4MCIgZmlsbC1vcGFjaXR5PSIuOCIvPjwvc3ZnPg==", "description": "Bundle with SCADA symbols", "order": 9200, "name": "SCADA symbols" diff --git a/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json b/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json deleted file mode 100644 index 22575e0697..0000000000 --- a/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "widgetsBundle": { - "alias": "scada_water_system_symbols", - "title": "SCADA water system symbols", - "scada": true, - "image": null, - "description": "Bundle with SCADA symbols for water system", - "order": 9300, - "name": "SCADA water system symbols" - }, - "widgetTypeFqns": [ - "horizontal_pipe", - "long_horizontal_pipe", - "vertical_pipe", - "long_vertical_pipe", - "left_bottom_elbow_pipe", - "bottom_right_elbow_pipe", - "top_right_elbow_pipe", - "left_top_elbow_pipe", - "cross_pipe", - "left_tee_pipe", - "bottom_tee_pipe", - "right_tee_pipe", - "top_tee_pipe", - "right_elbow_drain_pipe", - "left_elbow_drain_pipe", - "left_drain_pipe", - "right_drain_pipe", - "short_left_drain_pipe", - "short_right_drain_pipe", - "top_flow_meter", - "right_flow_meter", - "bottom_flow_meter", - "left_flow_meter", - "horizontal_inline_flow_meter", - "vertical_inline_flow_meter", - "left_analog_water_level_meter", - "right_analog_water_level_meter", - "leak_sensor", - "centrifugal_pump", - "small_right_motor_pump", - "small_left_motor_pump", - "right_motor_pump", - "left_motor_pump", - "right_heat_pump", - "left_heat_pump", - "short_bottom_filter", - "long_bottom_filter", - "short_top_filter", - "long_top_filter", - "stand_filter", - "horizontal_wheel_valve", - "vertical_wheel_valve", - "horizontal_ball_valve", - "vertical_ball_valve", - "water_stop", - "vertical_tank", - "stand_vertical_tank", - "cylindrical_tank", - "stand_cylindrical_tank", - "vertical_short_tank", - "stand_vertical_short_tank", - "large_cylindrical_tank", - "large_stand_cylindrical_tank", - "large_vertical_tank", - "large_stand_vertical_tank", - "horizontal_tank", - "stand_horizontal_tank", - "spherical_tank", - "small_spherical_tank", - "elevated_tank", - "pool" - ] -} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/scada_symbol.json b/application/src/main/data/json/system/widget_types/scada_symbol.json index 15c12e1b81..bdcdd1674d 100644 --- a/application/src/main/data/json/system/widget_types/scada_symbol.json +++ b/application/src/main/data/json/system/widget_types/scada_symbol.json @@ -3,7 +3,7 @@ "name": "SCADA symbol", "deprecated": false, "scada": true, - "image": null, + "image": "tb-image:bmV3X3NjYWRhX3N5bWJvbHNfc3lzdGVtX3dpZGdldF9pbWFnZV8oMSkuc3Zn:Ik5ldyBTQ0FEQSBzeW1ib2wiIHN5c3RlbSB3aWRnZXQgaW1hZ2U=:SU1BR0U=;data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE2MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBjbGlwLXBhdGg9InVybCgjYSkiIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBmaWxsPSIjMzA1NjgwIiBmaWxsLW9wYWNpdHk9Ii42Ij48cGF0aCBkPSJtMTQ3LjE2MyA0OC43NTM3LTE0LjcxOC0xNS4zODU1Yy0xLjIxMy0xLjI2MTQtMi42OTMtMi4xOTYtNC4zNC0yLjczOTYtNS4wNzUtNi41NDc1LTExLjE5OS0xMC42Nzc3LTIwLjEzNC0xMC42Nzc3LTguNjkwNiAwLTE2LjQzMDMgMy42MjQxLTIxLjUzMDMgMTAuMzI4SDcyLjQ0NzRjLTUuNTYzMS4wMDA1LTEwLjE1NyA0LjM2Ny0xMC4xNTcgOS45MzA3djM5Ljc5MDVoNS4wMjhWNDAuMjA5NmMwLTIuNzk1NSAyLjMzMzUtNC45MDIyIDUuMTI5LTQuOTAyMmgxMC43MjU3Yy0xLjkxMTIgMy4zNTE5LTMuMDA1NiA3Ljg0MTktMy4wMDU2IDEyLjM1ODZ2My44NDI1aC04LjM2MmMtLjY1MDggMC0xLjIzOC4yNjI1LTEuNDg4My44NjMxLS4yNTAyLjYwMDYtLjExNTYgMS4yMjg1LjM0MiAxLjY5MTFsMjIuNDE3MyAyMi42MjQ1Yy4zMjM0LjMyNjkuNzY0OC40OTUgMS4yMjQ2LjQ5NS40NTk3IDAgLjkwMTEtLjE5MjIgMS4yMjQ1LS41MTlsMjIuMjg4NC0yMi41MzA3Yy40NzktLjQ4NDQuNjIxLTEuMDgyNy4zNTgtMS43MTIzLS4yNjMtLjYyODUtLjg3Ny0uOTExNy0xLjU1OS0uOTExN0gxMDguMVY0Ny42NjZjMC00Ljk3MzIgMi40ODYtOS41NjUzIDUuODk1LTEyLjM1ODZoOS4xMjNjMS45ODEuNTU4NiAzLjQxOCAyLjA3MzcgMy40MTggNC4yMDIydjEwLjgxMTdjMCAyLjkwMTcgMi4zODYgNS42NTY0IDUuMjg3IDUuNjU2NGg4Ljg5OWMyLjUwMiAwIDQuMzg5IDEuODI2MyA0LjM4OSA0LjMyNjlsLS4xMzktLjIwOVYxMzAuMDVjMCAyLjc5NS0yLjAzMiA1LjI1Ny00LjgyNyA1LjI1N0g3Mi40NDc0Yy0yLjc5NTUgMC01LjEyOS0yLjQ2MS01LjEyOS01LjI1N3YtMi41NjRoLTUuMDI4djIuNTY0YzAgNS41NjQgNC41OTM5IDEwLjI4NSAxMC4xNTcgMTAuMjg1aDY3LjY5NzZjNS41NjMgMCA5Ljg1NS00LjcyMSA5Ljg1NS0xMC4yODVWNTYuMDg3OGMwLTIuNzQ4Ni0uOTMyLTUuMzUzMS0yLjgzNy03LjMzNDFaIi8+PHBhdGggZD0iTTEyNy42NTQgODguMTQ5NmMwLTEuNzI0LTEuMzk4LTMuMTIxOC0zLjEyMi0zLjEyMThINTMuMTIxN2MtMS43MjQgMC0zLjEyMTggMS4zOTc4LTMuMTIxOCAzLjEyMTh2MzEuNzQ0NGMwIDEuNzI0IDEuMzk3OCAzLjEyMiAzLjEyMTggMy4xMjJoNzEuNDEwM2MxLjcyNCAwIDMuMTIyLTEuMzk4IDMuMTIyLTMuMTIyVjg4LjE0OTZaTTc2LjEzNjMgMTExLjc1NWMtLjQxMjkuOTE0LTEuMDI3NCAxLjcwMi0xLjg0MzYgMi4zNjYtLjgxNTcuNjYzLTEuODI3NCAxLjE3OS0zLjAzNDcgMS41NDktMS4yMDY3LjM3LTIuNjA1LjU1NS00LjE5MjcuNTU1LTEuMjgzOCAwLTIuNTI4NS0uMTU4LTMuNzM1OC0uNDczLTEuMjA3Mi0uMzE1LTIuMjczMS0uODEtMy4xOTc3LTEuNDg1LS45MjUyLS42NzQtMS42NTkyLTEuNTUyLTIuMjAyMy0yLjU5Ni0uNTQ0MS0xLjA0NC0uODA1LTIuMDYyLS43ODMyLTMuNzM4aDQuOTU5OGMwIDEuMTE3LjE0MTMgMS40NjUuNDI0IDIuMDA5LjI4MjcuNTQ0LjY1ODEuOTk0IDEuMTI2MyAxLjMzMS40Njc2LjMzOCAxLjAxNjIuNTkyIDEuNjQ3NC43NTUuNjMwOC4xNjQgMS4yODMzLjI0NyAxLjk1NzYuMjQ3LjQ1NjQgMCAuOTQ2NC0uMDM3IDEuNDY4MS0uMTEzLjUyMjQtLjA3NiAxLjAxMTgtLjIyMiAxLjQ2ODgtLjQ0LjQ1NjQtLjIxOC44MzY4LS41MTcgMS4xNDE5LS44OTcuMzA0NC0uMzguNDU2NC0uODY1LjQ1NjQtMS40NTIgMC0uNjMxLS4yMDExLTEuMTQyLS42MDM0LTEuNTMzLS40MDI4LS4zOTItLjkzMDEtLjcxOC0xLjU4MjYtLjk3OS0uNjUyNi0uMjYxLTEuMzkyMi0uNDktMi4yMTktLjY4Ni0uODI2My0uMTk1LTEuNjY0My0uNDEzLTIuNTEyMy0uNjUyLS44NzA0LS4yMTgtMS43MTg1LS40ODQtMi41NDQ3LS44LS44MjY4LS4zMTUtMS41NjY1LS43MjMtMi4yMTktMS4yMjMtLjY1MjUtLjUtMS4xODA1LTEuMTI2LTEuNTgyNy0xLjg3Ni0uNDAyOC0uNzUtLjYwMzQtMS42NTgyLS42MDM0LTIuNzI0MSAwLTEuMTk2MS4yNTU0LTIuMjM1Mi43NjY1LTMuMTE2Mi41MTA2LS44ODEgMS4xNzk0LTEuNjE1MSAyLjAwNjctMi4yMDIyLjgyNjMtLjU4NzIgMS43NjItMS4wMjI0IDIuODA2Mi0xLjMwNTEgMS4wNDM2LS4yODI2IDIuMDg3Ny0uNDI0IDMuMTMxOC0uNDI0IDEuMjE3OSAwIDIuMzg2Ni4xMzYzIDMuNTA3My40MDc4IDEuMTIwMS4yNzIxIDIuMTE1MS43MTI5IDIuOTg1NSAxLjMyMTMuODcwMy42MDg5IDEuNTYwOSAxLjQ4NDkgMi4wNzIgMi40MzEyLjUxMDYuOTQ2NC43NjY1IDIuNDIzNS43NjY1IDMuNTQwOGgtNC45NTkyYy0uMDQzNi0uNTU4Ni0uMTkxMS0xLjM3MDktLjQ0MDItMS44MjczLS4yNTAzLS40NTctLjU4MjctLjg2NDktLjk5NTYtMS4xMjU3LS40MTI4LS4yNjA5LS44ODY2LS40NzA0LTEuNDE5LS41Nzk0LS41MzM1LS4xMDg0LTEuMTE1LS4xNzU0LTEuNzQ1OC0uMTc1NC0uNDEzNCAwLS44MjYyLjAzOC0xLjIzOTYuMTI0Ni0uNDEzNC4wODcxLS43ODg5LjIzNjMtMS4xMjYzLjQ1MzYtLjMzNzQuMjE3OS0uNjE1MS40ODc3LS44MzE4LjgxNDUtLjIxNzkuMzI2My0uMzI2My43Mzg2LS4zMjYzIDEuMjM5MiAwIC40NTY0LjA4NjYuODI2Mi4yNjE1IDEuMTA4OS4xNzM3LjI4MjcuNTE2Mi41NDM1IDEuMDI3OS43ODI1LjUxMDYuMjQgMS4yMTc5LjQ3OSAyLjEyMDcuNzE4LjkwMjIuMjQgMi4wODI2LjU0NCAzLjU0MDIuOTEzLjQzNDYuMDg4IDEuMDM4LjI0NSAxLjgxMDYuNDc0Ljc3MjEuMjI4IDEuNTM4Ni41OTIgMi4zIDEuMDkzLjc2MTUuNSAxLjQxOTYgMS4xNyAxLjk3NDMgMi4wMDcuNTU0Mi44MzguODMxOCAxLjkwOS44MzE4IDMuMjE0LjAwMTIgMS4wNjQtLjIwNjEgMi4wNTQtLjYxODkgMi45NjdabTE0LjQ4NiAzLjk5OWgtNS43NzQ5TDc3LjMxIDkyLjg0OTFoNS4yNTMxbDUuMTg3NyAxNi4yMDA5aC4wNjUzbDUuMjUzMS0xNi4yMDA5aDUuMjg1NWwtNy43MzI0IDIyLjkwNDlabTMwLjMyNzcgMGgtMy4yNDdsLS41MjEtMi42NjhjLS45MTQgMS4xNzUtMS45MjYgMS45ODMtMy4wMzUgMi40NTEtMS4xMS40NjctMi4yMy42OTUtMy4zNjEuNjk1LTEuNzg0IDAtMy4zODgtLjMxNC00LjgxMy0uOTMzLTEuNDI1LS42Mi0yLjYyNi0xLjQ3NS0zLjYwNS0yLjU2My0uOTc5LTEuMDg3LTEuNzMtMi4zNjctMi4yNTEtMy44MzUtLjUyMjYtMS40NjgtLjc4My0zLjA1MS0uNzgzLTQuNzQ4IDAtMS43NC4yNjA5LTMuMzU1Ljc4My00Ljg0NTMuNTIyLTEuNDg5OSAxLjI3Mi0yLjc4OTkgMi4yNTEtMy44OTk0Ljk3OS0xLjEwOTUgMi4xOC0xLjk3OTQgMy42MDUtMi42MTAxIDEuNDI1LS42MzA3IDMuMDI5LS45NDU4IDQuODEzLS45NDU4IDEuMTk2IDAgMi4zNTQuMTc5MyAzLjQ3NS41MzggMS4xMi4zNTkyIDIuMTMxLjg4NjYgMy4wMzQgMS41ODIxLjkwMy42OTY3IDEuNjQ4IDEuNTczOCAyLjIzNiAyLjU5NjcuNTg3IDEuMDIyOS45NDUgMi40MjUxIDEuMDc2IDMuNTQyOGgtNC44OTRjLS4zMDUtMS4xMTc3LS44OTItMi4zMDMyLTEuNzYyLTIuOTU1Ny0uODctLjY1MjUtMS45MjUtLjk4ODItMy4xNjQtLjk4ODItMS4xNTQgMC0yLjEzMi4yMTktMi45MzcuNjY0Mi0uODA1LjQ0NjQtMS40NTggMS4wNDE5LTEuOTU4IDEuNzkyMnMtLjg2NSAxLjYwMzUtMS4wOTMgMi41NjA1Yy0uMjI5Ljk1Ny0uMzQzIDEuOTQ2LS4zNDMgMi45NjggMCAuOTc5LjExNCAxLjkzMS4zNDMgMi44NTUuMjI4LjkyNS41OTMgMS43NTcgMS4wOTMgMi40OTYuNS43MzkgMS4xNTIgMS4zMzIgMS45NTggMS43NzguODA0LjQ0NiAxLjc4My42NjkgMi45MzcuNjY5IDEuNjk2IDAgMy4wMDYtLjIwNiAzLjkzMS0xLjA2NS45MjQtLjg1OSAxLjQ2Mi0yLjM5NSAxLjYxNS0zLjUxMmgtNS40Mzl2LTMuOTExaDEwLjA1NnYxMi4yOTFaIi8+PC9nPjxkZWZzPjxjbGlwUGF0aCBpZD0iYSI+PHBhdGggZmlsbD0iI2ZmZiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNTAgMTkuNjY0OCkiIGQ9Ik0wIDBoMTAwdjEyMC42N0gweiIvPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg==", "description": "", "descriptor": { "type": "rpc", diff --git a/application/src/main/data/upgrade/3.7.0/schema_update.sql b/application/src/main/data/upgrade/3.7.0/schema_update.sql index d400821fa3..05f7423003 100644 --- a/application/src/main/data/upgrade/3.7.0/schema_update.sql +++ b/application/src/main/data/upgrade/3.7.0/schema_update.sql @@ -195,4 +195,21 @@ $$ END $$; --- OAUTH2 UPDATE END \ No newline at end of file +-- OAUTH2 UPDATE END + +-- USER CREDENTIALS UPDATE START + +ALTER TABLE user_credentials ADD COLUMN IF NOT EXISTS activate_token_exp_time BIGINT; +-- Setting 24-hour TTL for existing activation tokens +UPDATE user_credentials SET activate_token_exp_time = cast(extract(EPOCH FROM NOW()) * 1000 AS BIGINT) + 86400000 + WHERE activate_token IS NOT NULL AND activate_token_exp_time IS NULL; + +ALTER TABLE user_credentials ADD COLUMN IF NOT EXISTS reset_token_exp_time BIGINT; +-- Setting 24-hour TTL for existing password reset tokens +UPDATE user_credentials SET reset_token_exp_time = cast(extract(EPOCH FROM NOW()) * 1000 AS BIGINT) + 86400000 + WHERE reset_token IS NOT NULL AND reset_token_exp_time IS NULL; + +UPDATE admin_settings SET json_value = (json_value::jsonb || '{"userActivationTokenTtl":24,"passwordResetTokenTtl":24}'::jsonb)::varchar + WHERE key = 'securitySettings'; + +-- USER CREDENTIALS UPDATE END diff --git a/application/src/main/java/org/thingsboard/server/controller/AdminController.java b/application/src/main/java/org/thingsboard/server/controller/AdminController.java index e4e6418168..a2115360d8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AdminController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AdminController.java @@ -73,6 +73,7 @@ import org.thingsboard.server.common.data.sync.vc.VcUtils; import org.thingsboard.server.config.annotations.ApiOperation; import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.settings.AdminSettingsService; +import org.thingsboard.server.dao.settings.SecuritySettingsService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService; import org.thingsboard.server.service.security.auth.oauth2.CookieUtils; @@ -109,6 +110,7 @@ public class AdminController extends BaseController { private final SmsService smsService; private final AdminSettingsService adminSettingsService; private final SystemSecurityService systemSecurityService; + private final SecuritySettingsService securitySettingsService; private final JwtSettingsService jwtSettingsService; private final JwtTokenFactory tokenFactory; private final EntitiesVersionControlService versionControlService; @@ -167,7 +169,7 @@ public class AdminController extends BaseController { @ResponseBody public SecuritySettings getSecuritySettings() throws ThingsboardException { accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ); - return checkNotNull(systemSecurityService.getSecuritySettings()); + return checkNotNull(securitySettingsService.getSecuritySettings()); } @ApiOperation(value = "Update Security Settings (saveSecuritySettings)", @@ -179,7 +181,7 @@ public class AdminController extends BaseController { @Parameter(description = "A JSON value representing the Security Settings.") @RequestBody SecuritySettings securitySettings) throws ThingsboardException { accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE); - securitySettings = checkNotNull(systemSecurityService.saveSecuritySettings(securitySettings)); + securitySettings = checkNotNull(securitySettingsService.saveSecuritySettings(securitySettings)); return securitySettings; } 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 f95dfcb648..17f7930eff 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AuthController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AuthController.java @@ -21,17 +21,15 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; 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.rule.engine.api.MailService; import org.thingsboard.server.cache.limits.RateLimitService; @@ -48,6 +46,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.config.annotations.ApiOperation; +import org.thingsboard.server.dao.settings.SecuritySettingsService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails; import org.thingsboard.server.service.security.model.ActivateUserRequest; @@ -59,9 +58,6 @@ import org.thingsboard.server.service.security.model.UserPrincipal; import org.thingsboard.server.service.security.model.token.JwtTokenFactory; import org.thingsboard.server.service.security.system.SystemSecurityService; -import java.net.URI; -import java.net.URISyntaxException; - @RestController @TbCoreComponent @RequestMapping("/api") @@ -75,6 +71,7 @@ public class AuthController extends BaseController { private final JwtTokenFactory tokenFactory; private final MailService mailService; private final SystemSecurityService systemSecurityService; + private final SecuritySettingsService securitySettingsService; private final RateLimitService rateLimitService; private final ApplicationEventPublisher eventPublisher; @@ -82,9 +79,8 @@ public class AuthController extends BaseController { @ApiOperation(value = "Get current User (getUser)", notes = "Get the information about the User which credentials are used to perform this REST API call.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/auth/user", method = RequestMethod.GET) - public @ResponseBody - User getUser() throws ThingsboardException { + @GetMapping(value = "/auth/user") + public User getUser() throws ThingsboardException { SecurityUser securityUser = getCurrentUser(); return userService.findUserById(securityUser.getTenantId(), securityUser.getId()); } @@ -92,8 +88,7 @@ public class AuthController extends BaseController { @ApiOperation(value = "Logout (logout)", notes = "Special API call to record the 'logout' of the user to the Audit Logs. Since platform uses [JWT](https://jwt.io/), the actual logout is the procedure of clearing the [JWT](https://jwt.io/) token on the client side. ") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/auth/logout", method = RequestMethod.POST) - @ResponseStatus(value = HttpStatus.OK) + @PostMapping(value = "/auth/logout") public void logout(HttpServletRequest request) throws ThingsboardException { logLogoutAction(request); } @@ -101,8 +96,7 @@ public class AuthController extends BaseController { @ApiOperation(value = "Change password for current User (changePassword)", notes = "Change the password for the User which credentials are used to perform this REST API call. Be aware that previously generated [JWT](https://jwt.io/) tokens will be still valid until they expire.") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/auth/changePassword", method = RequestMethod.POST) - @ResponseStatus(value = HttpStatus.OK) + @PostMapping(value = "/auth/changePassword") public JwtPair changePassword(@Parameter(description = "Change Password Request") @RequestBody ChangePasswordRequest changePasswordRequest) throws ThingsboardException { String currentPassword = changePasswordRequest.getCurrentPassword(); @@ -125,46 +119,34 @@ public class AuthController extends BaseController { @ApiOperation(value = "Get the current User password policy (getUserPasswordPolicy)", notes = "API call to get the password policy for the password validation form(s).") - @RequestMapping(value = "/noauth/userPasswordPolicy", method = RequestMethod.GET) - @ResponseBody + @GetMapping(value = "/noauth/userPasswordPolicy") public UserPasswordPolicy getUserPasswordPolicy() throws ThingsboardException { - SecuritySettings securitySettings = - checkNotNull(systemSecurityService.getSecuritySettings()); + SecuritySettings securitySettings = checkNotNull(securitySettingsService.getSecuritySettings()); return securitySettings.getPasswordPolicy(); } @ApiOperation(value = "Check Activate User Token (checkActivateToken)", notes = "Checks the activation token and forwards user to 'Create Password' page. " + "If token is valid, returns '303 See Other' (redirect) response code with the correct address of 'Create Password' page and same 'activateToken' specified in the URL parameters. " + - "If token is not valid, returns '409 Conflict'.") - @RequestMapping(value = "/noauth/activate", params = {"activateToken"}, method = RequestMethod.GET) - public ResponseEntity<String> checkActivateToken( + "If token is not valid, returns '409 Conflict'. " + + "If token is expired, redirects to error page.") + @GetMapping(value = "/noauth/activate", params = {"activateToken"}) + public ResponseEntity<?> checkActivateToken( @Parameter(description = "The activate token string.") @RequestParam(value = "activateToken") String activateToken) { - HttpHeaders headers = new HttpHeaders(); - HttpStatus responseStatus; UserCredentials userCredentials = userService.findUserCredentialsByActivateToken(TenantId.SYS_TENANT_ID, activateToken); - if (userCredentials != null) { - String createURI = "/login/createPassword"; - try { - URI location = new URI(createURI + "?activateToken=" + activateToken); - headers.setLocation(location); - responseStatus = HttpStatus.SEE_OTHER; - } catch (URISyntaxException e) { - log.error("Unable to create URI with address [{}]", createURI); - responseStatus = HttpStatus.BAD_REQUEST; - } - } else { - responseStatus = HttpStatus.CONFLICT; + if (userCredentials == null) { + return response(HttpStatus.CONFLICT); + } else if (userCredentials.isActivationTokenExpired()) { + return redirectTo("/activationLinkExpired"); } - return new ResponseEntity<>(headers, responseStatus); + return redirectTo("/login/createPassword?activateToken=" + activateToken); } @ApiOperation(value = "Request reset password email (requestResetPasswordByEmail)", notes = "Request to send the reset password email if the user with specified email address is present in the database. " + "Always return '200 OK' status for security purposes.") - @RequestMapping(value = "/noauth/resetPasswordByEmail", method = RequestMethod.POST) - @ResponseStatus(value = HttpStatus.OK) + @PostMapping(value = "/noauth/resetPasswordByEmail") public void requestResetPasswordByEmail( @Parameter(description = "The JSON object representing the reset password email request.") @RequestBody ResetPasswordEmailRequest resetPasswordByEmailRequest, @@ -177,7 +159,7 @@ public class AuthController extends BaseController { String resetUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl, userCredentials.getResetToken()); - mailService.sendResetPasswordEmailAsync(resetUrl, email); + mailService.sendResetPasswordEmailAsync(resetUrl, userCredentials.getResetTokenTtl(), email); } catch (Exception e) { log.warn("Error occurred: {}", e.getMessage()); } @@ -186,32 +168,22 @@ public class AuthController extends BaseController { @ApiOperation(value = "Check password reset token (checkResetToken)", notes = "Checks the password reset token and forwards user to 'Reset Password' page. " + "If token is valid, returns '303 See Other' (redirect) response code with the correct address of 'Reset Password' page and same 'resetToken' specified in the URL parameters. " + - "If token is not valid, returns '409 Conflict'.") - @RequestMapping(value = "/noauth/resetPassword", params = {"resetToken"}, method = RequestMethod.GET) - public ResponseEntity<String> checkResetToken( + "If token is not valid, returns '409 Conflict'. " + + "If token is expired, redirects to error page.") + @GetMapping(value = "/noauth/resetPassword", params = {"resetToken"}) + public ResponseEntity<?> checkResetToken( @Parameter(description = "The reset token string.") @RequestParam(value = "resetToken") String resetToken) { - HttpHeaders headers = new HttpHeaders(); - HttpStatus responseStatus; - String resetURI = "/login/resetPassword"; UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken); - - if (userCredentials != null) { - if (!rateLimitService.checkRateLimit(LimitedApi.PASSWORD_RESET, userCredentials.getUserId(), defaultLimitsConfiguration)) { - return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).build(); - } - try { - URI location = new URI(resetURI + "?resetToken=" + resetToken); - headers.setLocation(location); - responseStatus = HttpStatus.SEE_OTHER; - } catch (URISyntaxException e) { - log.error("Unable to create URI with address [{}]", resetURI); - responseStatus = HttpStatus.BAD_REQUEST; - } - } else { - responseStatus = HttpStatus.CONFLICT; + if (userCredentials == null) { + return response(HttpStatus.CONFLICT); + } else if (userCredentials.isResetTokenExpired()) { + return redirectTo("/passwordResetLinkExpired"); + } + if (!rateLimitService.checkRateLimit(LimitedApi.PASSWORD_RESET, userCredentials.getUserId(), defaultLimitsConfiguration)) { + return response(HttpStatus.TOO_MANY_REQUESTS); } - return new ResponseEntity<>(headers, responseStatus); + return redirectTo("/login/resetPassword?resetToken=" + resetToken); } @ApiOperation(value = "Activate User", @@ -220,15 +192,12 @@ public class AuthController extends BaseController { "The response already contains the [JWT](https://jwt.io) activation and refresh tokens, " + "to simplify the user activation flow and avoid asking user to input password again after activation. " + "If token is valid, returns the object that contains [JWT](https://jwt.io/) access and refresh tokens. " + - "If token is not valid, returns '404 Bad Request'.") - @RequestMapping(value = "/noauth/activate", method = RequestMethod.POST) - @ResponseStatus(value = HttpStatus.OK) - @ResponseBody - public JwtPair activateUser( - @Parameter(description = "Activate user request.") - @RequestBody ActivateUserRequest activateRequest, - @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, - HttpServletRequest request) throws ThingsboardException { + "If token is not valid, returns '400 Bad Request'.") + @PostMapping(value = "/noauth/activate") + public JwtPair activateUser(@Parameter(description = "Activate user request.") + @RequestBody ActivateUserRequest activateRequest, + @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, + HttpServletRequest request) { String activateToken = activateRequest.getActivateToken(); String password = activateRequest.getPassword(); systemSecurityService.validatePassword(password, null); @@ -258,18 +227,18 @@ public class AuthController extends BaseController { @ApiOperation(value = "Reset password (resetPassword)", notes = "Checks the password reset token and updates the password. " + "If token is valid, returns the object that contains [JWT](https://jwt.io/) access and refresh tokens. " + - "If token is not valid, returns '404 Bad Request'.") - @RequestMapping(value = "/noauth/resetPassword", method = RequestMethod.POST) - @ResponseStatus(value = HttpStatus.OK) - @ResponseBody - public JwtPair resetPassword( - @Parameter(description = "Reset password request.") - @RequestBody ResetPasswordRequest resetPasswordRequest, - HttpServletRequest request) throws ThingsboardException { + "If token is not valid, returns '400 Bad Request'.") + @PostMapping(value = "/noauth/resetPassword") + public JwtPair resetPassword(@Parameter(description = "Reset password request.") + @RequestBody ResetPasswordRequest resetPasswordRequest, + HttpServletRequest request) throws ThingsboardException { String resetToken = resetPasswordRequest.getResetToken(); String password = resetPasswordRequest.getPassword(); UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken); if (userCredentials != null) { + if (userCredentials.isResetTokenExpired()) { + throw new ThingsboardException("Password reset token expired", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } systemSecurityService.validatePassword(password, userCredentials); if (passwordEncoder.matches(password, userCredentials.getPassword())) { throw new ThingsboardException("New password should be different from existing!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); @@ -277,6 +246,7 @@ public class AuthController extends BaseController { String encodedPassword = passwordEncoder.encode(password); userCredentials.setPassword(encodedPassword); userCredentials.setResetToken(null); + userCredentials.setResetTokenExpTime(null); userCredentials = userService.replaceUserCredentials(TenantId.SYS_TENANT_ID, userCredentials); User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId()); UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail()); 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 8021e71fd6..d266c7e6cc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -27,7 +27,9 @@ import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DataAccessException; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -132,8 +134,8 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.mobile.MobileAppService; import org.thingsboard.server.dao.model.ModelConstants; -import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; import org.thingsboard.server.dao.oauth2.OAuth2ClientService; +import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; @@ -170,8 +172,8 @@ import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; +import java.net.URI; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -191,7 +193,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; @TbCoreComponent public abstract class BaseController { - private final Logger log = org.slf4j.LoggerFactory.getLogger(getClass()); + protected final Logger log = org.slf4j.LoggerFactory.getLogger(getClass()); /*Swagger UI description*/ @@ -912,6 +914,23 @@ public abstract class BaseController { } } + protected <T> ResponseEntity<T> response(HttpStatus status) { + return ResponseEntity.status(status).build(); + } + + protected <T> ResponseEntity<T> redirectTo(String location) { + URI uri; + try { + uri = URI.create(location); + } catch (IllegalArgumentException e) { + log.error("Failed to create URI from '{}'", location, e); + throw e; + } + return ResponseEntity.status(HttpStatus.SEE_OTHER) + .location(uri) + .build(); + } + protected List<OAuth2ClientId> getOAuth2ClientIds(UUID[] ids) throws ThingsboardException { if (ids == null) { return Collections.emptyList(); diff --git a/application/src/main/java/org/thingsboard/server/controller/ImageController.java b/application/src/main/java/org/thingsboard/server/controller/ImageController.java index 6ebb6fffe8..88b33389a5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ImageController.java +++ b/application/src/main/java/org/thingsboard/server/controller/ImageController.java @@ -312,7 +312,7 @@ public class ImageController extends BaseController { if (StringUtils.isNotEmpty(etag)) { etag = StringUtils.remove(etag, '\"'); // etag is wrapped in double quotes due to HTTP specification if (etag.equals(tbImageService.getETag(cacheKey))) { - return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build(); + return response(HttpStatus.NOT_MODIFIED); } } diff --git a/application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java b/application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java index ca8b11ee80..11f017b85f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java @@ -183,8 +183,7 @@ public class MobileApplicationController extends BaseController { .header("Location", appStoreLink) .build(); } else { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .build(); + return response(HttpStatus.NOT_FOUND); } } diff --git a/application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java b/application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java index bc12171306..9600ac0221 100644 --- a/application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java +++ b/application/src/main/java/org/thingsboard/server/controller/SystemInfoController.java @@ -164,6 +164,7 @@ public class SystemInfoController extends BaseController { } else { infoObject.put("version", "unknown"); } + infoObject.put("type", "CE"); return infoObject; } } diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java index 1772a64772..a71bd4dd38 100644 --- a/application/src/main/java/org/thingsboard/server/controller/UserController.java +++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java @@ -21,7 +21,6 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpStatus; @@ -44,6 +43,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.UserActivationLink; import org.thingsboard.server.common.data.UserEmailInfo; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; @@ -119,7 +119,6 @@ public class UserController extends BaseController { public static final String USER_ID = "userId"; public static final String PATHS = "paths"; public static final String YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION = "You don't have permission to perform this operation!"; - public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s"; public static final String MOBILE_TOKEN_HEADER = "X-Mobile-Token"; @Value("${security.user_token_access_enabled}") @@ -130,12 +129,8 @@ public class UserController extends BaseController { private final SystemSecurityService systemSecurityService; private final ApplicationEventPublisher eventPublisher; private final TbUserService tbUserService; - - @Autowired - private EntityQueryService entityQueryService; - - @Autowired - private EntityService entityService; + private final EntityQueryService entityQueryService; + private final EntityService entityService; @ApiOperation(value = "Get User (getUserById)", notes = "Fetch the User object based on the provided User Id. " + @@ -212,7 +207,7 @@ public class UserController extends BaseController { public User saveUser( @Parameter(description = "A JSON value representing the User.", required = true) @RequestBody User user, - @Parameter(description = "Send activation email (or use activation link)" , schema = @Schema(defaultValue = "true")) + @Parameter(description = "Send activation email (or use activation link)", schema = @Schema(defaultValue = "true")) @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, HttpServletRequest request) throws ThingsboardException { if (!Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { user.setTenantId(getCurrentUser().getTenantId()); @@ -230,45 +225,39 @@ public class UserController extends BaseController { @Parameter(description = "Email of the user", required = true) @RequestParam(value = "email") String email, HttpServletRequest request) throws ThingsboardException { - User user = checkNotNull(userService.findUserByEmail(getCurrentUser().getTenantId(), email)); - - accessControlService.checkPermission(getCurrentUser(), Resource.USER, Operation.READ, - user.getId(), user); + SecurityUser securityUser = getCurrentUser(); + User user = checkNotNull(userService.findUserByEmail(securityUser.getTenantId(), email)); + accessControlService.checkPermission(securityUser, Resource.USER, Operation.READ, user.getId(), user); - UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId()); - if (!userCredentials.isEnabled() && userCredentials.getActivateToken() != null) { - String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request); - String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl, - userCredentials.getActivateToken()); - mailService.sendActivationEmail(activateUrl, email); - } else { - throw new ThingsboardException("User is already activated!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); - } + UserActivationLink activationLink = tbUserService.getActivationLink(securityUser.getTenantId(), securityUser.getCustomerId(), user.getId(), request); + mailService.sendActivationEmail(activationLink.value(), activationLink.ttlMs(), email); } - @ApiOperation(value = "Get the activation link (getActivationLink)", + @ApiOperation(value = "Get activation link (getActivationLink)", notes = "Get the activation link for the user. " + "The base url for activation link is configurable in the general settings of system administrator. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") - @RequestMapping(value = "/user/{userId}/activationLink", method = RequestMethod.GET, produces = "text/plain") + @GetMapping(value = "/user/{userId}/activationLink", produces = "text/plain") @ResponseBody - public String getActivationLink( - @Parameter(description = USER_ID_PARAM_DESCRIPTION) - @PathVariable(USER_ID) String strUserId, - HttpServletRequest request) throws ThingsboardException { + public String getActivationLink(@Parameter(description = USER_ID_PARAM_DESCRIPTION) + @PathVariable(USER_ID) String strUserId, + HttpServletRequest request) throws ThingsboardException { + return getActivationLinkInfo(strUserId, request).value(); + } + + @ApiOperation(value = "Get activation link info (getActivationLinkInfo)", + notes = "Get the activation link info for the user. " + + "The base url for activation link is configurable in the general settings of system administrator. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") + @GetMapping(value = "/user/{userId}/activationLinkInfo") + public UserActivationLink getActivationLinkInfo(@Parameter(description = USER_ID_PARAM_DESCRIPTION) + @PathVariable(USER_ID) String strUserId, + HttpServletRequest request) throws ThingsboardException { checkParameter(USER_ID, strUserId); UserId userId = new UserId(toUUID(strUserId)); - User user = checkUserId(userId, Operation.READ); - SecurityUser authUser = getCurrentUser(); - UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), user.getId()); - if (!userCredentials.isEnabled() && userCredentials.getActivateToken() != null) { - String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request); - String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl, - userCredentials.getActivateToken()); - return activateUrl; - } else { - throw new ThingsboardException("User is already activated!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); - } + checkUserId(userId, Operation.READ); + SecurityUser securityUser = getCurrentUser(); + return tbUserService.getActivationLink(securityUser.getTenantId(), securityUser.getCustomerId(), userId, request); } @ApiOperation(value = "Delete User (deleteUser)", @@ -411,7 +400,7 @@ public class UserController extends BaseController { public void setUserCredentialsEnabled( @Parameter(description = USER_ID_PARAM_DESCRIPTION) @PathVariable(USER_ID) String strUserId, - @Parameter(description = "Enable (\"true\") or disable (\"false\") the credentials." , schema = @Schema(defaultValue = "true")) + @Parameter(description = "Enable (\"true\") or disable (\"false\") the credentials.", schema = @Schema(defaultValue = "true")) @RequestParam(required = false, defaultValue = "true") boolean userCredentialsEnabled) throws ThingsboardException { checkParameter(USER_ID, strUserId); UserId userId = new UserId(toUUID(strUserId)); 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 index 840750a781..17ceb17ed1 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java @@ -34,8 +34,10 @@ import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.EntityAlarm; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.domain.Domain; +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.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; @@ -134,6 +136,17 @@ public class EdgeEventSourcingListener { return; } try { + if (event.getEntityId().getEntityType().equals(EntityType.RULE_CHAIN) && event.getEdgeId() != null && event.getActionType().equals(ActionType.ASSIGNED_TO_EDGE)) { + try { + Edge edge = JacksonUtil.fromString(event.getBody(), Edge.class); + if (edge != null && new RuleChainId(event.getEntityId().getId()).equals(edge.getRootRuleChainId())) { + log.trace("[{}] skipping ASSIGNED_TO_EDGE event of RULE_CHAIN entity in case Edge Root Rule Chain: {}", event.getTenantId(), event); + return; + } + } catch (Exception ignored) { + return; + } + } log.trace("[{}] ActionEntityEvent called: {}", event.getTenantId(), event); tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), event.getEdgeId(), event.getEntityId(), event.getBody(), null, EdgeUtils.getEdgeEventActionTypeByActionType(event.getActionType()), diff --git a/application/src/main/java/org/thingsboard/server/service/edge/RelatedEdgesSourcingListener.java b/application/src/main/java/org/thingsboard/server/service/edge/RelatedEdgesSourcingListener.java index 851f59c3ab..2132b9e4a6 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/RelatedEdgesSourcingListener.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/RelatedEdgesSourcingListener.java @@ -55,6 +55,7 @@ public class RelatedEdgesSourcingListener { @TransactionalEventListener(fallbackExecution = true) public void handleEvent(ActionEntityEvent<?> event) { executorService.submit(() -> { + log.trace("[{}] ActionEntityEvent called: {}", event.getTenantId(), event); try { switch (event.getActionType()) { case ASSIGNED_TO_EDGE, UNASSIGNED_FROM_EDGE -> @@ -69,6 +70,7 @@ public class RelatedEdgesSourcingListener { @TransactionalEventListener(fallbackExecution = true) public void handleEvent(DeleteEntityEvent<?> event) { executorService.submit(() -> { + log.trace("[{}] DeleteEntityEvent called: {}", event.getTenantId(), event); try { relatedEdgesService.publishRelatedEdgeIdsEvictEvent(event.getTenantId(), event.getEntityId()); } catch (Exception e) { 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 299d499daa..ad4b7c097e 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 @@ -22,7 +22,9 @@ import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.UserActivationLink; 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.CustomerId; import org.thingsboard.server.common.data.id.TenantId; @@ -33,7 +35,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.security.system.SystemSecurityService; -import static org.thingsboard.server.controller.UserController.ACTIVATE_URL_PATTERN; +import java.util.concurrent.TimeUnit; @Service @TbCoreComponent @@ -53,13 +55,9 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse boolean sendEmail = tbUser.getId() == null && sendActivationMail; User savedUser = checkNotNull(userService.saveUser(tenantId, tbUser)); if (sendEmail) { - UserCredentials userCredentials = userService.findUserCredentialsByUserId(tenantId, savedUser.getId()); - String baseUrl = systemSecurityService.getBaseUrl(tenantId, customerId, request); - String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl, - userCredentials.getActivateToken()); - String email = savedUser.getEmail(); + UserActivationLink activationLink = getActivationLink(tenantId, customerId, savedUser.getId(), request); try { - mailService.sendActivationEmail(activateUrl, email); + mailService.sendActivationEmail(activationLink.value(), activationLink.ttlMs(), savedUser.getEmail()); } catch (ThingsboardException e) { userService.deleteUser(tenantId, savedUser); throw e; @@ -87,4 +85,24 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse throw e; } } + + @Override + public UserActivationLink getActivationLink(TenantId tenantId, CustomerId customerId, UserId userId, HttpServletRequest request) throws ThingsboardException { + UserCredentials userCredentials = userService.findUserCredentialsByUserId(tenantId, userId); + if (!userCredentials.isEnabled() && userCredentials.getActivateToken() != null) { + long ttl = userCredentials.getActivationTokenTtl(); + if (ttl < TimeUnit.MINUTES.toMillis(15)) { // renew link if less than 15 minutes before expiration + userCredentials = userService.generateUserActivationToken(userCredentials); + userCredentials = userService.saveUserCredentials(tenantId, userCredentials); + ttl = userCredentials.getActivationTokenTtl(); + log.debug("[{}][{}] Regenerated expired user activation token", tenantId, userId); + } + String baseUrl = systemSecurityService.getBaseUrl(tenantId, customerId, request); + String link = baseUrl + "/api/noauth/activate?activateToken=" + userCredentials.getActivateToken(); + return new UserActivationLink(link, ttl); + } else { + throw new ThingsboardException("User is already activated!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java index 388db9df40..e7689692a4 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/TbUserService.java @@ -16,14 +16,19 @@ package org.thingsboard.server.service.entitiy.user; import jakarta.servlet.http.HttpServletRequest; +import org.thingsboard.server.common.data.UserActivationLink; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; public interface TbUserService { User save(TenantId tenantId, CustomerId customerId, User tbUser, boolean sendActivationMail, HttpServletRequest request, User user) throws ThingsboardException; void delete(TenantId tenantId, CustomerId customerId, User user, User responsibleUser) throws ThingsboardException; + + UserActivationLink getActivationLink(TenantId tenantId, CustomerId customerId, UserId userId, HttpServletRequest request) throws ThingsboardException; + } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java index 0085df35d7..1a03ae491a 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java @@ -92,4 +92,5 @@ public class DefaultCacheCleanupService implements CacheCleanupService { } cacheManager.getCacheNames().forEach(this::clearCacheByName); } + } 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 3577683729..1603720450 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 @@ -160,12 +160,12 @@ public class DefaultMailService implements MailService { } @Override - public void sendActivationEmail(String activationLink, String email) throws ThingsboardException { - + public void sendActivationEmail(String activationLink, long ttlMs, String email) throws ThingsboardException { String subject = messages.getMessage("activation.subject", null, Locale.US); Map<String, Object> model = new HashMap<>(); model.put("activationLink", activationLink); + model.put("activationLinkTtlInHours", (int) Math.ceil(ttlMs / 3600000.0)); model.put(TARGET_EMAIL, email); String message = mergeTemplateIntoString("activation.ftl", model); @@ -188,12 +188,13 @@ public class DefaultMailService implements MailService { } @Override - public void sendResetPasswordEmail(String passwordResetLink, String email) throws ThingsboardException { + public void sendResetPasswordEmail(String passwordResetLink, long ttlMs, String email) throws ThingsboardException { String subject = messages.getMessage("reset.password.subject", null, Locale.US); Map<String, Object> model = new HashMap<>(); model.put("passwordResetLink", passwordResetLink); + model.put("passwordResetLinkTtlInHours", (int) Math.ceil(ttlMs / 3600000.0)); model.put(TARGET_EMAIL, email); String message = mergeTemplateIntoString("reset.password.ftl", model); @@ -202,10 +203,10 @@ public class DefaultMailService implements MailService { } @Override - public void sendResetPasswordEmailAsync(String passwordResetLink, String email) { + public void sendResetPasswordEmailAsync(String passwordResetLink, long ttlMs, String email) { passwordResetExecutorService.execute(() -> { try { - this.sendResetPasswordEmail(passwordResetLink, email); + this.sendResetPasswordEmail(passwordResetLink, ttlMs, email); } catch (Exception e) { log.error("Error occurred: {} ", e.getMessage()); } diff --git a/application/src/main/java/org/thingsboard/server/service/mail/DefaultTbMailConfigTemplateService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultTbMailConfigTemplateService.java index 14e52c1326..7c86771f8d 100644 --- a/application/src/main/java/org/thingsboard/server/service/mail/DefaultTbMailConfigTemplateService.java +++ b/application/src/main/java/org/thingsboard/server/service/mail/DefaultTbMailConfigTemplateService.java @@ -32,7 +32,7 @@ public class DefaultTbMailConfigTemplateService implements TbMailConfigTemplateS @PostConstruct private void postConstruct() throws IOException { - mailConfigTemplates = JacksonUtil.toJsonNode(new ClassPathResource("/templates/mail_config_templates.json").getFile()); + mailConfigTemplates = JacksonUtil.toJsonNode(new ClassPathResource("/templates/mail_config_templates.json").getInputStream()); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/mobile/secret/MobileAppSecretServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/mobile/secret/MobileAppSecretServiceImpl.java index bef31622ff..73496ca1a0 100644 --- a/application/src/main/java/org/thingsboard/server/service/mobile/secret/MobileAppSecretServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/mobile/secret/MobileAppSecretServiceImpl.java @@ -25,11 +25,12 @@ import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.security.model.JwtPair; import org.thingsboard.server.dao.entity.AbstractCachedService; +import org.thingsboard.server.dao.settings.SecuritySettingsService; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.token.JwtTokenFactory; -import org.thingsboard.server.service.security.system.SystemSecurityService; -import static org.thingsboard.server.service.security.system.DefaultSystemSecurityService.DEFAULT_MOBILE_SECRET_KEY_LENGTH; +import static org.thingsboard.server.dao.settings.DefaultSecuritySettingsService.DEFAULT_MOBILE_SECRET_KEY_LENGTH; + @Service @Slf4j @@ -37,12 +38,12 @@ import static org.thingsboard.server.service.security.system.DefaultSystemSecuri public class MobileAppSecretServiceImpl extends AbstractCachedService<String, JwtPair, MobileSecretEvictEvent> implements MobileAppSecretService { private final JwtTokenFactory tokenFactory; - private final SystemSecurityService systemSecurityService; + private final SecuritySettingsService securitySettingsService; @Override public String generateMobileAppSecret(SecurityUser securityUser) { log.trace("Executing generateSecret for user [{}]", securityUser.getId()); - Integer mobileSecretKeyLength = systemSecurityService.getSecuritySettings().getMobileSecretKeyLength(); + Integer mobileSecretKeyLength = securitySettingsService.getSecuritySettings().getMobileSecretKeyLength(); String secret = StringUtils.generateSafeToken(mobileSecretKeyLength == null ? DEFAULT_MOBILE_SECRET_KEY_LENGTH : mobileSecretKeyLength); cache.put(secret, tokenFactory.createTokenPair(securityUser)); return secret; @@ -63,4 +64,5 @@ public class MobileAppSecretServiceImpl extends AbstractCachedService<String, Jw public void handleEvictEvent(MobileSecretEvictEvent event) { cache.evict(event.getSecret()); } + } diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestAuthenticationProvider.java b/application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestAuthenticationProvider.java index 65fa344957..b9fe54deec 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestAuthenticationProvider.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/rest/RestAuthenticationProvider.java @@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.settings.SecuritySettingsService; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.auth.MfaAuthenticationToken; @@ -58,6 +59,7 @@ import java.util.UUID; public class RestAuthenticationProvider implements AuthenticationProvider { private final SystemSecurityService systemSecurityService; + private final SecuritySettingsService securitySettingsService; private final UserService userService; private final CustomerService customerService; private final TwoFactorAuthService twoFactorAuthService; @@ -66,10 +68,12 @@ public class RestAuthenticationProvider implements AuthenticationProvider { public RestAuthenticationProvider(final UserService userService, final CustomerService customerService, final SystemSecurityService systemSecurityService, + SecuritySettingsService securitySettingsService, TwoFactorAuthService twoFactorAuthService) { this.userService = userService; this.customerService = customerService; this.systemSecurityService = systemSecurityService; + this.securitySettingsService = securitySettingsService; this.twoFactorAuthService = twoFactorAuthService; } @@ -82,13 +86,13 @@ public class RestAuthenticationProvider implements AuthenticationProvider { throw new BadCredentialsException("Authentication Failed. Bad user principal."); } - UserPrincipal userPrincipal = (UserPrincipal) principal; + UserPrincipal userPrincipal = (UserPrincipal) principal; SecurityUser securityUser; if (userPrincipal.getType() == UserPrincipal.Type.USER_NAME) { String username = userPrincipal.getValue(); String password = (String) authentication.getCredentials(); - SecuritySettings securitySettings = systemSecurityService.getSecuritySettings(); + SecuritySettings securitySettings = securitySettingsService.getSecuritySettings(); UserPasswordPolicy passwordPolicy = securitySettings.getPasswordPolicy(); if (Boolean.TRUE.equals(passwordPolicy.getForceUserToResetPasswordIfNotValid())) { try { diff --git a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java index 1b8cec2c91..6516bd7ce6 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java @@ -18,8 +18,8 @@ package org.thingsboard.server.service.security.system; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.passay.CharacterRule; import org.passay.EnglishCharacterData; @@ -29,9 +29,6 @@ import org.passay.PasswordValidator; import org.passay.Rule; import org.passay.RuleResult; import org.passay.WhitespaceRule; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.Cacheable; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.LockedException; @@ -55,6 +52,7 @@ import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettin import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.settings.AdminSettingsService; +import org.thingsboard.server.dao.settings.SecuritySettingsService; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserServiceImpl; import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails; @@ -68,76 +66,23 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; -import static org.thingsboard.server.common.data.CacheConstants.SECURITY_SETTINGS_CACHE; - @Service @Slf4j +@RequiredArgsConstructor public class DefaultSystemSecurityService implements SystemSecurityService { - public static final int DEFAULT_MOBILE_SECRET_KEY_LENGTH = 64; - - @Autowired - private AdminSettingsService adminSettingsService; - - @Autowired - private BCryptPasswordEncoder encoder; - - @Autowired - private UserService userService; - - @Autowired - private MailService mailService; - - @Autowired - private AuditLogService auditLogService; - - @Resource - private SystemSecurityService self; - - @Cacheable(cacheNames = SECURITY_SETTINGS_CACHE, key = "'securitySettings'") - @Override - public SecuritySettings getSecuritySettings() { - SecuritySettings securitySettings = null; - AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "securitySettings"); - if (adminSettings != null) { - try { - securitySettings = JacksonUtil.convertValue(adminSettings.getJsonValue(), SecuritySettings.class); - } catch (Exception e) { - throw new RuntimeException("Failed to load security settings!", e); - } - } else { - securitySettings = new SecuritySettings(); - securitySettings.setPasswordPolicy(new UserPasswordPolicy()); - securitySettings.getPasswordPolicy().setMinimumLength(6); - securitySettings.getPasswordPolicy().setMaximumLength(72); - securitySettings.setMobileSecretKeyLength(DEFAULT_MOBILE_SECRET_KEY_LENGTH); - } - return securitySettings; - } - - @CacheEvict(cacheNames = SECURITY_SETTINGS_CACHE, key = "'securitySettings'") - @Override - public SecuritySettings saveSecuritySettings(SecuritySettings securitySettings) { - AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "securitySettings"); - if (adminSettings == null) { - adminSettings = new AdminSettings(); - adminSettings.setTenantId(TenantId.SYS_TENANT_ID); - adminSettings.setKey("securitySettings"); - } - adminSettings.setJsonValue(JacksonUtil.valueToTree(securitySettings)); - AdminSettings savedAdminSettings = adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings); - try { - return JacksonUtil.convertValue(savedAdminSettings.getJsonValue(), SecuritySettings.class); - } catch (Exception e) { - throw new RuntimeException("Failed to load security settings!", e); - } - } + private final AdminSettingsService adminSettingsService; + private final BCryptPasswordEncoder encoder; + private final UserService userService; + private final MailService mailService; + private final AuditLogService auditLogService; + private final SecuritySettingsService securitySettingsService; @Override public void validateUserCredentials(TenantId tenantId, UserCredentials userCredentials, String username, String password) throws AuthenticationException { if (!encoder.matches(password, userCredentials.getPassword())) { int failedLoginAttempts = userService.increaseFailedLoginAttempts(tenantId, userCredentials.getUserId()); - SecuritySettings securitySettings = self.getSecuritySettings(); + SecuritySettings securitySettings = securitySettingsService.getSecuritySettings(); if (securitySettings.getMaxFailedLoginAttempts() != null && securitySettings.getMaxFailedLoginAttempts() > 0) { if (failedLoginAttempts > securitySettings.getMaxFailedLoginAttempts() && userCredentials.isEnabled()) { lockAccount(userCredentials.getUserId(), username, securitySettings.getUserLockoutNotificationEmail(), securitySettings.getMaxFailedLoginAttempts()); @@ -153,7 +98,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService { userService.resetFailedLoginAttempts(tenantId, userCredentials.getUserId()); - SecuritySettings securitySettings = self.getSecuritySettings(); + SecuritySettings securitySettings = securitySettingsService.getSecuritySettings(); if (isPositiveInteger(securitySettings.getPasswordPolicy().getPasswordExpirationPeriodDays())) { if ((userCredentials.getCreatedTime() + TimeUnit.DAYS.toMillis(securitySettings.getPasswordPolicy().getPasswordExpirationPeriodDays())) @@ -181,7 +126,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService { if (maxVerificationFailures != null && maxVerificationFailures > 0 && failedVerificationAttempts >= maxVerificationFailures) { userService.setUserCredentialsEnabled(TenantId.SYS_TENANT_ID, userId, false); - SecuritySettings securitySettings = self.getSecuritySettings(); + SecuritySettings securitySettings = securitySettingsService.getSecuritySettings(); lockAccount(userId, securityUser.getEmail(), securitySettings.getUserLockoutNotificationEmail(), maxVerificationFailures); throw new LockedException("User account was locked due to exceeded 2FA verification attempts"); } @@ -200,7 +145,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService { @Override public void validatePassword(String password, UserCredentials userCredentials) throws DataValidationException { - SecuritySettings securitySettings = self.getSecuritySettings(); + SecuritySettings securitySettings = securitySettingsService.getSecuritySettings(); UserPasswordPolicy passwordPolicy = securitySettings.getPasswordPolicy(); validatePasswordByPolicy(password, passwordPolicy); @@ -330,4 +275,5 @@ public class DefaultSystemSecurityService implements SystemSecurityService { private static boolean isPositiveInteger(Integer val) { return val != null && val.intValue() > 0; } + } diff --git a/application/src/main/java/org/thingsboard/server/service/security/system/SystemSecurityService.java b/application/src/main/java/org/thingsboard/server/service/security/system/SystemSecurityService.java index 737bf95b13..8c1ac733ee 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/system/SystemSecurityService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/system/SystemSecurityService.java @@ -22,7 +22,6 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.UserCredentials; -import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings; import org.thingsboard.server.dao.exception.DataValidationException; @@ -30,10 +29,6 @@ import org.thingsboard.server.service.security.model.SecurityUser; public interface SystemSecurityService { - SecuritySettings getSecuritySettings(); - - SecuritySettings saveSecuritySettings(SecuritySettings securitySettings); - void validatePasswordByPolicy(String password, UserPasswordPolicy passwordPolicy); void validateUserCredentials(TenantId tenantId, UserCredentials userCredentials, String username, String password) throws AuthenticationException; @@ -47,4 +42,5 @@ public interface SystemSecurityService { void logLoginAction(User user, Object authenticationDetails, ActionType actionType, Exception e); void logLoginAction(User user, Object authenticationDetails, ActionType actionType, String provider, Exception e); + } diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java index 632ea44940..019b6eb5e8 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java @@ -94,7 +94,7 @@ import java.util.stream.Collectors; public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubscriptionService { private static final int DEFAULT_LIMIT = 100; - private final Map<String, Map<Integer, TbAbstractSubCtx>> subscriptionsBySessionId = new ConcurrentHashMap<>(); + private final ConcurrentMap<String, ConcurrentMap<Integer, TbAbstractSubCtx>> subscriptionsBySessionId = new ConcurrentHashMap<>(); @Autowired @Lazy @@ -495,7 +495,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc } private TbEntityDataSubCtx createSubCtx(WebSocketSessionRef sessionRef, EntityDataCmd cmd) { - Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); + Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new ConcurrentHashMap<>()); TbEntityDataSubCtx ctx = new TbEntityDataSubCtx(serviceId, wsService, entityService, localSubscriptionService, attributesService, stats, sessionRef, cmd.getCmdId(), maxEntitiesPerDataSubscription); if (cmd.getQuery() != null) { @@ -506,7 +506,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc } private TbEntityCountSubCtx createSubCtx(WebSocketSessionRef sessionRef, EntityCountCmd cmd) { - Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); + Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new ConcurrentHashMap<>()); TbEntityCountSubCtx ctx = new TbEntityCountSubCtx(serviceId, wsService, entityService, localSubscriptionService, attributesService, stats, sessionRef, cmd.getCmdId()); if (cmd.getQuery() != null) { @@ -518,7 +518,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc private TbAlarmDataSubCtx createSubCtx(WebSocketSessionRef sessionRef, AlarmDataCmd cmd) { - Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); + Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new ConcurrentHashMap<>()); TbAlarmDataSubCtx ctx = new TbAlarmDataSubCtx(serviceId, wsService, entityService, localSubscriptionService, attributesService, stats, alarmService, sessionRef, cmd.getCmdId(), maxEntitiesPerAlarmSubscription, maxAlarmQueriesPerRefreshInterval); @@ -528,7 +528,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc } private TbAlarmCountSubCtx createSubCtx(WebSocketSessionRef sessionRef, AlarmCountCmd cmd) { - Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); + Map<Integer, TbAbstractSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new ConcurrentHashMap<>()); TbAlarmCountSubCtx ctx = new TbAlarmCountSubCtx(serviceId, wsService, entityService, localSubscriptionService, attributesService, stats, alarmService, sessionRef, cmd.getCmdId()); if (cmd.getQuery() != null) { diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java index bbfdd2d44f..1e701c7b5c 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbLocalSubscriptionService.java @@ -85,7 +85,7 @@ import java.util.stream.Collectors; @Service public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionService { - private final ConcurrentMap<String, Map<Integer, TbSubscription<?>>> subscriptionsBySessionId = new ConcurrentHashMap<>(); + private final ConcurrentMap<String, ConcurrentMap<Integer, TbSubscription<?>>> subscriptionsBySessionId = new ConcurrentHashMap<>(); private final ConcurrentMap<UUID, TbEntityLocalSubsInfo> subscriptionsByEntityId = new ConcurrentHashMap<>(); private final ConcurrentMap<UUID, TbEntityUpdatesInfo> entityUpdates = new ConcurrentHashMap<>(); diff --git a/application/src/main/resources/templates/activation.ftl b/application/src/main/resources/templates/activation.ftl index ce51930521..d5c148a56b 100644 --- a/application/src/main/resources/templates/activation.ftl +++ b/application/src/main/resources/templates/activation.ftl @@ -88,7 +88,7 @@ background-color: #f6f6f6; </tr> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> - To confirm your email address and choose a password, just click the button below. + To confirm your email address and choose a password, just click the button below. The link will expire in ${activationLinkTtlInHours} hours. </td> </tr> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> diff --git a/application/src/main/resources/templates/reset.password.ftl b/application/src/main/resources/templates/reset.password.ftl index 3f36c922f0..6b2fa5e8bf 100644 --- a/application/src/main/resources/templates/reset.password.ftl +++ b/application/src/main/resources/templates/reset.password.ftl @@ -93,7 +93,7 @@ background-color: #f6f6f6; </tr> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> <td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> - Click below in order to proceed password reset procedure. + Click below in order to proceed password reset procedure. The link will expire in ${passwordResetLinkTtlInHours} hours. </td> </tr> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 785f124583..e1893511f3 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1658,6 +1658,8 @@ queue: connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}" # RabbitMQ has a timeout for connection handshake. When clients run in heavily constrained environments, it may be necessary to increase the timeout handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}" + # The maximum number of messages returned in a single call of doPoll() method + max_poll_messages: "${TB_QUEUE_RABBIT_MQ_MAX_POLL_MESSAGES:1}" queue-properties: # RabbitMQ properties for Rule Engine queues rule-engine: "${TB_QUEUE_RABBIT_MQ_RE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" 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 eba04e7b5e..af20c71e5b 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -145,6 +145,7 @@ import java.util.function.Consumer; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; @@ -340,7 +341,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { currentActivateToken = activationLink.split("=")[1]; return null; } - }).when(mailService).sendActivationEmail(anyString(), anyString()); + }).when(mailService).sendActivationEmail(anyString(), anyLong(), anyString()); Mockito.doAnswer(new Answer<Void>() { public Void answer(InvocationOnMock invocation) { @@ -349,7 +350,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { currentResetPasswordToken = passwordResetLink.split("=")[1]; return null; } - }).when(mailService).sendResetPasswordEmailAsync(anyString(), anyString()); + }).when(mailService).sendResetPasswordEmailAsync(anyString(), anyLong(), anyString()); } @After diff --git a/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java index 1cf389a93d..817ded33e7 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java @@ -16,20 +16,30 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.JsonNode; +import org.assertj.core.data.Offset; import org.junit.After; import org.junit.Test; import org.mockito.Mockito; +import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.http.HttpHeaders; import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.UserActivationLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.dao.user.UserCredentialsDao; import org.thingsboard.server.service.security.auth.rest.LoginRequest; import org.thingsboard.server.service.security.model.ChangePasswordRequest; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.within; import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.anyString; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; @@ -39,55 +49,55 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @DaoSqlTest public class AuthControllerTest extends AbstractControllerTest { + @SpyBean + private UserCredentialsDao userCredentialsDao; + @After public void tearDown() throws Exception { loginSysAdmin(); - SecuritySettings securitySettings = doGet("/api/admin/securitySettings", SecuritySettings.class); - - securitySettings.getPasswordPolicy().setMaximumLength(72); - securitySettings.getPasswordPolicy().setForceUserToResetPasswordIfNotValid(false); - - doPost("/api/admin/securitySettings", securitySettings).andExpect(status().isOk()); + updateSecuritySettings(securitySettings -> { + securitySettings.getPasswordPolicy().setMaximumLength(72); + securitySettings.getPasswordPolicy().setForceUserToResetPasswordIfNotValid(false); + }); } @Test public void testGetUser() throws Exception { - doGet("/api/auth/user") - .andExpect(status().isUnauthorized()); - + .andExpect(status().isUnauthorized()); + loginSysAdmin(); doGet("/api/auth/user") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.authority",is(Authority.SYS_ADMIN.name()))) - .andExpect(jsonPath("$.email",is(SYS_ADMIN_EMAIL))); - + .andExpect(status().isOk()) + .andExpect(jsonPath("$.authority", is(Authority.SYS_ADMIN.name()))) + .andExpect(jsonPath("$.email", is(SYS_ADMIN_EMAIL))); + loginTenantAdmin(); doGet("/api/auth/user") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.authority",is(Authority.TENANT_ADMIN.name()))) - .andExpect(jsonPath("$.email",is(TENANT_ADMIN_EMAIL))); - + .andExpect(status().isOk()) + .andExpect(jsonPath("$.authority", is(Authority.TENANT_ADMIN.name()))) + .andExpect(jsonPath("$.email", is(TENANT_ADMIN_EMAIL))); + loginCustomerUser(); doGet("/api/auth/user") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.authority",is(Authority.CUSTOMER_USER.name()))) - .andExpect(jsonPath("$.email",is(CUSTOMER_USER_EMAIL))); + .andExpect(status().isOk()) + .andExpect(jsonPath("$.authority", is(Authority.CUSTOMER_USER.name()))) + .andExpect(jsonPath("$.email", is(CUSTOMER_USER_EMAIL))); } - + @Test public void testLoginLogout() throws Exception { loginSysAdmin(); doGet("/api/auth/user") - .andExpect(status().isOk()) - .andExpect(jsonPath("$.authority",is(Authority.SYS_ADMIN.name()))) - .andExpect(jsonPath("$.email",is(SYS_ADMIN_EMAIL))); + .andExpect(status().isOk()) + .andExpect(jsonPath("$.authority", is(Authority.SYS_ADMIN.name()))) + .andExpect(jsonPath("$.email", is(SYS_ADMIN_EMAIL))); TimeUnit.SECONDS.sleep(1); //We need to make sure that event for invalidating token was successfully processed logout(); doGet("/api/auth/user") - .andExpect(status().isUnauthorized()); + .andExpect(status().isUnauthorized()); resetTokens(); } @@ -97,14 +107,14 @@ public class AuthControllerTest extends AbstractControllerTest { loginSysAdmin(); doGet("/api/auth/user") .andExpect(status().isOk()) - .andExpect(jsonPath("$.authority",is(Authority.SYS_ADMIN.name()))) - .andExpect(jsonPath("$.email",is(SYS_ADMIN_EMAIL))); + .andExpect(jsonPath("$.authority", is(Authority.SYS_ADMIN.name()))) + .andExpect(jsonPath("$.email", is(SYS_ADMIN_EMAIL))); refreshToken(); doGet("/api/auth/user") .andExpect(status().isOk()) - .andExpect(jsonPath("$.authority",is(Authority.SYS_ADMIN.name()))) - .andExpect(jsonPath("$.email",is(SYS_ADMIN_EMAIL))); + .andExpect(jsonPath("$.authority", is(Authority.SYS_ADMIN.name()))) + .andExpect(jsonPath("$.email", is(SYS_ADMIN_EMAIL))); } @Test @@ -131,10 +141,10 @@ public class AuthControllerTest extends AbstractControllerTest { loginUser(TENANT_ADMIN_EMAIL, newPassword); loginSysAdmin(); - SecuritySettings securitySettings = doGet("/api/admin/securitySettings", SecuritySettings.class); - securitySettings.getPasswordPolicy().setMaximumLength(15); - securitySettings.getPasswordPolicy().setForceUserToResetPasswordIfNotValid(true); - doPost("/api/admin/securitySettings", securitySettings).andExpect(status().isOk()); + updateSecuritySettings(securitySettings -> { + securitySettings.getPasswordPolicy().setMaximumLength(15); + securitySettings.getPasswordPolicy().setForceUserToResetPasswordIfNotValid(true); + }); //try to login with user password that is not valid after security settings was updated doPost("/api/auth/login", new LoginRequest(TENANT_ADMIN_EMAIL, newPassword)) @@ -142,6 +152,7 @@ public class AuthControllerTest extends AbstractControllerTest { .andExpect(jsonPath("$.message", is("The entered password violates our policies. If this is your real password, please reset it."))); } + @Test public void testShouldNotResetPasswordToTooLongValue() throws Exception { loginTenantAdmin(); @@ -163,9 +174,95 @@ public class AuthControllerTest extends AbstractControllerTest { Mockito.doNothing().when(mailService).sendPasswordWasResetEmail(anyString(), anyString()); doPost("/api/noauth/resetPassword", resetPasswordRequest) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.message", - is("Password must be no more than 72 characters in length."))); + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message", + is("Password must be no more than 72 characters in length."))); + } + + @Test + public void testPasswordResetLinkTtl() throws Exception { + loginSysAdmin(); + int ttl = 24; + updateSecuritySettings(securitySettings -> { + securitySettings.setPasswordResetTokenTtl(ttl); + }); + doPost("/api/noauth/resetPasswordByEmail", JacksonUtil.newObjectNode() + .put("email", TENANT_ADMIN_EMAIL)).andExpect(status().isOk()); + + UserCredentials userCredentials = userCredentialsDao.findByUserId(tenantId, tenantAdminUserId.getId()); + assertThat(userCredentials.getResetTokenExpTime()).isCloseTo(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(ttl), Offset.offset(120000L)); + userCredentials.setResetTokenExpTime(System.currentTimeMillis() - 1); + userCredentialsDao.save(tenantId, userCredentials); + + doGet("/api/noauth/resetPassword?resetToken={resetToken}", this.currentResetPasswordToken) + .andExpect(status().isSeeOther()) + .andExpect(header().string(HttpHeaders.LOCATION, "/passwordResetLinkExpired")); + JsonNode resetPasswordRequest = JacksonUtil.newObjectNode() + .put("resetToken", this.currentResetPasswordToken) + .put("password", "wefwefe"); + doPost("/api/noauth/resetPassword", resetPasswordRequest).andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message", is("Password reset token expired"))); + } + + @Test + public void testActivationLinkTtl() throws Exception { + loginSysAdmin(); + int ttl = 24; + updateSecuritySettings(securitySettings -> { + securitySettings.setUserActivationTokenTtl(ttl); + }); + + loginTenantAdmin(); + User user = new User(); + user.setAuthority(Authority.TENANT_ADMIN); + user.setEmail("tenant-admin-2@thingsboard.org"); + user = doPost("/api/user", user, User.class); + + UserCredentials userCredentials = userCredentialsDao.findByUserId(tenantId, user.getUuidId()); + assertThat(userCredentials.getActivateTokenExpTime()).isCloseTo(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(ttl), Offset.offset(120000L)); + String initialActivationLink = getActivationLink(user); + String initialActivationToken = StringUtils.substringAfterLast(initialActivationLink, "activateToken="); + UserActivationLink activationLinkInfo = getActivationLinkInfo(user); + assertThat(TimeUnit.MILLISECONDS.toHours(activationLinkInfo.ttlMs())).isCloseTo(ttl, within(1L)); + assertThat(activationLinkInfo.value()).isEqualTo(initialActivationLink); + + // expiring activation token + userCredentials.setActivateTokenExpTime(System.currentTimeMillis() - 1); + userCredentialsDao.save(tenantId, userCredentials); + doGet("/api/noauth/activate?activateToken={activateToken}", initialActivationToken) + .andExpect(status().isSeeOther()) + .andExpect(header().string(HttpHeaders.LOCATION, "/activationLinkExpired")); + doPost("/api/noauth/activate", JacksonUtil.newObjectNode() + .put("activateToken", initialActivationToken) + .put("password", "wefewe")).andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message", is("Activation token expired"))); + + // checking that activation link is regenerated when requested + UserActivationLink regeneratedActivationLink = getActivationLinkInfo(user); + assertThat(regeneratedActivationLink.value()).isNotEqualTo(initialActivationLink); + assertThat(TimeUnit.MILLISECONDS.toHours(regeneratedActivationLink.ttlMs())).isCloseTo(ttl, within(1L)); + + // checking link renewal if less than 15 minutes before expiration + userCredentials = userCredentialsDao.findByUserId(tenantId, user.getUuidId()); + userCredentials.setActivateTokenExpTime(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(30)); + userCredentialsDao.save(tenantId, userCredentials); + activationLinkInfo = getActivationLinkInfo(user); + assertThat(activationLinkInfo.value()).isEqualTo(regeneratedActivationLink.value()); + assertThat(TimeUnit.MILLISECONDS.toMinutes(activationLinkInfo.ttlMs())).isCloseTo(30, within(1L)); + + userCredentials.setActivateTokenExpTime(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(10)); + userCredentialsDao.save(tenantId, userCredentials); + UserActivationLink newActivationLink = getActivationLinkInfo(user); + assertThat(newActivationLink.value()).isNotEqualTo(regeneratedActivationLink.value()); + assertThat(TimeUnit.MILLISECONDS.toHours(newActivationLink.ttlMs())).isCloseTo(ttl, within(1L)); + String newActivationToken = StringUtils.substringAfterLast(newActivationLink.value(), "activateToken="); + + userCredentials = userCredentialsDao.findByUserId(tenantId, user.getUuidId()); + assertThat(userCredentials.getActivateTokenExpTime()).isCloseTo(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(ttl), Offset.offset(120000L)); + + doPost("/api/noauth/activate", JacksonUtil.newObjectNode() + .put("activateToken", newActivationToken) + .put("password", "wefewe")).andExpect(status().isOk()); } @Test @@ -173,4 +270,19 @@ public class AuthControllerTest extends AbstractControllerTest { doGet("/login").andExpect(status().isOk()); doGet("/home").andExpect(status().isOk()); } + + private void updateSecuritySettings(Consumer<SecuritySettings> updater) throws Exception { + SecuritySettings securitySettings = doGet("/api/admin/securitySettings", SecuritySettings.class); + updater.accept(securitySettings); + doPost("/api/admin/securitySettings", securitySettings).andExpect(status().isOk()); + } + + private String getActivationLink(User user) throws Exception { + return doGet("/api/user/" + user.getId() + "/activationLink", String.class); + } + + private UserActivationLink getActivationLinkInfo(User user) throws Exception { + return doGet("/api/user/" + user.getId() + "/activationLinkInfo", UserActivationLink.class); + } + } 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 b3a1dd790e..5484c29305 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java @@ -103,6 +103,7 @@ import org.thingsboard.server.gen.edge.v1.UserUpdateMsg; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Random; import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -124,6 +125,8 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { protected EdgeImitator edgeImitator; protected Edge edge; + private Random random = new Random(); + @Autowired protected EdgeEventService edgeEventService; @@ -163,15 +166,10 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { } private RuleChainId getEdgeRootRuleChainId() throws Exception { - List<RuleChain> edgeRuleChains = doGetTypedWithPageLink("/api/edge/" + edge.getUuidId() + "/ruleChains?", - new TypeReference<PageData<RuleChain>>() { - }, new PageLink(100)).getData(); - for (RuleChain edgeRuleChain : edgeRuleChains) { - if (edgeRuleChain.isRoot()) { - return edgeRuleChain.getId(); - } - } - throw new RuntimeException("Root rule chain not found"); + return doGetTypedWithPageLink("/api/ruleChains?type={type}&", new TypeReference<PageData<RuleChain>>() {}, + new PageLink(100, 0, "Edge Root Rule Chain"), + "EDGE") + .getData().get(0).getId(); } @After @@ -196,6 +194,8 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { Asset savedAsset = saveAsset("Edge Asset 1"); + updateRootRuleChainMetadata(); + edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class); doPost("/api/edge/" + edge.getUuidId() @@ -207,6 +207,13 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { TimeUnit.MILLISECONDS.sleep(1000); } + protected void updateRootRuleChainMetadata() throws Exception { + RuleChainId rootRuleChainId = getEdgeRootRuleChainId(); + RuleChainMetaData rootRuleChainMetadata = doGet("/api/ruleChain/" + rootRuleChainId.getId().toString() + "/metadata", RuleChainMetaData.class); + rootRuleChainMetadata.getNodes().forEach(n -> n.setDebugMode(random.nextBoolean())); + doPost("/api/ruleChain/metadata", rootRuleChainMetadata, RuleChainMetaData.class); + } + protected void extendDeviceProfileData(DeviceProfile deviceProfile) { DeviceProfileData profileData = deviceProfile.getProfileData(); List<DeviceProfileAlarm> alarms = new ArrayList<>(); 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 b6311da80a..3b252046ab 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg; +import org.thingsboard.server.gen.edge.v1.ResourceUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UplinkMsg; @@ -44,12 +45,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. public class DashboardEdgeTest extends AbstractEdgeTest { private static final int MOBILE_ORDER = 5; - private static final String IMAGE = "data:image/png;base64,iVBORw0KGgoA"; + private static final String IMAGE = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"; @Test public void testDashboards() throws Exception { // create dashboard and assign to edge - edgeImitator.expectMessageAmount(1); + edgeImitator.expectMessageAmount(2); Dashboard dashboard = new Dashboard(); dashboard.setTitle("Edge Test Dashboard"); dashboard.setMobileHide(true); @@ -59,23 +60,26 @@ public class DashboardEdgeTest extends AbstractEdgeTest { doPost("/api/edge/" + edge.getUuidId() + "/dashboard/" + savedDashboard.getUuidId(), Dashboard.class); Assert.assertTrue(edgeImitator.waitForMessages()); - AbstractMessage latestMessage = edgeImitator.getLatestMessage(); - Assert.assertTrue(latestMessage instanceof DashboardUpdateMsg); - DashboardUpdateMsg dashboardUpdateMsg = (DashboardUpdateMsg) latestMessage; + Optional<DashboardUpdateMsg> dashboardUpdateMsgOpt = edgeImitator.findMessageByType(DashboardUpdateMsg.class); + Assert.assertTrue(dashboardUpdateMsgOpt.isPresent()); + DashboardUpdateMsg dashboardUpdateMsg = dashboardUpdateMsgOpt.get(); Dashboard dashboardMsg = JacksonUtil.fromString(dashboardUpdateMsg.getEntity(), Dashboard.class, true); Assert.assertNotNull(dashboardMsg); Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, dashboardUpdateMsg.getMsgType()); Assert.assertEquals(savedDashboard, dashboardMsg); - Assert.assertEquals(IMAGE, dashboardMsg.getImage()); + Assert.assertEquals("tb-image;/api/images/tenant/edge_test_dashboard_dashboard_image.svg", dashboardMsg.getImage()); Assert.assertEquals(MOBILE_ORDER, dashboardMsg.getMobileOrder().intValue()); testAutoGeneratedCodeByProtobuf(dashboardUpdateMsg); + Optional<ResourceUpdateMsg> resourceUpdateMsg = edgeImitator.findMessageByType(ResourceUpdateMsg.class); + Assert.assertTrue(resourceUpdateMsg.isPresent()); + // update dashboard edgeImitator.expectMessageAmount(1); savedDashboard.setTitle("Updated Edge Test Dashboard"); savedDashboard = doPost("/api/dashboard", savedDashboard, Dashboard.class); Assert.assertTrue(edgeImitator.waitForMessages()); - latestMessage = edgeImitator.getLatestMessage(); + AbstractMessage latestMessage = edgeImitator.getLatestMessage(); Assert.assertTrue(latestMessage instanceof DashboardUpdateMsg); dashboardUpdateMsg = (DashboardUpdateMsg) latestMessage; dashboardMsg = JacksonUtil.fromString(dashboardUpdateMsg.getEntity(), Dashboard.class, true); 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 c694df84f8..eaf4468156 100644 --- a/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java @@ -185,6 +185,18 @@ public class RuleChainEdgeTest extends AbstractEdgeTest { return doPost("/api/ruleChain/metadata", ruleChainMetaData, RuleChainMetaData.class); } + @Test + public void testUpdateRootRuleChain() throws Exception { + edgeImitator.expectMessageAmount(2); + updateRootRuleChainMetadata(); + Assert.assertTrue(edgeImitator.waitForMessages()); + + Optional<RuleChainUpdateMsg> ruleChainUpdateMsgOpt = edgeImitator.findMessageByType(RuleChainUpdateMsg.class); + Assert.assertTrue(ruleChainUpdateMsgOpt.isPresent()); + Optional<RuleChainMetadataUpdateMsg> ruleChainMetadataUpdateMsgOpt = edgeImitator.findMessageByType(RuleChainMetadataUpdateMsg.class); + Assert.assertTrue(ruleChainMetadataUpdateMsgOpt.isPresent()); + } + @Test public void testSetRootRuleChain() throws Exception { // create rule chain diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/CaffeineTbTransactionalCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/CaffeineTbTransactionalCache.java index 4ce6571f1c..d2ea960e68 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/CaffeineTbTransactionalCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/CaffeineTbTransactionalCache.java @@ -54,11 +54,6 @@ public abstract class CaffeineTbTransactionalCache<K extends Serializable, V ext return SimpleTbCacheValueWrapper.wrap(cache.get(key)); } - @Override - public TbCacheValueWrapper<V> get(K key, boolean transactionMode) { - return get(key); - } - @Override public void put(K key, V value) { lock.lock(); diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbCacheTransaction.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbCacheTransaction.java index 3dcb6e878f..fb852493ce 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbCacheTransaction.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbCacheTransaction.java @@ -31,7 +31,7 @@ public class RedisTbCacheTransaction<K extends Serializable, V extends Serializa @Override public void put(K key, V value) { - cache.put(key, value, connection, true); + cache.put(key, value, connection); } @Override diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java index fbf88bb5e4..8ee58ab8eb 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java @@ -87,17 +87,11 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend @Override public TbCacheValueWrapper<V> get(K key) { - return get(key, false); - } - - @Override - public TbCacheValueWrapper<V> get(K key, boolean transactionMode) { if (!cacheEnabled) { return null; } try (var connection = connectionFactory.getConnection()) { - byte[] rawKey = getRawKey(key); - byte[] rawValue = doGet(connection, rawKey, transactionMode); + byte[] rawValue = doGet(key, connection); if (rawValue == null || rawValue.length == 0) { return null; } else if (Arrays.equals(rawValue, BINARY_NULL_VALUE)) { @@ -114,8 +108,8 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend } } - protected byte[] doGet(RedisConnection connection, byte[] rawKey, boolean transactionMode) { - return connection.stringCommands().get(rawKey); + protected byte[] doGet(K key, RedisConnection connection) { + return connection.stringCommands().get(getRawKey(key)); } @Override @@ -124,11 +118,11 @@ public abstract class RedisTbTransactionalCache<K extends Serializable, V extend return; } try (var connection = connectionFactory.getConnection()) { - put(key, value, connection, false); + put(key, value, connection); } } - public void put(K key, V value, RedisConnection connection, boolean transactionMode) { + public void put(K key, V value, RedisConnection connection) { put(connection, key, value, RedisStringCommands.SetOption.UPSERT); } diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/TbTransactionalCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/TbTransactionalCache.java index 765c82a8db..44d5e09330 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/TbTransactionalCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TbTransactionalCache.java @@ -27,8 +27,6 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ TbCacheValueWrapper<V> get(K key); - TbCacheValueWrapper<V> get(K key, boolean transactionMode); - void put(K key, V value); void putIfAbsent(K key, V value); @@ -53,7 +51,7 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ if (putToCache) { return getAndPutInTransaction(key, dbCall, cacheNullValue); } else { - TbCacheValueWrapper<V> cacheValueWrapper = get(key, true); + TbCacheValueWrapper<V> cacheValueWrapper = get(key); if (cacheValueWrapper != null) { return cacheValueWrapper.get(); } @@ -66,7 +64,7 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ } default <R> R getAndPutInTransaction(K key, Supplier<R> dbCall, Function<V, R> cacheValueToResult, Function<R, V> dbValueToCacheValue, boolean cacheNullValue) { - TbCacheValueWrapper<V> cacheValueWrapper = get(key, true); + TbCacheValueWrapper<V> cacheValueWrapper = get(key); if (cacheValueWrapper != null) { V cacheValue = cacheValueWrapper.get(); return cacheValue != null ? cacheValueToResult.apply(cacheValue) : null; @@ -92,7 +90,7 @@ public interface TbTransactionalCache<K extends Serializable, V extends Serializ if (putToCache) { return getAndPutInTransaction(key, dbCall, cacheValueToResult, dbValueToCacheValue, cacheNullValue); } else { - TbCacheValueWrapper<V> cacheValueWrapper = get(key, true); + TbCacheValueWrapper<V> cacheValueWrapper = get(key); if (cacheValueWrapper != null) { var cacheValue = cacheValueWrapper.get(); return cacheValue == null ? null : cacheValueToResult.apply(cacheValue); diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/VersionedCacheKey.java b/common/cache/src/main/java/org/thingsboard/server/cache/VersionedCacheKey.java new file mode 100644 index 0000000000..f339d9def3 --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/VersionedCacheKey.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache; + +import java.io.Serializable; + +public interface VersionedCacheKey extends Serializable { + + default boolean isVersioned() { + return false; + } + +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/VersionedCaffeineTbCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/VersionedCaffeineTbCache.java index f9c22ecc32..535fa64cd9 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/VersionedCaffeineTbCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/VersionedCaffeineTbCache.java @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.util.TbPair; import java.io.Serializable; -public abstract class VersionedCaffeineTbCache<K extends Serializable, V extends Serializable & HasVersion> extends CaffeineTbTransactionalCache<K, V> implements VersionedTbCache<K, V> { +public abstract class VersionedCaffeineTbCache<K extends VersionedCacheKey, V extends Serializable & HasVersion> extends CaffeineTbTransactionalCache<K, V> implements VersionedTbCache<K, V> { public VersionedCaffeineTbCache(CacheManager cacheManager, String cacheName) { super(cacheManager, cacheName); diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/VersionedRedisTbCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/VersionedRedisTbCache.java index 6ef3918a68..e9b64822e9 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/VersionedRedisTbCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/VersionedRedisTbCache.java @@ -30,7 +30,7 @@ import java.io.Serializable; import java.util.Arrays; @Slf4j -public abstract class VersionedRedisTbCache<K extends Serializable, V extends Serializable & HasVersion> extends RedisTbTransactionalCache<K, V> implements VersionedTbCache<K, V> { +public abstract class VersionedRedisTbCache<K extends VersionedCacheKey, V extends Serializable & HasVersion> extends RedisTbTransactionalCache<K, V> implements VersionedTbCache<K, V> { private static final int VERSION_SIZE = 8; private static final int VALUE_END_OFFSET = -1; @@ -79,15 +79,20 @@ public abstract class VersionedRedisTbCache<K extends Serializable, V extends Se } @Override - protected byte[] doGet(RedisConnection connection, byte[] rawKey, boolean transactionMode) { - if (transactionMode) { - return super.doGet(connection, rawKey, true); + protected byte[] doGet(K key, RedisConnection connection) { + if (!key.isVersioned()) { + return super.doGet(key, connection); } + byte[] rawKey = getRawKey(key); return connection.stringCommands().getRange(rawKey, VERSION_SIZE, VALUE_END_OFFSET); } @Override public void put(K key, V value) { + if (!key.isVersioned()) { + super.put(key, value); + return; + } Long version = getVersion(value); if (version == null) { return; @@ -96,9 +101,9 @@ public abstract class VersionedRedisTbCache<K extends Serializable, V extends Se } @Override - public void put(K key, V value, RedisConnection connection, boolean transactionMode) { - if (transactionMode) { - super.put(key, value, connection, true); // because scripting commands are not supported in transaction mode + public void put(K key, V value, RedisConnection connection) { + if (!key.isVersioned()) { + super.put(key, value, connection); // because scripting commands are not supported in transaction mode return; } Long version = getVersion(value); diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/VersionedTbCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/VersionedTbCache.java index faf63495b2..c610825faf 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/VersionedTbCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/VersionedTbCache.java @@ -22,7 +22,7 @@ import java.util.Collection; import java.util.Optional; import java.util.function.Supplier; -public interface VersionedTbCache<K extends Serializable, V extends Serializable & HasVersion> extends TbTransactionalCache<K, V> { +public interface VersionedTbCache<K extends VersionedCacheKey, V extends Serializable & HasVersion> extends TbTransactionalCache<K, V> { TbCacheValueWrapper<V> get(K key); diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/device/DeviceCacheKey.java b/common/cache/src/main/java/org/thingsboard/server/cache/device/DeviceCacheKey.java index ed6258842d..2a0819851e 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/device/DeviceCacheKey.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/device/DeviceCacheKey.java @@ -19,17 +19,17 @@ import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.thingsboard.server.cache.VersionedCacheKey; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import java.io.Serial; -import java.io.Serializable; @Getter @EqualsAndHashCode @RequiredArgsConstructor @Builder -public class DeviceCacheKey implements Serializable { +public class DeviceCacheKey implements VersionedCacheKey { @Serial private static final long serialVersionUID = 6366389552842340207L; @@ -61,4 +61,9 @@ public class DeviceCacheKey implements Serializable { } } + @Override + public boolean isVersioned() { + return deviceId != null; + } + } 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 42f635cd43..8f22812cfc 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 @@ -59,6 +59,10 @@ public interface UserService extends EntityDaoService { UserCredentials requestExpiredPasswordReset(TenantId tenantId, UserCredentialsId userCredentialsId); + UserCredentials generatePasswordResetToken(UserCredentials userCredentials); + + UserCredentials generateUserActivationToken(UserCredentials userCredentials); + UserCredentials replaceUserCredentials(TenantId tenantId, UserCredentials userCredentials); void deleteUser(TenantId tenantId, User user); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/UserActivationLink.java b/common/data/src/main/java/org/thingsboard/server/common/data/UserActivationLink.java new file mode 100644 index 0000000000..f532a9b066 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/UserActivationLink.java @@ -0,0 +1,19 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data; + +public record UserActivationLink(String value, long ttlMs) { +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/UserCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/UserCredentials.java index ed036e482a..1104ae2949 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/UserCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/UserCredentials.java @@ -16,41 +16,31 @@ package org.thingsboard.server.common.data.security; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.databind.JsonNode; +import lombok.Data; import lombok.EqualsAndHashCode; -import org.thingsboard.server.common.data.BaseData; +import lombok.ToString; +import org.thingsboard.server.common.data.BaseDataWithAdditionalInfo; import org.thingsboard.server.common.data.id.UserCredentialsId; import org.thingsboard.server.common.data.id.UserId; -import org.thingsboard.server.common.data.validation.NoXss; -import static org.thingsboard.server.common.data.BaseDataWithAdditionalInfo.getJson; -import static org.thingsboard.server.common.data.BaseDataWithAdditionalInfo.setJson; +import java.io.Serial; +@Data @EqualsAndHashCode(callSuper = true) -public class UserCredentials extends BaseData<UserCredentialsId> { +@ToString(callSuper = true) +public class UserCredentials extends BaseDataWithAdditionalInfo<UserCredentialsId> { + @Serial private static final long serialVersionUID = -2108436378880529163L; private UserId userId; private boolean enabled; private String password; private String activateToken; + private Long activateTokenExpTime; private String resetToken; + private Long resetTokenExpTime; - @NoXss - private transient JsonNode additionalInfo; - - @JsonIgnore - private byte[] additionalInfoBytes; - - public JsonNode getAdditionalInfo() { - return getJson(() -> additionalInfo, () -> additionalInfoBytes); - } - - public void setAdditionalInfo(JsonNode settings) { - setJson(settings, json -> this.additionalInfo = json, bytes -> this.additionalInfoBytes = bytes); - } - public UserCredentials() { super(); } @@ -59,75 +49,25 @@ public class UserCredentials extends BaseData<UserCredentialsId> { super(id); } - public UserCredentials(UserCredentials userCredentials) { - super(userCredentials); - this.userId = userCredentials.getUserId(); - this.password = userCredentials.getPassword(); - this.enabled = userCredentials.isEnabled(); - this.activateToken = userCredentials.getActivateToken(); - this.resetToken = userCredentials.getResetToken(); - setAdditionalInfo(userCredentials.getAdditionalInfo()); - } - - public UserId getUserId() { - return userId; - } - - public void setUserId(UserId userId) { - this.userId = userId; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - public String getActivateToken() { - return activateToken; + @JsonIgnore + public boolean isActivationTokenExpired() { + return getActivationTokenTtl() == 0; } - public void setActivateToken(String activateToken) { - this.activateToken = activateToken; - } - - public String getResetToken() { - return resetToken; + @JsonIgnore + public long getActivationTokenTtl() { + return activateTokenExpTime != null ? Math.max(activateTokenExpTime - System.currentTimeMillis(), 0) : 0; } - public void setResetToken(String resetToken) { - this.resetToken = resetToken; + @JsonIgnore + public boolean isResetTokenExpired() { + return getResetTokenTtl() == 0; } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("UserCredentials [userId="); - builder.append(userId); - builder.append(", enabled="); - builder.append(enabled); - builder.append(", password="); - builder.append(password); - builder.append(", activateToken="); - builder.append(activateToken); - builder.append(", resetToken="); - builder.append(resetToken); - builder.append(", createdTime="); - builder.append(createdTime); - builder.append(", id="); - builder.append(id); - builder.append("]"); - return builder.toString(); + @JsonIgnore + public long getResetTokenTtl() { + return resetTokenExpTime != null ? Math.max(resetTokenExpTime - System.currentTimeMillis(), 0) : 0; } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/SecuritySettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/SecuritySettings.java index aa4d303440..70e1853ffd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/model/SecuritySettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/model/SecuritySettings.java @@ -16,22 +16,39 @@ package org.thingsboard.server.common.data.security.model; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; import lombok.Data; +import java.io.Serial; import java.io.Serializable; @Schema @Data public class SecuritySettings implements Serializable { + @Serial private static final long serialVersionUID = -1307613974597312465L; - @Schema(description = "The user password policy object." ) + @Schema(description = "The user password policy object.") private UserPasswordPolicy passwordPolicy; - @Schema(description = "Maximum number of failed login attempts allowed before user account is locked." ) + + @Schema(description = "Maximum number of failed login attempts allowed before user account is locked.") private Integer maxFailedLoginAttempts; - @Schema(description = "Email to use for notifications about locked users." ) + + @Schema(description = "Email to use for notifications about locked users.") private String userLockoutNotificationEmail; - @Schema(description = "Mobile secret key length" ) + + @Schema(description = "Mobile secret key length") private Integer mobileSecretKeyLength; + + @NotNull @Min(1) @Max(24) + @Schema(description = "TTL in hours for user activation link", minimum = "1", maximum = "24", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer userActivationTokenTtl; + + @NotNull @Min(1) @Max(24) + @Schema(description = "TTL in hours for password reset link", minimum = "1", maximum = "24", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer passwordResetTokenTtl; + } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqConsumerTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqConsumerTemplate.java index 4913d52fa8..e50afabb5d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqConsumerTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqConsumerTemplate.java @@ -20,6 +20,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.GetResponse; +import java.util.ArrayList; +import java.util.Collection; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.queue.TbQueueAdmin; @@ -31,7 +33,6 @@ import org.thingsboard.server.queue.common.DefaultTbQueueMsg; import java.io.IOException; import java.util.Collections; import java.util.List; -import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; @@ -44,6 +45,7 @@ public class TbRabbitMqConsumerTemplate<T extends TbQueueMsg> extends AbstractTb private final TbQueueMsgDecoder<T> decoder; private final Channel channel; private final Connection connection; + private final int maxPollMessages; private volatile Set<String> queues; @@ -51,6 +53,7 @@ public class TbRabbitMqConsumerTemplate<T extends TbQueueMsg> extends AbstractTb super(topic); this.admin = admin; this.decoder = decoder; + this.maxPollMessages = rabbitMqSettings.getMaxPollMessages(); try { connection = rabbitMqSettings.getConnectionFactory().newConnection(); } catch (IOException | TimeoutException e) { @@ -70,13 +73,19 @@ public class TbRabbitMqConsumerTemplate<T extends TbQueueMsg> extends AbstractTb protected List<GetResponse> doPoll(long durationInMillis) { List<GetResponse> result = queues.stream() .map(queue -> { - try { - return channel.basicGet(queue, false); - } catch (IOException e) { - log.error("Failed to get messages from queue: [{}]", queue); - throw new RuntimeException("Failed to get messages from queue.", e); + List<GetResponse> messages = new ArrayList<>(); + for (int i = 0; i < maxPollMessages; i++) { + GetResponse response = doQueuePoll(queue); + if (response == null) { + break; + } + messages.add(response); } - }).filter(Objects::nonNull).collect(Collectors.toList()); + return messages; + }) + .filter(r -> !r.isEmpty()) + .flatMap(Collection::stream) + .collect(Collectors.toList()); if (result.size() > 0) { return result; } else { @@ -84,6 +93,15 @@ public class TbRabbitMqConsumerTemplate<T extends TbQueueMsg> extends AbstractTb } } + protected GetResponse doQueuePoll(String queue) { + try { + return channel.basicGet(queue, false); + } catch (IOException e) { + log.error("Failed to get messages from queue: [{}]", queue); + throw new RuntimeException("Failed to get messages from queue.", e); + } + } + @Override protected void doSubscribe(List<String> topicNames) { queues = partitions.stream() diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqSettings.java b/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqSettings.java index 432bce1d01..c0a2912f23 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqSettings.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqSettings.java @@ -46,6 +46,8 @@ public class TbRabbitMqSettings { private int connectionTimeout; @Value("${queue.rabbitmq.handshake_timeout:}") private int handshakeTimeout; + @Value("${queue.rabbitmq.max_poll_messages:1}") + private int maxPollMessages; private ConnectionFactory connectionFactory; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/scheduler/DefaultSchedulerComponent.java b/common/queue/src/main/java/org/thingsboard/server/queue/scheduler/DefaultSchedulerComponent.java index a166259256..095e5b18dc 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/scheduler/DefaultSchedulerComponent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/scheduler/DefaultSchedulerComponent.java @@ -17,6 +17,7 @@ package org.thingsboard.server.queue.scheduler; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -26,14 +27,15 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +@Slf4j @Component public class DefaultSchedulerComponent implements SchedulerComponent { - protected ScheduledExecutorService schedulerExecutor; + private ScheduledExecutorService schedulerExecutor; @PostConstruct public void init() { - this.schedulerExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("queue-scheduler")); + schedulerExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("queue-scheduler")); } @PreDestroy @@ -52,10 +54,19 @@ public class DefaultSchedulerComponent implements SchedulerComponent { } public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { - return schedulerExecutor.scheduleAtFixedRate(command, initialDelay, period, unit); + return schedulerExecutor.scheduleAtFixedRate(() -> runSafely(command), initialDelay, period, unit); } public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { - return schedulerExecutor.scheduleWithFixedDelay(command, initialDelay, delay, unit); + return schedulerExecutor.scheduleWithFixedDelay(() -> runSafely(command), initialDelay, delay, unit); } + + private void runSafely(Runnable command) { + try { + command.run(); + } catch (Throwable t) { + log.error("Unexpected error occurred while executing task!", t); + } + } + } diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqConsumerTemplateTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqConsumerTemplateTest.java new file mode 100644 index 0000000000..2d6a50cea4 --- /dev/null +++ b/common/queue/src/test/java/org/thingsboard/server/queue/rabbitmq/TbRabbitMqConsumerTemplateTest.java @@ -0,0 +1,128 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.queue.rabbitmq; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.GetResponse; +import java.nio.charset.StandardCharsets; +import java.util.Set; +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.queue.TbQueueAdmin; +import org.thingsboard.server.queue.TbQueueMsgDecoder; +import org.thingsboard.server.queue.common.DefaultTbQueueMsg; + +@ExtendWith(MockitoExtension.class) +class TbRabbitMqConsumerTemplateTest { + + private static final String TOPIC = "some-topic"; + + @Mock + private TbQueueAdmin admin; + + @Mock + private ConnectionFactory connectionFactory; + + @Mock + private TbQueueMsgDecoder<DefaultTbQueueMsg> decoder; + + @Mock + private Connection connection; + + @Mock + private Channel channel; + + @Mock + private TopicPartitionInfo partition; + + @Mock + private GetResponse getResponse; + + private TbRabbitMqConsumerTemplate<DefaultTbQueueMsg> consumer; + + private void setUpConsumerWithMaxPollMessages(int maxPollMessages) throws Exception { + when(connectionFactory.newConnection()).thenReturn(connection); + when(connection.createChannel()).thenReturn(channel); + TbRabbitMqSettings settings = new TbRabbitMqSettings(); + settings.setMaxPollMessages(maxPollMessages); + settings.setConnectionFactory(connectionFactory); + + consumer = new TbRabbitMqConsumerTemplate<>(admin, settings, TOPIC, decoder); + when(partition.getFullTopicName()).thenReturn(TOPIC); + consumer.subscribe(Set.of(partition)); + } + + @Test + void pollWithMax5PollMessagesReturnsEmptyListIfNoMessages() throws Exception { + setUpConsumerWithMaxPollMessages(5); + when(channel.basicGet(anyString(), anyBoolean())).thenReturn(null); + + assertThat(consumer.poll(0L)).isEmpty(); + + verify(channel).basicGet(anyString(), anyBoolean()); + } + + @Test + void pollWithMax5PollMessagesReturns5MessagesIfQueueContains5() throws Exception { + setUpConsumerWithMaxPollMessages(5); + when(getResponse.getBody()).thenReturn(newMessageBody()); + when(channel.basicGet(anyString(), anyBoolean())).thenReturn(getResponse); + + assertThat(consumer.poll(0L)).hasSize(5); + + verify(channel, times(5)).basicGet(anyString(), anyBoolean()); + } + + @Test + void pollWithMax1PollMessageReturns1MessageIfQueueContainsMore() throws Exception { + setUpConsumerWithMaxPollMessages(1); + when(getResponse.getBody()).thenReturn(newMessageBody()); + when(channel.basicGet(anyString(), anyBoolean())).thenReturn(getResponse); + + assertThat(consumer.poll(0L)).hasSize(1); + + verify(channel).basicGet(anyString(), anyBoolean()); + } + + @Test + void pollWithMax3PollMessagesReturns2MessagesIfQueueContains2() throws Exception { + setUpConsumerWithMaxPollMessages(3); + when(getResponse.getBody()).thenReturn(newMessageBody()); + when(channel.basicGet(anyString(), anyBoolean())).thenReturn(getResponse, getResponse, null); + + assertThat(consumer.poll(0L)).hasSize(2); + + verify(channel, times(3)).basicGet(anyString(), anyBoolean()); + } + + private byte[] newMessageBody() { + return ("{\"key\": \"" + UUID.randomUUID() + "\"}").getBytes(StandardCharsets.UTF_8); + } + +} \ No newline at end of file diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/scheduler/DefaultSchedulerComponentTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/scheduler/DefaultSchedulerComponentTest.java new file mode 100644 index 0000000000..cff306c748 --- /dev/null +++ b/common/queue/src/test/java/org/thingsboard/server/queue/scheduler/DefaultSchedulerComponentTest.java @@ -0,0 +1,95 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.queue.scheduler; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.assertj.core.api.Assertions.assertThat; + +class DefaultSchedulerComponentTest { + + DefaultSchedulerComponent schedulerComponent; + + @BeforeEach + void setup() { + schedulerComponent = new DefaultSchedulerComponent(); + schedulerComponent.init(); + } + + @AfterEach + void cleanup() { + schedulerComponent.destroy(); + } + + @Test + @DisplayName("scheduleAtFixedRate() should continue periodic execution even if command throws exception") + void scheduleAtFixedRateShouldNotStopPeriodicExecutionWhenCommandThrowsException() { + // GIVEN + var wasExecutedAtLeastOnce = new AtomicBoolean(false); + + Runnable exceptionThrowingCommand = () -> { + try { + throw new RuntimeException("Unexpected exception"); + } finally { + wasExecutedAtLeastOnce.set(true); + } + }; + + // WHEN + ScheduledFuture<?> future = schedulerComponent.scheduleAtFixedRate(exceptionThrowingCommand, 0, 200, TimeUnit.MILLISECONDS); + + // THEN + Awaitility.await().alias("Wait until command is executed at least once") + .atMost(5, TimeUnit.SECONDS) + .until(wasExecutedAtLeastOnce::get); + + assertThat(future.isDone()).as("Periodic execution should not stop after unhandled exception is thrown by the command").isFalse(); + } + + @Test + @DisplayName("scheduleWithFixedDelay() should continue periodic execution even if command throws exception") + void scheduleWithFixedDelayShouldNotStopPeriodicExecutionWhenCommandThrowsException() { + // GIVEN + var wasExecutedAtLeastOnce = new AtomicBoolean(false); + + Runnable exceptionThrowingCommand = () -> { + try { + throw new RuntimeException("Unexpected exception"); + } finally { + wasExecutedAtLeastOnce.set(true); + } + }; + + // WHEN + ScheduledFuture<?> future = schedulerComponent.scheduleWithFixedDelay(exceptionThrowingCommand, 0, 200, TimeUnit.MILLISECONDS); + + // THEN + Awaitility.await().alias("Wait until command is executed at least once") + .atMost(5, TimeUnit.SECONDS) + .until(wasExecutedAtLeastOnce::get); + + assertThat(future.isDone()).as("Periodic execution should not stop after unhandled exception is thrown by the command").isFalse(); + } + +} diff --git a/common/transport/coap/src/main/proto/efento/proto_config.proto b/common/transport/coap/src/main/proto/efento/proto_config.proto index 25dbec883f..5a82ec078c 100644 --- a/common/transport/coap/src/main/proto/efento/proto_config.proto +++ b/common/transport/coap/src/main/proto/efento/proto_config.proto @@ -31,7 +31,7 @@ message ProtoOutputControlState { uint32 channel_state = 2; } -/* Message containing request data for accesing calibration parameters */ +/* Message containing request data for accessing calibration parameters */ message ProtoCalibrationParameters { /* Request details. Bitmask: */ @@ -349,4 +349,4 @@ message ProtoConfig { /* BLE advertising period configuration. */ ProtoBleAdvertisingPeriod ble_advertising_period = 59; -} \ No newline at end of file +} diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 4212386410..f839ed4b18 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -1063,6 +1063,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement log.debug("[{}][{}][{}] IOException: {}", sessionId, Optional.ofNullable(this.deviceSessionCtx.getDeviceInfo()).map(TransportDeviceInfo::getDeviceId).orElse(null), Optional.ofNullable(this.deviceSessionCtx.getDeviceInfo()).map(TransportDeviceInfo::getDeviceName).orElse(""), + cause.getMessage(), cause); } else if (log.isInfoEnabled()) { log.info("[{}][{}][{}] IOException: {}", sessionId, diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/AbstractActivityManager.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/AbstractActivityManager.java index f754d6f5b1..ac535d28e1 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/AbstractActivityManager.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/AbstractActivityManager.java @@ -69,7 +69,7 @@ public abstract class AbstractActivityManager<Key, Metadata> implements Activity log.error("Failed to process activity event: provided activity key is null."); return; } - log.debug("Received activity event for key: [{}]", key); + log.debug("Received activity event for key: [{}]. Event time: [{}].", key, newLastRecordedTime); var shouldReport = new AtomicBoolean(false); var lastRecordedTime = new AtomicLong(); @@ -94,7 +94,7 @@ public abstract class AbstractActivityManager<Key, Metadata> implements Activity }); if (shouldReport.get() && lastReportedTime.get() < lastRecordedTime.get()) { - log.debug("Going to report first activity event for key: [{}].", key); + log.debug("Going to report first activity event for key: [{}]. Event time: [{}].", key, lastRecordedTime.get()); reportActivity(key, metadata, lastRecordedTime.get(), new ActivityReportCallback<>() { @Override public void onSuccess(Key key, long reportedTime) { @@ -103,7 +103,7 @@ public abstract class AbstractActivityManager<Key, Metadata> implements Activity @Override public void onFailure(Key key, Throwable t) { - log.debug("Failed to report first activity event for key: [{}].", key, t); + log.debug("Failed to report first activity event for key: [{}]. Event time: [{}].", key, lastRecordedTime.get(), t); } }); } @@ -113,50 +113,59 @@ public abstract class AbstractActivityManager<Key, Metadata> implements Activity public void onReportingPeriodEnd() { log.debug("Going to end reporting period."); for (Map.Entry<Key, ActivityStateWrapper> entry : states.entrySet()) { - var key = entry.getKey(); - var stateWrapper = entry.getValue(); - var currentState = stateWrapper.getState(); - - long lastRecordedTime = currentState.getLastRecordedTime(); - long lastReportedTime = stateWrapper.getLastReportedTime(); - var metadata = currentState.getMetadata(); - - boolean hasExpired; - boolean shouldReport; - - var updatedState = updateState(key, currentState); - if (updatedState != null) { - stateWrapper.setState(updatedState); - lastRecordedTime = updatedState.getLastRecordedTime(); - metadata = updatedState.getMetadata(); - hasExpired = hasExpired(lastRecordedTime); - shouldReport = stateWrapper.getStrategy().onReportingPeriodEnd(); - } else { - states.remove(key); - hasExpired = false; - shouldReport = true; + Key key = entry.getKey(); + ActivityStateWrapper stateWrapper = entry.getValue(); + try { + reportLastEvent(key, stateWrapper); + } catch (Exception e) { + log.error("Failed to report last activity event on reporting period end for key: [{}]. State: [{}].", key, stateWrapper, e); } + } + } - if (hasExpired) { - states.remove(key); - onStateExpiry(key, metadata); - shouldReport = true; - } + private void reportLastEvent(Key key, ActivityStateWrapper stateWrapper) { + var currentState = stateWrapper.getState(); + + long lastRecordedTime = currentState.getLastRecordedTime(); + long lastReportedTime = stateWrapper.getLastReportedTime(); + var metadata = currentState.getMetadata(); + + boolean hasExpired; + boolean shouldReport; + + var updatedState = updateState(key, currentState); + if (updatedState != null) { + stateWrapper.setState(updatedState); + lastRecordedTime = updatedState.getLastRecordedTime(); + metadata = updatedState.getMetadata(); + hasExpired = hasExpired(lastRecordedTime); + shouldReport = stateWrapper.getStrategy().onReportingPeriodEnd(); + } else { + states.remove(key); + hasExpired = false; + shouldReport = true; + } - if (shouldReport && lastReportedTime < lastRecordedTime) { - log.debug("Going to report last activity event for key: [{}].", key); - reportActivity(key, metadata, lastRecordedTime, new ActivityReportCallback<>() { - @Override - public void onSuccess(Key key, long reportedTime) { - updateLastReportedTime(key, reportedTime); - } - - @Override - public void onFailure(Key key, Throwable t) { - log.debug("Failed to report last activity event for key: [{}].", key, t); - } - }); - } + if (hasExpired) { + states.remove(key); + onStateExpiry(key, metadata); + shouldReport = true; + } + + if (shouldReport && lastReportedTime < lastRecordedTime) { + long timeToReport = lastRecordedTime; + log.debug("Going to report last activity event for key: [{}]. Event time: [{}].", key, timeToReport); + reportActivity(key, metadata, timeToReport, new ActivityReportCallback<>() { + @Override + public void onSuccess(Key key, long reportedTime) { + updateLastReportedTime(key, reportedTime); + } + + @Override + public void onFailure(Key key, Throwable t) { + log.debug("Failed to report last activity event for key: [{}]. Event time: [{}].", key, timeToReport, t); + } + }); } } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstAndLastEventActivityStrategy.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstAndLastEventActivityStrategy.java index a5a59046ae..9ced9bd90b 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstAndLastEventActivityStrategy.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstAndLastEventActivityStrategy.java @@ -16,7 +16,9 @@ package org.thingsboard.server.common.transport.activity.strategy; import lombok.EqualsAndHashCode; +import lombok.ToString; +@ToString @EqualsAndHashCode public final class FirstAndLastEventActivityStrategy implements ActivityStrategy { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstEventActivityStrategy.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstEventActivityStrategy.java index 5353635c45..3b5d9dfc8d 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstEventActivityStrategy.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/activity/strategy/FirstEventActivityStrategy.java @@ -16,7 +16,9 @@ package org.thingsboard.server.common.transport.activity.strategy; import lombok.EqualsAndHashCode; +import lombok.ToString; +@ToString @EqualsAndHashCode public final class FirstEventActivityStrategy implements ActivityStrategy { diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index ff5716a361..02af9b53f8 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.kv.KvEntry; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.Reader; import java.io.Writer; import java.nio.file.Files; @@ -259,6 +260,15 @@ public class JacksonUtil { } } + public static JsonNode toJsonNode(InputStream value) { + try { + return value != null ? OBJECT_MAPPER.readTree(value) : null; + } catch (IOException e) { + throw new IllegalArgumentException("The given InputStream value: " + + value + " cannot be transformed to a JsonNode", e); + } + } + public static ObjectNode newObjectNode() { return newObjectNode(OBJECT_MAPPER); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileCacheKey.java index 1e91d43a8f..aa3f6ce89f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileCacheKey.java @@ -16,14 +16,14 @@ package org.thingsboard.server.dao.asset; import lombok.Data; +import org.thingsboard.server.cache.VersionedCacheKey; import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.TenantId; import java.io.Serial; -import java.io.Serializable; @Data -public class AssetProfileCacheKey implements Serializable { +public class AssetProfileCacheKey implements VersionedCacheKey { @Serial private static final long serialVersionUID = 8220455917177676472L; @@ -63,4 +63,9 @@ public class AssetProfileCacheKey implements Serializable { } } + @Override + public boolean isVersioned() { + return assetProfileId != null; + } + } 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 95786f0a6a..7d4d5300f9 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 @@ -236,8 +236,9 @@ public class AssetProfileServiceImpl extends CachedVersionedEntityService<AssetP log.trace("Executing findOrCreateAssetProfile"); AssetProfile assetProfile = findAssetProfileByName(tenantId, name, false); if (assetProfile == null) { + boolean isDefault = "default".equals(name) && findDefaultAssetProfile(tenantId) == null; try { - assetProfile = this.doCreateDefaultAssetProfile(tenantId, name, name.equals("default"), true); + assetProfile = this.doCreateAssetProfile(tenantId, name, isDefault, true); } catch (DataValidationException e) { if (ASSET_PROFILE_WITH_SUCH_NAME_ALREADY_EXISTS.equals(e.getMessage())) { assetProfile = findAssetProfileByName(tenantId, name, false); @@ -252,10 +253,10 @@ public class AssetProfileServiceImpl extends CachedVersionedEntityService<AssetP @Override public AssetProfile createDefaultAssetProfile(TenantId tenantId) { log.trace("Executing createDefaultAssetProfile tenantId [{}]", tenantId); - return doCreateDefaultAssetProfile(tenantId, "default", true, false); + return doCreateAssetProfile(tenantId, "default", true, false); } - private AssetProfile doCreateDefaultAssetProfile(TenantId tenantId, String profileName, boolean defaultProfile, boolean publishSaveEvent) { + private AssetProfile doCreateAssetProfile(TenantId tenantId, String profileName, boolean defaultProfile, boolean publishSaveEvent) { validateId(tenantId, id -> INCORRECT_TENANT_ID + id); AssetProfile assetProfile = new AssetProfile(); assetProfile.setTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeCacheKey.java index 2cbd444f80..def2c6c45c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeCacheKey.java @@ -18,16 +18,16 @@ package org.thingsboard.server.dao.attributes; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.thingsboard.server.cache.VersionedCacheKey; import org.thingsboard.server.common.data.AttributeScope; import org.thingsboard.server.common.data.id.EntityId; import java.io.Serial; -import java.io.Serializable; @EqualsAndHashCode @Getter @AllArgsConstructor -public class AttributeCacheKey implements Serializable { +public class AttributeCacheKey implements VersionedCacheKey { @Serial private static final long serialVersionUID = 2013369077925351881L; @@ -41,4 +41,9 @@ public class AttributeCacheKey implements Serializable { return "{" + entityId + "}" + scope + "_" + key; } + @Override + public boolean isVersioned() { + return true; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCacheKey.java index ad886b6a7c..55e8aa66eb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileCacheKey.java @@ -16,15 +16,15 @@ package org.thingsboard.server.dao.device; import lombok.Data; +import org.thingsboard.server.cache.VersionedCacheKey; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import java.io.Serial; -import java.io.Serializable; @Data -public class DeviceProfileCacheKey implements Serializable { +public class DeviceProfileCacheKey implements VersionedCacheKey { @Serial private static final long serialVersionUID = 8220455917177676472L; @@ -74,4 +74,9 @@ public class DeviceProfileCacheKey implements Serializable { return tenantId + "_" + name; } + @Override + public boolean isVersioned() { + return deviceProfileId != null; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 1528763775..09e2be01e0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -271,8 +271,9 @@ public class DeviceProfileServiceImpl extends CachedVersionedEntityService<Devic log.trace("Executing findOrCreateDefaultDeviceProfile"); DeviceProfile deviceProfile = findDeviceProfileByName(tenantId, name, false); if (deviceProfile == null) { + boolean isDefault = "default".equals(name) && findDefaultDeviceProfile(tenantId) == null; try { - deviceProfile = this.doCreateDefaultDeviceProfile(tenantId, name, name.equals("default"), true); + deviceProfile = this.doCreateDeviceProfile(tenantId, name, isDefault, true); } catch (DataValidationException e) { if (DEVICE_PROFILE_WITH_SUCH_NAME_ALREADY_EXISTS.equals(e.getMessage())) { deviceProfile = findDeviceProfileByName(tenantId, name, false); @@ -287,10 +288,10 @@ public class DeviceProfileServiceImpl extends CachedVersionedEntityService<Devic @Override public DeviceProfile createDefaultDeviceProfile(TenantId tenantId) { log.trace("Executing createDefaultDeviceProfile tenantId [{}]", tenantId); - return doCreateDefaultDeviceProfile(tenantId, "default", true, false); + return doCreateDeviceProfile(tenantId, "default", true, false); } - private DeviceProfile doCreateDefaultDeviceProfile(TenantId tenantId, String profileName, boolean defaultProfile, boolean publishSaveEvent) { + private DeviceProfile doCreateDeviceProfile(TenantId tenantId, String profileName, boolean defaultProfile, boolean publishSaveEvent) { validateId(tenantId, id -> INCORRECT_TENANT_ID + id); DeviceProfile deviceProfile = new DeviceProfile(); deviceProfile.setTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/BaseRelatedEdgesService.java b/dao/src/main/java/org/thingsboard/server/dao/edge/BaseRelatedEdgesService.java index 265831640c..bedee455f4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/BaseRelatedEdgesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/BaseRelatedEdgesService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.edge; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -30,6 +31,7 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; @Service +@Slf4j public class BaseRelatedEdgesService extends AbstractCachedEntityService<RelatedEdgesCacheKey, RelatedEdgesCacheValue, RelatedEdgesEvictEvent> implements RelatedEdgesService { public static final int RELATED_EDGES_CACHE_ITEMS = 1000; @@ -47,6 +49,7 @@ public class BaseRelatedEdgesService extends AbstractCachedEntityService<Related @Override public PageData<EdgeId> findEdgeIdsByEntityId(TenantId tenantId, EntityId entityId, PageLink pageLink) { + log.trace("Executing findEdgeIdsByEntityId, tenantId [{}], entityId [{}], pageLink [{}]", tenantId, entityId, pageLink); if (!pageLink.equals(FIRST_PAGE)) { return edgeService.findEdgeIdsByTenantIdAndEntityId(tenantId, entityId, pageLink); } @@ -56,6 +59,7 @@ public class BaseRelatedEdgesService extends AbstractCachedEntityService<Related @Override public void publishRelatedEdgeIdsEvictEvent(TenantId tenantId, EntityId entityId) { + log.trace("Executing publishRelatedEdgeIdsEvictEvent, tenantId [{}], entityId [{}]", tenantId, entityId); publishEvictEvent(new RelatedEdgesEvictEvent(tenantId, entityId)); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/CachedVersionedEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/CachedVersionedEntityService.java index 356fafbbff..46045ab928 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/CachedVersionedEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/CachedVersionedEntityService.java @@ -16,12 +16,13 @@ package org.thingsboard.server.dao.entity; import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.cache.VersionedCacheKey; import org.thingsboard.server.cache.VersionedTbCache; import org.thingsboard.server.common.data.HasVersion; import java.io.Serializable; -public abstract class CachedVersionedEntityService<K extends Serializable, V extends Serializable & HasVersion, E> extends AbstractCachedEntityService<K, V, E> { +public abstract class CachedVersionedEntityService<K extends VersionedCacheKey, V extends Serializable & HasVersion, E> extends AbstractCachedEntityService<K, V, E> { @Autowired protected VersionedTbCache<K, V> cache; diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheKey.java index 59df403165..deb1d85b78 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewCacheKey.java @@ -18,17 +18,17 @@ package org.thingsboard.server.dao.entityview; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.thingsboard.server.cache.VersionedCacheKey; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import java.io.Serial; -import java.io.Serializable; @Getter @EqualsAndHashCode @Builder -public class EntityViewCacheKey implements Serializable { +public class EntityViewCacheKey implements VersionedCacheKey { @Serial private static final long serialVersionUID = 5986277528222738163L; @@ -68,4 +68,9 @@ public class EntityViewCacheKey implements Serializable { } } + @Override + public boolean isVersioned() { + return entityViewId != null; + } + } 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 1fbab9c47c..b920160cc0 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 @@ -79,7 +79,9 @@ public class ModelConstants { public static final String USER_CREDENTIALS_ENABLED_PROPERTY = "enabled"; public static final String USER_CREDENTIALS_PASSWORD_PROPERTY = "password"; //NOSONAR, the constant used to identify password column name (not password value itself) public static final String USER_CREDENTIALS_ACTIVATE_TOKEN_PROPERTY = "activate_token"; + public static final String USER_CREDENTIALS_ACTIVATE_TOKEN_EXP_TIME_PROPERTY = "activate_token_exp_time"; public static final String USER_CREDENTIALS_RESET_TOKEN_PROPERTY = "reset_token"; + public static final String USER_CREDENTIALS_RESET_TOKEN_EXP_TIME_PROPERTY = "reset_token_exp_time"; public static final String USER_CREDENTIALS_ADDITIONAL_PROPERTY = "additional_info"; /** diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserCredentialsEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserCredentialsEntity.java index 59ba5ac4dd..edd1536a04 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserCredentialsEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/UserCredentialsEntity.java @@ -50,9 +50,15 @@ public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials> @Column(name = ModelConstants.USER_CREDENTIALS_ACTIVATE_TOKEN_PROPERTY, unique = true) private String activateToken; + @Column(name = ModelConstants.USER_CREDENTIALS_ACTIVATE_TOKEN_EXP_TIME_PROPERTY) + private Long activateTokenExpTime; + @Column(name = ModelConstants.USER_CREDENTIALS_RESET_TOKEN_PROPERTY, unique = true) private String resetToken; + @Column(name = ModelConstants.USER_CREDENTIALS_RESET_TOKEN_EXP_TIME_PROPERTY) + private Long resetTokenExpTime; + @Convert(converter = JsonConverter.class) @Column(name = ModelConstants.USER_CREDENTIALS_ADDITIONAL_PROPERTY) private JsonNode additionalInfo; @@ -72,7 +78,9 @@ public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials> this.enabled = userCredentials.isEnabled(); this.password = userCredentials.getPassword(); this.activateToken = userCredentials.getActivateToken(); + this.activateTokenExpTime = userCredentials.getActivateTokenExpTime(); this.resetToken = userCredentials.getResetToken(); + this.resetTokenExpTime = userCredentials.getResetTokenExpTime(); this.additionalInfo = userCredentials.getAdditionalInfo(); } @@ -86,7 +94,9 @@ public final class UserCredentialsEntity extends BaseSqlEntity<UserCredentials> userCredentials.setEnabled(enabled); userCredentials.setPassword(password); userCredentials.setActivateToken(activateToken); + userCredentials.setActivateTokenExpTime(activateTokenExpTime); userCredentials.setResetToken(resetToken); + userCredentials.setResetTokenExpTime(resetTokenExpTime); userCredentials.setAdditionalInfo(additionalInfo); return userCredentials; } 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 902bf0f6a7..6f34437e0d 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 @@ -640,10 +640,8 @@ 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()); - } + eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).edgeId(edgeId).entityId(ruleChainId) + .actionType(ActionType.ASSIGNED_TO_EDGE).body(JacksonUtil.toString(edge)).build()); return ruleChain; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/settings/DefaultSecuritySettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/settings/DefaultSecuritySettingsService.java new file mode 100644 index 0000000000..18c2f68c0a --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/settings/DefaultSecuritySettingsService.java @@ -0,0 +1,81 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.settings; + +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.AdminSettings; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.security.model.SecuritySettings; +import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; +import org.thingsboard.server.dao.service.ConstraintValidator; + +import static org.thingsboard.server.common.data.CacheConstants.SECURITY_SETTINGS_CACHE; + +@Service +@RequiredArgsConstructor +public class DefaultSecuritySettingsService implements SecuritySettingsService { + + private final AdminSettingsService adminSettingsService; + + public static final int DEFAULT_MOBILE_SECRET_KEY_LENGTH = 64; + + @Cacheable(cacheNames = SECURITY_SETTINGS_CACHE, key = "'securitySettings'") + @Override + public SecuritySettings getSecuritySettings() { + AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "securitySettings"); + SecuritySettings securitySettings; + if (adminSettings != null) { + try { + securitySettings = JacksonUtil.convertValue(adminSettings.getJsonValue(), SecuritySettings.class); + } catch (Exception e) { + throw new RuntimeException("Failed to load security settings!", e); + } + } else { + securitySettings = new SecuritySettings(); + securitySettings.setPasswordPolicy(new UserPasswordPolicy()); + securitySettings.getPasswordPolicy().setMinimumLength(6); + securitySettings.getPasswordPolicy().setMaximumLength(72); + securitySettings.setMobileSecretKeyLength(DEFAULT_MOBILE_SECRET_KEY_LENGTH); + securitySettings.setPasswordResetTokenTtl(24); + securitySettings.setUserActivationTokenTtl(24); + } + return securitySettings; + } + + @CacheEvict(cacheNames = SECURITY_SETTINGS_CACHE, key = "'securitySettings'") + @Override + public SecuritySettings saveSecuritySettings(SecuritySettings securitySettings) { + ConstraintValidator.validateFields(securitySettings); + AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "securitySettings"); + if (adminSettings == null) { + adminSettings = new AdminSettings(); + adminSettings.setTenantId(TenantId.SYS_TENANT_ID); + adminSettings.setKey("securitySettings"); + } + adminSettings.setJsonValue(JacksonUtil.valueToTree(securitySettings)); + AdminSettings savedAdminSettings = adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings); + try { + return JacksonUtil.convertValue(savedAdminSettings.getJsonValue(), SecuritySettings.class); + } catch (Exception e) { + throw new RuntimeException("Failed to load security settings!", e); + } + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/settings/SecuritySettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/settings/SecuritySettingsService.java new file mode 100644 index 0000000000..8b9e3bfeee --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/settings/SecuritySettingsService.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.settings; + +import org.thingsboard.server.common.data.security.model.SecuritySettings; + +public interface SecuritySettingsService { + + SecuritySettings getSecuritySettings(); + + SecuritySettings saveSecuritySettings(SecuritySettings securitySettings); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TsLatestCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TsLatestCacheKey.java index 9880f21cc1..593bc55e1e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TsLatestCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TsLatestCacheKey.java @@ -18,15 +18,15 @@ package org.thingsboard.server.dao.timeseries; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.thingsboard.server.cache.VersionedCacheKey; import org.thingsboard.server.common.data.id.EntityId; import java.io.Serial; -import java.io.Serializable; @EqualsAndHashCode @Getter @AllArgsConstructor -public class TsLatestCacheKey implements Serializable { +public class TsLatestCacheKey implements VersionedCacheKey { @Serial private static final long serialVersionUID = 2024369077925351881L; @@ -39,4 +39,9 @@ public class TsLatestCacheKey implements Serializable { return "{" + entityId + "}" + key; } + @Override + public boolean isVersioned() { + return true; + } + } 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 f64ccf4970..ba0d3d69f3 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 @@ -63,6 +63,7 @@ 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; +import org.thingsboard.server.dao.settings.SecuritySettingsService; import org.thingsboard.server.dao.sql.JpaExecutorService; import java.util.ArrayList; @@ -72,6 +73,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.TimeUnit; import static org.thingsboard.server.common.data.StringUtils.generateSafeToken; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -102,6 +104,7 @@ public class UserServiceImpl extends AbstractCachedEntityService<UserCacheKey, U private final UserAuthSettingsDao userAuthSettingsDao; private final UserSettingsService userSettingsService; private final UserSettingsDao userSettingsDao; + private final SecuritySettingsService securitySettingsService; private final DataValidator<User> userValidator; private final DataValidator<UserCredentials> userCredentialsValidator; private final ApplicationEventPublisher eventPublisher; @@ -178,9 +181,9 @@ public class UserServiceImpl extends AbstractCachedEntityService<UserCacheKey, U countService.publishCountEntityEvictEvent(savedUser.getTenantId(), EntityType.USER); UserCredentials userCredentials = new UserCredentials(); userCredentials.setEnabled(false); - userCredentials.setActivateToken(generateSafeToken(DEFAULT_TOKEN_LENGTH)); userCredentials.setUserId(new UserId(savedUser.getUuidId())); userCredentials.setAdditionalInfo(JacksonUtil.newObjectNode()); + userCredentials = generateUserActivationToken(userCredentials); userCredentialsDao.save(user.getTenantId(), userCredentials); } eventPublisher.publishEvent(SaveEntityEvent.builder() @@ -242,8 +245,12 @@ public class UserServiceImpl extends AbstractCachedEntityService<UserCacheKey, U if (userCredentials.isEnabled()) { throw new IncorrectParameterException("User credentials already activated"); } + if (userCredentials.isActivationTokenExpired()) { + throw new IncorrectParameterException("Activation token expired"); + } userCredentials.setEnabled(true); userCredentials.setActivateToken(null); + userCredentials.setActivateTokenExpTime(null); userCredentials.setPassword(password); if (userCredentials.getPassword() != null) { updatePasswordHistory(userCredentials); @@ -263,7 +270,7 @@ public class UserServiceImpl extends AbstractCachedEntityService<UserCacheKey, U if (!userCredentials.isEnabled()) { throw new DisabledException(String.format("User credentials not enabled [%s]", email)); } - userCredentials.setResetToken(generateSafeToken(DEFAULT_TOKEN_LENGTH)); + userCredentials = generatePasswordResetToken(userCredentials); return saveUserCredentials(tenantId, userCredentials); } @@ -273,10 +280,26 @@ public class UserServiceImpl extends AbstractCachedEntityService<UserCacheKey, U if (!userCredentials.isEnabled()) { throw new IncorrectParameterException("Unable to reset password for inactive user"); } - userCredentials.setResetToken(generateSafeToken(DEFAULT_TOKEN_LENGTH)); + userCredentials = generatePasswordResetToken(userCredentials); return saveUserCredentials(tenantId, userCredentials); } + @Override + public UserCredentials generatePasswordResetToken(UserCredentials userCredentials) { + userCredentials.setResetToken(generateSafeToken(DEFAULT_TOKEN_LENGTH)); + int ttlHours = securitySettingsService.getSecuritySettings().getPasswordResetTokenTtl(); + userCredentials.setResetTokenExpTime(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(ttlHours)); + return userCredentials; + } + + @Override + public UserCredentials generateUserActivationToken(UserCredentials userCredentials) { + userCredentials.setActivateToken(generateSafeToken(DEFAULT_TOKEN_LENGTH)); + int ttlHours = securitySettingsService.getSecuritySettings().getUserActivationTokenTtl(); + userCredentials.setActivateTokenExpTime(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(ttlHours)); + return userCredentials; + } + @Override public UserCredentials replaceUserCredentials(TenantId tenantId, UserCredentials userCredentials) { log.trace("Executing replaceUserCredentials [{}]", userCredentials); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 46e739e5d5..9c95f385f8 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -491,9 +491,11 @@ CREATE TABLE IF NOT EXISTS user_credentials ( id uuid NOT NULL CONSTRAINT user_credentials_pkey PRIMARY KEY, created_time bigint NOT NULL, activate_token varchar(255) UNIQUE, + activate_token_exp_time BIGINT, enabled boolean, password varchar(255), reset_token varchar(255) UNIQUE, + reset_token_exp_time BIGINT, user_id uuid UNIQUE, additional_info varchar DEFAULT '{}' ); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java index d7b17fe53a..7271a0fc8a 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java @@ -163,6 +163,18 @@ public class AssetProfileServiceTest extends AbstractServiceTest { }); } + @Test + public void testSaveAssetProfileWithNameDefaultAndProfileWithIsDefaultAndDifferentNameAlreadyExists() { + AssetProfile defaultAssetProfile = assetProfileService.findDefaultAssetProfile(tenantId); + Assert.assertNotNull(defaultAssetProfile); + defaultAssetProfile.setName("Asset Profile 1"); + assetProfileService.saveAssetProfile(defaultAssetProfile); + AssetProfile createdAssetProfile = assetProfileService.findOrCreateAssetProfile(tenantId, "default"); + Assert.assertNotNull(createdAssetProfile); + Assert.assertEquals("default", createdAssetProfile.getName()); + Assert.assertFalse(createdAssetProfile.isDefault()); + } + @Test public void testDeleteAssetProfileWithExistingAsset() { AssetProfile assetProfile = this.createAssetProfile(tenantId, "Asset Profile"); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java index 51abe245b2..aa14e20151 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java @@ -209,6 +209,18 @@ public class DeviceProfileServiceTest extends AbstractServiceTest { }); } + @Test + public void testSaveDeviceProfileWithNameDefaultAndProfileWithIsDefaultAndDifferentNameAlreadyExists() { + DeviceProfile defaultDeviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId); + Assert.assertNotNull(defaultDeviceProfile); + defaultDeviceProfile.setName("Device Profile 1"); + deviceProfileService.saveDeviceProfile(defaultDeviceProfile); + DeviceProfile createdDeviceProfile = deviceProfileService.findOrCreateDeviceProfile(tenantId, "default"); + Assert.assertNotNull(createdDeviceProfile); + Assert.assertEquals("default", createdDeviceProfile.getName()); + Assert.assertFalse(createdDeviceProfile.isDefault()); + } + @Ignore @Test public void testChangeDeviceProfileTypeWithExistingDevices() { diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserCredentialsDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserCredentialsDaoTest.java index a1e559414e..d68197c1bd 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserCredentialsDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/user/JpaUserCredentialsDaoTest.java @@ -63,7 +63,9 @@ public class JpaUserCredentialsDaoTest extends AbstractJpaDaoTest { userCredentials.setUserId(new UserId(UUID.randomUUID())); userCredentials.setPassword("password"); userCredentials.setActivateToken("ACTIVATE_TOKEN_" + number); + userCredentials.setActivateTokenExpTime(123L); userCredentials.setResetToken("RESET_TOKEN_" + number); + userCredentials.setResetTokenExpTime(321L); return userCredentialsDao.save(SYSTEM_TENANT_ID, userCredentials); } diff --git a/msa/js-executor/config/default.yml b/msa/js-executor/config/default.yml index 0e15413e31..f5bde183e4 100644 --- a/msa/js-executor/config/default.yml +++ b/msa/js-executor/config/default.yml @@ -34,7 +34,7 @@ kafka: partitions_consumed_concurrently: "1" # (EXPERIMENTAL) increase this value if you are planning to handle more than one partition (scale up, scale down) - this will decrease the latency requestTimeout: "30000" # The default value in kafkajs is: 30000 connectionTimeout: "1000" # The default value in kafkajs is: 1000 - compression: "gzip" # gzip or uncompressed + compression: "none" # gzip or uncompressed topic_properties: "retention.ms:604800000;segment.bytes:52428800;retention.bytes:104857600;partitions:100;min.insync.replicas:1" use_confluent_cloud: false client_id: "kafkajs" #inject pod name to easy identify the client using /opt/kafka/bin/kafka-consumer-groups.sh 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 5c3e311a1e..86c856f304 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttHandler.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttHandler.java @@ -15,10 +15,30 @@ */ package org.thingsboard.mqtt; -import com.google.common.util.concurrent.ListenableFuture; +import java.util.concurrent.Future; import io.netty.buffer.ByteBuf; public interface MqttHandler { - - ListenableFuture<Void> onMessage(String topic, ByteBuf payload); + /** + * Changing ListenableFuture to Future allows you to choose CompletableFuture, + * which gives developers the freedom to choose the orchestration method. + * CompletableFuture is a newer, more evolved version that eliminates callback hell, + * is easier to use, and comes with the JDK. jdk 1.8 was previously used with the Before JDK1.8, + * use ListenableFuture, after that, it is recommended to use CompletableFuture. + * ListenableFuture It's still written that way.{@link MqttMessageListener#onMessage(topic, payload)} + * public ListenableFuture<Void> 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(); + * } + * CompletableFuture It's like this. + * public CompletableFuture<Void> 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 CompletableFuture.completedFuture(null); + * } + * This change does not affect the system's current use of ListenableFuture so that it is free to choose between ListenableFuture or + * CompletableFuture in new development. + */ + Future<Void> onMessage(String topic, ByteBuf payload); } diff --git a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java index 6d1fcec080..818d714a3b 100644 --- a/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java +++ b/rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java @@ -515,13 +515,16 @@ public class RestClient implements Closeable { return restTemplate.postForEntity(baseURL + "/api/alarm", alarm, Alarm.class).getBody(); } - public List<EntitySubtype> getAlarmTypes(PageLink pageLink) { + public PageData<EntitySubtype> getAlarmTypes(PageLink pageLink) { + Map<String, String> params = new HashMap<>(); + addPageLinkToParam(params, pageLink); return restTemplate.exchange( baseURL + "/api/alarm/types?" + getUrlParams(pageLink), HttpMethod.GET, HttpEntity.EMPTY, - new ParameterizedTypeReference<List<EntitySubtype>>() { - }).getBody(); + new ParameterizedTypeReference<PageData<EntitySubtype>>() { + }, + params).getBody(); } public AlarmComment saveAlarmComment(AlarmId alarmId, AlarmComment alarmComment) { diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java index ecaf7ef3f9..043181a710 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/MailService.java @@ -32,13 +32,13 @@ public interface MailService { void sendTestMail(JsonNode config, String email) throws ThingsboardException; - void sendActivationEmail(String activationLink, String email) throws ThingsboardException; + void sendActivationEmail(String activationLink, long ttlMs, String email) throws ThingsboardException; void sendAccountActivatedEmail(String loginLink, String email) throws ThingsboardException; - void sendResetPasswordEmail(String passwordResetLink, String email) throws ThingsboardException; + void sendResetPasswordEmail(String passwordResetLink, long ttlMs, String email) throws ThingsboardException; - void sendResetPasswordEmailAsync(String passwordResetLink, String email); + void sendResetPasswordEmailAsync(String passwordResetLink, long ttlMs, String email); void sendPasswordWasResetEmail(String loginLink, String email) throws ThingsboardException; 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 f8ec81abcf..d7476bf08e 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 @@ -135,7 +135,6 @@ public class TbHttpClient { this.webClient = WebClient.builder() .clientConnector(new ReactorClientHttpConnector(httpClient)) - .defaultHeader(HttpHeaders.CONNECTION, "close") //In previous realization this header was present! (Added for hotfix "Connection reset") .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize( (config.getMaxInMemoryBufferSizeInKb() > 0 ? config.getMaxInMemoryBufferSizeInKb() : 256) * 1024)) .build(); 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 2c723830bd..0892bcd150 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,25 +1,25 @@ -System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/input","@angular/material/form-field","@angular/material/slide-toggle","@angular/flex-layout/flex","@ngx-translate/core","@angular/material/button","@angular/material/icon","@angular/material/select","@angular/material/core","@angular/material/tooltip","@angular/material/expansion","rxjs","@shared/components/hint-tooltip-icon.component","@shared/components/help-popup.component","@shared/pipe/safe.pipe","@core/public-api","@shared/components/js-func.component","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/checkbox","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/relation/relation-type-autocomplete.component","@shared/components/entity/entity-select.component","@shared/components/toggle-header.component","@shared/components/toggle-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","@home/components/public-api","tslib","@shared/components/entity/entity-subtype-list.component","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@shared/components/string-items-list.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","@angular/cdk/platform"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,p,d,u,c,g,f,y,b,x,h,v,C,F,k,T,L,I,N,S,q,A,M,E,G,w,D,V,P,R,O,_,B,K,z,H,U,j,$,J,Q,Y,W,Z,X,ee,te,ne,re,oe,ae,ie,le,se,me,pe,de,ue,ce,ge,fe,ye,be,xe,he,ve,Ce,Fe,ke,Te,Le,Ie,Ne,Se,qe,Ae,Me,Ee,Ge,we,De,Ve,Pe,Re,Oe,_e,Be,Ke,ze,He,Ue,je,$e,Je,Qe,Ye,We,Ze,Xe,et,tt,nt,rt,ot,at,it,lt,st,mt,pt;return{setters:[function(e){t=e,n=e.Component,r=e.InjectionToken,o=e.Injectable,a=e.Inject,i=e.Optional,l=e.EventEmitter,s=e.Directive,m=e.Input,p=e.Output,d=e.NgModule,u=e.ViewChild,c=e.forwardRef},function(e){g=e.RuleNodeConfigurationComponent,f=e.AttributeScope,y=e.telemetryTypeTranslations,b=e.ScriptLanguage,x=e.AlarmSeverity,h=e.alarmSeverityTranslations,v=e.EntitySearchDirection,C=e.EntityType,F=e.entityFields,k=e.PageComponent,T=e.messageTypeNames,L=e.MessageType,I=e.coerceBoolean,N=e.entitySearchDirectionTranslations,S=e,q=e.AlarmStatus,A=e.alarmStatusTranslations,M=e.SharedModule,E=e.AggregationType,G=e.aggregationTranslations,w=e.NotificationType,D=e.SlackChanelType,V=e.SlackChanelTypesTranslateMap},function(e){P=e},function(e){R=e,O=e.Validators,_=e.NgControl,B=e.NG_VALUE_ACCESSOR,K=e.NG_VALIDATORS,z=e.FormArray,H=e.FormGroup},function(e){U=e,j=e.DOCUMENT,$=e.CommonModule},function(e){J=e},function(e){Q=e},function(e){Y=e},function(e){W=e},function(e){Z=e},function(e){X=e},function(e){ee=e},function(e){te=e},function(e){ne=e},function(e){re=e},function(e){oe=e},function(e){ae=e.Subject,ie=e.takeUntil,le=e.of,se=e.EMPTY,me=e.fromEvent},function(e){pe=e},function(e){de=e},function(e){ue=e},function(e){ce=e.getCurrentAuthState,ge=e,fe=e.isDefinedAndNotNull,ye=e.isEqual,be=e.deepTrim,xe=e.isObject,he=e.isNotEmptyStr},function(e){ve=e},function(e){Ce=e},function(e){Fe=e.ENTER,ke=e.COMMA,Te=e.SEMICOLON},function(e){Le=e},function(e){Ie=e},function(e){Ne=e},function(e){Se=e},function(e){qe=e},function(e){Ae=e},function(e){Me=e},function(e){Ee=e.coerceBooleanProperty,Ge=e.coerceElement,we=e.coerceNumberProperty},function(e){De=e},function(e){Ve=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e.tap,_e=e.map,Be=e.startWith,Ke=e.mergeMap,ze=e.share,He=e.takeUntil,Ue=e.auditTime},function(e){je=e},function(e){$e=e},function(e){Je=e.HomeComponentsModule},function(e){Qe=e.__decorate},function(e){Ye=e},function(e){We=e},function(e){Ze=e},function(e){Xe=e},function(e){et=e},function(e){tt=e},function(e){nt=e},function(e){rt=e},function(e){ot=e},function(e){at=e},function(e){it=e},function(e){lt=e},function(e){st=e},function(e){mt=e.normalizePassiveListenerOptions,pt=e}],execute:function(){class dt extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",dt),dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:dt,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:dt,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"<div></div>",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:dt,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"<div></div>"}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class ut extends g{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,[O.required,O.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",ut),ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ut,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ut,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="assignCustomerConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\') ||\n assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.customer-name-pattern-hint</mat-hint>\n </mat-form-field>\n <div class="tb-form-row">\n <mat-slide-toggle class="mat-slide" formControlName="createCustomerIfNotExists">\n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ut,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'<section [formGroup]="assignCustomerConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\') ||\n assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.customer-name-pattern-hint</mat-hint>\n </mat-form-field>\n <div class="tb-form-row">\n <mat-slide-toggle class="mat-slide" formControlName="createCustomerIfNotExists">\n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});const ct=new r("WindowToken","undefined"!=typeof window&&window.document?{providedIn:"root",factory:()=>window}:{providedIn:"root",factory:()=>{}});class gt{constructor(e,t,n){this.ngZone=e,this.document=t,this.window=n,this.copySubject=new ae,this.copyResponse$=this.copySubject.asObservable(),this.config={}}configure(e){this.config=e}copy(e){if(!this.isSupported||!e)return this.pushCopyResponse({isSuccess:!1,content:e});const t=this.copyFromContent(e);return t?this.pushCopyResponse({content:e,isSuccess:t}):this.pushCopyResponse({isSuccess:!1,content:e})}get isSupported(){return!!this.document.queryCommandSupported&&!!this.document.queryCommandSupported("copy")&&!!this.window}isTargetValid(e){if(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement){if(e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');return!0}throw new Error("Target should be input or textarea")}copyFromInputElement(e,t=!0){try{this.selectTarget(e);const n=this.copyText();return this.clearSelection(t?e:void 0,this.window),n&&this.isCopySuccessInIE11()}catch(e){return!1}}isCopySuccessInIE11(){const e=this.window.clipboardData;return!(e&&e.getData&&!e.getData("Text"))}copyFromContent(e,t=this.document.body){if(this.tempTextArea&&!t.contains(this.tempTextArea)&&this.destroy(this.tempTextArea.parentElement||void 0),!this.tempTextArea){this.tempTextArea=this.createTempTextArea(this.document,this.window);try{t.appendChild(this.tempTextArea)}catch(e){throw new Error("Container should be a Dom element")}}this.tempTextArea.value=e;const n=this.copyFromInputElement(this.tempTextArea,!1);return this.config.cleanUpAfterCopy&&this.destroy(this.tempTextArea.parentElement||void 0),n}destroy(e=this.document.body){this.tempTextArea&&(e.removeChild(this.tempTextArea),this.tempTextArea=void 0)}selectTarget(e){return e.select(),e.setSelectionRange(0,e.value.length),e.value.length}copyText(){return this.document.execCommand("copy")}clearSelection(e,t){e&&e.focus(),t.getSelection()?.removeAllRanges()}createTempTextArea(e,t){const n="rtl"===e.documentElement.getAttribute("dir");let r;r=e.createElement("textarea"),r.style.fontSize="12pt",r.style.border="0",r.style.padding="0",r.style.margin="0",r.style.position="absolute",r.style[n?"right":"left"]="-9999px";const o=t.pageYOffset||e.documentElement.scrollTop;return r.style.top=o+"px",r.setAttribute("readonly",""),r}pushCopyResponse(e){this.copySubject.observers.length>0&&this.ngZone.run((()=>{this.copySubject.next(e)}))}pushCopyReponse(e){this.pushCopyResponse(e)}}gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:gt,deps:[{token:t.NgZone},{token:j},{token:ct,optional:!0}],target:t.ɵɵFactoryTarget.Injectable}),gt.ɵprov=t.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:gt,providedIn:"root"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:gt,decorators:[{type:o,args:[{providedIn:"root"}]}],ctorParameters:function(){return[{type:t.NgZone},{type:void 0,decorators:[{type:a,args:[j]}]},{type:void 0,decorators:[{type:i},{type:a,args:[ct]}]}]}});class ft{constructor(e,t,n,r){this.ngZone=e,this.host=t,this.renderer=n,this.clipboardSrv=r,this.cbOnSuccess=new l,this.cbOnError=new l,this.onClick=e=>{this.clipboardSrv.isSupported?this.targetElm&&this.clipboardSrv.isTargetValid(this.targetElm)?this.handleResult(this.clipboardSrv.copyFromInputElement(this.targetElm),this.targetElm.value,e):this.cbContent&&this.handleResult(this.clipboardSrv.copyFromContent(this.cbContent,this.container),this.cbContent,e):this.handleResult(!1,void 0,e)}}ngOnInit(){this.ngZone.runOutsideAngular((()=>{this.clickListener=this.renderer.listen(this.host.nativeElement,"click",this.onClick)}))}ngOnDestroy(){this.clickListener&&this.clickListener(),this.clipboardSrv.destroy(this.container)}handleResult(e,t,n){let r={isSuccess:e,content:t,successMessage:this.cbSuccessMsg,event:n};e?this.cbOnSuccess.observed&&this.ngZone.run((()=>{this.cbOnSuccess.emit(r)})):this.cbOnError.observed&&this.ngZone.run((()=>{this.cbOnError.emit(r)})),this.clipboardSrv.pushCopyResponse(r)}}ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:ft,deps:[{token:t.NgZone},{token:t.ElementRef},{token:t.Renderer2},{token:gt}],target:t.ɵɵFactoryTarget.Directive}),ft.ɵdir=t.ɵɵngDeclareDirective({minVersion:"12.0.0",version:"13.0.1",type:ft,selector:"[ngxClipboard]",inputs:{targetElm:["ngxClipboard","targetElm"],container:"container",cbContent:"cbContent",cbSuccessMsg:"cbSuccessMsg"},outputs:{cbOnSuccess:"cbOnSuccess",cbOnError:"cbOnError"},ngImport:t}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:ft,decorators:[{type:s,args:[{selector:"[ngxClipboard]"}]}],ctorParameters:function(){return[{type:t.NgZone},{type:t.ElementRef},{type:t.Renderer2},{type:gt}]},propDecorators:{targetElm:[{type:m,args:["ngxClipboard"]}],container:[{type:m}],cbContent:[{type:m}],cbSuccessMsg:[{type:m}],cbOnSuccess:[{type:p}],cbOnError:[{type:p}]}});class yt{constructor(e,t,n){this._clipboardService=e,this._viewContainerRef=t,this._templateRef=n}ngOnInit(){this._clipboardService.isSupported&&this._viewContainerRef.createEmbeddedView(this._templateRef)}}yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:yt,deps:[{token:gt},{token:t.ViewContainerRef},{token:t.TemplateRef}],target:t.ɵɵFactoryTarget.Directive}),yt.ɵdir=t.ɵɵngDeclareDirective({minVersion:"12.0.0",version:"13.0.1",type:yt,selector:"[ngxClipboardIfSupported]",ngImport:t}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:yt,decorators:[{type:s,args:[{selector:"[ngxClipboardIfSupported]"}]}],ctorParameters:function(){return[{type:gt},{type:t.ViewContainerRef},{type:t.TemplateRef}]}});class bt{}bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:bt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),bt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:bt,declarations:[ft,yt],imports:[$],exports:[ft,yt]}),bt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:bt,imports:[[$]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:bt,decorators:[{type:d,args:[{imports:[$],declarations:[ft,yt],exports:[ft,yt]}]}]});class xt{constructor(){this.textAlign="left"}}e("ExampleHintComponent",xt),xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:xt,deps:[],target:t.ɵɵFactoryTarget.Component}),xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:xt,selector:"tb-example-hint",inputs:{hintText:"hintText",popupHelpLink:"popupHelpLink",textAlign:"textAlign"},ngImport:t,template:'<div [hidden]="!hintText" class="tb-form-hint tb-primary-fill space-between">\n <div [innerHTML]=" hintText | translate | safe: \'html\'"\n [style.text-align]="textAlign"\n class="hint-text"></div>\n <div *ngIf="popupHelpLink" class="see-example" tb-help-popup="{{ popupHelpLink }}"\n hintMode\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}">\n </div>\n</div>\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}:host .hint-text{width:100%}\n"],dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.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","hintMode"]},{kind:"pipe",type:ue.SafePipe,name:"safe"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:xt,decorators:[{type:n,args:[{selector:"tb-example-hint",template:'<div [hidden]="!hintText" class="tb-form-hint tb-primary-fill space-between">\n <div [innerHTML]=" hintText | translate | safe: \'html\'"\n [style.text-align]="textAlign"\n class="hint-text"></div>\n <div *ngIf="popupHelpLink" class="see-example" tb-help-popup="{{ popupHelpLink }}"\n hintMode\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}">\n </div>\n</div>\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}:host .hint-text{width:100%}\n"]}]}],propDecorators:{hintText:[{type:m}],popupHelpLink:[{type:m}],textAlign:[{type:m}]}});class ht extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=f,this.attributeScopes=Object.keys(f),this.telemetryTypeTranslationsMap=y}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[O.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]],updateAttributesOnlyOnValueChange:[!!e&&e.updateAttributesOnlyOnValueChange,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==f.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===f.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1}),this.attributesConfigForm.get("updateAttributesOnlyOnValueChange").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",ht),ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ht,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ht,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="attributesConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="attributesConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="attributesConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div tb-hint-tooltip-icon="{{ (attributesConfigForm.get(\'updateAttributesOnlyOnValueChange\').value\n ? \'tb.rulenode.update-attributes-only-on-value-change-hint-enabled\'\n : \'tb.rulenode.update-attributes-only-on-value-change-hint\') | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="updateAttributesOnlyOnValueChange">\n {{ \'tb.rulenode.update-attributes-only-on-value-change\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.send-attributes-updated-notification-hint\' | translate }}"\n *ngIf="attributesConfigForm.get(\'scope\').value !== attributeScopeMap.CLIENT_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="sendAttributesUpdatedNotification">\n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.notify-device-on-update-hint\' | translate }}"\n *ngIf="attributesConfigForm.get(\'scope\').value === attributeScopeMap.SHARED_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="notifyDevice">\n {{ \'tb.rulenode.notify-device\' | translate }}\n </mat-slide-toggle>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"component",type:oe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:oe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:oe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:ft,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ht,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'<section [formGroup]="attributesConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="attributesConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="attributesConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div tb-hint-tooltip-icon="{{ (attributesConfigForm.get(\'updateAttributesOnlyOnValueChange\').value\n ? \'tb.rulenode.update-attributes-only-on-value-change-hint-enabled\'\n : \'tb.rulenode.update-attributes-only-on-value-change-hint\') | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="updateAttributesOnlyOnValueChange">\n {{ \'tb.rulenode.update-attributes-only-on-value-change\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.send-attributes-updated-notification-hint\' | translate }}"\n *ngIf="attributesConfigForm.get(\'scope\').value !== attributeScopeMap.CLIENT_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="sendAttributesUpdatedNotification">\n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.notify-device-on-update-hint\' | translate }}"\n *ngIf="attributesConfigForm.get(\'scope\').value === attributeScopeMap.SHARED_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="notifyDevice">\n {{ \'tb.rulenode.notify-device\' | translate }}\n </mat-slide-toggle>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class vt extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ce(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,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:b.JS,[O.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[O.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===b.JS?[O.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===b.TBEL?[O.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),e}testScript(e){const t=this.clearAlarmConfigForm.get("scriptLang").value,n=t===b.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",vt),vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vt,deps:[{token:P.Store},{token:R.UntypedFormBuilder},{token:ge.NodeScriptTestService},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:vt,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:'<section [formGroup]="clearAlarmConfigForm" fxLayout="column">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="clearAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/clear_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="clearAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="alarmDetailsBuildTbel"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/clear_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="clearAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ve.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ce.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vt,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'<section [formGroup]="clearAlarmConfigForm" fxLayout="column">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="clearAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/clear_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="clearAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="alarmDetailsBuildTbel"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/clear_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="clearAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder},{type:ge.NodeScriptTestService},{type:Z.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class Ct extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(x),this.alarmSeverityTranslationMap=h,this.separatorKeysCodes=[Fe,ke,Te],this.tbelEnabled=ce(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,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:b.JS,[O.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([O.required]),this.createAlarmConfigForm.get("severity").setValidators([O.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==b.TBEL||this.tbelEnabled||(r=b.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===b.JS?[O.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===b.TBEL?[O.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),e}testScript(e){const t=this.createAlarmConfigForm.get("scriptLang").value,n=t===b.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",Ct),Ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ct,deps:[{token:P.Store},{token:R.UntypedFormBuilder},{token:ge.NodeScriptTestService},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ct,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:'<section [formGroup]="createAlarmConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMessageAlarmData">\n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="overwriteAlarmDetails" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === true">\n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false ||\n createAlarmConfigForm.get(\'overwriteAlarmDetails\').value === true">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="createAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/create_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="createAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="alarmDetailsBuildTbel"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/create_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n </section>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false">\n <mat-form-field fxFlex subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="createAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="dynamicSeverity">\n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n </mat-checkbox>\n <mat-form-field fxFlex *ngIf="!createAlarmConfigForm.get(\'dynamicSeverity\').value">\n <mat-label translate>tb.rulenode.alarm-severity</mat-label>\n <mat-select formControlName="severity" required>\n <mat-option *ngFor="let severity of alarmSeverities" [value]="severity">\n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex *ngIf="createAlarmConfigForm.get(\'dynamicSeverity\').value" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-severity-pattern</mat-label>\n <input matInput formControlName="severity" required>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n <mat-hint [innerHTML]="\'tb.rulenode.alarm-severity-pattern-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="propagate">\n {{ \'tb.rulenode.propagate\' | translate }}\n </mat-checkbox>\n <section *ngIf="createAlarmConfigForm.get(\'propagate\').value === true">\n <mat-form-field floatLabel="always" class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.relation-types-list</mat-label>\n <mat-chip-grid #relationTypesChipList>\n <mat-chip-row\n *ngFor="let key of createAlarmConfigForm.get(\'relationTypes\').value;"\n (removed)="removeKey(key, \'relationTypes\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text" placeholder="{{\'tb.rulenode.relation-types-list\' | translate}}"\n [matChipInputFor]="relationTypesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'relationTypes\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-grid>\n <mat-hint translate>tb.rulenode.relation-types-list-hint</mat-hint>\n </mat-form-field>\n </section>\n <mat-checkbox formControlName="propagateToOwner">\n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="propagateToTenant">\n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n </mat-checkbox>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ve.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Ie.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:Ie.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:Ie.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:Ie.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:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ce.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:ue.SafePipe,name:"safe"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ct,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'<section [formGroup]="createAlarmConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMessageAlarmData">\n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="overwriteAlarmDetails" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === true">\n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false ||\n createAlarmConfigForm.get(\'overwriteAlarmDetails\').value === true">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="createAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/create_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="createAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="alarmDetailsBuildTbel"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/create_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n </section>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false">\n <mat-form-field fxFlex subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="createAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="dynamicSeverity">\n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n </mat-checkbox>\n <mat-form-field fxFlex *ngIf="!createAlarmConfigForm.get(\'dynamicSeverity\').value">\n <mat-label translate>tb.rulenode.alarm-severity</mat-label>\n <mat-select formControlName="severity" required>\n <mat-option *ngFor="let severity of alarmSeverities" [value]="severity">\n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex *ngIf="createAlarmConfigForm.get(\'dynamicSeverity\').value" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-severity-pattern</mat-label>\n <input matInput formControlName="severity" required>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n <mat-hint [innerHTML]="\'tb.rulenode.alarm-severity-pattern-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="propagate">\n {{ \'tb.rulenode.propagate\' | translate }}\n </mat-checkbox>\n <section *ngIf="createAlarmConfigForm.get(\'propagate\').value === true">\n <mat-form-field floatLabel="always" class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.relation-types-list</mat-label>\n <mat-chip-grid #relationTypesChipList>\n <mat-chip-row\n *ngFor="let key of createAlarmConfigForm.get(\'relationTypes\').value;"\n (removed)="removeKey(key, \'relationTypes\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text" placeholder="{{\'tb.rulenode.relation-types-list\' | translate}}"\n [matChipInputFor]="relationTypesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'relationTypes\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-grid>\n <mat-hint translate>tb.rulenode.relation-types-list-hint</mat-hint>\n </mat-form-field>\n </section>\n <mat-checkbox formControlName="propagateToOwner">\n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="propagateToTenant">\n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n </mat-checkbox>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder},{type:ge.NodeScriptTestService},{type:Z.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class Ft extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(v),this.directionTypeTranslations=new Map([[v.FROM,"tb.rulenode.search-direction-from"],[v.TO,"tb.rulenode.search-direction-to"]]),this.entityType=C,this.entityTypeNamePatternTranslation=new Map([[C.DEVICE,"tb.rulenode.device-name-pattern"],[C.ASSET,"tb.rulenode.asset-name-pattern"],[C.ENTITY_VIEW,"tb.rulenode.entity-view-name-pattern"],[C.CUSTOMER,"tb.rulenode.customer-title-pattern"],[C.USER,"tb.rulenode.user-name-pattern"],[C.DASHBOARD,"tb.rulenode.dashboard-name-pattern"],[C.EDGE,"tb.rulenode.edge-name-pattern"]]),this.allowedEntityTypes=[C.DEVICE,C.ASSET,C.ENTITY_VIEW,C.TENANT,C.CUSTOMER,C.USER,C.DASHBOARD,C.EDGE]}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[O.required]],entityType:[e?e.entityType:null,[O.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[O.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]]})}validatorTriggers(){return["entityType","createEntityIfNotExists"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;if(t?this.createRelationConfigForm.get("entityNamePattern").setValidators([O.required,O.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==C.DEVICE&&t!==C.ASSET)this.createRelationConfigForm.get("entityTypePattern").setValidators([]);else{const e=[O.pattern(/.*\S.*/)];this.createRelationConfigForm.get("createEntityIfNotExists").value&&e.push(O.required),this.createRelationConfigForm.get("entityTypePattern").setValidators(e)}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",Ft),Ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ft,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ft,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="createRelationConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n </div>\n </div>\n\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.target-entity</div>\n <div fxLayout="row" fxLayoutGap="16px">\n <tb-entity-type-select\n fxFlex\n showLabel\n required\n [allowedEntityTypes]="allowedEntityTypes"\n formControlName="entityType">\n </tb-entity-type-select>\n\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value &&\n createRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n fxFlex class="mat-block">\n <mat-label>{{ entityTypeNamePatternTranslation.get(createRelationConfigForm.get(\'entityType\').value) | translate }}</mat-label>\n <input required matInput formControlName="entityNamePattern">\n </mat-form-field>\n\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.profile-name</mat-label>\n <input matInput formControlName="entityTypePattern">\n </mat-form-field>\n </div>\n\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"></tb-example-hint>\n\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.create-entity-if-not-exists-hint\' | translate }}"\n *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n style="margin-bottom: 18px"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="createEntityIfNotExists">\n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n <section class="tb-form-panel stroked no-padding">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header style="padding: 16px">\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-panel no-border no-padding-top">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.remove-current-relations-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="removeCurrentRelations">\n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.change-originator-to-related-entity-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="changeOriginatorToRelatedEntity">\n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ne.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"component",type:oe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:oe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:oe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ft,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'<section [formGroup]="createRelationConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n </div>\n </div>\n\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.target-entity</div>\n <div fxLayout="row" fxLayoutGap="16px">\n <tb-entity-type-select\n fxFlex\n showLabel\n required\n [allowedEntityTypes]="allowedEntityTypes"\n formControlName="entityType">\n </tb-entity-type-select>\n\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value &&\n createRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n fxFlex class="mat-block">\n <mat-label>{{ entityTypeNamePatternTranslation.get(createRelationConfigForm.get(\'entityType\').value) | translate }}</mat-label>\n <input required matInput formControlName="entityNamePattern">\n </mat-form-field>\n\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.profile-name</mat-label>\n <input matInput formControlName="entityTypePattern">\n </mat-form-field>\n </div>\n\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"></tb-example-hint>\n\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.create-entity-if-not-exists-hint\' | translate }}"\n *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n style="margin-bottom: 18px"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="createEntityIfNotExists">\n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n <section class="tb-form-panel stroked no-padding">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header style="padding: 16px">\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-panel no-border no-padding-top">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.remove-current-relations-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="removeCurrentRelations">\n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.change-originator-to-related-entity-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="changeOriginatorToRelatedEntity">\n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class kt extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(v),this.directionTypeTranslations=new Map([[v.FROM,"tb.rulenode.del-relation-direction-from"],[v.TO,"tb.rulenode.del-relation-direction-to"]]),this.entityTypeNamePatternTranslation=new Map([[C.DEVICE,"tb.rulenode.device-name-pattern"],[C.ASSET,"tb.rulenode.asset-name-pattern"],[C.ENTITY_VIEW,"tb.rulenode.entity-view-name-pattern"],[C.CUSTOMER,"tb.rulenode.customer-title-pattern"],[C.USER,"tb.rulenode.user-name-pattern"],[C.DASHBOARD,"tb.rulenode.dashboard-name-pattern"],[C.EDGE,"tb.rulenode.edge-name-pattern"]]),this.entityType=C,this.allowedEntityTypes=[C.DEVICE,C.ASSET,C.ENTITY_VIEW,C.TENANT,C.CUSTOMER,C.USER,C.DASHBOARD,C.EDGE]}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[O.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[O.required]]})}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([O.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n&&n!==C.TENANT?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([O.required,O.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",kt),kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kt,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:kt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deleteRelationConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.delete-relation-with-specific-entity-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="deleteForSingleEntity">\n {{ \'tb.rulenode.delete-relation-with-specific-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n <div *ngIf="deleteRelationConfigForm.get(\'deleteForSingleEntity\').value">\n <div fxLayout="row" fxLayoutGap="10px">\n <tb-entity-type-select\n fxFlex\n showLabel\n required\n [allowedEntityTypes]="allowedEntityTypes"\n formControlName="entityType">\n </tb-entity-type-select>\n <mat-form-field *ngIf="deleteRelationConfigForm.get(\'entityType\').value && deleteRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n fxFlex class="mat-block">\n <mat-label>{{ entityTypeNamePatternTranslation.get(deleteRelationConfigForm.get(\'entityType\').value) | translate }}</mat-label>\n <input required matInput formControlName="entityNamePattern">\n </mat-form-field>\n </div>\n <tb-example-hint *ngIf="deleteRelationConfigForm.get(\'entityType\').value && deleteRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n [hintText]="\'tb.rulenode.kv-map-single-pattern-hint\'"></tb-example-hint>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ne.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'<section [formGroup]="deleteRelationConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.delete-relation-with-specific-entity-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="deleteForSingleEntity">\n {{ \'tb.rulenode.delete-relation-with-specific-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n <div *ngIf="deleteRelationConfigForm.get(\'deleteForSingleEntity\').value">\n <div fxLayout="row" fxLayoutGap="10px">\n <tb-entity-type-select\n fxFlex\n showLabel\n required\n [allowedEntityTypes]="allowedEntityTypes"\n formControlName="entityType">\n </tb-entity-type-select>\n <mat-form-field *ngIf="deleteRelationConfigForm.get(\'entityType\').value && deleteRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n fxFlex class="mat-block">\n <mat-label>{{ entityTypeNamePatternTranslation.get(deleteRelationConfigForm.get(\'entityType\').value) | translate }}</mat-label>\n <input required matInput formControlName="entityNamePattern">\n </mat-form-field>\n </div>\n <tb-example-hint *ngIf="deleteRelationConfigForm.get(\'entityType\').value && deleteRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n [hintText]="\'tb.rulenode.kv-map-single-pattern-hint\'"></tb-example-hint>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Tt extends g{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],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart]})}validatorTriggers(){return["persistAlarmRulesState"]}updateValidators(e){this.deviceProfile.get("persistAlarmRulesState").value?this.deviceProfile.get("fetchAlarmRulesStateOnStart").enable({emitEvent:!1}):(this.deviceProfile.get("fetchAlarmRulesStateOnStart").setValue(!1,{emitEvent:!1}),this.deviceProfile.get("fetchAlarmRulesStateOnStart").disable({emitEvent:!1})),this.deviceProfile.get("fetchAlarmRulesStateOnStart").updateValueAndValidity({emitEvent:e})}}e("DeviceProfileConfigComponent",Tt),Tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tt,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Tt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deviceProfile" class="tb-form-panel stroked">\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.device-profile-node-hint</div>\n <div tb-hint-tooltip-icon="{{\'tb.rulenode.persist-alarm-rules-hint\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="persistAlarmRulesState">\n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{\'tb.rulenode.fetch-alarm-rules-hint\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchAlarmRulesStateOnStart">\n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',dependencies:[{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tt,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'<section [formGroup]="deviceProfile" class="tb-form-panel stroked">\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.device-profile-node-hint</div>\n <div tb-hint-tooltip-icon="{{\'tb.rulenode.persist-alarm-rules-hint\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="persistAlarmRulesState">\n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{\'tb.rulenode.fetch-alarm-rules-hint\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchAlarmRulesStateOnStart">\n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Lt extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ce(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-generator-function"}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[O.required,O.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[O.required,O.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:b.JS,[O.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===b.JS?[O.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===b.TBEL?[O.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.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===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}var It;e("GeneratorConfigComponent",Lt),Lt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Lt,deps:[{token:P.Store},{token:R.UntypedFormBuilder},{token:ge.NodeScriptTestService},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Lt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Lt,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:'<section [formGroup]="generatorConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-count</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="msgCount">\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'required\')">\n {{ \'tb.rulenode.message-count-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'min\')">\n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <div fxLayout="column">\n <label class="tb-small">{{ \'tb.rulenode.originator\' | translate }}</label>\n <tb-entity-select\n required="false"\n formControlName="originator">\n </tb-entity-select>\n </div>\n\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="generatorConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n helpId="rulenode/generator_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="generatorConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/generator_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:qe.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:ve.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ce.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Lt,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'<section [formGroup]="generatorConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-count</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="msgCount">\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'required\')">\n {{ \'tb.rulenode.message-count-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'min\')">\n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <div fxLayout="column">\n <label class="tb-small">{{ \'tb.rulenode.originator\' | translate }}</label>\n <tb-entity-select\n required="false"\n formControlName="originator">\n </tb-entity-select>\n </div>\n\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="generatorConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n helpId="rulenode/generator_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="generatorConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/generator_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder},{type:ge.NodeScriptTestService},{type:Z.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,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 Nt=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"]]),St=new Map([[It.CUSTOMER,"tb.rulenode.originator-customer-desc"],[It.TENANT,"tb.rulenode.originator-tenant-desc"],[It.RELATED,"tb.rulenode.originator-related-entity-desc"],[It.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator-desc"],[It.ENTITY,"tb.rulenode.originator-entity-by-name-pattern-desc"]]),qt=[F.createdTime,F.name,{value:"type",name:"tb.rulenode.profile-name",keyName:"originatorProfileName"},F.firstName,F.lastName,F.email,F.title,F.country,F.state,F.city,F.address,F.address2,F.zip,F.phone,F.label,{value:"id",name:"tb.rulenode.id",keyName:"id"},{value:"additionalInfo",name:"tb.rulenode.additional-info",keyName:"additionalInfo"}],At=new Map([["type","profileName"],["createdTime","createdTime"],["name","name"],["firstName","firstName"],["lastName","lastName"],["email","email"],["title","title"],["country","country"],["state","state"],["city","city"],["address","address"],["address2","address2"],["zip","zip"],["phone","phone"],["label","label"],["id","id"],["additionalInfo","additionalInfo"]]);var Mt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(Mt||(Mt={}));const Et=new Map([[Mt.CIRCLE,"tb.rulenode.perimeter-circle"],[Mt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var Gt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(Gt||(Gt={}));const wt=new Map([[Gt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[Gt.SECONDS,"tb.rulenode.time-unit-seconds"],[Gt.MINUTES,"tb.rulenode.time-unit-minutes"],[Gt.HOURS,"tb.rulenode.time-unit-hours"],[Gt.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 Vt=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 Pt;!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"}(Pt||(Pt={}));const Rt=new Map([[Pt.ID,"tb.rulenode.entity-details-id"],[Pt.TITLE,"tb.rulenode.entity-details-title"],[Pt.COUNTRY,"tb.rulenode.entity-details-country"],[Pt.STATE,"tb.rulenode.entity-details-state"],[Pt.CITY,"tb.rulenode.entity-details-city"],[Pt.ZIP,"tb.rulenode.entity-details-zip"],[Pt.ADDRESS,"tb.rulenode.entity-details-address"],[Pt.ADDRESS2,"tb.rulenode.entity-details-address2"],[Pt.PHONE,"tb.rulenode.entity-details-phone"],[Pt.EMAIL,"tb.rulenode.entity-details-email"],[Pt.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var Ot;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(Ot||(Ot={}));const _t=new Map([[Ot.FIRST,"tb.rulenode.first"],[Ot.LAST,"tb.rulenode.last"],[Ot.ALL,"tb.rulenode.all"]]),Bt=new Map([[Ot.FIRST,"tb.rulenode.first-mode-hint"],[Ot.LAST,"tb.rulenode.last-mode-hint"],[Ot.ALL,"tb.rulenode.all-mode-hint"]]);var Kt,zt;!function(e){e.ASC="ASC",e.DESC="DESC"}(Kt||(Kt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(zt||(zt={}));const Ht=new Map([[zt.ATTRIBUTES,"tb.rulenode.attributes"],[zt.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[zt.FIELDS,"tb.rulenode.fields"]]),Ut=new Map([[zt.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[zt.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[zt.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),jt=new Map([[Kt.ASC,"tb.rulenode.ascending"],[Kt.DESC,"tb.rulenode.descending"]]);var $t;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}($t||($t={}));const Jt=new Map([[$t.STANDARD,"tb.rulenode.sqs-queue-standard"],[$t.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Qt=["anonymous","basic","cert.PEM"],Yt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Wt=["sas","cert.PEM"],Zt=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Xt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Xt||(Xt={}));const en=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],tn=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 nn;!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"}(nn||(nn={}));const rn=new Map([[nn.CUSTOM,{value:nn.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[nn.ADD,{value:nn.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[nn.SUB,{value:nn.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[nn.MULT,{value:nn.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[nn.DIV,{value:nn.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[nn.SIN,{value:nn.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[nn.SINH,{value:nn.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[nn.COS,{value:nn.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[nn.COSH,{value:nn.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[nn.TAN,{value:nn.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[nn.TANH,{value:nn.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[nn.ACOS,{value:nn.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[nn.ASIN,{value:nn.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[nn.ATAN,{value:nn.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[nn.ATAN2,{value:nn.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}],[nn.EXP,{value:nn.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[nn.EXPM1,{value:nn.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[nn.SQRT,{value:nn.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[nn.CBRT,{value:nn.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[nn.GET_EXP,{value:nn.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[nn.HYPOT,{value:nn.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[nn.LOG,{value:nn.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[nn.LOG10,{value:nn.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[nn.LOG1P,{value:nn.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[nn.CEIL,{value:nn.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[nn.FLOOR,{value:nn.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[nn.FLOOR_DIV,{value:nn.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[nn.FLOOR_MOD,{value:nn.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[nn.ABS,{value:nn.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[nn.MIN,{value:nn.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[nn.MAX,{value:nn.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[nn.POW,{value:nn.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}],[nn.SIGNUM,{value:nn.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[nn.RAD,{value:nn.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[nn.DEG,{value:nn.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var on,an,ln;!function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT"}(on||(on={})),function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES"}(an||(an={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(ln||(ln={}));const sn=new Map([[ln.DATA,"tb.rulenode.message-to-metadata"],[ln.METADATA,"tb.rulenode.metadata-to-message"]]),mn=(new Map([[ln.DATA,"tb.rulenode.from-message"],[ln.METADATA,"tb.rulenode.from-metadata"]]),new Map([[ln.DATA,"tb.rulenode.message"],[ln.METADATA,"tb.rulenode.metadata"]])),pn=new Map([[ln.DATA,"tb.rulenode.message"],[ln.METADATA,"tb.rulenode.message-metadata"]]),dn=new Map([[on.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Fetch argument value from incoming message"}],[on.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Fetch argument value from incoming message metadata"}],[on.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Fetch attribute value from database"}],[on.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Fetch latest time-series value from database"}],[on.CONSTANT,{name:"tb.rulenode.constant-type",description:"Define constant value"}]]),un=new Map([[an.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Add result to the outgoing message"}],[an.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Add result to the outgoing message metadata"}],[an.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Store result as an entity attribute in the database"}],[an.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Store result as an entity time-series in the database"}]]),cn=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var gn,fn;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(gn||(gn={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(fn||(fn={}));const yn=new Map([[gn.SHARED_SCOPE,"tb.rulenode.shared-scope"],[gn.SERVER_SCOPE,"tb.rulenode.server-scope"],[gn.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);var bn;!function(e){e.ON_FIRST_MESSAGE="ON_FIRST_MESSAGE",e.ON_EACH_MESSAGE="ON_EACH_MESSAGE"}(bn||(bn={}));const xn=new Map([[bn.ON_EACH_MESSAGE,{value:!0,name:"tb.rulenode.presence-monitoring-strategy-on-each-message"}],[bn.ON_FIRST_MESSAGE,{value:!1,name:"tb.rulenode.presence-monitoring-strategy-on-first-message"}]]);class hn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Mt,this.perimeterTypes=Object.keys(Mt),this.perimeterTypeTranslationMap=Et,this.rangeUnits=Object.keys(Dt),this.rangeUnitTranslationMap=Vt,this.presenceMonitoringStrategies=xn,this.presenceMonitoringStrategyKeys=Array.from(this.presenceMonitoringStrategies.keys()),this.timeUnits=Object.keys(Gt),this.timeUnitsTranslationMap=wt,this.defaultPaddingEnable=!0}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({reportPresenceStatusOnEachMessage:[!e||e.reportPresenceStatusOnEachMessage,[O.required]],latitudeKeyName:[e?e.latitudeKeyName:null,[O.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[O.required]],perimeterType:[e?e.perimeterType:null,[O.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,[O.required,O.min(1),O.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[O.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[O.required,O.min(1),O.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[O.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([O.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==Mt.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([]),this.defaultPaddingEnable=!0):(this.geoActionConfigForm.get("centerLatitude").setValidators([O.required,O.min(-90),O.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([O.required,O.min(-180),O.max(180)]),this.geoActionConfigForm.get("range").setValidators([O.required,O.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([O.required]),this.defaultPaddingEnable=!1),t||n!==Mt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([O.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",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:hn,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:hn,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="geoActionConfigForm" class="tb-form-panel no-border no-padding">\n <section class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.coordinate-field-names</div>\n <section>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.latitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.longitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.coordinate-field-hint</div>\n </section>\n </section>\n <section class="tb-form-panel stroked" [class.no-padding-bottom]="!defaultPaddingEnable">\n <div class="tb-form-panel-title" translate>tb.rulenode.geofence-configuration</div>\n <section fxLayout="column">\n <mat-form-field fxFlex class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.perimeter-type\' | translate }}</mat-label>\n <mat-select formControlName="perimeterType">\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div tb-hint-tooltip-icon="{{ geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE\n ? (\'tb.rulenode.fetch-circle-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoActionConfigForm.get(\'perimeterKeyName\').valid\n ? geoActionConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'})\n : (\'tb.rulenode.fetch-poligon-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoActionConfigForm.get(\'perimeterKeyName\').valid\n ? geoActionConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'}) }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchPerimeterInfoFromMessageMetadata">\n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field *ngIf="geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value" class="mat-block">\n <mat-label>{{ \'tb.rulenode.perimeter-key-name\' | translate }}</mat-label>\n <input matInput formControlName="perimeterKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'perimeterKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n </mat-error>\n <mat-hint>{{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}</mat-hint>\n </mat-form-field>\n <div fxLayout="column"\n *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-latitude\' | translate }}</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-longitude\' | translate }}</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range\' | translate }}</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range-units\' | translate }}</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="geoActionConfigForm.get(\'rangeUnit\').hasError(\'required\')">\n {{ \'tb.rulenode.range-units-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <div fxLayout="column" *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.polygon-definition</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-icon matSuffix class="margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.polygon-definition-hint\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="geoActionConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </section>\n </section>\n <section class="tb-form-panel stroked no-padding-bottom">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.lt-md="16px" fxLayoutAlign="space-between">\n <div class="tb-form-panel-title">{{ \'tb.rulenode.presence-monitoring-strategy\' | translate }}</div>\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="reportPresenceStatusOnEachMessage" appearance="fill" >\n <tb-toggle-option *ngFor="let strategy of presenceMonitoringStrategyKeys" [value]="presenceMonitoringStrategies.get(strategy).value">\n {{ presenceMonitoringStrategies.get(strategy).name | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n <div class="tb-form-hint tb-primary-fill"> {{ geoActionConfigForm.get(\'reportPresenceStatusOnEachMessage\').value === false ?\n (\'tb.rulenode.presence-monitoring-strategy-on-first-message-hint\' | translate) :\n (\'tb.rulenode.presence-monitoring-strategy-on-each-message-hint\' | translate) }}\n </div>\n <section fxLayout="column">\n <div *ngIf="geoActionConfigForm.get(\'reportPresenceStatusOnEachMessage\').value === false">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minInsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration-time-unit</mat-label>\n <mat-select formControlName="minInsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minOutsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration-time-unit</mat-label>\n <mat-select formControlName="minOutsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n </section>\n </section>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Ae.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Me.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'<section [formGroup]="geoActionConfigForm" class="tb-form-panel no-border no-padding">\n <section class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.coordinate-field-names</div>\n <section>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.latitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.longitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.coordinate-field-hint</div>\n </section>\n </section>\n <section class="tb-form-panel stroked" [class.no-padding-bottom]="!defaultPaddingEnable">\n <div class="tb-form-panel-title" translate>tb.rulenode.geofence-configuration</div>\n <section fxLayout="column">\n <mat-form-field fxFlex class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.perimeter-type\' | translate }}</mat-label>\n <mat-select formControlName="perimeterType">\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div tb-hint-tooltip-icon="{{ geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE\n ? (\'tb.rulenode.fetch-circle-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoActionConfigForm.get(\'perimeterKeyName\').valid\n ? geoActionConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'})\n : (\'tb.rulenode.fetch-poligon-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoActionConfigForm.get(\'perimeterKeyName\').valid\n ? geoActionConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'}) }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchPerimeterInfoFromMessageMetadata">\n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field *ngIf="geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value" class="mat-block">\n <mat-label>{{ \'tb.rulenode.perimeter-key-name\' | translate }}</mat-label>\n <input matInput formControlName="perimeterKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'perimeterKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n </mat-error>\n <mat-hint>{{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}</mat-hint>\n </mat-form-field>\n <div fxLayout="column"\n *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-latitude\' | translate }}</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-longitude\' | translate }}</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range\' | translate }}</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range-units\' | translate }}</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="geoActionConfigForm.get(\'rangeUnit\').hasError(\'required\')">\n {{ \'tb.rulenode.range-units-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <div fxLayout="column" *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.polygon-definition</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-icon matSuffix class="margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.polygon-definition-hint\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="geoActionConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </section>\n </section>\n <section class="tb-form-panel stroked no-padding-bottom">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.lt-md="16px" fxLayoutAlign="space-between">\n <div class="tb-form-panel-title">{{ \'tb.rulenode.presence-monitoring-strategy\' | translate }}</div>\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="reportPresenceStatusOnEachMessage" appearance="fill" >\n <tb-toggle-option *ngFor="let strategy of presenceMonitoringStrategyKeys" [value]="presenceMonitoringStrategies.get(strategy).value">\n {{ presenceMonitoringStrategies.get(strategy).name | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n <div class="tb-form-hint tb-primary-fill"> {{ geoActionConfigForm.get(\'reportPresenceStatusOnEachMessage\').value === false ?\n (\'tb.rulenode.presence-monitoring-strategy-on-first-message-hint\' | translate) :\n (\'tb.rulenode.presence-monitoring-strategy-on-each-message-hint\' | translate) }}\n </div>\n <section fxLayout="column">\n <div *ngIf="geoActionConfigForm.get(\'reportPresenceStatusOnEachMessage\').value === false">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minInsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration-time-unit</mat-label>\n <mat-select formControlName="minInsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minOutsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration-time-unit</mat-label>\n <mat-select formControlName="minOutsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n </section>\n </section>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class vn extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ce(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,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:b.JS,[O.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===b.JS?[O.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===b.TBEL?[O.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),e}testScript(e){const t=this.logConfigForm.get("scriptLang").value,n=t===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vn,deps:[{token:P.Store},{token:R.UntypedFormBuilder},{token:ge.NodeScriptTestService},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:vn,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:'<section [formGroup]="logConfigForm" fxLayout="column">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="logConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/log_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="logConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/log_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ve.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ce.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vn,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'<section [formGroup]="logConfigForm" fxLayout="column">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="logConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/log_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="logConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/log_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder},{type:ge.NodeScriptTestService},{type:Z.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class Cn extends g{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,[O.required,O.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[O.required]]})}}e("MsgCountConfigComponent",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Cn,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Cn,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="msgCountConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.interval-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="interval">\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'required\')">\n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'min\')">\n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.output-timeseries-key-prefix</mat-label>\n <input required matInput formControlName="telemetryPrefix">\n <mat-error *ngIf="msgCountConfigForm.get(\'telemetryPrefix\').hasError(\'required\')">\n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Cn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'<section [formGroup]="msgCountConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.interval-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="interval">\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'required\')">\n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'min\')">\n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.output-timeseries-key-prefix</mat-label>\n <input required matInput formControlName="telemetryPrefix">\n <mat-error *ngIf="msgCountConfigForm.get(\'telemetryPrefix\').hasError(\'required\')">\n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Fn extends g{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,[O.required,O.min(1),O.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([O.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([O.required,O.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Fn,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Fn,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="msgDelayConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMetadataPeriodInSecondsPatterns">\n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.use-metadata-period-in-seconds-patterns-hint</div>\n <mat-form-field *ngIf="msgDelayConfigForm.get(\'useMetadataPeriodInSecondsPatterns\').value !== true; else periodInSecondsPattern"\n class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <ng-template #periodInSecondsPattern>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.period-in-seconds-pattern</mat-label>\n <input required matInput formControlName="periodInSecondsPattern">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSecondsPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n </ng-template>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.max-pending-messages</mat-label>\n <input required type="number" min="1" max="100000" step="1" matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'<section [formGroup]="msgDelayConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMetadataPeriodInSecondsPatterns">\n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.use-metadata-period-in-seconds-patterns-hint</div>\n <mat-form-field *ngIf="msgDelayConfigForm.get(\'useMetadataPeriodInSecondsPatterns\').value !== true; else periodInSecondsPattern"\n class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <ng-template #periodInSecondsPattern>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.period-in-seconds-pattern</mat-label>\n <input required matInput formControlName="periodInSecondsPattern">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSecondsPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n </ng-template>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.max-pending-messages</mat-label>\n <input required type="number" min="1" max="100000" step="1" matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class kn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(f),this.telemetryTypeTranslationsMap=y}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[O.required]]})}}e("PushToCloudConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kn,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:kn,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="pushToCloudConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="pushToCloudConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="pushToCloudConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ft,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'<section [formGroup]="pushToCloudConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="pushToCloudConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="pushToCloudConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Tn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(f),this.telemetryTypeTranslationsMap=y}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[O.required]]})}}e("PushToEdgeConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tn,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Tn,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="pushToEdgeConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="pushToEdgeConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="pushToEdgeConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ft,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'<section [formGroup]="pushToEdgeConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="pushToEdgeConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="pushToEdgeConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Ln extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({serviceIdMetaDataAttribute:[e?e.serviceIdMetaDataAttribute:null,[]],sessionIdMetaDataAttribute:[e?e.sessionIdMetaDataAttribute:null,[]],requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ln,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ln,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="rpcReplyConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.reply-routing-configuration</div>\n <tb-example-hint [hintText]="\'tb.rulenode.reply-routing-configuration-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.service-id-metadata-attribute</mat-label>\n <input matInput formControlName="serviceIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.session-id-metadata-attribute</mat-label>\n <input matInput formControlName="sessionIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'<section [formGroup]="rpcReplyConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.reply-routing-configuration</div>\n <tb-example-hint [hintText]="\'tb.rulenode.reply-routing-configuration-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.service-id-metadata-attribute</mat-label>\n <input matInput formControlName="serviceIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.session-id-metadata-attribute</mat-label>\n <input matInput formControlName="sessionIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class In extends g{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,[O.required,O.min(0)]]})}}e("RpcRequestConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:In,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:In,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="rpcRequestConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.timeout-sec</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="timeoutInSeconds" required>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'<section [formGroup]="rpcRequestConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.timeout-sec</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="timeoutInSeconds" required>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Nn extends k{get required(){return this.requiredValue}set required(e){this.requiredValue=Ee(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(_),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,[O.required]],value:[e[n],[O.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:["",[O.required]],value:["",[O.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",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Nn,deps:[{token:P.Store},{token:Z.TranslateService},{token:t.Injector},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Nn,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:B,useExisting:c((()=>Nn)),multi:!0},{provide:K,useExisting:c((()=>Nn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section fxLayout="column" class="tb-kv-map-config" [formGroup]="kvListFormGroup">\n <div class="header" fxFlex fxLayout="row" fxLayoutGap="8px">\n <span class="cell tb-required" fxFlex>{{ keyText | translate }}</span>\n <span class="cell tb-required" fxFlex>{{ valText | translate }}</span>\n <span [fxShow]="!disabled" style="width: 52px;" innerHTML="&nbsp"></span>\n </div>\n <div class="body">\n <div class="row" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"\n formArrayName="keyVals"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index">\n <mat-form-field fxFlex class="cell mat-block">\n <input [formControl]="keyValControl.get(\'key\')" matInput required\n placeholder="{{ keyText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'key\').hasError(\'required\')">\n {{ keyRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="cell mat-block">\n <input [formControl]="keyValControl.get(\'value\')" matInput required\n placeholder="{{ valText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'value\').hasError(\'required\')">\n {{ valRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <button mat-icon-button color="primary"\n [fxShow]="!disabled"\n type="button"\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n <div *ngIf="hintText" class="tb-hint" [innerHTML]="hintText | translate | safe: \'html\'"></div>\n </div>\n <tb-error [error]="ngControl.hasError(\'kvMapRequired\') || ngControl.hasError(\'uniqueKeyValuePair\') ?\n (ngControl.hasError(\'kvMapRequired\') ? translate.instant(requiredText) :\n translate.instant(\'tb.key-val.unique-key-value-pair-error\', {keyText: translate.instant(keyText),\n valText: translate.instant(valText)})) : \'\'"></tb-error>\n <div style="margin-top: 16px;">\n <button mat-button mat-raised-button color="primary"\n [fxShow]="!disabled"\n [disabled]="isLoading$ | async"\n (click)="addKeyVal()"\n type="button"\n matTooltip="{{ \'tb.key-val.add-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n </div>\n</section>\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 .header .tb-required:after{color:#757575;font-size:12px;font-weight:700}: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",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:De.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:Ve.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:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:U.AsyncPipe,name:"async"},{kind:"pipe",type:ue.SafePipe,name:"safe"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:B,useExisting:c((()=>Nn)),multi:!0},{provide:K,useExisting:c((()=>Nn)),multi:!0}],template:'<section fxLayout="column" class="tb-kv-map-config" [formGroup]="kvListFormGroup">\n <div class="header" fxFlex fxLayout="row" fxLayoutGap="8px">\n <span class="cell tb-required" fxFlex>{{ keyText | translate }}</span>\n <span class="cell tb-required" fxFlex>{{ valText | translate }}</span>\n <span [fxShow]="!disabled" style="width: 52px;" innerHTML="&nbsp"></span>\n </div>\n <div class="body">\n <div class="row" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"\n formArrayName="keyVals"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index">\n <mat-form-field fxFlex class="cell mat-block">\n <input [formControl]="keyValControl.get(\'key\')" matInput required\n placeholder="{{ keyText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'key\').hasError(\'required\')">\n {{ keyRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="cell mat-block">\n <input [formControl]="keyValControl.get(\'value\')" matInput required\n placeholder="{{ valText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'value\').hasError(\'required\')">\n {{ valRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <button mat-icon-button color="primary"\n [fxShow]="!disabled"\n type="button"\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n <div *ngIf="hintText" class="tb-hint" [innerHTML]="hintText | translate | safe: \'html\'"></div>\n </div>\n <tb-error [error]="ngControl.hasError(\'kvMapRequired\') || ngControl.hasError(\'uniqueKeyValuePair\') ?\n (ngControl.hasError(\'kvMapRequired\') ? translate.instant(requiredText) :\n translate.instant(\'tb.key-val.unique-key-value-pair-error\', {keyText: translate.instant(keyText),\n valText: translate.instant(valText)})) : \'\'"></tb-error>\n <div style="margin-top: 16px;">\n <button mat-button mat-raised-button color="primary"\n [fxShow]="!disabled"\n [disabled]="isLoading$ | async"\n (click)="addKeyVal()"\n type="button"\n matTooltip="{{ \'tb.key-val.add-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n </div>\n</section>\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 .header .tb-required:after{color:#757575;font-size:12px;font-weight:700}: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",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:Z.TranslateService},{type:t.Injector},{type:R.FormBuilder}]},propDecorators:{disabled:[{type:m}],uniqueKeyValuePairValidator:[{type:m}],requiredText:[{type:m}],keyText:[{type:m}],keyRequiredText:[{type:m}],valText:[{type:m}],valRequiredText:[{type:m}],hintText:[{type:m}],required:[{type:m}]}});class Sn extends g{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,[O.required,O.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[O.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Sn,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Sn,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="saveToCustomTableConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.custom-table-name</mat-label>\n <input required matInput formControlName="tableName">\n <mat-error *ngIf="saveToCustomTableConfigForm.get(\'tableName\').hasError(\'required\') ||\n saveToCustomTableConfigForm.get(\'tableName\').hasError(\'pattern\')">\n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.custom-table-hint</mat-hint>\n </mat-form-field>\n <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label>\n <tb-kv-map-config-old\n required\n formControlName="fieldsMapping"\n requiredText="tb.rulenode.fields-mapping-required"\n keyText="tb.rulenode.message-field"\n keyRequiredText="tb.rulenode.message-field-required"\n valText="tb.rulenode.table-col"\n valRequiredText="tb.rulenode.table-col-required">\n </tb-kv-map-config-old>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'<section [formGroup]="saveToCustomTableConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.custom-table-name</mat-label>\n <input required matInput formControlName="tableName">\n <mat-error *ngIf="saveToCustomTableConfigForm.get(\'tableName\').hasError(\'required\') ||\n saveToCustomTableConfigForm.get(\'tableName\').hasError(\'pattern\')">\n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.custom-table-hint</mat-hint>\n </mat-form-field>\n <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label>\n <tb-kv-map-config-old\n required\n formControlName="fieldsMapping"\n requiredText="tb.rulenode.fields-mapping-required"\n keyText="tb.rulenode.message-field"\n keyRequiredText="tb.rulenode.message-field-required"\n valText="tb.rulenode.table-col"\n valRequiredText="tb.rulenode.table-col-required">\n </tb-kv-map-config-old>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class qn extends g{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,[O.required,O.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:qn,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:qn,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="timeseriesConfigForm" class="tb-form-panel no-border no-padding">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.default-ttl</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="defaultTTL" required>\n <mat-icon class="help-icon margin-8 cursor-pointer"\n aria-hidden="false"\n aria-label="help-icon"\n matSuffix\n matTooltip="{{ \'tb.rulenode.default-ttl-hint\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'required\')">\n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'min\')">\n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <div class="tb-form-panel stroked">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.use-server-ts-hint\' | translate}}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="useServerTs">\n {{ \'tb.rulenode.use-server-ts\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.skip-latest-persistence-hint\' | translate}}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="skipLatestPersistence">\n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'<section [formGroup]="timeseriesConfigForm" class="tb-form-panel no-border no-padding">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.default-ttl</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="defaultTTL" required>\n <mat-icon class="help-icon margin-8 cursor-pointer"\n aria-hidden="false"\n aria-label="help-icon"\n matSuffix\n matTooltip="{{ \'tb.rulenode.default-ttl-hint\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'required\')">\n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'min\')">\n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <div class="tb-form-panel stroked">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.use-server-ts-hint\' | translate}}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="useServerTs">\n {{ \'tb.rulenode.use-server-ts\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.skip-latest-persistence-hint\' | translate}}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="skipLatestPersistence">\n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class An extends g{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,[]],createCustomerIfNotExists:[!!e&&e?.createCustomerIfNotExists,[]]})}validatorTriggers(){return["createCustomerIfNotExists"]}updateValidators(e){this.unassignCustomerConfigForm.get("createCustomerIfNotExists").value?this.unassignCustomerConfigForm.get("customerNamePattern").setValidators([O.required,O.pattern(/.*\S.*/)]):this.unassignCustomerConfigForm.get("customerNamePattern").setValidators([]),this.unassignCustomerConfigForm.get("customerNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:An,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:An,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="unassignCustomerConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n\n <div class="tb-form-panel stroked" [class.no-padding-bottom]="unassignCustomerConfigForm.get(\'createCustomerIfNotExists\').value">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.unassign-from-customer-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="createCustomerIfNotExists">\n {{ \'tb.rulenode.unassign-from-customer\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic" *ngIf="unassignCustomerConfigForm.get(\'createCustomerIfNotExists\').value">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\') ||\n unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.customer-name-pattern-hint</mat-hint>\n </mat-form-field>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'<section [formGroup]="unassignCustomerConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n\n <div class="tb-form-panel stroked" [class.no-padding-bottom]="unassignCustomerConfigForm.get(\'createCustomerIfNotExists\').value">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.unassign-from-customer-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="createCustomerIfNotExists">\n {{ \'tb.rulenode.unassign-from-customer\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic" *ngIf="unassignCustomerConfigForm.get(\'createCustomerIfNotExists\').value">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\') ||\n unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.customer-name-pattern-hint</mat-hint>\n </mat-form-field>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Mn extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendRestApiCallReplyConfigForm}onConfigurationSet(e){this.sendRestApiCallReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]],serviceIdMetaDataAttribute:[e?e.serviceIdMetaDataAttribute:null,[]]})}}e("SendRestApiCallReplyConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Mn,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Mn,selector:"tb-action-node-send-rest-api-call-reply-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="sendRestApiCallReplyConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.reply-routing-configuration</div>\n <tb-example-hint [hintText]="\'tb.rulenode.reply-routing-configuration-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.service-id-metadata-attribute</mat-label>\n <input matInput formControlName="serviceIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"tb-action-node-send-rest-api-call-reply-config",template:'<section [formGroup]="sendRestApiCallReplyConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.reply-routing-configuration</div>\n <tb-example-hint [hintText]="\'tb.rulenode.reply-routing-configuration-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.service-id-metadata-attribute</mat-label>\n <input matInput formControlName="serviceIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class En extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=f,this.attributeScopes=Object.keys(f),this.telemetryTypeTranslationsMap=y,this.separatorKeysCodes=[Fe,ke,Te]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[O.required]],keys:[e?e.keys:null,[O.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==f.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",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:En,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:En,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deleteAttributesConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="deleteAttributesConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="deleteAttributesConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label>{{ \'tb.rulenode.attributes-keys\' | translate }}</mat-label>\n <mat-chip-grid formControlName="keys" #attributeChipList>\n <mat-chip-row\n *ngFor="let key of deleteAttributesConfigForm.get(\'keys\').value;"\n (removed)="removeKey(key)">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text"\n [matChipInputFor]="attributeChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event)"\n [matChipInputAddOnBlur]="true">\n </mat-chip-grid>\n <mat-error *ngIf="deleteAttributesConfigForm.get(\'keys\').hasError(\'required\')">{{ \'tb.rulenode.attributes-keys-required\' | translate }}</mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.send-attributes-deleted-notification-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="sendAttributesDeletedNotification">\n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.notify-device-on-delete-hint\' | translate }}"\n *ngIf="deleteAttributesConfigForm.get(\'scope\').value === attributeScopeMap.SHARED_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="notifyDevice">\n {{ \'tb.rulenode.notify-device\' | translate }}\n </mat-slide-toggle>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"component",type:oe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:oe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:oe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"component",type:Ie.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:Ie.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:Ie.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:Ie.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:ft,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'<section [formGroup]="deleteAttributesConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="deleteAttributesConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="deleteAttributesConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label>{{ \'tb.rulenode.attributes-keys\' | translate }}</mat-label>\n <mat-chip-grid formControlName="keys" #attributeChipList>\n <mat-chip-row\n *ngFor="let key of deleteAttributesConfigForm.get(\'keys\').value;"\n (removed)="removeKey(key)">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text"\n [matChipInputFor]="attributeChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event)"\n [matChipInputAddOnBlur]="true">\n </mat-chip-grid>\n <mat-error *ngIf="deleteAttributesConfigForm.get(\'keys\').hasError(\'required\')">{{ \'tb.rulenode.attributes-keys-required\' | translate }}</mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.send-attributes-deleted-notification-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="sendAttributesDeletedNotification">\n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.notify-device-on-delete-hint\' | translate }}"\n *ngIf="deleteAttributesConfigForm.get(\'scope\').value === attributeScopeMap.SHARED_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="notifyDevice">\n {{ \'tb.rulenode.notify-device\' | translate }}\n </mat-slide-toggle>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:u,args:["attributeChipList"]}]}});class Gn extends k{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t){super(e),this.store=e,this.fb=t,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=rn,this.ArgumentType=on,this.attributeScopeMap=yn,this.argumentTypeMap=dn,this.arguments=Object.values(on),this.attributeScope=Object.values(gn),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){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()}get 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.argumentsFormArray.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.argumentsFormArray.removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormArray,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===nn.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([O.minLength(this.minArgs),O.maxLength(this.maxArgs)]);this.argumentsFormArray.length>this.maxArgs;)this.removeArgument(this.maxArgs-1);for(;this.argumentsFormArray.length<this.minArgs;)this.addArgument(e);this.argumentsFormGroup.get("arguments").updateValueAndValidity({emitEvent:!1})}}createArgumentControl(e,t){const n=this.fb.group({type:[e?.type,[O.required]],key:[e?.key,[O.required]],name:[cn[t],[O.required]],attributeScope:[e?.attributeScope??gn.SERVER_SCOPE,[O.required]],defaultValue:[e?.defaultValue?e?.defaultValue:null]});return this.updateArgumentControlValidators(n),this.valueChangeSubscription.push(n.get("type").valueChanges.subscribe((()=>{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===on.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==on.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormArray.controls.forEach(((e,t)=>{e.get("name").setValue(cn[t])}))}updateModel(){const e=this.argumentsFormArray.value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Gn,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Gn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:B,useExisting:c((()=>Gn)),multi:!0},{provide:K,useExisting:c((()=>Gn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section fxLayout="column">\n\n <div [ngClass]="{\'tb-readonly\': disabled}"\n style="max-height: 500px; overflow: auto;">\n <mat-list class="tb-drop-list arguments-list" cdkDropList cdkDropListOrientation="vertical"\n [formGroup]="argumentsFormGroup"\n (cdkDropListDropped)="onDrop($event)"\n [cdkDropListDisabled]="disabled">\n <mat-list-item *ngFor="let argumentControl of argumentsFormArray.controls; let $index = index"\n formArrayName="arguments"\n cdkDrag class="tb-argument tb-draggable"\n [cdkDragDisabled]="disabled"\n style="height: 100%">\n <div fxFlex fxLayout="row" fxLayoutAlign="start center">\n <button *ngIf="!disabled" mat-icon-button color="primary"\n cdkDragHandle\n class="tb-drag-handle handle"\n style="min-width: 40px; margin: 0"\n matTooltip="{{ \'action.drag\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>drag_handle</mat-icon>\n </button>\n <div fxFlex fxLAyout="row" fxLayoutAlign="start center" fxLayoutGap="16px">\n <span *ngIf="displayArgumentName"\n style="padding: 0 10px; min-width: 20px;">{{argumentControl.get(\'name\').value}}.</span>\n <div fxFlex fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.argument-source-field-input</mat-label>\n <mat-select [formControl]="argumentControl.get(\'type\')" required>\n <mat-select-trigger>\n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n </mat-select-trigger>\n <mat-option *ngFor="let argument of arguments" [value]="argument"\n style="border-bottom: 1px solid #eee;">\n {{ argumentTypeMap.get(argument).name | translate }}\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ argumentTypeMap.get(argument).description }}\n </small>\n </mat-option>\n </mat-select>\n <mat-error *ngIf="argumentControl.get(\'type\').hasError(\'required\')" translate>\n tb.rulenode.argument-source-field-input-required\n </mat-error>\n </mat-form-field>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block"\n *ngIf="argumentControl.get(\'type\').value && argumentControl.get(\'type\').value !== ArgumentType.CONSTANT">\n <mat-label translate>tb.rulenode.argument-key-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'key\')" matInput required/>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.math-templatization-tooltip\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="argumentControl.get(\'key\').hasError(\'required\')" translate>\n tb.rulenode.argument-key-field-input-required\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block"\n *ngIf="argumentControl.get(\'type\').value === ArgumentType.CONSTANT">\n <mat-label translate>tb.rulenode.constant-value-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'key\')"\n matInput\n required\n step="1" min="0"\n type="number"/>\n <mat-error *ngIf="argumentControl.get(\'key\').hasError(\'required\')" translate>\n tb.rulenode.constant-value-field-input-required\n </mat-error>\n </mat-form-field>\n <mat-form-field *ngIf="argumentControl.get(\'type\').value && argumentControl.get(\'type\').value !== ArgumentType.CONSTANT"\n fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.default-value-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'defaultValue\')" matInput step="1" type="number"/>\n </mat-form-field>\n </div>\n <mat-form-field *ngIf="argumentControl.get(\'type\').value === ArgumentType.ATTRIBUTE" class="mat-block">\n <mat-label translate>tb.rulenode.attribute-scope-field-input</mat-label>\n <mat-select required [formControl]="argumentControl.get(\'attributeScope\')">\n <mat-option *ngFor="let scope of attributeScope" [value]="scope">\n {{ attributeScopeMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="argumentControl.get(\'attributeScope\').hasError(\'required\')" translate>\n tb.rulenode.attribute-scope-field-input-required\n </mat-error>\n </mat-form-field>\n </div>\n <button *ngIf="!disabled" mat-icon-button color="primary" style="min-width: 40px;"\n (click)="removeArgument($index)"\n matTooltip="{{ \'action.remove\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </mat-list-item>\n </mat-list>\n </div>\n <div *ngIf="!argumentsFormArray.length">\n <span translate fxLayoutAlign="center center"\n class="tb-prompt">tb.rulenode.no-arguments-prompt</span>\n </div>\n <button mat-button mat-raised-button color="primary"\n [disabled]="argumentsFormArray.length >= maxArgs"\n (click)="addArgument()"\n type="button"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n</section>\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:U.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:te.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Pe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:Pe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:Re.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:Re.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:Re.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:Ve.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:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Gn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:B,useExisting:c((()=>Gn)),multi:!0},{provide:K,useExisting:c((()=>Gn)),multi:!0}],template:'<section fxLayout="column">\n\n <div [ngClass]="{\'tb-readonly\': disabled}"\n style="max-height: 500px; overflow: auto;">\n <mat-list class="tb-drop-list arguments-list" cdkDropList cdkDropListOrientation="vertical"\n [formGroup]="argumentsFormGroup"\n (cdkDropListDropped)="onDrop($event)"\n [cdkDropListDisabled]="disabled">\n <mat-list-item *ngFor="let argumentControl of argumentsFormArray.controls; let $index = index"\n formArrayName="arguments"\n cdkDrag class="tb-argument tb-draggable"\n [cdkDragDisabled]="disabled"\n style="height: 100%">\n <div fxFlex fxLayout="row" fxLayoutAlign="start center">\n <button *ngIf="!disabled" mat-icon-button color="primary"\n cdkDragHandle\n class="tb-drag-handle handle"\n style="min-width: 40px; margin: 0"\n matTooltip="{{ \'action.drag\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>drag_handle</mat-icon>\n </button>\n <div fxFlex fxLAyout="row" fxLayoutAlign="start center" fxLayoutGap="16px">\n <span *ngIf="displayArgumentName"\n style="padding: 0 10px; min-width: 20px;">{{argumentControl.get(\'name\').value}}.</span>\n <div fxFlex fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.argument-source-field-input</mat-label>\n <mat-select [formControl]="argumentControl.get(\'type\')" required>\n <mat-select-trigger>\n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n </mat-select-trigger>\n <mat-option *ngFor="let argument of arguments" [value]="argument"\n style="border-bottom: 1px solid #eee;">\n {{ argumentTypeMap.get(argument).name | translate }}\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ argumentTypeMap.get(argument).description }}\n </small>\n </mat-option>\n </mat-select>\n <mat-error *ngIf="argumentControl.get(\'type\').hasError(\'required\')" translate>\n tb.rulenode.argument-source-field-input-required\n </mat-error>\n </mat-form-field>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block"\n *ngIf="argumentControl.get(\'type\').value && argumentControl.get(\'type\').value !== ArgumentType.CONSTANT">\n <mat-label translate>tb.rulenode.argument-key-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'key\')" matInput required/>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.math-templatization-tooltip\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="argumentControl.get(\'key\').hasError(\'required\')" translate>\n tb.rulenode.argument-key-field-input-required\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block"\n *ngIf="argumentControl.get(\'type\').value === ArgumentType.CONSTANT">\n <mat-label translate>tb.rulenode.constant-value-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'key\')"\n matInput\n required\n step="1" min="0"\n type="number"/>\n <mat-error *ngIf="argumentControl.get(\'key\').hasError(\'required\')" translate>\n tb.rulenode.constant-value-field-input-required\n </mat-error>\n </mat-form-field>\n <mat-form-field *ngIf="argumentControl.get(\'type\').value && argumentControl.get(\'type\').value !== ArgumentType.CONSTANT"\n fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.default-value-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'defaultValue\')" matInput step="1" type="number"/>\n </mat-form-field>\n </div>\n <mat-form-field *ngIf="argumentControl.get(\'type\').value === ArgumentType.ATTRIBUTE" class="mat-block">\n <mat-label translate>tb.rulenode.attribute-scope-field-input</mat-label>\n <mat-select required [formControl]="argumentControl.get(\'attributeScope\')">\n <mat-option *ngFor="let scope of attributeScope" [value]="scope">\n {{ attributeScopeMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="argumentControl.get(\'attributeScope\').hasError(\'required\')" translate>\n tb.rulenode.attribute-scope-field-input-required\n </mat-error>\n </mat-form-field>\n </div>\n <button *ngIf="!disabled" mat-icon-button color="primary" style="min-width: 40px;"\n (click)="removeArgument($index)"\n matTooltip="{{ \'action.remove\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </mat-list-item>\n </mat-list>\n </div>\n <div *ngIf="!argumentsFormArray.length">\n <span translate fxLayoutAlign="center center"\n class="tb-prompt">tb.rulenode.no-arguments-prompt</span>\n </div>\n <button mat-button mat-raised-button color="primary"\n [disabled]="argumentsFormArray.length >= maxArgs"\n (click)="addArgument()"\n type="button"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n</section>\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:P.Store},{type:R.FormBuilder}]},propDecorators:{disabled:[{type:m}],function:[{type:m}]}});class wn extends k{get required(){return this.requiredValue}set required(e){this.requiredValue=Ee(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=[...rn.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(Oe((e=>{let t;t="string"==typeof e&&nn[e]?nn[e]:null,this.updateView(t)})),_e((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=rn.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",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:wn,deps:[{token:P.Store},{token:Z.TranslateService},{token:t.Injector},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:wn,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:B,useExisting:c((()=>wn)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'<mat-form-field [formGroup]="mathFunctionForm" class="mat-block">\n <mat-label translate>tb.rulenode.functions-field-input</mat-label>\n <input [required]="required"\n (focusin)="onFocus()"\n type="text"\n #operationInput matInput\n formControlName="operation"\n [matAutocomplete]="auto">\n <button *ngIf="mathFunctionForm.get(\'operation\').value"\n type="button"\n matSuffix mat-icon-button aria-label="Clear"\n (click)="clear()">\n <mat-icon class="material-icons">close</mat-icon>\n </button>\n <mat-autocomplete #auto="matAutocomplete" class="tb-autocomplete" [displayWith]="mathFunctionDisplayFn">\n <mat-option *ngFor="let option of filteredOptions | async" [value]="option.value">\n <span [innerHTML]="option.value + \' | \' + option.name | highlight:searchText"></span>\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ option.description }}\n </small>\n </mat-option>\n <mat-option *ngIf="!(filteredOptions | async)?.length" [value]="null">\n <span translate>tb.rulenode.no-option-found</span>\n </mat-option>\n </mat-autocomplete>\n</mat-form-field>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:je.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:je.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.AsyncPipe,name:"async"},{kind:"pipe",type:$e.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:B,useExisting:c((()=>wn)),multi:!0}],template:'<mat-form-field [formGroup]="mathFunctionForm" class="mat-block">\n <mat-label translate>tb.rulenode.functions-field-input</mat-label>\n <input [required]="required"\n (focusin)="onFocus()"\n type="text"\n #operationInput matInput\n formControlName="operation"\n [matAutocomplete]="auto">\n <button *ngIf="mathFunctionForm.get(\'operation\').value"\n type="button"\n matSuffix mat-icon-button aria-label="Clear"\n (click)="clear()">\n <mat-icon class="material-icons">close</mat-icon>\n </button>\n <mat-autocomplete #auto="matAutocomplete" class="tb-autocomplete" [displayWith]="mathFunctionDisplayFn">\n <mat-option *ngFor="let option of filteredOptions | async" [value]="option.value">\n <span [innerHTML]="option.value + \' | \' + option.name | highlight:searchText"></span>\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ option.description }}\n </small>\n </mat-option>\n <mat-option *ngIf="!(filteredOptions | async)?.length" [value]="null">\n <span translate>tb.rulenode.no-option-found</span>\n </mat-option>\n </mat-autocomplete>\n</mat-form-field>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:Z.TranslateService},{type:t.Injector},{type:R.UntypedFormBuilder}]},propDecorators:{required:[{type:m}],disabled:[{type:m}],operationInput:[{type:u,args:["operationInput",{static:!0}]}]}});class Dn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=nn,this.ArgumentTypeResult=an,this.argumentTypeResultMap=un,this.attributeScopeMap=yn,this.argumentsResult=Object.values(an),this.attributeScopeResult=Object.values(fn)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[O.required]],arguments:[e?e.arguments:null,[O.required]],customFunction:[e?e.customFunction:"",[O.required]],result:this.fb.group({type:[e?e.result.type:null,[O.required]],attributeScope:[e?e.result.attributeScope:null,[O.required]],key:[e?e.result.key:"",[O.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===nn.CUSTOM?(this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}),null===this.mathFunctionConfigForm.get("customFunction").value&&this.mathFunctionConfigForm.get("customFunction").patchValue("(x - 32) / 1.8",{emitEvent:!1})):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===an.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",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Dn,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Dn,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="mathFunctionConfigForm" fxLayout="column">\n <tb-math-function-autocomplete\n fxFlex="30" fxFlex.md fxFlex.xs\n required\n formControlName="operation">\n </tb-math-function-autocomplete>\n <fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title" translate>tb.rulenode.argument-tile</legend>\n <tb-arguments-map-config formControlName="arguments"\n [function]="mathFunctionConfigForm.get(\'operation\').value">\n </tb-arguments-map-config>\n </fieldset>\n <fieldset *ngIf="mathFunctionConfigForm.get(\'operation\').value === MathFunction.CUSTOM"\n class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title">{{\'tb.rulenode.custom-expression-field-input\' | translate }} *</legend>\n <mat-form-field fxFlex class="mat-block no-margin-top" subscriptSizing="dynamic">\n <input matInput formControlName="customFunction" required/>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'customFunction\').hasError(\'required\')" translate>\n tb.rulenode.custom-expression-field-input-required\n </mat-error>\n <mat-hint translate>tb.rulenode.custom-expression-field-input-hint</mat-hint>\n </mat-form-field>\n </fieldset>\n <fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title" translate>tb.rulenode.result-title</legend>\n <div formGroupName="result">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.type-field-input</mat-label>\n <mat-select formControlName="type" required>\n <mat-select-trigger>\n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n </mat-select-trigger>\n <mat-option *ngFor="let argument of argumentsResult" [value]="argument"\n style="border-bottom: 1px solid #eee;">\n {{ argumentTypeResultMap.get(argument).name | translate }}\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ argumentTypeResultMap.get(argument).description }}\n </small>\n </mat-option>\n </mat-select>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'result.type\').hasError(\'required\')" translate>\n tb.rulenode.type-field-input-required\n </mat-error>\n </mat-form-field>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex class="mat-block" *ngIf="mathFunctionConfigForm.get(\'result\').get(\'type\').value === ArgumentTypeResult.ATTRIBUTE">\n <mat-label translate>tb.rulenode.attribute-scope-field-input</mat-label>\n <mat-select required formControlName="attributeScope">\n <mat-option *ngFor="let scope of attributeScopeResult" [value]="scope">\n {{ attributeScopeMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.key-field-input</mat-label>\n <input matInput formControlName="key" required/>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.math-templatization-tooltip\' | translate }}">help</mat-icon>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'result.key\').hasError(\'required\')" translate>\n tb.rulenode.key-field-input-required\n </mat-error>\n </mat-form-field>\n </div>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex floatLabel="always" class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.number-floating-point-field-input</mat-label>\n <input formControlName="resultValuePrecision"\n matInput\n step="1" min="0"\n type="number"/>\n <mat-hint [innerHTML]="\'tb.rulenode.number-floating-point-field-input-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n </div>\n <div *ngIf="[ArgumentTypeResult.ATTRIBUTE, ArgumentTypeResult.TIME_SERIES].includes(mathFunctionConfigForm.get(\'result\').get(\'type\').value)"\n fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start" fxLayoutGap.gt-xs="16px" style="padding-top: 16px;">\n <mat-checkbox formControlName="addToBody">\n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="addToMetadata">\n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n </mat-checkbox>\n </div>\n </div>\n </fieldset>\n</section>\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:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:te.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:R.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Gn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:wn,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:ue.SafePipe,name:"safe"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'<section [formGroup]="mathFunctionConfigForm" fxLayout="column">\n <tb-math-function-autocomplete\n fxFlex="30" fxFlex.md fxFlex.xs\n required\n formControlName="operation">\n </tb-math-function-autocomplete>\n <fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title" translate>tb.rulenode.argument-tile</legend>\n <tb-arguments-map-config formControlName="arguments"\n [function]="mathFunctionConfigForm.get(\'operation\').value">\n </tb-arguments-map-config>\n </fieldset>\n <fieldset *ngIf="mathFunctionConfigForm.get(\'operation\').value === MathFunction.CUSTOM"\n class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title">{{\'tb.rulenode.custom-expression-field-input\' | translate }} *</legend>\n <mat-form-field fxFlex class="mat-block no-margin-top" subscriptSizing="dynamic">\n <input matInput formControlName="customFunction" required/>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'customFunction\').hasError(\'required\')" translate>\n tb.rulenode.custom-expression-field-input-required\n </mat-error>\n <mat-hint translate>tb.rulenode.custom-expression-field-input-hint</mat-hint>\n </mat-form-field>\n </fieldset>\n <fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title" translate>tb.rulenode.result-title</legend>\n <div formGroupName="result">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.type-field-input</mat-label>\n <mat-select formControlName="type" required>\n <mat-select-trigger>\n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n </mat-select-trigger>\n <mat-option *ngFor="let argument of argumentsResult" [value]="argument"\n style="border-bottom: 1px solid #eee;">\n {{ argumentTypeResultMap.get(argument).name | translate }}\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ argumentTypeResultMap.get(argument).description }}\n </small>\n </mat-option>\n </mat-select>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'result.type\').hasError(\'required\')" translate>\n tb.rulenode.type-field-input-required\n </mat-error>\n </mat-form-field>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex class="mat-block" *ngIf="mathFunctionConfigForm.get(\'result\').get(\'type\').value === ArgumentTypeResult.ATTRIBUTE">\n <mat-label translate>tb.rulenode.attribute-scope-field-input</mat-label>\n <mat-select required formControlName="attributeScope">\n <mat-option *ngFor="let scope of attributeScopeResult" [value]="scope">\n {{ attributeScopeMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.key-field-input</mat-label>\n <input matInput formControlName="key" required/>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.math-templatization-tooltip\' | translate }}">help</mat-icon>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'result.key\').hasError(\'required\')" translate>\n tb.rulenode.key-field-input-required\n </mat-error>\n </mat-form-field>\n </div>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex floatLabel="always" class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.number-floating-point-field-input</mat-label>\n <input formControlName="resultValuePrecision"\n matInput\n step="1" min="0"\n type="number"/>\n <mat-hint [innerHTML]="\'tb.rulenode.number-floating-point-field-input-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n </div>\n <div *ngIf="[ArgumentTypeResult.ATTRIBUTE, ArgumentTypeResult.TIME_SERIES].includes(mathFunctionConfigForm.get(\'result\').get(\'type\').value)"\n fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start" fxLayoutGap.gt-xs="16px" style="padding-top: 16px;">\n <mat-checkbox formControlName="addToBody">\n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="addToMetadata">\n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n </mat-checkbox>\n </div>\n </div>\n </fieldset>\n</section>\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:P.Store},{type:R.UntypedFormBuilder}]}});class Vn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageTypeNames=T,this.eventOptions=[L.CONNECT_EVENT,L.ACTIVITY_EVENT,L.DISCONNECT_EVENT,L.INACTIVITY_EVENT]}configForm(){return this.deviceState}prepareInputConfig(e){return{event:fe(e?.event)?e.event:L.ACTIVITY_EVENT}}onConfigurationSet(e){this.deviceState=this.fb.group({event:[e.event,[O.required]]})}}e("DeviceStateConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Vn,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Vn,selector:"tb-action-node-device-state-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deviceState">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label>{{ \'tb.rulenode.select-device-connectivity-event\' | translate }}</mat-label>\n <mat-select formControlName="event">\n <mat-option *ngFor="let eventOption of eventOptions" [value]="eventOption">\n {{ messageTypeNames.get(eventOption) }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-action-node-device-state-config",template:'<section [formGroup]="deviceState">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label>{{ \'tb.rulenode.select-device-connectivity-event\' | translate }}</mat-label>\n <mat-select formControlName="event">\n <mat-option *ngFor="let eventOption of eventOptions" [value]="eventOption">\n {{ messageTypeNames.get(eventOption) }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class Pn{constructor(e,t){this.injector=e,this.fb=t,this.propagateChange=()=>{},this.destroy$=new ae,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1,this.duplicateValuesValidator=e=>e.controls.key.value===e.controls.value.value&&e.controls.key.value&&e.controls.value.value?{uniqueKeyValuePair:!0}:null,this.oneMapRequiredValidator=e=>e.get("keyVals").value.length,this.propagateNestedErrors=e=>{if(this.kvListFormGroup&&this.kvListFormGroup.get("keyVals")&&"VALID"===this.kvListFormGroup.get("keyVals")?.status)return null;const t={};if(this.kvListFormGroup&&this.kvListFormGroup.setErrors(null),e instanceof z||e instanceof H){if(e.errors)for(const n of Object.keys(e.errors))t[n]=!0;for(const n of Object.keys(e.controls)){const r=this.propagateNestedErrors(e.controls[n]);if(r&&Object.keys(r).length)for(const e of Object.keys(r))t[e]=!0}return t}if(e.errors)for(const n of Object.keys(e.errors))t[n]=!0;return ye(t,{})?null:t}}ngOnInit(){this.ngControl=this.injector.get(_),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({keyVals:this.fb.array([])},{validators:[this.propagateNestedErrors,this.oneMapRequiredValidator]}),this.kvListFormGroup.valueChanges.pipe(ie(this.destroy$)).subscribe((()=>{this.updateModel()}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}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){const t=Object.keys(e).map((t=>({key:t,value:e[t]})));if(this.keyValsFormArray().length===t.length)this.keyValsFormArray().patchValue(t,{emitEvent:!1});else{const e=[];t.forEach((t=>{e.push(this.fb.group({key:[t.key,[O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[t.value,[O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]},{validators:this.uniqueKeyValuePairValidator?[this.duplicateValuesValidator]:[]}))})),this.kvListFormGroup.setControl("keyVals",this.fb.array(e,this.propagateNestedErrors),{emitEvent:!1})}}removeKeyVal(e){this.keyValsFormArray().removeAt(e)}addKeyVal(){this.keyValsFormArray().push(this.fb.group({key:["",[O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]},{validators:this.uniqueKeyValuePairValidator?[this.duplicateValuesValidator]:[]}))}validate(){const e=this.kvListFormGroup.get("keyVals").value;if(!e.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const t of e)if(t.key===t.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",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Pn,deps:[{token:t.Injector},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Pn,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:B,useExisting:c((()=>Pn)),multi:!0},{provide:K,useExisting:c((()=>Pn)),multi:!0}],ngImport:t,template:'<section [formGroup]="kvListFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title">{{ labelText }}</div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'kvMapRequired\')">\n {{ requiredText }}\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'required\')">\n tb.rulenode.map-fields-required\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'uniqueKeyValuePair\')">\n {{ \'tb.key-val.unique-key-value-pair-error\' | translate:\n {\n valText: valText,\n keyText: keyText\n } }}\n </div>\n </div>\n <div class="tb-form-panel no-border no-padding">\n <div class="tb-form-table">\n <div class="tb-form-table-header">\n <div class="tb-form-table-header-cell field-space">{{ keyText }}</div>\n <div class="tb-form-table-header-cell field-space">{{ valText }}</div>\n <div class="tb-form-table-header-cell actions-header"></div>\n </div>\n <div class="tb-form-table-body">\n <div class="tb-form-table-row"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index;">\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="keyText+\'*\'" [formControl]="keyValControl.get(\'key\')" matInput/>\n </mat-form-field>\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="valText+\'*\'" [formControl]="keyValControl.get(\'value\')" matInput/>\n </mat-form-field>\n <div class="tb-form-table-row-cell-buttons">\n <button [class.tb-hidden]="keyValsFormArray().controls.length === 1"\n type="button"\n mat-icon-button\n (click)="removeKeyVal($index)"\n [disabled]="disabled"\n matTooltip="{{ \'tb.key-val.remove-mapping-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div>\n <button type="button" mat-stroked-button color="primary" (click)="addKeyVal()">\n {{ \'tb.key-val.add-mapping-entry\' | translate }}\n </button>\n </div>\n <tb-example-hint [hintText]="hintText" [popupHelpLink]="popupHelpLink" *ngIf="popupHelpLink || hintText"></tb-example-hint>\n</section>\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),Qe([I()],Pn.prototype,"disabled",void 0),Qe([I()],Pn.prototype,"uniqueKeyValuePairValidator",void 0),Qe([I()],Pn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:B,useExisting:c((()=>Pn)),multi:!0},{provide:K,useExisting:c((()=>Pn)),multi:!0}],template:'<section [formGroup]="kvListFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title">{{ labelText }}</div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'kvMapRequired\')">\n {{ requiredText }}\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'required\')">\n tb.rulenode.map-fields-required\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'uniqueKeyValuePair\')">\n {{ \'tb.key-val.unique-key-value-pair-error\' | translate:\n {\n valText: valText,\n keyText: keyText\n } }}\n </div>\n </div>\n <div class="tb-form-panel no-border no-padding">\n <div class="tb-form-table">\n <div class="tb-form-table-header">\n <div class="tb-form-table-header-cell field-space">{{ keyText }}</div>\n <div class="tb-form-table-header-cell field-space">{{ valText }}</div>\n <div class="tb-form-table-header-cell actions-header"></div>\n </div>\n <div class="tb-form-table-body">\n <div class="tb-form-table-row"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index;">\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="keyText+\'*\'" [formControl]="keyValControl.get(\'key\')" matInput/>\n </mat-form-field>\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="valText+\'*\'" [formControl]="keyValControl.get(\'value\')" matInput/>\n </mat-form-field>\n <div class="tb-form-table-row-cell-buttons">\n <button [class.tb-hidden]="keyValsFormArray().controls.length === 1"\n type="button"\n mat-icon-button\n (click)="removeKeyVal($index)"\n [disabled]="disabled"\n matTooltip="{{ \'tb.key-val.remove-mapping-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div>\n <button type="button" mat-stroked-button color="primary" (click)="addKeyVal()">\n {{ \'tb.key-val.add-mapping-entry\' | translate }}\n </button>\n </div>\n <tb-example-hint [hintText]="hintText" [popupHelpLink]="popupHelpLink" *ngIf="popupHelpLink || hintText"></tb-example-hint>\n</section>\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:t.Injector},{type:R.FormBuilder}]},propDecorators:{disabled:[{type:m}],uniqueKeyValuePairValidator:[{type:m}],labelText:[{type:m}],requiredText:[{type:m}],keyText:[{type:m}],keyRequiredText:[{type:m}],valText:[{type:m}],valRequiredText:[{type:m}],hintText:[{type:m}],popupHelpLink:[{type:m}],required:[{type:m}]}});class Rn extends k{get required(){return this.requiredValue}set required(e){this.requiredValue=Ee(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(v),this.directionTypeTranslations=N,this.entityType=C,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[O.required]],maxLevel:[null,[O.min(1)]],relationType:[null],deviceTypes:[null,[O.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",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Rn,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Rn,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:B,useExisting:c((()=>Rn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section fxLayout="column" [formGroup]="deviceRelationsQueryFormGroup">\n <div fxLayoutGap="22px" fxLayout="row">\n <mat-form-field class="mat-block" subscriptSizing="dynamic" fxFlex="50" style="min-width: 100px;" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n <mat-error *ngIf="deviceRelationsQueryFormGroup.get(\'maxLevel\').hasError(\'min\')">\n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.last-level-device-relation-tooltip\' | translate }}"\n *ngIf="deviceRelationsQueryFormGroup.get(\'maxLevel\').value > 1"\n class="tb-form-row no-border no-padding last-level-slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-slide-toggle>\n </div>\n <tb-relation-type-autocomplete\n fxFlex\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <tb-entity-subtype-list\n required\n [label]="\'tb.rulenode.device-profiles\' | translate"\n [entityType]="entityType.DEVICE"\n [emptyInputPlaceholder]="\'tb.rulenode.add-device-profile\' | translate"\n [filledInputPlaceholder]="\'tb.rulenode.add-device-profile\' | translate"\n formControlName="deviceTypes">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.device-profile\' | translate } }}">help</mat-icon>\n </tb-entity-subtype-list>\n</section>\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ye.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","floatLabel","label","disabled","entityType","emptyInputPlaceholder","filledInputPlaceholder","appearance","subscriptSizing","additionalClasses"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:B,useExisting:c((()=>Rn)),multi:!0}],template:'<section fxLayout="column" [formGroup]="deviceRelationsQueryFormGroup">\n <div fxLayoutGap="22px" fxLayout="row">\n <mat-form-field class="mat-block" subscriptSizing="dynamic" fxFlex="50" style="min-width: 100px;" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n <mat-error *ngIf="deviceRelationsQueryFormGroup.get(\'maxLevel\').hasError(\'min\')">\n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.last-level-device-relation-tooltip\' | translate }}"\n *ngIf="deviceRelationsQueryFormGroup.get(\'maxLevel\').value > 1"\n class="tb-form-row no-border no-padding last-level-slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-slide-toggle>\n </div>\n <tb-relation-type-autocomplete\n fxFlex\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <tb-entity-subtype-list\n required\n [label]="\'tb.rulenode.device-profiles\' | translate"\n [entityType]="entityType.DEVICE"\n [emptyInputPlaceholder]="\'tb.rulenode.add-device-profile\' | translate"\n [filledInputPlaceholder]="\'tb.rulenode.add-device-profile\' | translate"\n formControlName="deviceTypes">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.device-profile\' | translate } }}">help</mat-icon>\n </tb-entity-subtype-list>\n</section>\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]},propDecorators:{disabled:[{type:m}],required:[{type:m}]}});class On extends k{get required(){return this.requiredValue}set required(e){this.requiredValue=Ee(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(v),this.directionTypeTranslations=N,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[O.required]],maxLevel:[null,[O.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",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:On,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:On,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:B,useExisting:c((()=>On)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section [formGroup]="relationsQueryFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.relations-query</div>\n <section>\n <div fxLayoutGap="16px" fxLayout="row">\n <mat-form-field fxFlex="50" class="mat-block" style="min-width: 100px;" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n <mat-error *ngIf="relationsQueryFormGroup.get(\'maxLevel\').hasError(\'min\')">\n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.last-level-relation-tooltip\' | translate }}"\n *ngIf="relationsQueryFormGroup.get(\'maxLevel\').value > 1"\n class="tb-form-row no-border no-padding last-level-slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-slide-toggle>\n </div>\n </section>\n <section [formGroup]="relationsQueryFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters">\n </tb-relation-filters>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:We.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:B,useExisting:c((()=>On)),multi:!0}],template:'<section [formGroup]="relationsQueryFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.relations-query</div>\n <section>\n <div fxLayoutGap="16px" fxLayout="row">\n <mat-form-field fxFlex="50" class="mat-block" style="min-width: 100px;" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n <mat-error *ngIf="relationsQueryFormGroup.get(\'maxLevel\').hasError(\'min\')">\n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.last-level-relation-tooltip\' | translate }}"\n *ngIf="relationsQueryFormGroup.get(\'maxLevel\').value > 1"\n class="tb-form-row no-border no-padding last-level-slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-slide-toggle>\n </div>\n </section>\n <section [formGroup]="relationsQueryFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters">\n </tb-relation-filters>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]},propDecorators:{disabled:[{type:m}],required:[{type:m}]}});class _n extends k{get required(){return this.requiredValue}set required(e){this.requiredValue=Ee(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.add-message-type",this.separatorKeysCodes=[Fe,ke,Te],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(L))this.messageTypesList.push({name:T.get(L[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Be(""),_e((e=>e||"")),Ke((e=>this.fetchMessageTypes(e))),ze())}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&&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 le(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return le(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t;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",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:_n,deps:[{token:P.Store},{token:Z.TranslateService},{token:S.TruncatePipe},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:_n,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:B,useExisting:c((()=>_n)),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:'<mat-form-field [formGroup]="messageTypeConfigForm" style="width: 100%;">\n <mat-label *ngIf="label">{{ label }}</mat-label>\n <mat-chip-grid #chipList [required]="required">\n <mat-chip-row\n *ngFor="let messageType of messageTypes"\n [removable]="true"\n (removed)="remove(messageType)">\n {{messageType.name}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text" placeholder="{{ placeholder | translate }}"\n #messageTypeInput\n (focusin)="onFocus()"\n formControlName="messageType"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="messageTypeAutocomplete"\n [matChipInputFor]="chipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="add($event)">\n </mat-chip-grid>\n <mat-autocomplete #messageTypeAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="selected($event)"\n [displayWith]="displayMessageTypeFn">\n <mat-option *ngFor="let messageType of filteredMessageTypes | async" [value]="messageType">\n <span [innerHTML]="messageType.name | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredMessageTypes | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty">\n <span translate>tb.rulenode.no-message-types-found</span>\n </div>\n <ng-template #searchNotEmpty>\n <span>\n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, &apos;...&apos;)}\n }}\n </span>\n </ng-template>\n <span>\n <a translate (click)="createMessageType($event, searchText)">tb.rulenode.create-new-message-type</a>\n </span>\n </div>\n </mat-option>\n </mat-autocomplete>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.message-type\' | translate } }}">help</mat-icon>\n <mat-error *ngIf="chipList.errorState">\n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n </mat-error>\n</mat-form-field>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:je.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:je.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:je.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:Ie.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:Ie.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:Ie.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:Ie.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:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.AsyncPipe,name:"async"},{kind:"pipe",type:$e.HighlightPipe,name:"highlight"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:B,useExisting:c((()=>_n)),multi:!0}],template:'<mat-form-field [formGroup]="messageTypeConfigForm" style="width: 100%;">\n <mat-label *ngIf="label">{{ label }}</mat-label>\n <mat-chip-grid #chipList [required]="required">\n <mat-chip-row\n *ngFor="let messageType of messageTypes"\n [removable]="true"\n (removed)="remove(messageType)">\n {{messageType.name}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text" placeholder="{{ placeholder | translate }}"\n #messageTypeInput\n (focusin)="onFocus()"\n formControlName="messageType"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="messageTypeAutocomplete"\n [matChipInputFor]="chipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="add($event)">\n </mat-chip-grid>\n <mat-autocomplete #messageTypeAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="selected($event)"\n [displayWith]="displayMessageTypeFn">\n <mat-option *ngFor="let messageType of filteredMessageTypes | async" [value]="messageType">\n <span [innerHTML]="messageType.name | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredMessageTypes | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty">\n <span translate>tb.rulenode.no-message-types-found</span>\n </div>\n <ng-template #searchNotEmpty>\n <span>\n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, &apos;...&apos;)}\n }}\n </span>\n </ng-template>\n <span>\n <a translate (click)="createMessageType($event, searchText)">tb.rulenode.create-new-message-type</a>\n </span>\n </div>\n </mat-option>\n </mat-autocomplete>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.message-type\' | translate } }}">help</mat-icon>\n <mat-error *ngIf="chipList.errorState">\n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n </mat-error>\n</mat-form-field>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:Z.TranslateService},{type:S.TruncatePipe},{type:R.FormBuilder}]},propDecorators:{required:[{type:m}],label:[{type:m}],placeholder:[{type:m}],disabled:[{type:m}],chipList:[{type:u,args:["chipList",{static:!1}]}],matAutocomplete:[{type:u,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:u,args:["messageTypeInput",{static:!1}]}]}});class Bn extends k{get required(){return this.requiredValue}set required(e){this.requiredValue=Ee(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=Qt,this.credentialsTypeTranslationsMap=Yt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[O.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){fe(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([O.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[O.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(O.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",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Bn,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Bn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:B,useExisting:c((()=>Bn)),multi:!0},{provide:K,useExisting:c((()=>Bn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'<section [formGroup]="credentialsConfigFormGroup" fxLayout="column">\n <mat-expansion-panel class="tb-credentials-config-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allCredentialsTypes" [value]="credentialsType"\n [disabled]="credentialsType === \'cert.PEM\' && disableCertPemCredentials">\n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="credentialsConfigFormGroup.get(\'type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="basic">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input required matInput formControlName="username">\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'username\').hasError(\'required\')">\n {{ \'tb.rulenode.username-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" [required]="passwordFieldRequired" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'password\').hasError(\'required\')">\n {{ \'tb.rulenode.password-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <div class="tb-hint">{{ \'tb.rulenode.credentials-pem-hint\' | translate }}</div>\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'caCertFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'certFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'certFileName\').setValue($event)"\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'privateKeyFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'privateKeyFileName\').setValue($event)"\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </ng-template>\n </section>\n </ng-template>\n </mat-expansion-panel>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:U.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:oe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:oe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:oe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:oe.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:oe.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ze.FileInputComponent,selector:"tb-file-input",inputs:["label","hint","accept","noFileText","inputId","allowedExtensions","dropLabel","maxSizeByte","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:B,useExisting:c((()=>Bn)),multi:!0},{provide:K,useExisting:c((()=>Bn)),multi:!0}],template:'<section [formGroup]="credentialsConfigFormGroup" fxLayout="column">\n <mat-expansion-panel class="tb-credentials-config-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allCredentialsTypes" [value]="credentialsType"\n [disabled]="credentialsType === \'cert.PEM\' && disableCertPemCredentials">\n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="credentialsConfigFormGroup.get(\'type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="basic">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input required matInput formControlName="username">\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'username\').hasError(\'required\')">\n {{ \'tb.rulenode.username-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" [required]="passwordFieldRequired" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'password\').hasError(\'required\')">\n {{ \'tb.rulenode.password-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <div class="tb-hint">{{ \'tb.rulenode.credentials-pem-hint\' | translate }}</div>\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'caCertFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'certFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'certFileName\').setValue($event)"\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'privateKeyFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'privateKeyFileName\').setValue($event)"\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </ng-template>\n </section>\n </ng-template>\n </mat-expansion-panel>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]},propDecorators:{required:[{type:m}],disableCertPemCredentials:[{type:m}],passwordFieldRequired:[{type:m}]}});class Kn{set required(e){this.requiredValue!==e&&(this.requiredValue=e,this.updateValidators())}get required(){return this.requiredValue}constructor(e){this.fb=e,this.subscriptSizing="fixed",this.messageTypes=[{name:"Post attributes",value:"POST_ATTRIBUTES_REQUEST"},{name:"Post telemetry",value:"POST_TELEMETRY_REQUEST"},{name:"Custom",value:""}],this.propagateChange=()=>{},this.destroy$=new ae,this.messageTypeFormGroup=this.fb.group({messageTypeAlias:[null,[O.required]],messageType:[{value:null,disabled:!0},[O.maxLength(255)]]}),this.messageTypeFormGroup.get("messageTypeAlias").valueChanges.pipe(ie(this.destroy$)).subscribe((e=>this.updateMessageTypeValue(e))),this.messageTypeFormGroup.valueChanges.pipe(ie(this.destroy$)).subscribe((()=>this.updateView()))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnTouched(e){}registerOnChange(e){this.propagateChange=e}writeValue(e){this.modelValue=e;let t=this.messageTypes.find((t=>t.value===e));t||(t=this.messageTypes.find((e=>""===e.value))),this.messageTypeFormGroup.get("messageTypeAlias").patchValue(t,{emitEvent:!1}),this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1})}validate(){return this.messageTypeFormGroup.valid?null:{messageTypeInvalid:!0}}setDisabledState(e){this.disabled=e,e?this.messageTypeFormGroup.disable({emitEvent:!1}):(this.messageTypeFormGroup.enable({emitEvent:!1}),"Custom"!==this.messageTypeFormGroup.get("messageTypeAlias").value?.name&&this.messageTypeFormGroup.get("messageType").disable({emitEvent:!1}))}updateView(){const e=this.messageTypeFormGroup.getRawValue().messageType;this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}updateValidators(){this.messageTypeFormGroup.get("messageType").setValidators(this.required?[O.required,O.maxLength(255)]:[O.maxLength(255)]),this.messageTypeFormGroup.get("messageType").updateValueAndValidity({emitEvent:!1})}updateMessageTypeValue(e){"Custom"!==e?.name?this.messageTypeFormGroup.get("messageType").disable({emitEvent:!1}):this.messageTypeFormGroup.get("messageType").enable({emitEvent:!1}),this.messageTypeFormGroup.get("messageType").patchValue(e.value??null)}}e("OutputMessageTypeAutocompleteComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Kn,deps:[{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Kn,selector:"tb-output-message-type-autocomplete",inputs:{subscriptSizing:"subscriptSizing",disabled:"disabled",required:"required"},providers:[{provide:B,useExisting:c((()=>Kn)),multi:!0},{provide:K,useExisting:c((()=>Kn)),multi:!0}],ngImport:t,template:'<section class="tb-form-row no-border no-padding tb-standard-fields column-xs" [formGroup]="messageTypeFormGroup">\n <mat-form-field class="flex" subscriptSizing="{{ subscriptSizing }}" hideRequiredMarker>\n <mat-label>{{\'tb.rulenode.output-message-type\' | translate}}</mat-label>\n <mat-select formControlName="messageTypeAlias">\n <mat-option *ngFor="let msgType of messageTypes" [value]="msgType">\n {{msgType.name}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex" subscriptSizing="{{ subscriptSizing }}" [hideRequiredMarker]="messageTypeFormGroup.get(\'messageType\').disabled">\n <mat-label>{{\'tb.rulenode.message-type-value\' | translate}}</mat-label>\n <input matInput type="text" formControlName="messageType">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n *ngIf="messageTypeFormGroup.get(\'messageType\').value"\n ngxClipboard\n [cbContent]="messageTypeFormGroup.get(\'messageType\').value"\n matTooltip="{{ \'tb.rulenode.copy-message-type\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n <mat-error *ngIf="messageTypeFormGroup.get(\'messageType\').hasError(\'required\')">\n {{ \'tb.rulenode.message-type-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="messageTypeFormGroup.get(\'messageType\').hasError(\'maxlength\')">\n {{ \'tb.rulenode.message-type-value-max-length\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ft,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),Qe([I()],Kn.prototype,"disabled",void 0),Qe([I()],Kn.prototype,"required",null),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:B,useExisting:c((()=>Kn)),multi:!0},{provide:K,useExisting:c((()=>Kn)),multi:!0}],template:'<section class="tb-form-row no-border no-padding tb-standard-fields column-xs" [formGroup]="messageTypeFormGroup">\n <mat-form-field class="flex" subscriptSizing="{{ subscriptSizing }}" hideRequiredMarker>\n <mat-label>{{\'tb.rulenode.output-message-type\' | translate}}</mat-label>\n <mat-select formControlName="messageTypeAlias">\n <mat-option *ngFor="let msgType of messageTypes" [value]="msgType">\n {{msgType.name}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex" subscriptSizing="{{ subscriptSizing }}" [hideRequiredMarker]="messageTypeFormGroup.get(\'messageType\').disabled">\n <mat-label>{{\'tb.rulenode.message-type-value\' | translate}}</mat-label>\n <input matInput type="text" formControlName="messageType">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n *ngIf="messageTypeFormGroup.get(\'messageType\').value"\n ngxClipboard\n [cbContent]="messageTypeFormGroup.get(\'messageType\').value"\n matTooltip="{{ \'tb.rulenode.copy-message-type\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n <mat-error *ngIf="messageTypeFormGroup.get(\'messageType\').hasError(\'required\')">\n {{ \'tb.rulenode.message-type-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="messageTypeFormGroup.get(\'messageType\').hasError(\'maxlength\')">\n {{ \'tb.rulenode.message-type-value-max-length\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n\n'}]}],ctorParameters:function(){return[{type:R.FormBuilder}]},propDecorators:{subscriptSizing:[{type:m}],disabled:[{type:m}],required:[{type:m}]}});class zn{constructor(e,t){this.fb=e,this.translate=t,this.translation=mn,this.propagateChange=()=>{},this.destroy$=new ae,this.selectOptions=[]}ngOnInit(){this.initOptions(),this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(He(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}initOptions(){for(const e of this.translation.keys())this.selectOptions.push({value:e,name:this.translate.instant(this.translation.get(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})}}e("MsgMetadataChipComponent",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zn,deps:[{token:R.FormBuilder},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:zn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText",translation:"translation"},providers:[{provide:B,useExisting:c((()=>zn)),multi:!0}],ngImport:t,template:'<div [formGroup]="chipControlGroup" class="tb-form-row space-between">\n <div class="fixed-title-width">{{ labelText }}</div>\n <mat-chip-listbox formControlName="chipControl">\n <mat-chip-option *ngFor="let option of selectOptions"\n selectable="{{ chipControlGroup.get(\'chipControl\').value !== option.value }}"\n color="primary"\n [value]="option.value">{{ option.name }}</mat-chip-option>\n </mat-chip-listbox>\n</div>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:Ie.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:Ie.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:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:B,useExisting:c((()=>zn)),multi:!0}],template:'<div [formGroup]="chipControlGroup" class="tb-form-row space-between">\n <div class="fixed-title-width">{{ labelText }}</div>\n <mat-chip-listbox formControlName="chipControl">\n <mat-chip-option *ngFor="let option of selectOptions"\n selectable="{{ chipControlGroup.get(\'chipControl\').value !== option.value }}"\n color="primary"\n [value]="option.value">{{ option.name }}</mat-chip-option>\n </mat-chip-listbox>\n</div>\n'}]}],ctorParameters:function(){return[{type:R.FormBuilder},{type:Z.TranslateService}]},propDecorators:{labelText:[{type:m}],translation:[{type:m}]}});class Hn extends k{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new ae,this.sourceFieldSubcritption=[],this.propagateChange=null,this.disabled=!1,this.required=!1,this.oneMapRequiredValidator=e=>e.get("keyVals").value.length,this.propagateNestedErrors=e=>{if(this.svListFormGroup&&this.svListFormGroup.get("keyVals")&&"VALID"===this.svListFormGroup.get("keyVals")?.status)return null;const t={};if(this.svListFormGroup&&this.svListFormGroup.setErrors(null),e instanceof z||e instanceof H){if(e.errors)for(const n of Object.keys(e.errors))t[n]=!0;for(const n of Object.keys(e.controls)){const r=this.propagateNestedErrors(e.controls[n]);if(r&&Object.keys(r).length)for(const e of Object.keys(r))t[e]=!0}return t}if(e.errors)for(const n of Object.keys(e.errors))t[n]=!0;return ye(t,{})?null:t}}ngOnInit(){this.ngControl=this.injector.get(_),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({keyVals:this.fb.array([])},{validators:[this.propagateNestedErrors,this.oneMapRequiredValidator]}),this.svListFormGroup.valueChanges.pipe(He(this.destroy$)).subscribe((()=>{this.updateModel()}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}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){const t=Object.keys(e).map((t=>({key:t,value:e[t]})));if(this.keyValsFormArray().length===t.length)this.keyValsFormArray().patchValue(t,{emitEvent:!1});else{const e=[];t.forEach((t=>{e.push(this.fb.group({key:[t.key,[O.required]],value:[t.value,[O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))})),this.svListFormGroup.setControl("keyVals",this.fb.array(e,this.propagateNestedErrors),{emitEvent:!1});for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e)}}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)fe(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.keyValsFormArray().removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){this.keyValsFormArray().push(this.fb.group({key:["",[O.required]],value:["",[O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(this.keyValsFormArray().at(this.keyValsFormArray().length-1))}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(He(this.destroy$)).subscribe((t=>{const n=At.get(t);e.get("value").patchValue(this.targetKeyPrefix+n[0].toUpperCase()+n.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",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Hn,deps:[{token:P.Store},{token:Z.TranslateService},{token:t.Injector},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Hn,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:B,useExisting:c((()=>Hn)),multi:!0},{provide:K,useExisting:c((()=>Hn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section [formGroup]="svListFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title">{{ labelText }}</div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="svListFormGroup.hasError(\'required\')">\n tb.rulenode.map-fields-required\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="svListFormGroup.hasError(\'svMapRequired\')">\n {{ requiredText }}\n </div>\n </div>\n <div class="tb-form-panel no-border no-padding">\n <div class="tb-form-table">\n <div class="tb-form-table-header">\n <div class="tb-form-table-header-cell field-space">{{ selectText }}</div>\n <div class="tb-form-table-header-cell field-space">{{ valText }}</div>\n <div class="tb-form-table-header-cell actions-header"></div>\n </div>\n <div class="tb-form-table-body">\n <div class="tb-form-table-row"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index;">\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <mat-select [placeholder]="selectText" [formControl]="keyValControl.get(\'key\')" required>\n <mat-option *ngFor="let option of filterSelectOptions(keyValControl)" [value]="option.value">\n {{option.name}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="valText" [formControl]="keyValControl.get(\'value\')" matInput/>\n </mat-form-field>\n <div class="tb-form-table-row-cell-buttons">\n <button [ngClass]="{\'tb-hidden\': keyValsFormArray().controls.length === 1}"\n type="button"\n mat-icon-button\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-mapping-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div>\n <button [disabled]="(isLoading$ | async) || keyValsFormArray().length >= selectOptions.length"\n type="button" mat-stroked-button color="primary" (click)="addKeyVal()">\n {{ \'tb.key-val.add-mapping-entry\' | translate }}\n </button>\n </div>\n <tb-example-hint [hintText]="hintText" [popupHelpLink]="popupHelpLink"></tb-example-hint>\n</section>\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:Ve.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:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:U.AsyncPipe,name:"async"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),Qe([I()],Hn.prototype,"disabled",void 0),Qe([I()],Hn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:B,useExisting:c((()=>Hn)),multi:!0},{provide:K,useExisting:c((()=>Hn)),multi:!0}],template:'<section [formGroup]="svListFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title">{{ labelText }}</div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="svListFormGroup.hasError(\'required\')">\n tb.rulenode.map-fields-required\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="svListFormGroup.hasError(\'svMapRequired\')">\n {{ requiredText }}\n </div>\n </div>\n <div class="tb-form-panel no-border no-padding">\n <div class="tb-form-table">\n <div class="tb-form-table-header">\n <div class="tb-form-table-header-cell field-space">{{ selectText }}</div>\n <div class="tb-form-table-header-cell field-space">{{ valText }}</div>\n <div class="tb-form-table-header-cell actions-header"></div>\n </div>\n <div class="tb-form-table-body">\n <div class="tb-form-table-row"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index;">\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <mat-select [placeholder]="selectText" [formControl]="keyValControl.get(\'key\')" required>\n <mat-option *ngFor="let option of filterSelectOptions(keyValControl)" [value]="option.value">\n {{option.name}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="valText" [formControl]="keyValControl.get(\'value\')" matInput/>\n </mat-form-field>\n <div class="tb-form-table-row-cell-buttons">\n <button [ngClass]="{\'tb-hidden\': keyValsFormArray().controls.length === 1}"\n type="button"\n mat-icon-button\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-mapping-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div>\n <button [disabled]="(isLoading$ | async) || keyValsFormArray().length >= selectOptions.length"\n type="button" mat-stroked-button color="primary" (click)="addKeyVal()">\n {{ \'tb.key-val.add-mapping-entry\' | translate }}\n </button>\n </div>\n <tb-example-hint [hintText]="hintText" [popupHelpLink]="popupHelpLink"></tb-example-hint>\n</section>\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:Z.TranslateService},{type:t.Injector},{type:R.FormBuilder}]},propDecorators:{selectOptions:[{type:m}],disabled:[{type:m}],labelText:[{type:m}],requiredText:[{type:m}],targetKeyPrefix:[{type:m}],selectText:[{type:m}],selectRequiredText:[{type:m}],valText:[{type:m}],valRequiredText:[{type:m}],hintText:[{type:m}],popupHelpLink:[{type:m}],required:[{type:m}]}});class Un extends k{get required(){return this.requiredValue}set required(e){this.requiredValue=Ee(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(v),this.directionTypeTranslations=N,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[O.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",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Un,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Un,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:B,useExisting:c((()=>Un)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section fxLayout="column" [formGroup]="relationsQueryFormGroup">\n <mat-checkbox formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-checkbox>\n <div fxLayoutGap="8px" fxLayout="row">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n </mat-form-field>\n </div>\n <div class="mat-caption" style="color: #6e6e6e;" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters"\n ></tb-relation-filters>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:We.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:B,useExisting:c((()=>Un)),multi:!0}],template:'<section fxLayout="column" [formGroup]="relationsQueryFormGroup">\n <mat-checkbox formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-checkbox>\n <div fxLayoutGap="8px" fxLayout="row">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n </mat-form-field>\n </div>\n <div class="mat-caption" style="color: #6e6e6e;" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters"\n ></tb-relation-filters>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]},propDecorators:{disabled:[{type:m}],required:[{type:m}]}});class jn{constructor(e,t){this.translate=e,this.fb=t,this.propagateChange=e=>{},this.destroy$=new ae,this.separatorKeysCodes=[Fe,ke,Te],this.onTouched=()=>{}}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[[],[]],sharedAttributeNames:[[],[]],serverAttributeNames:[[],[]],latestTsKeyNames:[[],[]],getLatestValueWithTs:[!1,[]]},{validators:this.atLeastOne(O.required,["clientAttributeNames","sharedAttributeNames","serverAttributeNames","latestTsKeyNames"])}),this.attributeControlGroup.valueChanges.pipe(He(this.destroy$)).subscribe((e=>{this.propagateChange(this.preparePropagateValue(e))}))}preparePropagateValue(e){const t={};for(const n in e)t[n]="getLatestValueWithTs"===n||fe(e[n])?e[n]:[];return t}validate(){return this.attributeControlGroup.valid?null:{atLeastOneRequired:!0}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}writeValue(e){this.attributeControlGroup.setValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){this.onTouched=e}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SelectAttributesComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:jn,deps:[{token:Z.TranslateService},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:jn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:B,useExisting:c((()=>jn)),multi:!0},{provide:K,useExisting:jn,multi:!0}],ngImport:t,template:'<div class="tb-form-panel no-padding no-border" [formGroup]="attributeControlGroup">\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\' | translate"\n [popupHelpLink]="popupHelpLink"></tb-example-hint>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.client-attributes\' | translate" formControlName="clientAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.shared-attributes\' | translate" formControlName="sharedAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.server-attributes\' | translate" formControlName="serverAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" editable class="mat-block"\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-telemetry-key\' | translate"\n [label]="\'tb.rulenode.latest-telemetry\' | translate" formControlName="latestTsKeyNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp-tooltip\' | translate:\n { latestTsKeyName: attributeControlGroup.get(\'latestTsKeyNames\').value[0]} }}"\n *ngIf="attributeControlGroup.get(\'latestTsKeyNames\').value?.length > 0"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="getLatestValueWithTs">\n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n </mat-slide-toggle>\n </div>\n</div>\n\n<ng-template #helpIcon>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n</ng-template>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.NgTemplateOutlet,selector:"[ngTemplateOutlet]",inputs:["ngTemplateOutletContext","ngTemplateOutlet","ngTemplateOutletInjector"]},{kind:"component",type:et.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:B,useExisting:c((()=>jn)),multi:!0},{provide:K,useExisting:jn,multi:!0}],template:'<div class="tb-form-panel no-padding no-border" [formGroup]="attributeControlGroup">\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\' | translate"\n [popupHelpLink]="popupHelpLink"></tb-example-hint>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.client-attributes\' | translate" formControlName="clientAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.shared-attributes\' | translate" formControlName="sharedAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.server-attributes\' | translate" formControlName="serverAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" editable class="mat-block"\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-telemetry-key\' | translate"\n [label]="\'tb.rulenode.latest-telemetry\' | translate" formControlName="latestTsKeyNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp-tooltip\' | translate:\n { latestTsKeyName: attributeControlGroup.get(\'latestTsKeyNames\').value[0]} }}"\n *ngIf="attributeControlGroup.get(\'latestTsKeyNames\').value?.length > 0"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="getLatestValueWithTs">\n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n </mat-slide-toggle>\n </div>\n</div>\n\n<ng-template #helpIcon>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n</ng-template>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:Z.TranslateService},{type:R.FormBuilder}]},propDecorators:{popupHelpLink:[{type:m}]}});class $n extends k{constructor(e,t){super(e),this.store=e,this.fb=t,this.propagateChange=null,this.destroy$=new ae,this.alarmStatus=q,this.alarmStatusTranslations=A}ngOnInit(){this.alarmStatusGroup=this.fb.group({alarmStatus:[null,[]]}),this.alarmStatusGroup.get("alarmStatus").valueChanges.pipe(He(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}setDisabledState(e){e?this.alarmStatusGroup.disable({emitEvent:!1}):this.alarmStatusGroup.enable({emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}writeValue(e){this.alarmStatusGroup.get("alarmStatus").patchValue(e,{emitEvent:!1})}}e("AlarmStatusSelectComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$n,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:$n,selector:"tb-alarm-status-select",providers:[{provide:B,useExisting:c((()=>$n)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section [formGroup]="alarmStatusGroup" fxLayout="column" fxLayoutAlign="center center">\n <mat-chip-listbox multiple formControlName="alarmStatus" class="chip-listbox" fxLayout="column">\n <div class="toggle-column">\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.ACTIVE_UNACK">\n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n </mat-chip-option>\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.ACTIVE_ACK">\n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n </mat-chip-option>\n </div>\n <div class="toggle-column">\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.CLEARED_UNACK">\n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n </mat-chip-option>\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.CLEARED_ACK">\n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_ACK) | translate }}\n </mat-chip-option>\n </div>\n </mat-chip-listbox>\n</section>\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"],dependencies:[{kind:"component",type:Ie.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:Ie.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:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-alarm-status-select",providers:[{provide:B,useExisting:c((()=>$n)),multi:!0}],template:'<section [formGroup]="alarmStatusGroup" fxLayout="column" fxLayoutAlign="center center">\n <mat-chip-listbox multiple formControlName="alarmStatus" class="chip-listbox" fxLayout="column">\n <div class="toggle-column">\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.ACTIVE_UNACK">\n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n </mat-chip-option>\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.ACTIVE_ACK">\n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n </mat-chip-option>\n </div>\n <div class="toggle-column">\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.CLEARED_UNACK">\n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n </mat-chip-option>\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.CLEARED_ACK">\n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_ACK) | translate }}\n </mat-chip-option>\n </div>\n </mat-chip-listbox>\n</section>\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"]}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class Jn{}e("RulenodeCoreConfigCommonModule",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Jn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Jn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:Jn,declarations:[Pn,Rn,On,_n,Bn,Gn,wn,Kn,Nn,zn,Hn,Un,jn,$n,xt],imports:[$,M,Je],exports:[Pn,Rn,On,_n,Bn,Gn,wn,Kn,Nn,zn,Hn,Un,jn,$n,xt]}),Jn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Jn,imports:[$,M,Je]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Jn,decorators:[{type:d,args:[{declarations:[Pn,Rn,On,_n,Bn,Gn,wn,Kn,Nn,zn,Hn,Un,jn,$n,xt],imports:[$,M,Je],exports:[Pn,Rn,On,_n,Bn,Gn,wn,Kn,Nn,zn,Hn,Un,jn,$n,xt]}]}]});class Qn{}e("RuleNodeCoreConfigActionModule",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Qn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Qn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:Qn,declarations:[En,ht,qn,In,vn,ut,vt,Ct,Ft,Fn,kt,Lt,hn,Cn,Ln,Sn,An,Mn,Tt,Tn,kn,Dn,Vn],imports:[$,M,Je,Jn],exports:[En,ht,qn,In,vn,ut,vt,Ct,Ft,Fn,kt,Lt,hn,Cn,Ln,Sn,An,Mn,Tt,Tn,kn,Dn,Vn]}),Qn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Qn,imports:[$,M,Je,Jn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Qn,decorators:[{type:d,args:[{declarations:[En,ht,qn,In,vn,ut,vt,Ct,Ft,Fn,kt,Lt,hn,Cn,Ln,Sn,An,Mn,Tt,Tn,kn,Dn,Vn],imports:[$,M,Je,Jn],exports:[En,ht,qn,In,vn,ut,vt,Ct,Ft,Fn,kt,Lt,hn,Cn,Ln,Sn,An,Mn,Tt,Tn,kn,Dn,Vn]}]}]});class Yn extends g{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[Fe,ke,Te]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[O.min(0),O.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]],excludeZeroDeltas:[e.excludeZeroDeltas,[]]})}prepareInputConfig(e){return{inputValueKey:fe(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:fe(e?.outputValueKey)?e.outputValueKey:null,useCache:!fe(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!fe(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:fe(e?.periodValueKey)?e.periodValueKey:null,round:fe(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!fe(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative,excludeZeroDeltas:!!fe(e?.excludeZeroDeltas)&&e.excludeZeroDeltas}}prepareOutputConfig(e){return be(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([O.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Yn,deps:[{token:P.Store},{token:Z.TranslateService},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Yn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"<section [formGroup]=\"calculateDeltaConfigForm\">\n <div fxLayout.gt-sm=\"row\" fxLayoutGap.gt-sm=\"22px\">\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.input-value-key' | translate }}</mat-label>\n <input matInput formControlName=\"inputValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('inputValueKey').hasError('required') ||\n calculateDeltaConfigForm.get('inputValueKey').hasError('pattern')\">\n {{ 'tb.rulenode.input-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.output-value-key' | translate }}</mat-label>\n <input matInput formControlName=\"outputValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('outputValueKey').hasError('required') ||\n calculateDeltaConfigForm.get('outputValueKey').hasError('pattern')\">\n {{ 'tb.rulenode.output-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}</mat-label>\n <input type=\"number\" min=\"0\" max=\"15\" step=\"1\" matInput formControlName=\"round\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('round').hasError('min')\">\n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n </mat-error>\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('round').hasError('max')\">\n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n </mat-error>\n </mat-form-field>\n <div class=\"tb-form-panel no-padding no-border\">\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.failure-if-delta-negative-tooltip' | translate }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"tellFailureIfDeltaIsNegative\">\n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.use-caching-tooltip' | translate :\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"useCache\">\n {{ 'tb.rulenode.use-caching' | translate }}\n </mat-slide-toggle>\n </div>\n <div class=\"tb-form-panel stroked\" [class.no-padding-bottom]=\"calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value\">\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.add-time-difference-between-readings-tooltip' | translate:\n { periodValueKey: (calculateDeltaConfigForm.get('periodValueKey').valid &&\n calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value) ? calculateDeltaConfigForm.get('periodValueKey').value :\n 'periodInMs' } }}\"\n class=\"tb-form-row no-border no-padding\">\n <mat-slide-toggle class=\"mat-slide\" formControlName=\"addPeriodBetweenMsgs\">\n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n </mat-slide-toggle>\n </div>\n <mat-form-field class=\"mat-block\" *ngIf=\"calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value\">\n <mat-label>{{ 'tb.rulenode.period-value-key' | translate }}</mat-label>\n <input required matInput formControlName=\"periodValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('periodValueKey').hasError('required')\">\n {{ 'tb.rulenode.period-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon=\"{{ calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value ? ('tb.rulenode.exclude-zero-deltas-time-difference-hint' | translate :{\n outputValueKey: calculateDeltaConfigForm.get('outputValueKey').valid ? calculateDeltaConfigForm.get('outputValueKey').value : 'tb.rulenode.output-value-key' | translate,\n periodValueKey: calculateDeltaConfigForm.get('periodValueKey').valid ? calculateDeltaConfigForm.get('periodValueKey').value : 'tb.rulenode.period-value-key' | translate\n }) : ('tb.rulenode.exclude-zero-deltas-hint' | translate :{ outputValueKey: calculateDeltaConfigForm.get('outputValueKey').valid ? calculateDeltaConfigForm.get('outputValueKey').value : 'tb.rulenode.output-value-key' | translate }) }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"excludeZeroDeltas\">\n {{ 'tb.rulenode.exclude-zero-deltas' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n",dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"<section [formGroup]=\"calculateDeltaConfigForm\">\n <div fxLayout.gt-sm=\"row\" fxLayoutGap.gt-sm=\"22px\">\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.input-value-key' | translate }}</mat-label>\n <input matInput formControlName=\"inputValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('inputValueKey').hasError('required') ||\n calculateDeltaConfigForm.get('inputValueKey').hasError('pattern')\">\n {{ 'tb.rulenode.input-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.output-value-key' | translate }}</mat-label>\n <input matInput formControlName=\"outputValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('outputValueKey').hasError('required') ||\n calculateDeltaConfigForm.get('outputValueKey').hasError('pattern')\">\n {{ 'tb.rulenode.output-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}</mat-label>\n <input type=\"number\" min=\"0\" max=\"15\" step=\"1\" matInput formControlName=\"round\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('round').hasError('min')\">\n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n </mat-error>\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('round').hasError('max')\">\n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n </mat-error>\n </mat-form-field>\n <div class=\"tb-form-panel no-padding no-border\">\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.failure-if-delta-negative-tooltip' | translate }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"tellFailureIfDeltaIsNegative\">\n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.use-caching-tooltip' | translate :\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"useCache\">\n {{ 'tb.rulenode.use-caching' | translate }}\n </mat-slide-toggle>\n </div>\n <div class=\"tb-form-panel stroked\" [class.no-padding-bottom]=\"calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value\">\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.add-time-difference-between-readings-tooltip' | translate:\n { periodValueKey: (calculateDeltaConfigForm.get('periodValueKey').valid &&\n calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value) ? calculateDeltaConfigForm.get('periodValueKey').value :\n 'periodInMs' } }}\"\n class=\"tb-form-row no-border no-padding\">\n <mat-slide-toggle class=\"mat-slide\" formControlName=\"addPeriodBetweenMsgs\">\n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n </mat-slide-toggle>\n </div>\n <mat-form-field class=\"mat-block\" *ngIf=\"calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value\">\n <mat-label>{{ 'tb.rulenode.period-value-key' | translate }}</mat-label>\n <input required matInput formControlName=\"periodValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('periodValueKey').hasError('required')\">\n {{ 'tb.rulenode.period-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon=\"{{ calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value ? ('tb.rulenode.exclude-zero-deltas-time-difference-hint' | translate :{\n outputValueKey: calculateDeltaConfigForm.get('outputValueKey').valid ? calculateDeltaConfigForm.get('outputValueKey').value : 'tb.rulenode.output-value-key' | translate,\n periodValueKey: calculateDeltaConfigForm.get('periodValueKey').valid ? calculateDeltaConfigForm.get('periodValueKey').value : 'tb.rulenode.period-value-key' | translate\n }) : ('tb.rulenode.exclude-zero-deltas-hint' | translate :{ outputValueKey: calculateDeltaConfigForm.get('outputValueKey').valid ? calculateDeltaConfigForm.get('outputValueKey').value : 'tb.rulenode.output-value-key' | translate }) }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"excludeZeroDeltas\">\n {{ 'tb.rulenode.exclude-zero-deltas' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n"}]}],ctorParameters:function(){return[{type:P.Store},{type:Z.TranslateService},{type:R.FormBuilder}]}});class Wn extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=zt;for(const e of Ht.keys())e!==zt.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ht.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,be(e)}prepareInputConfig(e){let t,n;return t=fe(e?.telemetry)?e.telemetry?zt.LATEST_TELEMETRY:zt.ATTRIBUTES:fe(e?.dataToFetch)?e.dataToFetch:zt.ATTRIBUTES,n=fe(e?.attrMapping)?e.attrMapping:fe(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:fe(e?.fetchTo)?e.fetchTo:ln.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===zt.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[O.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Wn,deps:[{token:P.Store},{token:R.FormBuilder},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Wn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="customerAttributesConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.mapping-of-customers</div>\n <div fxFlex fxLayoutAlign="center center">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\',\'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\',\'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\',\'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/customer_attributes_node_fields_templatization">\n </tb-kv-map-config>\n <tb-msg-metadata-chip\n [labelText]="customerAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.LATEST_TELEMETRY ?\n (\'tb.rulenode.add-mapped-latest-telemetry-to\' | translate) : (\'tb.rulenode.add-mapped-attribute-to\' | translate)"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Ae.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Me.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:Pn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'<section [formGroup]="customerAttributesConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.mapping-of-customers</div>\n <div fxFlex fxLayoutAlign="center center">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\',\'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\',\'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\',\'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/customer_attributes_node_fields_templatization">\n </tb-kv-map-config>\n <tb-msg-metadata-chip\n [labelText]="customerAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.LATEST_TELEMETRY ?\n (\'tb.rulenode.add-mapped-latest-telemetry-to\' | translate) : (\'tb.rulenode.add-mapped-attribute-to\' | translate)"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder},{type:Z.TranslateService}]}});class Zn extends g{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,[O.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return xe(e)&&(e.attributesControl={clientAttributeNames:fe(e?.clientAttributeNames)?e.clientAttributeNames:[],latestTsKeyNames:fe(e?.latestTsKeyNames)?e.latestTsKeyNames:[],serverAttributeNames:fe(e?.serverAttributeNames)?e.serverAttributeNames:[],sharedAttributeNames:fe(e?.sharedAttributeNames)?e.sharedAttributeNames:[],getLatestValueWithTs:!!fe(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:fe(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!fe(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:fe(e?.fetchTo)?e.fetchTo:ln.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",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Zn,deps:[{token:P.Store},{token:Z.TranslateService},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Zn,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deviceAttributesConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.device-relations-query</div>\n <tb-device-relations-query-config\n required\n formControlName="deviceRelationsQuery">\n </tb-device-relations-query-config>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.related-device-attributes</div>\n <div class="tb-form-panel-hint tb-error" translate\n [hidden]="!(deviceAttributesConfigForm.get(\'attributesControl\').touched &&\n deviceAttributesConfigForm.get(\'attributesControl\').hasError(\'atLeastOneRequired\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-select-attributes formControlName="attributesControl"\n popupHelpLink="rulenode/related_device_attributes_node_fields_templatization"></tb-select-attributes>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="\'tb.rulenode.add-selected-attributes-to\' | translate"></tb-msg-metadata-chip>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-tooltip\' | translate }}"\n class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="tellFailureIfAbsent">\n {{ \'tb.rulenode.tell-failure\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:Rn,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"component",type:jn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'<section [formGroup]="deviceAttributesConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.device-relations-query</div>\n <tb-device-relations-query-config\n required\n formControlName="deviceRelationsQuery">\n </tb-device-relations-query-config>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.related-device-attributes</div>\n <div class="tb-form-panel-hint tb-error" translate\n [hidden]="!(deviceAttributesConfigForm.get(\'attributesControl\').touched &&\n deviceAttributesConfigForm.get(\'attributesControl\').hasError(\'atLeastOneRequired\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-select-attributes formControlName="attributesControl"\n popupHelpLink="rulenode/related_device_attributes_node_fields_templatization"></tb-select-attributes>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="\'tb.rulenode.add-selected-attributes-to\' | translate"></tb-msg-metadata-chip>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-tooltip\' | translate }}"\n class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="tellFailureIfAbsent">\n {{ \'tb.rulenode.tell-failure\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:Z.TranslateService},{type:R.FormBuilder}]}});class Xn extends g{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.predefinedValues=[];for(const e of Object.keys(Pt))this.predefinedValues.push({value:Pt[e],name:this.translate.instant(Rt.get(Pt[e]))})}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return t=fe(e?.addToMetadata)?e.addToMetadata?ln.METADATA:ln.DATA:e?.fetchTo?e.fetchTo:ln.DATA,{detailsList:fe(e?.detailsList)?e.detailsList:null,fetchTo:t}}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[O.required]],fetchTo:[e.fetchTo,[]]})}}e("EntityDetailsConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Xn,deps:[{token:P.Store},{token:Z.TranslateService},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Xn,selector:"tb-enrichment-node-entity-details-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="entityDetailsConfigForm">\n <tb-string-items-list [predefinedValues]="predefinedValues"\n class="mat-block" required\n [label]="\'tb.rulenode.select-details\' | translate"\n [placeholder]="\'tb.rulenode.add-detail\' | translate"\n [requiredText]="\'tb.rulenode.entity-details-list-empty\' | translate"\n formControlName="detailsList">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.detail\' | translate } }}">\n help\n </mat-icon>\n </tb-string-items-list>\n <tb-msg-metadata-chip\n [labelText]="\'tb.rulenode.add-selected-details-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:et.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'<section [formGroup]="entityDetailsConfigForm">\n <tb-string-items-list [predefinedValues]="predefinedValues"\n class="mat-block" required\n [label]="\'tb.rulenode.select-details\' | translate"\n [placeholder]="\'tb.rulenode.add-detail\' | translate"\n [requiredText]="\'tb.rulenode.entity-details-list-empty\' | translate"\n formControlName="detailsList">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.detail\' | translate } }}">\n help\n </mat-icon>\n </tb-string-items-list>\n <tb-msg-metadata-chip\n [labelText]="\'tb.rulenode.add-selected-details-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:Z.TranslateService},{type:R.FormBuilder}]}});class er extends g{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[Fe,ke,Te],this.aggregationTypes=E,this.aggregations=Object.values(E),this.aggregationTypesTranslations=G,this.fetchMode=Ot,this.samplingOrders=Object.values(Kt),this.samplingOrdersTranslate=jt,this.timeUnits=Object.values(Gt),this.timeUnitsTranslationMap=wt,this.deduplicationStrategiesHintTranslations=Bt,this.headerOptions=[],this.timeUnitMap={[Gt.MILLISECONDS]:1,[Gt.SECONDS]:1e3,[Gt.MINUTES]:6e4,[Gt.HOURS]:36e5,[Gt.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 _t.keys())this.headerOptions.push({value:e,name:this.translate.instant(_t.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[O.required]],aggregation:[e.aggregation,[O.required]],fetchMode:[e.fetchMode,[O.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,be(e)}prepareInputConfig(e){return xe(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:fe(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:fe(e?.aggregation)?e.aggregation:E.NONE,fetchMode:fe(e?.fetchMode)?e.fetchMode:Ot.FIRST,orderBy:fe(e?.orderBy)?e.orderBy:Kt.ASC,limit:fe(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!fe(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:fe(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:fe(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:Gt.MINUTES,endInterval:fe(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:fe(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:Gt.MINUTES},startIntervalPattern:fe(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:fe(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===Ot.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([O.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([O.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([O.required,O.min(2),O.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([O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([O.required,O.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([O.required,O.min(1),O.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([O.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([O.required,O.min(1),O.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([O.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="")}defaultPaddingEnable(){return this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value===Ot.ALL&&this.getTelemetryFromDatabaseConfigForm.get("aggregation").value===E.NONE}}e("GetTelemetryFromDatabaseConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:er,deps:[{token:P.Store},{token:Z.TranslateService},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:er,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="getTelemetryFromDatabaseConfigForm" class="tb-form-panel no-padding no-border">\n <tb-string-items-list class="mat-block" editable [placeholder]="\'tb.rulenode.add-timeseries-key\' | translate"\n subscriptSizing="dynamic" required\n [requiredText]="\'tb.rulenode.timeseries-keys-required\' | translate"\n [label]="\'tb.rulenode.timeseries-keys\' | translate" formControlName="latestTsKeyNames"\n [hint]="\'tb.rulenode.general-pattern-hint\' | translate">\n <div matHintEnd class="see-example" tb-help-popup="{{\'rulenode/originator_telemetry_node_fields_templatization\'}}"\n hintMode\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}"></div>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.timeseries-key\' | translate } }}">help\n </mat-icon>\n </tb-string-items-list>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.fetch-interval</div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.use-metadata-dynamic-interval-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="useMetadataIntervalPatterns">\n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n </mat-slide-toggle>\n </div>\n <div formGroupName="interval" fxLayout="column"\n *ngIf="getTelemetryFromDatabaseConfigForm.get(\'useMetadataIntervalPatterns\').value === false; else intervalPattern">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="0" fxLayoutGap.gt-sm="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.interval-start\' | translate }}</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="startInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.time-unit\' | translate }}</mat-label>\n <mat-select formControlName="startIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="0" fxLayoutGap.gt-sm="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.interval-end\' | translate }}</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="endInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.time-unit\' | translate }}</mat-label>\n <mat-select formControlName="endIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class="description-block tb-primary-fill" [class.error]="getTelemetryFromDatabaseConfigForm.get(\'interval\').invalid">\n <mat-icon class="description-icon">error_outline</mat-icon>\n <div class="description-text">\n <ng-container *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval\').valid; else invalidText">\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 </ng-container>\n <ng-template #invalidText>\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n </ng-template>\n </div>\n </div>\n </div>\n <ng-template #intervalPattern>\n <div fxLayout="column" class="input-block">\n <mat-form-field fxFlex class="mat-block">\n <mat-label>{{ \'tb.rulenode.start-interval\' | translate }}</mat-label>\n <input matInput formControlName="startIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'required\') ||\n getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.start-interval-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label>{{ \'tb.rulenode.end-interval\' | translate }}</mat-label>\n <input matInput formControlName="endIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'required\') ||\n getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.end-interval-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-example-hint [hintText]="\'tb.rulenode.metadata-dynamic-interval-hint\' | translate"\n popupHelpLink="rulenode/originator_telemetry_node_fields_templatization">\n </tb-example-hint>\n </div>\n </ng-template>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.fetch-strategy</div>\n <div class="tb-form-panel no-border no-padding item-center">\n <div class="fetch-mod-toggle">\n <tb-toggle-select formControlName="fetchMode" appearance="fill">\n <tb-toggle-option *ngFor="let data of headerOptions" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n <div class="tb-form-hint tb-primary-fill hint-container">\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n </div>\n </div>\n <div *ngIf="getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value === fetchMode.ALL">\n <mat-form-field class="mat-block" hideRequiredMarker\n [subscriptSizing]="defaultPaddingEnable() ? \'fixed\' : \'dynamic\'">\n <mat-label>{{ \'aggregation.function\' | translate }}</mat-label>\n <mat-select formControlName="aggregation" required>\n <mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">\n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div *ngIf="getTelemetryFromDatabaseConfigForm.get(\'aggregation\').value === aggregationTypes.NONE">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label> {{ "tb.rulenode.order-by-timestamp" | translate }} </mat-label>\n <mat-select formControlName="orderBy" required>\n <mat-option *ngFor="let order of samplingOrders" [value]="order">\n {{ samplingOrdersTranslate.get(order) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label>{{ "tb.rulenode.limit" | translate }}</mat-label>\n <input type="number" min="2" max="1000" step="1" matInput formControlName="limit" required>\n <mat-hint>{{ "tb.rulenode.limit-hint" | translate }}</mat-hint>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'required\')">\n {{ \'tb.rulenode.limit-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'min\')">\n {{ \'tb.rulenode.limit-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'max\')">\n {{ \'tb.rulenode.limit-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n </div>\n</section>\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{width:100%}:host .hint-container{width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.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","hintMode"]},{kind:"component",type:et.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:R.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Ae.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Me.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:er,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'<section [formGroup]="getTelemetryFromDatabaseConfigForm" class="tb-form-panel no-padding no-border">\n <tb-string-items-list class="mat-block" editable [placeholder]="\'tb.rulenode.add-timeseries-key\' | translate"\n subscriptSizing="dynamic" required\n [requiredText]="\'tb.rulenode.timeseries-keys-required\' | translate"\n [label]="\'tb.rulenode.timeseries-keys\' | translate" formControlName="latestTsKeyNames"\n [hint]="\'tb.rulenode.general-pattern-hint\' | translate">\n <div matHintEnd class="see-example" tb-help-popup="{{\'rulenode/originator_telemetry_node_fields_templatization\'}}"\n hintMode\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}"></div>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.timeseries-key\' | translate } }}">help\n </mat-icon>\n </tb-string-items-list>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.fetch-interval</div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.use-metadata-dynamic-interval-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="useMetadataIntervalPatterns">\n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n </mat-slide-toggle>\n </div>\n <div formGroupName="interval" fxLayout="column"\n *ngIf="getTelemetryFromDatabaseConfigForm.get(\'useMetadataIntervalPatterns\').value === false; else intervalPattern">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="0" fxLayoutGap.gt-sm="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.interval-start\' | translate }}</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="startInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.time-unit\' | translate }}</mat-label>\n <mat-select formControlName="startIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="0" fxLayoutGap.gt-sm="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.interval-end\' | translate }}</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="endInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.time-unit\' | translate }}</mat-label>\n <mat-select formControlName="endIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class="description-block tb-primary-fill" [class.error]="getTelemetryFromDatabaseConfigForm.get(\'interval\').invalid">\n <mat-icon class="description-icon">error_outline</mat-icon>\n <div class="description-text">\n <ng-container *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval\').valid; else invalidText">\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 </ng-container>\n <ng-template #invalidText>\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n </ng-template>\n </div>\n </div>\n </div>\n <ng-template #intervalPattern>\n <div fxLayout="column" class="input-block">\n <mat-form-field fxFlex class="mat-block">\n <mat-label>{{ \'tb.rulenode.start-interval\' | translate }}</mat-label>\n <input matInput formControlName="startIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'required\') ||\n getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.start-interval-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label>{{ \'tb.rulenode.end-interval\' | translate }}</mat-label>\n <input matInput formControlName="endIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'required\') ||\n getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.end-interval-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-example-hint [hintText]="\'tb.rulenode.metadata-dynamic-interval-hint\' | translate"\n popupHelpLink="rulenode/originator_telemetry_node_fields_templatization">\n </tb-example-hint>\n </div>\n </ng-template>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.fetch-strategy</div>\n <div class="tb-form-panel no-border no-padding item-center">\n <div class="fetch-mod-toggle">\n <tb-toggle-select formControlName="fetchMode" appearance="fill">\n <tb-toggle-option *ngFor="let data of headerOptions" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n <div class="tb-form-hint tb-primary-fill hint-container">\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n </div>\n </div>\n <div *ngIf="getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value === fetchMode.ALL">\n <mat-form-field class="mat-block" hideRequiredMarker\n [subscriptSizing]="defaultPaddingEnable() ? \'fixed\' : \'dynamic\'">\n <mat-label>{{ \'aggregation.function\' | translate }}</mat-label>\n <mat-select formControlName="aggregation" required>\n <mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">\n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div *ngIf="getTelemetryFromDatabaseConfigForm.get(\'aggregation\').value === aggregationTypes.NONE">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label> {{ "tb.rulenode.order-by-timestamp" | translate }} </mat-label>\n <mat-select formControlName="orderBy" required>\n <mat-option *ngFor="let order of samplingOrders" [value]="order">\n {{ samplingOrdersTranslate.get(order) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label>{{ "tb.rulenode.limit" | translate }}</mat-label>\n <input type="number" min="2" max="1000" step="1" matInput formControlName="limit" required>\n <mat-hint>{{ "tb.rulenode.limit-hint" | translate }}</mat-hint>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'required\')">\n {{ \'tb.rulenode.limit-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'min\')">\n {{ \'tb.rulenode.limit-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'max\')">\n {{ \'tb.rulenode.limit-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n </div>\n</section>\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{width:100%}:host .hint-container{width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:Z.TranslateService},{type:R.FormBuilder}]}});class tr extends g{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 xe(e)&&(e.attributesControl={clientAttributeNames:fe(e?.clientAttributeNames)?e.clientAttributeNames:[],latestTsKeyNames:fe(e?.latestTsKeyNames)?e.latestTsKeyNames:[],serverAttributeNames:fe(e?.serverAttributeNames)?e.serverAttributeNames:[],sharedAttributeNames:fe(e?.sharedAttributeNames)?e.sharedAttributeNames:[],getLatestValueWithTs:!!fe(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:fe(e?.fetchTo)?e.fetchTo:ln.METADATA,tellFailureIfAbsent:!!fe(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:fe(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",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:tr,deps:[{token:P.Store},{token:Z.TranslateService},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:tr,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'<section class="tb-form-panel no-padding no-border" [formGroup]="originatorAttributesConfigForm">\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.originator-attributes</div>\n <div class="tb-form-panel-hint tb-error" translate\n [hidden]="!(originatorAttributesConfigForm.get(\'attributesControl\').touched &&\n originatorAttributesConfigForm.get(\'attributesControl\').hasError(\'atLeastOneRequired\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-select-attributes formControlName="attributesControl"\n popupHelpLink="rulenode/originator_attributes_node_fields_templatization">\n </tb-select-attributes>\n <tb-msg-metadata-chip [labelText]="\'tb.rulenode.add-originator-attributes-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-tooltip\' | translate }}" class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="tellFailureIfAbsent">\n {{ \'tb.rulenode.tell-failure\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"component",type:jn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'<section class="tb-form-panel no-padding no-border" [formGroup]="originatorAttributesConfigForm">\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.originator-attributes</div>\n <div class="tb-form-panel-hint tb-error" translate\n [hidden]="!(originatorAttributesConfigForm.get(\'attributesControl\').touched &&\n originatorAttributesConfigForm.get(\'attributesControl\').hasError(\'atLeastOneRequired\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-select-attributes formControlName="attributesControl"\n popupHelpLink="rulenode/originator_attributes_node_fields_templatization">\n </tb-select-attributes>\n <tb-msg-metadata-chip [labelText]="\'tb.rulenode.add-originator-attributes-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-tooltip\' | translate }}" class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="tellFailureIfAbsent">\n {{ \'tb.rulenode.tell-failure\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:Z.TranslateService},{type:R.FormBuilder}]}});class nr extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of qt)this.originatorFields.push({value:e.value,name:this.translate.instant(e.name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return be(e)}prepareInputConfig(e){return{dataMapping:fe(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:fe(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:fe(e?.fetchTo)?e.fetchTo:ln.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[O.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:nr,deps:[{token:P.Store},{token:R.FormBuilder},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:nr,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="originatorFieldsConfigForm" class="tb-form-panel no-padding no-border">\n <tb-sv-map-config\n required\n [selectOptions]="originatorFields"\n targetKeyPrefix="originator"\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="\'tb.rulenode.originator-fields-mapping\' | translate"\n [selectText]="\'tb.rulenode.source-field\' | translate"\n [selectRequiredText]="\'tb.rulenode.source-field-required\' | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.originator-fields-sv-map-hint\' | translate"\n popupHelpLink="rulenode/originator_fields_node_fields_templatization">\n </tb-sv-map-config>\n <tb-msg-metadata-chip [labelText]="\'tb.rulenode.add-mapped-originator-fields-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.skip-empty-fields-tooltip\' | translate }}" class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="ignoreNullStrings">\n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',dependencies:[{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"component",type:Hn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'<section [formGroup]="originatorFieldsConfigForm" class="tb-form-panel no-padding no-border">\n <tb-sv-map-config\n required\n [selectOptions]="originatorFields"\n targetKeyPrefix="originator"\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="\'tb.rulenode.originator-fields-mapping\' | translate"\n [selectText]="\'tb.rulenode.source-field\' | translate"\n [selectRequiredText]="\'tb.rulenode.source-field-required\' | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.originator-fields-sv-map-hint\' | translate"\n popupHelpLink="rulenode/originator_fields_node_fields_templatization">\n </tb-sv-map-config>\n <tb-msg-metadata-chip [labelText]="\'tb.rulenode.add-mapped-originator-fields-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.skip-empty-fields-tooltip\' | translate }}" class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="ignoreNullStrings">\n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder},{type:Z.TranslateService}]}});class rr extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=zt,this.msgMetadataLabelTranslations=Ut,this.originatorFields=[],this.fetchToData=[];for(const e of Object.keys(qt))this.originatorFields.push({value:qt[e].value,name:this.translate.instant(qt[e].name)});for(const e of Ht.keys())this.fetchToData.push({value:e,name:this.translate.instant(Ht.get(e))})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){e.dataToFetch===zt.FIELDS?(e.dataMapping=e.svMap,delete e.svMap):(e.dataMapping=e.kvMap,delete e.kvMap);const t={};if(e&&e.dataMapping)for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,delete e.svMap,delete e.kvMap,be(e)}prepareInputConfig(e){let t,n,r={[F.name.value]:`relatedEntity${this.translate.instant(F.name.name)}`},o={serialNumber:"sn"};return t=fe(e?.telemetry)?e.telemetry?zt.LATEST_TELEMETRY:zt.ATTRIBUTES:fe(e?.dataToFetch)?e.dataToFetch:zt.ATTRIBUTES,n=fe(e?.attrMapping)?e.attrMapping:fe(e?.dataMapping)?e.dataMapping:null,t===zt.FIELDS?r=n:o=n,{relationsQuery:fe(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:t,svMap:r,kvMap:o,fetchTo:fe(e?.fetchTo)?e.fetchTo:ln.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===zt.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[O.required]],dataToFetch:[e.dataToFetch,[]],kvMap:[e.kvMap,[O.required]],svMap:[e.svMap,[O.required]],fetchTo:[e.fetchTo,[]]})}validatorTriggers(){return["dataToFetch"]}updateValidators(e){this.relatedAttributesConfigForm.get("dataToFetch").value===zt.FIELDS?(this.relatedAttributesConfigForm.get("svMap").enable({emitEvent:!1}),this.relatedAttributesConfigForm.get("kvMap").disable({emitEvent:!1}),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity()):(this.relatedAttributesConfigForm.get("svMap").disable({emitEvent:!1}),this.relatedAttributesConfigForm.get("kvMap").enable({emitEvent:!1}),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity())}}e("RelatedAttributesConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:rr,deps:[{token:P.Store},{token:R.FormBuilder},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:rr,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="relatedAttributesConfigForm" class="tb-form-panel no-padding no-border">\n <tb-relations-query-config\n required\n formControlName="relationsQuery">\n </tb-relations-query-config>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.data-to-fetch</div>\n <tb-toggle-select formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n <tb-kv-map-config\n [hidden]="relatedAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.FIELDS"\n required\n formControlName="kvMap"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\',\'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\',\'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\',\'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/related_entity_data_node_fields_templatization">\n </tb-kv-map-config>\n <tb-sv-map-config\n [hidden]="relatedAttributesConfigForm.get(\'dataToFetch\').value !== DataToFetch.FIELDS"\n required\n [labelText]="\'tb.rulenode.fields-mapping\' | translate"\n targetKeyPrefix="relatedEntity"\n [selectOptions]="originatorFields"\n formControlName="svMap"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [selectText]="\'tb.rulenode.source-field\' | translate"\n [selectRequiredText]="\'tb.rulenode.source-field-required\' | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.sv-map-hint\' | translate"\n popupHelpLink="rulenode/related_entity_data_node_fields_templatization">\n </tb-sv-map-config>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="msgMetadataLabelTranslations.get(relatedAttributesConfigForm.get(\'dataToFetch\').value) | translate">\n </tb-msg-metadata-chip>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Ae.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Me.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:Pn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:On,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"component",type:Hn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'<section [formGroup]="relatedAttributesConfigForm" class="tb-form-panel no-padding no-border">\n <tb-relations-query-config\n required\n formControlName="relationsQuery">\n </tb-relations-query-config>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.data-to-fetch</div>\n <tb-toggle-select formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n <tb-kv-map-config\n [hidden]="relatedAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.FIELDS"\n required\n formControlName="kvMap"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\',\'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\',\'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\',\'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/related_entity_data_node_fields_templatization">\n </tb-kv-map-config>\n <tb-sv-map-config\n [hidden]="relatedAttributesConfigForm.get(\'dataToFetch\').value !== DataToFetch.FIELDS"\n required\n [labelText]="\'tb.rulenode.fields-mapping\' | translate"\n targetKeyPrefix="relatedEntity"\n [selectOptions]="originatorFields"\n formControlName="svMap"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [selectText]="\'tb.rulenode.source-field\' | translate"\n [selectRequiredText]="\'tb.rulenode.source-field-required\' | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.sv-map-hint\' | translate"\n popupHelpLink="rulenode/related_entity_data_node_fields_templatization">\n </tb-sv-map-config>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="msgMetadataLabelTranslations.get(relatedAttributesConfigForm.get(\'dataToFetch\').value) | translate">\n </tb-msg-metadata-chip>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder},{type:Z.TranslateService}]}});class or extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=zt;for(const e of Ht.keys())e!==zt.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ht.get(e))})}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=fe(e?.telemetry)?e.telemetry?zt.LATEST_TELEMETRY:zt.ATTRIBUTES:fe(e?.dataToFetch)?e.dataToFetch:zt.ATTRIBUTES,n=fe(e?.attrMapping)?e.attrMapping:fe(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:fe(e?.fetchTo)?e.fetchTo:ln.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===zt.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[O.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:or,deps:[{token:P.Store},{token:R.FormBuilder},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:or,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="tenantAttributesConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.mapping-of-tenant</div>\n <div fxFlex fxLayoutAlign="center center">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\', \'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\', \'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\', \'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/tenant_attributes_node_fields_templatization">\n </tb-kv-map-config>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="tenantAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.LATEST_TELEMETRY ?\n (\'tb.rulenode.add-mapped-latest-telemetry-to\' | translate) : (\'tb.rulenode.add-mapped-attribute-to\' | translate)">\n </tb-msg-metadata-chip>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Ae.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Me.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:Pn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'<section [formGroup]="tenantAttributesConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.mapping-of-tenant</div>\n <div fxFlex fxLayoutAlign="center center">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\', \'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\', \'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\', \'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/tenant_attributes_node_fields_templatization">\n </tb-kv-map-config>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="tenantAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.LATEST_TELEMETRY ?\n (\'tb.rulenode.add-mapped-latest-telemetry-to\' | translate) : (\'tb.rulenode.add-mapped-attribute-to\' | translate)">\n </tb-msg-metadata-chip>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder},{type:Z.TranslateService}]}});class ar extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:fe(e?.fetchTo)?e.fetchTo:ln.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ar,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ar,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="fetchDeviceCredentialsConfigForm">\n <tb-msg-metadata-chip\n [labelText]="\'tb.rulenode.fetch-credentials-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',dependencies:[{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'<section [formGroup]="fetchDeviceCredentialsConfigForm">\n <tb-msg-metadata-chip\n [labelText]="\'tb.rulenode.fetch-credentials-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class ir{}e("RulenodeCoreConfigEnrichmentModule",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ir,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ir.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:ir,declarations:[Wn,Xn,Zn,tr,nr,er,rr,or,Yn,ar],imports:[$,M,Jn],exports:[Wn,Xn,Zn,tr,nr,er,rr,or,Yn,ar]}),ir.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ir,imports:[$,M,Jn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ir,decorators:[{type:d,args:[{declarations:[Wn,Xn,Zn,tr,nr,er,rr,or,Yn,ar],imports:[$,M,Jn],exports:[Wn,Xn,Zn,tr,nr,er,rr,or,Yn,ar]}]}]});class lr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Wt,this.azureIotHubCredentialsTypeTranslationsMap=Zt}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[O.required]],host:[e?e.host:null,[O.required]],port:[e?e.port:null,[O.required,O.min(1),O.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[O.required,O.min(1),O.max(200)]],clientId:[e?e.clientId:null,[O.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[O.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([O.required]);break;case"cert.PEM":t.get("privateKey").setValidators([O.required]),t.get("privateKeyFileName").setValidators([O.required]),t.get("cert").setValidators([O.required]),t.get("certFileName").setValidators([O.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",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:lr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:lr,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="azureIotHubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.hostname</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.hostname-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.device-id</mat-label>\n <input required matInput formControlName="clientId" autocomplete="new-clientId">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'clientId\').hasError(\'required\')">\n {{ \'tb.rulenode.device-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-accordion>\n <mat-expansion-panel class="tb-mqtt-credentials-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title class="tb-required" translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <section formGroupName="credentials" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allAzureIotHubCredentialsTypes" [value]="credentialsType">\n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="azureIotHubConfigForm.get(\'credentials.type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="azureIotHubConfigForm.get(\'credentials.type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="sas">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.sas-key</mat-label>\n <input type="password" required matInput formControlName="sasKey" autocomplete="new-password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n <mat-error *ngIf="azureIotHubConfigForm.get(\'credentials.sasKey\').hasError(\'required\')">\n {{ \'tb.rulenode.sas-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.caCertFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.azure-ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.caCertFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.azure-ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.certFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.certFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.privateKeyFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.privateKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password" autocomplete="new-password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </ng-template>\n </section>\n </section>\n </mat-expansion-panel>\n </mat-accordion>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:U.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:oe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:oe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:oe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:oe.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:R.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Ze.FileInputComponent,selector:"tb-file-input",inputs:["label","hint","accept","noFileText","inputId","allowedExtensions","dropLabel","maxSizeByte","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'<section [formGroup]="azureIotHubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.hostname</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.hostname-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.device-id</mat-label>\n <input required matInput formControlName="clientId" autocomplete="new-clientId">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'clientId\').hasError(\'required\')">\n {{ \'tb.rulenode.device-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-accordion>\n <mat-expansion-panel class="tb-mqtt-credentials-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title class="tb-required" translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <section formGroupName="credentials" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allAzureIotHubCredentialsTypes" [value]="credentialsType">\n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="azureIotHubConfigForm.get(\'credentials.type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="azureIotHubConfigForm.get(\'credentials.type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="sas">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.sas-key</mat-label>\n <input type="password" required matInput formControlName="sasKey" autocomplete="new-password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n <mat-error *ngIf="azureIotHubConfigForm.get(\'credentials.sasKey\').hasError(\'required\')">\n {{ \'tb.rulenode.sas-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.caCertFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.azure-ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.caCertFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.azure-ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.certFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.certFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.privateKeyFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.privateKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password" autocomplete="new-password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </ng-template>\n </section>\n </section>\n </mat-expansion-panel>\n </mat-accordion>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class sr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=en,this.ToByteStandartCharsetTypeTranslationMap=tn}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[O.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[O.required]],retries:[e?e.retries:null,[O.min(0)]],batchSize:[e?e.batchSize:null,[O.min(0)]],linger:[e?e.linger:null,[O.min(0)]],bufferMemory:[e?e.bufferMemory:null,[O.min(0)]],acks:[e?e.acks:null,[O.required]],keySerializer:[e?e.keySerializer:null,[O.required]],valueSerializer:[e?e.valueSerializer:null,[O.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([O.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:sr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:sr,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="kafkaConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="kafkaConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.key-pattern</mat-label>\n <input matInput formControlName="keyPattern">\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <div class="tb-hint" translate>tb.rulenode.key-pattern-hint</div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.bootstrap-servers</mat-label>\n <input required matInput formControlName="bootstrapServers">\n <mat-error *ngIf="kafkaConfigForm.get(\'bootstrapServers\').hasError(\'required\')">\n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.retries</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="retries">\n <mat-error *ngIf="kafkaConfigForm.get(\'retries\').hasError(\'min\')">\n {{ \'tb.rulenode.min-retries-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.batch-size-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="batchSize">\n <mat-error *ngIf="kafkaConfigForm.get(\'batchSize\').hasError(\'min\')">\n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.linger-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="linger">\n <mat-error *ngIf="kafkaConfigForm.get(\'linger\').hasError(\'min\')">\n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.buffer-memory-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="bufferMemory">\n <mat-error *ngIf="kafkaConfigForm.get(\'bufferMemory\').hasError(\'min\')">\n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.acks</mat-label>\n <mat-select formControlName="acks" required>\n <mat-option *ngFor="let ackValue of ackValues" [value]="ackValue">\n {{ ackValue }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.key-serializer</mat-label>\n <input required matInput formControlName="keySerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'keySerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.value-serializer</mat-label>\n <input required matInput formControlName="valueSerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'valueSerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.other-properties</label>\n <tb-kv-map-config-old\n required="false"\n formControlName="otherProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <mat-checkbox fxFlex formControlName="addMetadataKeyValuesAsKafkaHeaders">\n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.add-metadata-key-values-as-kafka-headers-hint</div>\n <mat-form-field fxFlex class="mat-block" *ngIf="kafkaConfigForm.get(\'addMetadataKeyValuesAsKafkaHeaders\').value">\n <mat-label translate>tb.rulenode.charset-encoding</mat-label>\n <mat-select formControlName="kafkaHeadersCharset" required>\n <mat-option *ngFor="let charset of ToByteStandartCharsetTypesValues" [value]="charset">\n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:sr,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'<section [formGroup]="kafkaConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="kafkaConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.key-pattern</mat-label>\n <input matInput formControlName="keyPattern">\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <div class="tb-hint" translate>tb.rulenode.key-pattern-hint</div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.bootstrap-servers</mat-label>\n <input required matInput formControlName="bootstrapServers">\n <mat-error *ngIf="kafkaConfigForm.get(\'bootstrapServers\').hasError(\'required\')">\n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.retries</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="retries">\n <mat-error *ngIf="kafkaConfigForm.get(\'retries\').hasError(\'min\')">\n {{ \'tb.rulenode.min-retries-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.batch-size-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="batchSize">\n <mat-error *ngIf="kafkaConfigForm.get(\'batchSize\').hasError(\'min\')">\n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.linger-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="linger">\n <mat-error *ngIf="kafkaConfigForm.get(\'linger\').hasError(\'min\')">\n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.buffer-memory-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="bufferMemory">\n <mat-error *ngIf="kafkaConfigForm.get(\'bufferMemory\').hasError(\'min\')">\n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.acks</mat-label>\n <mat-select formControlName="acks" required>\n <mat-option *ngFor="let ackValue of ackValues" [value]="ackValue">\n {{ ackValue }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.key-serializer</mat-label>\n <input required matInput formControlName="keySerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'keySerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.value-serializer</mat-label>\n <input required matInput formControlName="valueSerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'valueSerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.other-properties</label>\n <tb-kv-map-config-old\n required="false"\n formControlName="otherProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <mat-checkbox fxFlex formControlName="addMetadataKeyValuesAsKafkaHeaders">\n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.add-metadata-key-values-as-kafka-headers-hint</div>\n <mat-form-field fxFlex class="mat-block" *ngIf="kafkaConfigForm.get(\'addMetadataKeyValuesAsKafkaHeaders\').value">\n <mat-label translate>tb.rulenode.charset-encoding</mat-label>\n <mat-select formControlName="kafkaHeadersCharset" required>\n <mat-option *ngFor="let charset of ToByteStandartCharsetTypesValues" [value]="charset">\n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class mr extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[O.required]],host:[e?e.host:null,[O.required]],port:[e?e.port:null,[O.required,O.min(1),O.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[O.required,O.min(1),O.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&he(e.clientId))},[]],parseToPlainText:[!!e&&e.parseToPlainText,[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})}updateValidators(e){he(this.mqttConfigForm.get("clientId").value)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1}),this.mqttConfigForm.get("appendClientIdSuffix").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["clientId"]}}e("MqttConfigComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:mr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:mr,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="mqttConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="mqttConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <div fxFlex fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="mqttConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.connect-timeout</mat-label>\n <input required type="number" step="1" min="1" max="200" matInput formControlName="connectTimeoutSec">\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'required\')">\n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'min\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'max\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.client-id</mat-label>\n <input matInput formControlName="clientId">\n <mat-hint>{{\'tb.rulenode.client-id-hint\' | translate}}</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="appendClientIdSuffix">\n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n </mat-checkbox>\n <div class="tb-hint">{{ "tb.rulenode.client-id-suffix-hint" | translate }}</div>\n <mat-checkbox formControlName="parseToPlainText">\n {{ \'tb.rulenode.parse-to-plain-text\' | translate }}\n </mat-checkbox>\n <div class="tb-hint">{{ "tb.rulenode.parse-to-plain-text-hint" | translate }}</div>\n <mat-checkbox formControlName="cleanSession">\n {{ \'tb.rulenode.clean-session\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="retainedMessage">\n {{ "tb.rulenode.retained-message" | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="ssl">\n {{ \'tb.rulenode.enable-ssl\' | translate }}\n </mat-checkbox>\n <tb-credentials-config formControlName="credentials" [passwordFieldRequired]="false"></tb-credentials-config>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Bn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'<section [formGroup]="mqttConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="mqttConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <div fxFlex fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="mqttConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.connect-timeout</mat-label>\n <input required type="number" step="1" min="1" max="200" matInput formControlName="connectTimeoutSec">\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'required\')">\n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'min\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'max\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.client-id</mat-label>\n <input matInput formControlName="clientId">\n <mat-hint>{{\'tb.rulenode.client-id-hint\' | translate}}</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="appendClientIdSuffix">\n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n </mat-checkbox>\n <div class="tb-hint">{{ "tb.rulenode.client-id-suffix-hint" | translate }}</div>\n <mat-checkbox formControlName="parseToPlainText">\n {{ \'tb.rulenode.parse-to-plain-text\' | translate }}\n </mat-checkbox>\n <div class="tb-hint">{{ "tb.rulenode.parse-to-plain-text-hint" | translate }}</div>\n <mat-checkbox formControlName="cleanSession">\n {{ \'tb.rulenode.clean-session\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="retainedMessage">\n {{ "tb.rulenode.retained-message" | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="ssl">\n {{ \'tb.rulenode.enable-ssl\' | translate }}\n </mat-checkbox>\n <tb-credentials-config formControlName="credentials" [passwordFieldRequired]="false"></tb-credentials-config>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class pr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=w,this.entityType=C}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[O.required]],targets:[e?e.targets:[],[O.required]]})}}e("NotificationConfigComponent",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:pr,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),pr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:pr,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="notificationConfigForm" fxLayout="column">\n <tb-template-autocomplete\n required\n allowCreate\n formControlName="templateId"\n [notificationTypes]="notificationType.RULE_NODE">\n </tb-template-autocomplete>\n <tb-entity-list\n required\n formControlName="targets"\n labelText="{{ \'notification.recipients\' | translate }}"\n placeholderText="{{ \'notification.recipient\' | translate }}"\n requiredText="{{ \'notification.recipients-required\' | translate }}"\n entityType="{{ entityType.NOTIFICATION_TARGET }}"\n subType="{{ notificationType.RULE_NODE }}">\n </tb-entity-list>\n</section>\n',dependencies:[{kind:"component",type:tt.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:nt.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:pr,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'<section [formGroup]="notificationConfigForm" fxLayout="column">\n <tb-template-autocomplete\n required\n allowCreate\n formControlName="templateId"\n [notificationTypes]="notificationType.RULE_NODE">\n </tb-template-autocomplete>\n <tb-entity-list\n required\n formControlName="targets"\n labelText="{{ \'notification.recipients\' | translate }}"\n placeholderText="{{ \'notification.recipient\' | translate }}"\n requiredText="{{ \'notification.recipients-required\' | translate }}"\n entityType="{{ entityType.NOTIFICATION_TARGET }}"\n subType="{{ notificationType.RULE_NODE }}">\n </tb-entity-list>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class dr extends g{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,[O.required]],topicName:[e?e.topicName:null,[O.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[O.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[O.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:dr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),dr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:dr,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="pubSubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.gcp-project-id</mat-label>\n <input required matInput formControlName="projectId">\n <mat-error *ngIf="pubSubConfigForm.get(\'projectId\').hasError(\'required\')">\n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.pubsub-topic-name</mat-label>\n <input required matInput formControlName="topicName">\n <mat-error *ngIf="pubSubConfigForm.get(\'topicName\').hasError(\'required\')">\n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input style="padding-bottom: 24px;"\n formControlName="serviceAccountKey"\n [existingFileName]="pubSubConfigForm.get(\'serviceAccountKeyFileName\').value"\n (fileNameChanged)="pubSubConfigForm.get(\'serviceAccountKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.gcp-service-account-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.message-attributes-hint\' | translate | safe: \'html\'"></div>\n <tb-kv-map-config-old\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ze.FileInputComponent,selector:"tb-file-input",inputs:["label","hint","accept","noFileText","inputId","allowedExtensions","dropLabel","maxSizeByte","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:ue.SafePipe,name:"safe"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:dr,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'<section [formGroup]="pubSubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.gcp-project-id</mat-label>\n <input required matInput formControlName="projectId">\n <mat-error *ngIf="pubSubConfigForm.get(\'projectId\').hasError(\'required\')">\n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.pubsub-topic-name</mat-label>\n <input required matInput formControlName="topicName">\n <mat-error *ngIf="pubSubConfigForm.get(\'topicName\').hasError(\'required\')">\n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input style="padding-bottom: 24px;"\n formControlName="serviceAccountKey"\n [existingFileName]="pubSubConfigForm.get(\'serviceAccountKeyFileName\').value"\n (fileNameChanged)="pubSubConfigForm.get(\'serviceAccountKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.gcp-service-account-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.message-attributes-hint\' | translate | safe: \'html\'"></div>\n <tb-kv-map-config-old\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class ur extends g{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,[O.required]],port:[e?e.port:null,[O.required,O.min(1),O.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,[O.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[O.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ur,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ur,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="rabbitMqConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.exchange-name-pattern</mat-label>\n <input matInput formControlName="exchangeNamePattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.routing-key-pattern</mat-label>\n <input matInput formControlName="routingKeyPattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-properties</mat-label>\n <mat-select formControlName="messageProperties">\n <mat-option *ngFor="let property of messageProperties" [value]="property">\n {{ property }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.virtual-host</mat-label>\n <input matInput formControlName="virtualHost">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n <mat-checkbox formControlName="automaticRecoveryEnabled">\n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.connection-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.handshake-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="handshakeTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'handshakeTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.client-properties</label>\n <tb-kv-map-config-old\n required="false"\n formControlName="clientProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ur,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'<section [formGroup]="rabbitMqConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.exchange-name-pattern</mat-label>\n <input matInput formControlName="exchangeNamePattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.routing-key-pattern</mat-label>\n <input matInput formControlName="routingKeyPattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-properties</mat-label>\n <mat-select formControlName="messageProperties">\n <mat-option *ngFor="let property of messageProperties" [value]="property">\n {{ property }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.virtual-host</mat-label>\n <input matInput formControlName="virtualHost">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n <mat-checkbox formControlName="automaticRecoveryEnabled">\n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.connection-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.handshake-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="handshakeTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'handshakeTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.client-properties</label>\n <tb-kv-map-config-old\n required="false"\n formControlName="clientProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class cr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Xt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[O.required]],requestMethod:[e?e.requestMethod:null,[O.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],parseToPlainText:[!!e&&e.parseToPlainText,[]],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,[O.min(0)]],headers:[e?e.headers:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("enableProxy").value,r=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!r?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[O.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[O.required,O.min(1),O.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([O.min(0)])),this.restApiCallConfigForm.get("readTimeoutMs").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",cr),cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:cr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),cr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:cr,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="restApiCallConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.endpoint-url-pattern</mat-label>\n <input required matInput formControlName="restEndpointUrlPattern">\n <mat-error *ngIf="restApiCallConfigForm.get(\'restEndpointUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.request-method</mat-label>\n <mat-select formControlName="requestMethod">\n <mat-option *ngFor="let requestType of httpRequestTypes" [value]="requestType">\n {{ requestType }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName="enableProxy">\n {{ \'tb.rulenode.enable-proxy\' | translate }}\n </mat-checkbox>\n <mat-checkbox *ngIf="!restApiCallConfigForm.get(\'enableProxy\').value" formControlName="useSimpleClientHttpFactory">\n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="parseToPlainText">\n {{ \'tb.rulenode.parse-to-plain-text\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 5px;" translate>tb.rulenode.parse-to-plain-text-hint</div>\n <mat-checkbox formControlName="ignoreRequestBody">\n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n </mat-checkbox>\n <div *ngIf="restApiCallConfigForm.get(\'enableProxy\').value">\n <mat-checkbox formControlName="useSystemProxyProperties">\n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n </mat-checkbox>\n <div *ngIf="!restApiCallConfigForm.get(\'useSystemProxyProperties\').value">\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="10">\n <mat-label translate>tb.rulenode.proxy-scheme</mat-label>\n <mat-select formControlName="proxyScheme">\n <mat-option *ngFor="let proxyScheme of proxySchemes" [value]="proxyScheme">\n {{ proxyScheme }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="md-block" fxFlex="100" fxFlex.gt-sm="50">\n <mat-label translate>tb.rulenode.proxy-host</mat-label>\n <input matInput required formControlName="proxyHost">\n <mat-error *ngIf="restApiCallConfigForm.get(\'proxyHost\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="40">\n <mat-label translate>tb.rulenode.proxy-port</mat-label>\n <input matInput required formControlName="proxyPort" type="number" step="1">\n <mat-error *ngIf="restApiCallConfigForm.get(\'proxyPort\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n </mat-error>\n <mat-error\n *ngIf="restApiCallConfigForm.get(\'proxyPort\').hasError(\'min\') || restApiCallConfigForm.get(\'proxyPort\').hasError(\'max\')">\n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-user</mat-label>\n <input matInput formControlName="proxyUser">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-password</mat-label>\n <input matInput formControlName="proxyPassword">\n </mat-form-field>\n </div>\n </div>\n <mat-form-field *ngIf="!restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value || restApiCallConfigForm.get(\'enableProxy\').value" class="mat-block"\n subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.read-timeout</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="readTimeoutMs">\n <mat-hint translate>tb.rulenode.read-timeout-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.max-parallel-requests-count</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="maxParallelRequestsCount">\n <mat-hint translate>tb.rulenode.max-parallel-requests-count-hint</mat-hint>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.headers</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.headers-hint\' | translate | safe: \'html\'"> </div>\n <tb-kv-map-config-old\n required="false"\n formControlName="headers"\n keyText="tb.rulenode.header"\n keyRequiredText="tb.rulenode.header-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <tb-credentials-config formControlName="credentials" [disableCertPemCredentials]="restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value"></tb-credentials-config>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Bn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:ue.SafePipe,name:"safe"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:cr,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'<section [formGroup]="restApiCallConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.endpoint-url-pattern</mat-label>\n <input required matInput formControlName="restEndpointUrlPattern">\n <mat-error *ngIf="restApiCallConfigForm.get(\'restEndpointUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.request-method</mat-label>\n <mat-select formControlName="requestMethod">\n <mat-option *ngFor="let requestType of httpRequestTypes" [value]="requestType">\n {{ requestType }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName="enableProxy">\n {{ \'tb.rulenode.enable-proxy\' | translate }}\n </mat-checkbox>\n <mat-checkbox *ngIf="!restApiCallConfigForm.get(\'enableProxy\').value" formControlName="useSimpleClientHttpFactory">\n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="parseToPlainText">\n {{ \'tb.rulenode.parse-to-plain-text\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 5px;" translate>tb.rulenode.parse-to-plain-text-hint</div>\n <mat-checkbox formControlName="ignoreRequestBody">\n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n </mat-checkbox>\n <div *ngIf="restApiCallConfigForm.get(\'enableProxy\').value">\n <mat-checkbox formControlName="useSystemProxyProperties">\n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n </mat-checkbox>\n <div *ngIf="!restApiCallConfigForm.get(\'useSystemProxyProperties\').value">\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="10">\n <mat-label translate>tb.rulenode.proxy-scheme</mat-label>\n <mat-select formControlName="proxyScheme">\n <mat-option *ngFor="let proxyScheme of proxySchemes" [value]="proxyScheme">\n {{ proxyScheme }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="md-block" fxFlex="100" fxFlex.gt-sm="50">\n <mat-label translate>tb.rulenode.proxy-host</mat-label>\n <input matInput required formControlName="proxyHost">\n <mat-error *ngIf="restApiCallConfigForm.get(\'proxyHost\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="40">\n <mat-label translate>tb.rulenode.proxy-port</mat-label>\n <input matInput required formControlName="proxyPort" type="number" step="1">\n <mat-error *ngIf="restApiCallConfigForm.get(\'proxyPort\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n </mat-error>\n <mat-error\n *ngIf="restApiCallConfigForm.get(\'proxyPort\').hasError(\'min\') || restApiCallConfigForm.get(\'proxyPort\').hasError(\'max\')">\n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-user</mat-label>\n <input matInput formControlName="proxyUser">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-password</mat-label>\n <input matInput formControlName="proxyPassword">\n </mat-form-field>\n </div>\n </div>\n <mat-form-field *ngIf="!restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value || restApiCallConfigForm.get(\'enableProxy\').value" class="mat-block"\n subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.read-timeout</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="readTimeoutMs">\n <mat-hint translate>tb.rulenode.read-timeout-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.max-parallel-requests-count</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="maxParallelRequestsCount">\n <mat-hint translate>tb.rulenode.max-parallel-requests-count-hint</mat-hint>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.headers</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.headers-hint\' | translate | safe: \'html\'"> </div>\n <tb-kv-map-config-old\n required="false"\n formControlName="headers"\n keyText="tb.rulenode.header"\n keyRequiredText="tb.rulenode.header-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <tb-credentials-config formControlName="credentials" [disableCertPemCredentials]="restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value"></tb-credentials-config>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class gr extends g{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([O.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([O.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([O.required,O.min(1),O.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([O.required,O.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[O.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[O.required,O.min(1),O.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",gr),gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:gr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),gr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:gr,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="sendEmailConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useSystemSmtpSettings">\n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="sendEmailConfigForm.get(\'useSystemSmtpSettings\').value === false">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.smtp-protocol</mat-label>\n <mat-select formControlName="smtpProtocol">\n <mat-option *ngFor="let smtpProtocol of smtpProtocols" [value]="smtpProtocol">\n {{ smtpProtocol.toUpperCase() }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-host</mat-label>\n <input required matInput formControlName="smtpHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpHost\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="smtpPort">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'min\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'max\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.timeout-msec</mat-label>\n <input required type="number" step="1" min="0" matInput formControlName="timeout">\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox formControlName="enableTls">\n {{ \'tb.rulenode.enable-tls\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block" *ngIf="sendEmailConfigForm.get(\'enableTls\').value === true">\n <mat-label translate>tb.rulenode.tls-version</mat-label>\n <mat-select formControlName="tlsVersion">\n <mat-option *ngFor="let tlsVersion of tlsVersions" [value]="tlsVersion">\n {{ tlsVersion }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-checkbox formControlName="enableProxy">\n {{ \'tb.rulenode.enable-proxy\' | translate }}\n </tb-checkbox>\n <div *ngIf="sendEmailConfigForm.get(\'enableProxy\').value">\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="60">\n <mat-label translate>tb.rulenode.proxy-host</mat-label>\n <input matInput required formControlName="proxyHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyHost\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="40">\n <mat-label translate>tb.rulenode.proxy-port</mat-label>\n <input matInput required formControlName="proxyPort" type="number" step="1" min="1" max="65535">\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyPort\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyPort\').hasError(\'min\') || sendEmailConfigForm.get(\'proxyPort\').hasError(\'max\')">\n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-user</mat-label>\n <input matInput formControlName="proxyUser">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-password</mat-label>\n <input matInput formControlName="proxyPassword">\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput placeholder="{{ \'tb.rulenode.enter-username\' | translate }}" formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input matInput type="password" placeholder="{{ \'tb.rulenode.enter-password\' | translate }}" formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:rt.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:gr,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'<section [formGroup]="sendEmailConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useSystemSmtpSettings">\n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="sendEmailConfigForm.get(\'useSystemSmtpSettings\').value === false">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.smtp-protocol</mat-label>\n <mat-select formControlName="smtpProtocol">\n <mat-option *ngFor="let smtpProtocol of smtpProtocols" [value]="smtpProtocol">\n {{ smtpProtocol.toUpperCase() }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-host</mat-label>\n <input required matInput formControlName="smtpHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpHost\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="smtpPort">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'min\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'max\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.timeout-msec</mat-label>\n <input required type="number" step="1" min="0" matInput formControlName="timeout">\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox formControlName="enableTls">\n {{ \'tb.rulenode.enable-tls\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block" *ngIf="sendEmailConfigForm.get(\'enableTls\').value === true">\n <mat-label translate>tb.rulenode.tls-version</mat-label>\n <mat-select formControlName="tlsVersion">\n <mat-option *ngFor="let tlsVersion of tlsVersions" [value]="tlsVersion">\n {{ tlsVersion }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-checkbox formControlName="enableProxy">\n {{ \'tb.rulenode.enable-proxy\' | translate }}\n </tb-checkbox>\n <div *ngIf="sendEmailConfigForm.get(\'enableProxy\').value">\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="60">\n <mat-label translate>tb.rulenode.proxy-host</mat-label>\n <input matInput required formControlName="proxyHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyHost\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="40">\n <mat-label translate>tb.rulenode.proxy-port</mat-label>\n <input matInput required formControlName="proxyPort" type="number" step="1" min="1" max="65535">\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyPort\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyPort\').hasError(\'min\') || sendEmailConfigForm.get(\'proxyPort\').hasError(\'max\')">\n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-user</mat-label>\n <input matInput formControlName="proxyUser">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-password</mat-label>\n <input matInput formControlName="proxyPassword">\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput placeholder="{{ \'tb.rulenode.enter-username\' | translate }}" formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input matInput type="password" placeholder="{{ \'tb.rulenode.enter-password\' | translate }}" formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class fr extends g{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,[O.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[O.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([O.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",fr),fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:fr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:fr,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="sendSmsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.numbers-to-template</mat-label>\n <input required matInput formControlName="numbersToTemplate">\n <mat-error *ngIf="sendSmsConfigForm.get(\'numbersToTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n </mat-error>\n <mat-hint [innerHTML]="\'tb.rulenode.numbers-to-template-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.sms-message-template</mat-label>\n <textarea required matInput formControlName="smsMessageTemplate" rows="6"></textarea>\n <mat-error *ngIf="sendSmsConfigForm.get(\'smsMessageTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="useSystemSmsSettings">\n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n </mat-checkbox>\n <tb-sms-provider-configuration\n *ngIf="sendSmsConfigForm.get(\'useSystemSmsSettings\').value === false"\n formControlName="smsProviderConfiguration"\n required>\n </tb-sms-provider-configuration>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ot.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:ue.SafePipe,name:"safe"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:fr,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'<section [formGroup]="sendSmsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.numbers-to-template</mat-label>\n <input required matInput formControlName="numbersToTemplate">\n <mat-error *ngIf="sendSmsConfigForm.get(\'numbersToTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n </mat-error>\n <mat-hint [innerHTML]="\'tb.rulenode.numbers-to-template-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.sms-message-template</mat-label>\n <textarea required matInput formControlName="smsMessageTemplate" rows="6"></textarea>\n <mat-error *ngIf="sendSmsConfigForm.get(\'smsMessageTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="useSystemSmsSettings">\n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n </mat-checkbox>\n <tb-sms-provider-configuration\n *ngIf="sendSmsConfigForm.get(\'useSystemSmsSettings\').value === false"\n formControlName="smsProviderConfiguration"\n required>\n </tb-sms-provider-configuration>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class yr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(D),this.slackChanelTypesTranslateMap=V}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,[O.required]],conversationType:[e?e.conversationType:null,[O.required]],conversation:[e?e.conversation:null,[O.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([O.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",yr),yr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:yr,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:yr,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="slackConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.message-template</mat-label>\n <input required matInput formControlName="messageTemplate">\n <mat-error *ngIf="slackConfigForm.get(\'messageTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.message-template-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="useSystemSettings">\n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n </mat-checkbox>\n <mat-form-field *ngIf="!slackConfigForm.get(\'useSystemSettings\').value" class="mat-block">\n <mat-label translate>tb.rulenode.slack-api-token</mat-label>\n <input required matInput formControlName="botToken">\n <mat-error *ngIf="slackConfigForm.get(\'botToken\').hasError(\'required\')">\n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label class="tb-title">{{ \'notification.slack-chanel-type\' | translate }}</label>\n <mat-radio-group formControlName="conversationType">\n <mat-radio-button *ngFor="let slackChanelType of slackChanelTypes" [value]="slackChanelType">\n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n </mat-radio-button>\n </mat-radio-group>\n <tb-slack-conversation-autocomplete\n formControlName="conversation"\n required\n [token]="slackConfigForm.get(\'useSystemSettings\').value ? \'\' : slackConfigForm.get(\'botToken\').value"\n [slackChanelType]="slackConfigForm.get(\'conversationType\').value">\n </tb-slack-conversation-autocomplete>\n</section>\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:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Le.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:at.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:at.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:it.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:yr,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'<section [formGroup]="slackConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.message-template</mat-label>\n <input required matInput formControlName="messageTemplate">\n <mat-error *ngIf="slackConfigForm.get(\'messageTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.message-template-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="useSystemSettings">\n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n </mat-checkbox>\n <mat-form-field *ngIf="!slackConfigForm.get(\'useSystemSettings\').value" class="mat-block">\n <mat-label translate>tb.rulenode.slack-api-token</mat-label>\n <input required matInput formControlName="botToken">\n <mat-error *ngIf="slackConfigForm.get(\'botToken\').hasError(\'required\')">\n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label class="tb-title">{{ \'notification.slack-chanel-type\' | translate }}</label>\n <mat-radio-group formControlName="conversationType">\n <mat-radio-button *ngFor="let slackChanelType of slackChanelTypes" [value]="slackChanelType">\n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n </mat-radio-button>\n </mat-radio-group>\n <tb-slack-conversation-autocomplete\n formControlName="conversation"\n required\n [token]="slackConfigForm.get(\'useSystemSettings\').value ? \'\' : slackConfigForm.get(\'botToken\').value"\n [slackChanelType]="slackConfigForm.get(\'conversationType\').value">\n </tb-slack-conversation-autocomplete>\n</section>\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:P.Store},{type:R.FormBuilder}]}});class br extends g{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,[O.required]],accessKeyId:[e?e.accessKeyId:null,[O.required]],secretAccessKey:[e?e.secretAccessKey:null,[O.required]],region:[e?e.region:null,[O.required]]})}}e("SnsConfigComponent",br),br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:br,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:br,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="snsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-arn-pattern</mat-label>\n <input required matInput formControlName="topicArnPattern">\n <mat-error *ngIf="snsConfigForm.get(\'topicArnPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="snsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="snsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="snsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:br,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'<section [formGroup]="snsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-arn-pattern</mat-label>\n <input required matInput formControlName="topicArnPattern">\n <mat-error *ngIf="snsConfigForm.get(\'topicArnPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="snsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="snsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="snsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class xr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=$t,this.sqsQueueTypes=Object.keys($t),this.sqsQueueTypeTranslationsMap=Jt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[O.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[O.required]],delaySeconds:[e?e.delaySeconds:null,[O.min(0),O.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[O.required]],secretAccessKey:[e?e.secretAccessKey:null,[O.required]],region:[e?e.region:null,[O.required]]})}}e("SqsConfigComponent",xr),xr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:xr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),xr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:xr,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="sqsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.queue-type</mat-label>\n <mat-select formControlName="queueType" required>\n <mat-option *ngFor="let type of sqsQueueTypes" [value]="type">\n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.queue-url-pattern</mat-label>\n <input required matInput formControlName="queueUrlPattern">\n <mat-error *ngIf="sqsConfigForm.get(\'queueUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field *ngIf="sqsConfigForm.get(\'queueType\').value === sqsQueueType.STANDARD" class="mat-block">\n <mat-label translate>tb.rulenode.delay-seconds</mat-label>\n <input required type="number" min="0" max="900" step="1" matInput formControlName="delaySeconds">\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n </mat-error>\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'max\')">\n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.message-attributes-hint\' | translate | safe: \'html\'"></div>\n <tb-kv-map-config-old\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="sqsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="sqsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="sqsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:ue.SafePipe,name:"safe"},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:xr,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'<section [formGroup]="sqsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.queue-type</mat-label>\n <mat-select formControlName="queueType" required>\n <mat-option *ngFor="let type of sqsQueueTypes" [value]="type">\n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.queue-url-pattern</mat-label>\n <input required matInput formControlName="queueUrlPattern">\n <mat-error *ngIf="sqsConfigForm.get(\'queueUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field *ngIf="sqsConfigForm.get(\'queueType\').value === sqsQueueType.STANDARD" class="mat-block">\n <mat-label translate>tb.rulenode.delay-seconds</mat-label>\n <input required type="number" min="0" max="900" step="1" matInput formControlName="delaySeconds">\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n </mat-error>\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'max\')">\n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.message-attributes-hint\' | translate | safe: \'html\'"></div>\n <tb-kv-map-config-old\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="sqsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="sqsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="sqsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class hr extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.lambdaConfigForm}onConfigurationSet(e){this.lambdaConfigForm=this.fb.group({functionName:[e?e.functionName:null,[O.required]],qualifier:[e?e.qualifier:null,[]],accessKey:[e?e.accessKey:null,[O.required]],secretKey:[e?e.secretKey:null,[O.required]],region:[e?e.region:null,[O.required]],connectionTimeout:[e?e.connectionTimeout:null,[O.required,O.min(0)]],requestTimeout:[e?e.requestTimeout:null,[O.required,O.min(0)]],tellFailureIfFuncThrowsExc:[!!e&&e.tellFailureIfFuncThrowsExc,[]]})}}e("LambdaConfigComponent",hr),hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:hr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),hr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:hr,selector:"tb-external-node-lambda-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="lambdaConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.function-configuration</div>\n </div>\n <tb-example-hint [hintText]="\'tb.rulenode.template-rules-hint\'"\n popupHelpLink="rulenode/node-templatization-doc">\n </tb-example-hint>\n <div class="tb-standard-fields">\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.function-name\' | translate}}</mat-label>\n <input required matInput formControlName="functionName">\n <mat-error *ngIf="lambdaConfigForm.get(\'functionName\').hasError(\'required\')">\n {{\'tb.rulenode.function-name-required\' | translate}}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.qualifier\' | translate}}</mat-label>\n <input required matInput formControlName="qualifier">\n <mat-hint translate>tb.rulenode.qualifier-hint</mat-hint>\n </mat-form-field>\n </div>\n </div>\n\n <div class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings" expanded>\n <mat-expansion-panel-header>\n <mat-panel-title class="tb-form-panel-title tb-required" translate>tb.rulenode.aws-credentials</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-standard-fields">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKey">\n <mat-error *ngIf="lambdaConfigForm.get(\'accessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretKey">\n <mat-error *ngIf="lambdaConfigForm.get(\'secretKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="lambdaConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </mat-expansion-panel>\n </div>\n <div class="tb-form-panel stroked no-padding">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header style="padding: 16px">\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-panel no-border no-padding no-gap" style="margin-top: 0">\n <div class="tb-form-row no-border same-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.connection-timeout</mat-label>\n <input type="number" required min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="lambdaConfigForm.get(\'connectionTimeout\').hasError(\'required\')">\n {{ \'tb.rulenode.connection-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="lambdaConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.connection-timeout-min\' | translate }}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.connection-timeout-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-timeout</mat-label>\n <input type="number" required min="0" matInput formControlName="requestTimeout">\n <mat-error *ngIf="lambdaConfigForm.get(\'requestTimeout\').hasError(\'required\')">\n {{ \'tb.rulenode.request-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="lambdaConfigForm.get(\'requestTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.request-timeout-min\' | translate }}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.request-timeout-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-aws-lambda-hint\' | translate }}"\n class="tb-form-row no-border" style="margin-bottom: 16px">\n <mat-slide-toggle class="mat-slide" formControlName="tellFailureIfFuncThrowsExc">\n {{ \'tb.rulenode.tell-failure-aws-lambda\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n </mat-expansion-panel>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"component",type:oe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:oe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:oe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:hr,decorators:[{type:n,args:[{selector:"tb-external-node-lambda-config",template:'<section [formGroup]="lambdaConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.function-configuration</div>\n </div>\n <tb-example-hint [hintText]="\'tb.rulenode.template-rules-hint\'"\n popupHelpLink="rulenode/node-templatization-doc">\n </tb-example-hint>\n <div class="tb-standard-fields">\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.function-name\' | translate}}</mat-label>\n <input required matInput formControlName="functionName">\n <mat-error *ngIf="lambdaConfigForm.get(\'functionName\').hasError(\'required\')">\n {{\'tb.rulenode.function-name-required\' | translate}}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.qualifier\' | translate}}</mat-label>\n <input required matInput formControlName="qualifier">\n <mat-hint translate>tb.rulenode.qualifier-hint</mat-hint>\n </mat-form-field>\n </div>\n </div>\n\n <div class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings" expanded>\n <mat-expansion-panel-header>\n <mat-panel-title class="tb-form-panel-title tb-required" translate>tb.rulenode.aws-credentials</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-standard-fields">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKey">\n <mat-error *ngIf="lambdaConfigForm.get(\'accessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretKey">\n <mat-error *ngIf="lambdaConfigForm.get(\'secretKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="lambdaConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </mat-expansion-panel>\n </div>\n <div class="tb-form-panel stroked no-padding">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header style="padding: 16px">\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-panel no-border no-padding no-gap" style="margin-top: 0">\n <div class="tb-form-row no-border same-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.connection-timeout</mat-label>\n <input type="number" required min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="lambdaConfigForm.get(\'connectionTimeout\').hasError(\'required\')">\n {{ \'tb.rulenode.connection-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="lambdaConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.connection-timeout-min\' | translate }}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.connection-timeout-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-timeout</mat-label>\n <input type="number" required min="0" matInput formControlName="requestTimeout">\n <mat-error *ngIf="lambdaConfigForm.get(\'requestTimeout\').hasError(\'required\')">\n {{ \'tb.rulenode.request-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="lambdaConfigForm.get(\'requestTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.request-timeout-min\' | translate }}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.request-timeout-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-aws-lambda-hint\' | translate }}"\n class="tb-form-row no-border" style="margin-bottom: 16px">\n <mat-slide-toggle class="mat-slide" formControlName="tellFailureIfFuncThrowsExc">\n {{ \'tb.rulenode.tell-failure-aws-lambda\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n </mat-expansion-panel>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class vr{}e("RulenodeCoreConfigExternalModule",vr),vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),vr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:vr,declarations:[br,xr,hr,dr,sr,mr,pr,ur,cr,gr,lr,fr,yr],imports:[$,M,Je,Jn],exports:[br,xr,hr,dr,sr,mr,pr,ur,cr,gr,lr,fr,yr]}),vr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vr,imports:[$,M,Je,Jn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vr,decorators:[{type:d,args:[{declarations:[br,xr,hr,dr,sr,mr,pr,ur,cr,gr,lr,fr,yr],imports:[$,M,Je,Jn],exports:[br,xr,hr,dr,sr,mr,pr,ur,cr,gr,lr,fr,yr]}]}]});class Cr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.searchText=""}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return{alarmStatusList:fe(e?.alarmStatusList)?e.alarmStatusList:null}}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e.alarmStatusList,[O.required]]})}}e("CheckAlarmStatusComponent",Cr),Cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Cr,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Cr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Cr,selector:"tb-filter-node-check-alarm-status-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="alarmStatusConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.alarm-status</div>\n <div class="tb-form-panel-hint tb-error" translate [hidden]="alarmStatusConfigForm.get(\'alarmStatusList\').valid">\n tb.rulenode.alarm-required\n </div>\n </div>\n <tb-alarm-status-select formControlName="alarmStatusList"></tb-alarm-status-select>\n</section>\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$n,selector:"tb-alarm-status-select"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Cr,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'<section [formGroup]="alarmStatusConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.alarm-status</div>\n <div class="tb-form-panel-hint tb-error" translate [hidden]="alarmStatusConfigForm.get(\'alarmStatusList\').valid">\n tb.rulenode.alarm-required\n </div>\n </div>\n <tb-alarm-status-select formControlName="alarmStatusList"></tb-alarm-status-select>\n</section>\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class Fr extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.checkMessageConfigForm}prepareInputConfig(e){return{messageNames:fe(e?.messageNames)?e.messageNames:[],metadataNames:fe(e?.metadataNames)?e.metadataNames:[],checkAllKeys:!!fe(e?.checkAllKeys)&&e.checkAllKeys}}prepareOutputConfig(e){return{messageNames:fe(e?.messageNames)?e.messageNames:[],metadataNames:fe(e?.metadataNames)?e.metadataNames:[],checkAllKeys:e.checkAllKeys}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e.messageNames,[]],metadataNames:[e.metadataNames,[]],checkAllKeys:[e.checkAllKeys,[]]},{validators:this.atLeastOne(O.required,["messageNames","metadataNames"])})}get touchedValidationControl(){return["messageNames","metadataNames"].some((e=>this.checkMessageConfigForm.get(e).touched))}}e("CheckMessageConfigComponent",Fr),Fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Fr,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Fr,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="checkMessageConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.fields-to-check</div>\n <div class="tb-form-panel-hint tb-error" translate [hidden]="!(touchedValidationControl && checkMessageConfigForm.hasError(\'atLeastOne\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-string-items-list editable subscriptSizing="dynamic"\n [label]="\'tb.rulenode.data-keys\' | translate"\n [placeholder]="\'tb.rulenode.add-message-field\' | translate"\n formControlName="messageNames">\n <mat-icon matSuffix color="primary" class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n </tb-string-items-list>\n <tb-string-items-list editable subscriptSizing="dynamic"\n [label]="\'tb.rulenode.metadata-keys\' | translate"\n [placeholder]="\'tb.rulenode.add-metadata-field\' | translate"\n formControlName="metadataNames">\n <mat-icon matSuffix color="primary" class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n </tb-string-items-list>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.check-all-keys-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="checkAllKeys">\n {{ \'tb.rulenode.check-all-keys\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:et.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Fr,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'<section [formGroup]="checkMessageConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.fields-to-check</div>\n <div class="tb-form-panel-hint tb-error" translate [hidden]="!(touchedValidationControl && checkMessageConfigForm.hasError(\'atLeastOne\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-string-items-list editable subscriptSizing="dynamic"\n [label]="\'tb.rulenode.data-keys\' | translate"\n [placeholder]="\'tb.rulenode.add-message-field\' | translate"\n formControlName="messageNames">\n <mat-icon matSuffix color="primary" class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n </tb-string-items-list>\n <tb-string-items-list editable subscriptSizing="dynamic"\n [label]="\'tb.rulenode.metadata-keys\' | translate"\n [placeholder]="\'tb.rulenode.add-metadata-field\' | translate"\n formControlName="metadataNames">\n <mat-icon matSuffix color="primary" class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n </tb-string-items-list>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.check-all-keys-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="checkAllKeys">\n {{ \'tb.rulenode.check-all-keys\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class kr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.values(v),this.entitySearchDirectionTranslationsMap=N}configForm(){return this.checkRelationConfigForm}prepareInputConfig(e){return{checkForSingleEntity:!!fe(e?.checkForSingleEntity)&&e.checkForSingleEntity,direction:fe(e?.direction)?e.direction:null,entityType:fe(e?.entityType)?e.entityType:null,entityId:fe(e?.entityId)?e.entityId:null,relationType:fe(e?.relationType)?e.relationType:null}}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[e.checkForSingleEntity,[]],direction:[e.direction,[]],entityType:[e.entityType,e&&e.checkForSingleEntity?[O.required]:[]],entityId:[e.entityId,e&&e.checkForSingleEntity?[O.required]:[]],relationType:[e.relationType,[O.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[O.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[O.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",kr),kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:kr,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="checkRelationConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-search-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'relation.direction\' | translate }}</mat-label>\n <mat-select formControlName="direction" required>\n <mat-option *ngFor="let direction of entitySearchDirection" [value]="direction">\n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.check-relation-to-specific-entity-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="checkForSingleEntity">\n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n <div *ngIf="checkRelationConfigForm.get(\'checkForSingleEntity\').value" class="same-width-component-row">\n <tb-entity-type-select\n style="min-width: 100px; flex: 1;"\n showLabel\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <tb-entity-autocomplete\n fxFlex\n required\n *ngIf="checkRelationConfigForm.get(\'entityType\').value"\n [entityType]="checkRelationConfigForm.get(\'entityType\').value"\n formControlName="entityId">\n </tb-entity-autocomplete>\n </div>\n </div>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:lt.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:Ne.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kr,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'<section [formGroup]="checkRelationConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-search-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'relation.direction\' | translate }}</mat-label>\n <mat-select formControlName="direction" required>\n <mat-option *ngFor="let direction of entitySearchDirection" [value]="direction">\n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.check-relation-to-specific-entity-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="checkForSingleEntity">\n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n <div *ngIf="checkRelationConfigForm.get(\'checkForSingleEntity\').value" class="same-width-component-row">\n <tb-entity-type-select\n style="min-width: 100px; flex: 1;"\n showLabel\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <tb-entity-autocomplete\n fxFlex\n required\n *ngIf="checkRelationConfigForm.get(\'entityType\').value"\n [entityType]="checkRelationConfigForm.get(\'entityType\').value"\n formControlName="entityId">\n </tb-entity-autocomplete>\n </div>\n </div>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Tr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Mt,this.perimeterTypes=Object.values(Mt),this.perimeterTypeTranslationMap=Et,this.rangeUnits=Object.values(Dt),this.rangeUnitTranslationMap=Vt,this.defaultPaddingEnable=!0}configForm(){return this.geoFilterConfigForm}prepareInputConfig(e){return{latitudeKeyName:fe(e?.latitudeKeyName)?e.latitudeKeyName:null,longitudeKeyName:fe(e?.longitudeKeyName)?e.longitudeKeyName:null,perimeterType:fe(e?.perimeterType)?e.perimeterType:null,fetchPerimeterInfoFromMessageMetadata:!!fe(e?.fetchPerimeterInfoFromMessageMetadata)&&e.fetchPerimeterInfoFromMessageMetadata,perimeterKeyName:fe(e?.perimeterKeyName)?e.perimeterKeyName:null,centerLatitude:fe(e?.centerLatitude)?e.centerLatitude:null,centerLongitude:fe(e?.centerLongitude)?e.centerLongitude:null,range:fe(e?.range)?e.range:null,rangeUnit:fe(e?.rangeUnit)?e.rangeUnit:null,polygonsDefinition:fe(e?.polygonsDefinition)?e.polygonsDefinition:null}}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e.latitudeKeyName,[O.required]],longitudeKeyName:[e.longitudeKeyName,[O.required]],perimeterType:[e.perimeterType,[O.required]],fetchPerimeterInfoFromMessageMetadata:[e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e.perimeterKeyName,[]],centerLatitude:[e.centerLatitude,[]],centerLongitude:[e.centerLongitude,[]],range:[e.range,[]],rangeUnit:[e.rangeUnit,[]],polygonsDefinition:[e.polygonsDefinition,[]]})}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([O.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==Mt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([]),this.defaultPaddingEnable=!0):(this.geoFilterConfigForm.get("centerLatitude").setValidators([O.required,O.min(-90),O.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([O.required,O.min(-180),O.max(180)]),this.geoFilterConfigForm.get("range").setValidators([O.required,O.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([O.required]),this.defaultPaddingEnable=!1),t||n!==Mt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([O.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",Tr),Tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tr,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Tr,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="geoFilterConfigForm" class="tb-form-panel no-border no-padding">\n <section class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.coordinate-field-names</div>\n <section>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.latitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.longitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.coordinate-field-hint</div>\n </section>\n </section>\n <section class="tb-form-panel stroked" [class.no-padding-bottom]="!defaultPaddingEnable">\n <div class="tb-form-panel-title" translate>tb.rulenode.geofence-configuration</div>\n <section fxLayout="column">\n <mat-form-field fxFlex class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.perimeter-type\' | translate }}</mat-label>\n <mat-select formControlName="perimeterType">\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div tb-hint-tooltip-icon="{{ geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE\n ? (\'tb.rulenode.fetch-circle-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoFilterConfigForm.get(\'perimeterKeyName\').valid\n ? geoFilterConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'})\n : (\'tb.rulenode.fetch-poligon-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoFilterConfigForm.get(\'perimeterKeyName\').valid\n ? geoFilterConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'}) }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchPerimeterInfoFromMessageMetadata">\n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field *ngIf="geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value" class="mat-block">\n <mat-label>{{ \'tb.rulenode.perimeter-key-name\' | translate }}</mat-label>\n <input matInput formControlName="perimeterKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'perimeterKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n </mat-error>\n <mat-hint>{{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}</mat-hint>\n </mat-form-field>\n <div fxLayout="column"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-latitude\' | translate }}</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-longitude\' | translate }}</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range\' | translate }}</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range-units\' | translate }}</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="geoFilterConfigForm.get(\'rangeUnit\').hasError(\'required\')">\n {{ \'tb.rulenode.range-units-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-label>{{ \'tb.rulenode.polygon-definition\' | translate }}</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-hint>{{ \'tb.rulenode.polygon-definition-hint\' | translate }}</mat-hint>\n <mat-error *ngIf="geoFilterConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n </section>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:W.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:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:R.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tr,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'<section [formGroup]="geoFilterConfigForm" class="tb-form-panel no-border no-padding">\n <section class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.coordinate-field-names</div>\n <section>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.latitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.longitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.coordinate-field-hint</div>\n </section>\n </section>\n <section class="tb-form-panel stroked" [class.no-padding-bottom]="!defaultPaddingEnable">\n <div class="tb-form-panel-title" translate>tb.rulenode.geofence-configuration</div>\n <section fxLayout="column">\n <mat-form-field fxFlex class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.perimeter-type\' | translate }}</mat-label>\n <mat-select formControlName="perimeterType">\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div tb-hint-tooltip-icon="{{ geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE\n ? (\'tb.rulenode.fetch-circle-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoFilterConfigForm.get(\'perimeterKeyName\').valid\n ? geoFilterConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'})\n : (\'tb.rulenode.fetch-poligon-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoFilterConfigForm.get(\'perimeterKeyName\').valid\n ? geoFilterConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'}) }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchPerimeterInfoFromMessageMetadata">\n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field *ngIf="geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value" class="mat-block">\n <mat-label>{{ \'tb.rulenode.perimeter-key-name\' | translate }}</mat-label>\n <input matInput formControlName="perimeterKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'perimeterKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n </mat-error>\n <mat-hint>{{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}</mat-hint>\n </mat-form-field>\n <div fxLayout="column"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-latitude\' | translate }}</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-longitude\' | translate }}</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range\' | translate }}</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range-units\' | translate }}</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="geoFilterConfigForm.get(\'rangeUnit\').hasError(\'required\')">\n {{ \'tb.rulenode.range-units-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-label>{{ \'tb.rulenode.polygon-definition\' | translate }}</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-hint>{{ \'tb.rulenode.polygon-definition-hint\' | translate }}</mat-hint>\n <mat-error *ngIf="geoFilterConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n </section>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class Lr extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}prepareInputConfig(e){return{messageTypes:fe(e?.messageTypes)?e.messageTypes:null}}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e.messageTypes,[O.required]]})}}e("MessageTypeConfigComponent",Lr),Lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Lr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Lr,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="messageTypeConfigForm">\n <tb-message-types-config\n required\n [label]="\'tb.rulenode.select-message-types\' | translate"\n formControlName="messageTypes">\n </tb-message-types-config>\n</section>\n',dependencies:[{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:_n,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Lr,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'<section [formGroup]="messageTypeConfigForm">\n <tb-message-types-config\n required\n [label]="\'tb.rulenode.select-message-types\' | translate"\n formControlName="messageTypes">\n </tb-message-types-config>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Ir extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[C.DEVICE,C.ASSET,C.ENTITY_VIEW,C.TENANT,C.CUSTOMER,C.USER,C.DASHBOARD,C.RULE_CHAIN,C.RULE_NODE,C.EDGE]}configForm(){return this.originatorTypeConfigForm}prepareInputConfig(e){return{originatorTypes:fe(e?.originatorTypes)?e.originatorTypes:null}}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e.originatorTypes,[O.required]]})}}e("OriginatorTypeConfigComponent",Ir),Ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ir,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ir,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="originatorTypeConfigForm">\n <tb-entity-type-list fxFlex\n formControlName="originatorTypes"\n [allowedEntityTypes]="allowedEntityTypes"\n [ignoreAuthorityFilter]="true"\n [emptyInputPlaceholder]="\'tb.rulenode.add-entity-type\' | translate"\n [filledInputPlaceholder]="\'tb.rulenode.add-entity-type\' | translate"\n [label]="\'tb.rulenode.select-entity-types\' | translate"\n required>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.entity-type\' | translate } }}">help</mat-icon>\n </tb-entity-type-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:st.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","additionalClasses","appearance","label","floatLabel","disabled","subscriptSizing","allowedEntityTypes","emptyInputPlaceholder","filledInputPlaceholder","ignoreAuthorityFilter"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:W.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ir,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'<section [formGroup]="originatorTypeConfigForm">\n <tb-entity-type-list fxFlex\n formControlName="originatorTypes"\n [allowedEntityTypes]="allowedEntityTypes"\n [ignoreAuthorityFilter]="true"\n [emptyInputPlaceholder]="\'tb.rulenode.add-entity-type\' | translate"\n [filledInputPlaceholder]="\'tb.rulenode.add-entity-type\' | translate"\n [label]="\'tb.rulenode.select-entity-types\' | translate"\n required>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.entity-type\' | translate } }}">help</mat-icon>\n </tb-entity-type-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Nr extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ce(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-filter-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e.scriptLang,[O.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===b.JS?[O.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===b.TBEL?[O.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),{scriptLang:fe(e?.scriptLang)?e.scriptLang:b.JS,jsScript:fe(e?.jsScript)?e.jsScript:null,tbelScript:fe(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Nr),Nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Nr,deps:[{token:P.Store},{token:R.UntypedFormBuilder},{token:ge.NodeScriptTestService},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Nr,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:'<section [formGroup]="scriptConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/filter_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/filter_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ve.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ce.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Nr,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'<section [formGroup]="scriptConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/filter_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/filter_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder},{type:ge.NodeScriptTestService},{type:Z.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class Sr extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ce(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-switch-function"}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e.scriptLang,[O.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===b.JS?[O.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===b.TBEL?[O.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),{scriptLang:fe(e?.scriptLang)?e.scriptLang:b.JS,jsScript:fe(e?.jsScript)?e.jsScript:null,tbelScript:fe(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.switchConfigForm.get("scriptLang").value,n=t===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Sr),Sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Sr,deps:[{token:P.Store},{token:R.UntypedFormBuilder},{token:ge.NodeScriptTestService},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Sr,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:'<section [formGroup]="switchConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="switchConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/switch_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="switchConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/switch_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ve.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ce.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Sr,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'<section [formGroup]="switchConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="switchConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/switch_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="switchConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/switch_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder},{type:ge.NodeScriptTestService},{type:Z.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class qr{}e("RuleNodeCoreConfigFilterModule",qr),qr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:qr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),qr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:qr,declarations:[Fr,kr,Tr,Lr,Ir,Nr,Sr,Cr],imports:[$,M,Jn],exports:[Fr,kr,Tr,Lr,Ir,Nr,Sr,Cr]}),qr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:qr,imports:[$,M,Jn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:qr,decorators:[{type:d,args:[{declarations:[Fr,kr,Tr,Lr,Ir,Nr,Sr,Cr],imports:[$,M,Jn],exports:[Fr,kr,Tr,Lr,Ir,Nr,Sr,Cr]}]}]});class Ar extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=It,this.originatorSources=Object.keys(It),this.originatorSourceTranslationMap=Nt,this.originatorSourceDescTranslationMap=St,this.allowedEntityTypes=[C.DEVICE,C.ASSET,C.ENTITY_VIEW,C.USER,C.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[O.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([O.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===It.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([O.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([O.required,O.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",Ar),Ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ar,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ar,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="changeOriginatorConfigForm" class="tb-form-panel no-border no-padding">\n <mat-form-field class="mat-block" subscriptSizing="dynamic" hideRequiredMarker>\n <mat-label translate>tb.rulenode.new-originator</mat-label>\n <mat-select formControlName="originatorSource" required>\n <mat-select-trigger>\n <span *ngIf="originatorSourceTranslationMap.get(changeOriginatorConfigForm.get(\'originatorSource\').value)">\n {{ originatorSourceTranslationMap.get(changeOriginatorConfigForm.get(\'originatorSource\').value) | translate }}\n </span>\n </mat-select-trigger>\n <mat-option *ngFor="let source of originatorSources" [value]="source">\n <span matListItemTitle>\n {{ originatorSourceTranslationMap.get(source) | translate }}\n </span>\n <br>\n <small matListItemMeta style="color: inherit">\n {{ originatorSourceDescTranslationMap.get(source) | translate }}\n </small>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div class="tb-form-panel stroked no-padding-bottom"\n *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === \'ENTITY\'">\n <tb-example-hint [hintText]="\'tb.rulenode.entity-name-pattern-hint\'"\n popupHelpLink="rulenode/change_originator_node_fields_templatization">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <tb-entity-type-select\n showLabel\n required\n [allowedEntityTypes] = "allowedEntityTypes"\n formControlName="entityType"\n class="mat-mdc-form-field flex">\n </tb-entity-type-select>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.entity-name-pattern</mat-label>\n <input required matInput formControlName="entityNamePattern">\n <mat-error *ngIf="changeOriginatorConfigForm.get(\'entityNamePattern\').hasError(\'required\') ||\n changeOriginatorConfigForm.get(\'entityNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <tb-relations-query-config\n required\n *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === originatorSource.RELATED"\n formControlName="relationsQuery">\n </tb-relations-query-config>\n</section>\n',dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ne.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:te.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Pe.MatListItemTitle,selector:"[matListItemTitle]"},{kind:"directive",type:Pe.MatListItemMeta,selector:"[matListItemMeta]"},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:On,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'<section [formGroup]="changeOriginatorConfigForm" class="tb-form-panel no-border no-padding">\n <mat-form-field class="mat-block" subscriptSizing="dynamic" hideRequiredMarker>\n <mat-label translate>tb.rulenode.new-originator</mat-label>\n <mat-select formControlName="originatorSource" required>\n <mat-select-trigger>\n <span *ngIf="originatorSourceTranslationMap.get(changeOriginatorConfigForm.get(\'originatorSource\').value)">\n {{ originatorSourceTranslationMap.get(changeOriginatorConfigForm.get(\'originatorSource\').value) | translate }}\n </span>\n </mat-select-trigger>\n <mat-option *ngFor="let source of originatorSources" [value]="source">\n <span matListItemTitle>\n {{ originatorSourceTranslationMap.get(source) | translate }}\n </span>\n <br>\n <small matListItemMeta style="color: inherit">\n {{ originatorSourceDescTranslationMap.get(source) | translate }}\n </small>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div class="tb-form-panel stroked no-padding-bottom"\n *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === \'ENTITY\'">\n <tb-example-hint [hintText]="\'tb.rulenode.entity-name-pattern-hint\'"\n popupHelpLink="rulenode/change_originator_node_fields_templatization">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <tb-entity-type-select\n showLabel\n required\n [allowedEntityTypes] = "allowedEntityTypes"\n formControlName="entityType"\n class="mat-mdc-form-field flex">\n </tb-entity-type-select>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.entity-name-pattern</mat-label>\n <input required matInput formControlName="entityNamePattern">\n <mat-error *ngIf="changeOriginatorConfigForm.get(\'entityNamePattern\').hasError(\'required\') ||\n changeOriginatorConfigForm.get(\'entityNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <tb-relations-query-config\n required\n *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === originatorSource.RELATED"\n formControlName="relationsQuery">\n </tb-relations-query-config>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class Mr extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ce(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,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:b.JS,[O.required]],jsScript:[e?e.jsScript:null,[O.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===b.JS?[O.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===b.TBEL?[O.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Mr),Mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Mr,deps:[{token:P.Store},{token:R.FormBuilder},{token:ge.NodeScriptTestService},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Mr,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:'<section [formGroup]="scriptConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Transform"\n helpId="rulenode/transformation_node_script_fn"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Transform"\n helpId="rulenode/tbel/transformation_node_script_fn"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ve.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:X.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:X.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ce.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Mr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'<section [formGroup]="scriptConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Transform"\n helpId="rulenode/transformation_node_script_fn"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Transform"\n helpId="rulenode/tbel/transformation_node_script_fn"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder},{type:ge.NodeScriptTestService},{type:Z.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}}); - /** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - const Er=mt({passive:!0});class Gr{constructor(e,t){this._platform=e,this._ngZone=t,this._monitoredElements=new Map}monitor(e){if(!this._platform.isBrowser)return se;const t=Ge(e),n=this._monitoredElements.get(t);if(n)return n.subject;const r=new ae,o="cdk-text-field-autofilled",a=e=>{"cdk-text-field-autofill-start"!==e.animationName||t.classList.contains(o)?"cdk-text-field-autofill-end"===e.animationName&&t.classList.contains(o)&&(t.classList.remove(o),this._ngZone.run((()=>r.next({target:e.target,isAutofilled:!1})))):(t.classList.add(o),this._ngZone.run((()=>r.next({target:e.target,isAutofilled:!0}))))};return this._ngZone.runOutsideAngular((()=>{t.addEventListener("animationstart",a,Er),t.classList.add("cdk-text-field-autofill-monitored")})),this._monitoredElements.set(t,{subject:r,unlisten:()=>{t.removeEventListener("animationstart",a,Er)}}),r}stopMonitoring(e){const t=Ge(e),n=this._monitoredElements.get(t);n&&(n.unlisten(),n.subject.complete(),t.classList.remove("cdk-text-field-autofill-monitored"),t.classList.remove("cdk-text-field-autofilled"),this._monitoredElements.delete(t))}ngOnDestroy(){this._monitoredElements.forEach(((e,t)=>this.stopMonitoring(t)))}}Gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Gr,deps:[{token:pt.Platform},{token:t.NgZone}],target:t.ɵɵFactoryTarget.Injectable}),Gr.ɵprov=t.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Gr,providedIn:"root"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Gr,decorators:[{type:o,args:[{providedIn:"root"}]}],ctorParameters:function(){return[{type:pt.Platform},{type:t.NgZone}]}});class wr{constructor(e,t){this._elementRef=e,this._autofillMonitor=t,this.cdkAutofill=new l}ngOnInit(){this._autofillMonitor.monitor(this._elementRef).subscribe((e=>this.cdkAutofill.emit(e)))}ngOnDestroy(){this._autofillMonitor.stopMonitoring(this._elementRef)}}wr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:wr,deps:[{token:t.ElementRef},{token:Gr}],target:t.ɵɵFactoryTarget.Directive}),wr.ɵdir=t.ɵɵngDeclareDirective({minVersion:"14.0.0",version:"15.2.0-rc.0",type:wr,selector:"[cdkAutofill]",outputs:{cdkAutofill:"cdkAutofill"},ngImport:t}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:wr,decorators:[{type:s,args:[{selector:"[cdkAutofill]"}]}],ctorParameters:function(){return[{type:t.ElementRef},{type:Gr}]},propDecorators:{cdkAutofill:[{type:p}]}}); - /** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - class Dr{get minRows(){return this._minRows}set minRows(e){this._minRows=we(e),this._setMinHeight()}get maxRows(){return this._maxRows}set maxRows(e){this._maxRows=we(e),this._setMaxHeight()}get enabled(){return this._enabled}set enabled(e){e=Ee(e),this._enabled!==e&&((this._enabled=e)?this.resizeToFitContent(!0):this.reset())}get placeholder(){return this._textareaElement.placeholder}set placeholder(e){this._cachedPlaceholderHeight=void 0,e?this._textareaElement.setAttribute("placeholder",e):this._textareaElement.removeAttribute("placeholder"),this._cacheTextareaPlaceholderHeight()}constructor(e,t,n,r){this._elementRef=e,this._platform=t,this._ngZone=n,this._destroyed=new ae,this._enabled=!0,this._previousMinRows=-1,this._isViewInited=!1,this._handleFocusEvent=e=>{this._hasFocus="focus"===e.type},this._document=r,this._textareaElement=this._elementRef.nativeElement}_setMinHeight(){const e=this.minRows&&this._cachedLineHeight?this.minRows*this._cachedLineHeight+"px":null;e&&(this._textareaElement.style.minHeight=e)}_setMaxHeight(){const e=this.maxRows&&this._cachedLineHeight?this.maxRows*this._cachedLineHeight+"px":null;e&&(this._textareaElement.style.maxHeight=e)}ngAfterViewInit(){this._platform.isBrowser&&(this._initialHeight=this._textareaElement.style.height,this.resizeToFitContent(),this._ngZone.runOutsideAngular((()=>{const e=this._getWindow();me(e,"resize").pipe(Ue(16),He(this._destroyed)).subscribe((()=>this.resizeToFitContent(!0))),this._textareaElement.addEventListener("focus",this._handleFocusEvent),this._textareaElement.addEventListener("blur",this._handleFocusEvent)})),this._isViewInited=!0,this.resizeToFitContent(!0))}ngOnDestroy(){this._textareaElement.removeEventListener("focus",this._handleFocusEvent),this._textareaElement.removeEventListener("blur",this._handleFocusEvent),this._destroyed.next(),this._destroyed.complete()}_cacheTextareaLineHeight(){if(this._cachedLineHeight)return;let e=this._textareaElement.cloneNode(!1);e.rows=1,e.style.position="absolute",e.style.visibility="hidden",e.style.border="none",e.style.padding="0",e.style.height="",e.style.minHeight="",e.style.maxHeight="",e.style.overflow="hidden",this._textareaElement.parentNode.appendChild(e),this._cachedLineHeight=e.clientHeight,e.remove(),this._setMinHeight(),this._setMaxHeight()}_measureScrollHeight(){const e=this._textareaElement,t=e.style.marginBottom||"",n=this._platform.FIREFOX,r=n&&this._hasFocus,o=n?"cdk-textarea-autosize-measuring-firefox":"cdk-textarea-autosize-measuring";r&&(e.style.marginBottom=`${e.clientHeight}px`),e.classList.add(o);const a=e.scrollHeight-4;return e.classList.remove(o),r&&(e.style.marginBottom=t),a}_cacheTextareaPlaceholderHeight(){if(!this._isViewInited||null!=this._cachedPlaceholderHeight)return;if(!this.placeholder)return void(this._cachedPlaceholderHeight=0);const e=this._textareaElement.value;this._textareaElement.value=this._textareaElement.placeholder,this._cachedPlaceholderHeight=this._measureScrollHeight(),this._textareaElement.value=e}ngDoCheck(){this._platform.isBrowser&&this.resizeToFitContent()}resizeToFitContent(e=!1){if(!this._enabled)return;if(this._cacheTextareaLineHeight(),this._cacheTextareaPlaceholderHeight(),!this._cachedLineHeight)return;const t=this._elementRef.nativeElement,n=t.value;if(!e&&this._minRows===this._previousMinRows&&n===this._previousValue)return;const r=this._measureScrollHeight(),o=Math.max(r,this._cachedPlaceholderHeight||0);t.style.height=`${o}px`,this._ngZone.runOutsideAngular((()=>{"undefined"!=typeof requestAnimationFrame?requestAnimationFrame((()=>this._scrollToCaretPosition(t))):setTimeout((()=>this._scrollToCaretPosition(t)))})),this._previousValue=n,this._previousMinRows=this._minRows}reset(){void 0!==this._initialHeight&&(this._textareaElement.style.height=this._initialHeight)}_noopInputHandler(){}_getDocument(){return this._document||document}_getWindow(){return this._getDocument().defaultView||window}_scrollToCaretPosition(e){const{selectionStart:t,selectionEnd:n}=e;!this._destroyed.isStopped&&this._hasFocus&&e.setSelectionRange(t,n)}}Dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Dr,deps:[{token:t.ElementRef},{token:pt.Platform},{token:t.NgZone},{token:j,optional:!0}],target:t.ɵɵFactoryTarget.Directive}),Dr.ɵdir=t.ɵɵngDeclareDirective({minVersion:"14.0.0",version:"15.2.0-rc.0",type:Dr,selector:"textarea[cdkTextareaAutosize]",inputs:{minRows:["cdkAutosizeMinRows","minRows"],maxRows:["cdkAutosizeMaxRows","maxRows"],enabled:["cdkTextareaAutosize","enabled"],placeholder:"placeholder"},host:{attributes:{rows:"1"},listeners:{input:"_noopInputHandler()"},classAttribute:"cdk-textarea-autosize"},exportAs:["cdkTextareaAutosize"],ngImport:t}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Dr,decorators:[{type:s,args:[{selector:"textarea[cdkTextareaAutosize]",exportAs:"cdkTextareaAutosize",host:{class:"cdk-textarea-autosize",rows:"1","(input)":"_noopInputHandler()"}}]}],ctorParameters:function(){return[{type:t.ElementRef},{type:pt.Platform},{type:t.NgZone},{type:void 0,decorators:[{type:i},{type:a,args:[j]}]}]},propDecorators:{minRows:[{type:m,args:["cdkAutosizeMinRows"]}],maxRows:[{type:m,args:["cdkAutosizeMaxRows"]}],enabled:[{type:m,args:["cdkTextareaAutosize"]}],placeholder:[{type:m}]}}); - /** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - class Vr{}Vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Vr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Vr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.0-rc.0",ngImport:t,type:Vr,declarations:[wr,Dr],exports:[wr,Dr]}),Vr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Vr}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Vr,decorators:[{type:d,args:[{declarations:[wr,Dr],exports:[wr,Dr]}]}]});class Pr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",description:"tb.mail-body-type.plain-text-description",value:"false"},{name:"tb.mail-body-type.html",description:"tb.mail-body-type.html-text-description",value:"true"},{name:"tb.mail-body-type.use-body-type-template",description:"tb.mail-body-type.dynamic-text-description",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[O.required]],toTemplate:[e?e.toTemplate:null,[O.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[O.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null,[O.required]],bodyTemplate:[e?e.bodyTemplate:null,[O.required]]})}prepareInputConfig(e){return{fromTemplate:fe(e?.fromTemplate)?e.fromTemplate:null,toTemplate:fe(e?.toTemplate)?e.toTemplate:null,ccTemplate:fe(e?.ccTemplate)?e.ccTemplate:null,bccTemplate:fe(e?.bccTemplate)?e.bccTemplate:null,subjectTemplate:fe(e?.subjectTemplate)?e.subjectTemplate:null,mailBodyType:fe(e?.mailBodyType)?e.mailBodyType:null,isHtmlTemplate:fe(e?.isHtmlTemplate)?e.isHtmlTemplate:null,bodyTemplate:fe(e?.bodyTemplate)?e.bodyTemplate:null}}updateValidators(e){"dynamic"===this.toEmailConfigForm.get("mailBodyType").value?this.toEmailConfigForm.get("isHtmlTemplate").enable({emitEvent:!1}):this.toEmailConfigForm.get("isHtmlTemplate").disable({emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["mailBodyType"]}getBodyTypeName(){return this.mailBodyTypes.find((e=>e.value===this.toEmailConfigForm.get("mailBodyType").value)).name}}e("ToEmailConfigComponent",Pr),Pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Pr,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Pr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="toEmailConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.email-sender</div>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.from-template</mat-label>\n <input required matInput formControlName="fromTemplate">\n <mat-hint align="start">\n {{ \'tb.rulenode.email-from-template-hint\' | translate }}\n </mat-hint>\n <mat-hint align="end">\n <div class="input-bottom-double-hint">\n <div class="see-example"\n hintMode\n tb-help-popup="{{\'rulenode/to_email_node_fields_templatization\'}}"\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px;"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}"></div>\n </div>\n </mat-hint>\n <mat-error *ngIf="toEmailConfigForm.get(\'fromTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.from-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel-title" translate>tb.rulenode.recipients</div>\n <tb-example-hint [hintText]="\'tb.rulenode.recipients-block-main-hint\' | translate"\n popupHelpLink="rulenode/to_email_node_fields_templatization">\n </tb-example-hint>\n </div>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.to-template</mat-label>\n <textarea required\n matInput\n class="tb-enable-vertical-resize"\n formControlName="toTemplate"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'toTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.to-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.cc-template</mat-label>\n <textarea matInput\n formControlName="ccTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.bcc-template</mat-label>\n <textarea matInput\n formControlName="bccTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n </mat-form-field>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.message-subject-and-content</div>\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\' | translate"\n popupHelpLink="rulenode/to_email_node_fields_templatization">\n </tb-example-hint>\n <section>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.subject-template</mat-label>\n <textarea required\n matInput\n formControlName="subjectTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'subjectTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.subject-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.mail-body-type</mat-label>\n <mat-select formControlName="mailBodyType">\n <mat-select-trigger>\n <span *ngIf="toEmailConfigForm.get(\'mailBodyType\').value">\n {{ getBodyTypeName() | translate }}\n </span>\n </mat-select-trigger>\n <mat-option *ngFor="let type of mailBodyTypes" [value]="type.value">\n <span matListItemTitle>\n {{ type.name | translate }}\n </span>\n <br>\n <small matListItemMeta style="color: inherit">\n {{ type.description | translate }}\n </small>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" *ngIf="toEmailConfigForm.get(\'mailBodyType\').value === \'dynamic\'">\n <mat-label translate>tb.rulenode.body-type-template</mat-label>\n <input required matInput formControlName="isHtmlTemplate">\n <mat-hint translate>tb.mail-body-type.after-template-evaluation-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.body-template</mat-label>\n <textarea required\n matInput\n formControlName="bodyTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'bodyTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.body-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n </div>\n</section>\n',styles:[":host .input-bottom-double-hint{display:inline-flex}:host .input-bottom-double-hint .see-example{flex-shrink:0;padding-right:16px}:host textarea.tb-enable-vertical-resize{resize:vertical}\n"],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.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","hintMode"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Dr,selector:"textarea[cdkTextareaAutosize]",inputs:["cdkAutosizeMinRows","cdkAutosizeMaxRows","cdkTextareaAutosize","placeholder"],exportAs:["cdkTextareaAutosize"]},{kind:"component",type:te.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:te.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:ne.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Pe.MatListItemTitle,selector:"[matListItemTitle]"},{kind:"directive",type:Pe.MatListItemMeta,selector:"[matListItemMeta]"},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Pr,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'<section [formGroup]="toEmailConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.email-sender</div>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.from-template</mat-label>\n <input required matInput formControlName="fromTemplate">\n <mat-hint align="start">\n {{ \'tb.rulenode.email-from-template-hint\' | translate }}\n </mat-hint>\n <mat-hint align="end">\n <div class="input-bottom-double-hint">\n <div class="see-example"\n hintMode\n tb-help-popup="{{\'rulenode/to_email_node_fields_templatization\'}}"\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px;"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}"></div>\n </div>\n </mat-hint>\n <mat-error *ngIf="toEmailConfigForm.get(\'fromTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.from-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel-title" translate>tb.rulenode.recipients</div>\n <tb-example-hint [hintText]="\'tb.rulenode.recipients-block-main-hint\' | translate"\n popupHelpLink="rulenode/to_email_node_fields_templatization">\n </tb-example-hint>\n </div>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.to-template</mat-label>\n <textarea required\n matInput\n class="tb-enable-vertical-resize"\n formControlName="toTemplate"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'toTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.to-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.cc-template</mat-label>\n <textarea matInput\n formControlName="ccTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.bcc-template</mat-label>\n <textarea matInput\n formControlName="bccTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n </mat-form-field>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.message-subject-and-content</div>\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\' | translate"\n popupHelpLink="rulenode/to_email_node_fields_templatization">\n </tb-example-hint>\n <section>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.subject-template</mat-label>\n <textarea required\n matInput\n formControlName="subjectTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'subjectTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.subject-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.mail-body-type</mat-label>\n <mat-select formControlName="mailBodyType">\n <mat-select-trigger>\n <span *ngIf="toEmailConfigForm.get(\'mailBodyType\').value">\n {{ getBodyTypeName() | translate }}\n </span>\n </mat-select-trigger>\n <mat-option *ngFor="let type of mailBodyTypes" [value]="type.value">\n <span matListItemTitle>\n {{ type.name | translate }}\n </span>\n <br>\n <small matListItemMeta style="color: inherit">\n {{ type.description | translate }}\n </small>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" *ngIf="toEmailConfigForm.get(\'mailBodyType\').value === \'dynamic\'">\n <mat-label translate>tb.rulenode.body-type-template</mat-label>\n <input required matInput formControlName="isHtmlTemplate">\n <mat-hint translate>tb.mail-body-type.after-template-evaluation-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.body-template</mat-label>\n <textarea required\n matInput\n formControlName="bodyTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'bodyTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.body-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n </div>\n</section>\n',styles:[":host .input-bottom-double-hint{display:inline-flex}:host .input-bottom-double-hint .see-example{flex-shrink:0;padding-right:16px}:host textarea.tb-enable-vertical-resize{resize:vertical}\n"]}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class Rr extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.copyFrom=[],this.translation=sn;for(const e of this.translation.keys())this.copyFrom.push({value:e,name:this.translate.instant(this.translation.get(e))})}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({copyFrom:[e.copyFrom,[O.required]],keys:[e?e.keys:null,[O.required]]})}configForm(){return this.copyKeysConfigForm}prepareInputConfig(e){let t;return t=fe(e?.fromMetadata)?e.copyFrom?ln.METADATA:ln.DATA:fe(e?.copyFrom)?e.copyFrom:ln.DATA,{keys:fe(e?.keys)?e.keys:null,copyFrom:t}}}e("CopyKeysConfigComponent",Rr),Rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Rr,deps:[{token:P.Store},{token:R.FormBuilder},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Rr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="copyKeysConfigForm" class="tb-form-panel no-padding no-border">\n <tb-msg-metadata-chip\n [labelText]="(\'tb.key-val.copy-key-values-from\' | translate)"\n [translation]="translation"\n formControlName="copyFrom">\n </tb-msg-metadata-chip>\n <tb-string-items-list class="mat-block"\n required\n [label]="\'tb.rulenode.keys\' | translate"\n [placeholder]="\'tb.rulenode.add-key\' | translate"\n [requiredText]="\'tb.key-val.at-least-one-key-error\' | translate"\n formControlName="keys">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.use-regular-expression-hint\' | translate }}">\n help\n </mat-icon>\n </tb-string-items-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:et.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'<section [formGroup]="copyKeysConfigForm" class="tb-form-panel no-padding no-border">\n <tb-msg-metadata-chip\n [labelText]="(\'tb.key-val.copy-key-values-from\' | translate)"\n [translation]="translation"\n formControlName="copyFrom">\n </tb-msg-metadata-chip>\n <tb-string-items-list class="mat-block"\n required\n [label]="\'tb.rulenode.keys\' | translate"\n [placeholder]="\'tb.rulenode.add-key\' | translate"\n [requiredText]="\'tb.key-val.at-least-one-key-error\' | translate"\n formControlName="keys">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.use-regular-expression-hint\' | translate }}">\n help\n </mat-icon>\n </tb-string-items-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder},{type:Z.TranslateService}]}});class Or extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.renameIn=[],this.translation=pn;for(const e of this.translation.keys())this.renameIn.push({value:e,name:this.translate.instant(this.translation.get(e))})}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({renameIn:[e?e.renameIn:null,[O.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[O.required]]})}prepareInputConfig(e){let t;return t=fe(e?.fromMetadata)?e.fromMetadata?ln.METADATA:ln.DATA:fe(e?.renameIn)?e?.renameIn:ln.DATA,{renameKeysMapping:fe(e?.renameKeysMapping)?e.renameKeysMapping:null,renameIn:t}}}e("RenameKeysConfigComponent",Or),Or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Or,deps:[{token:P.Store},{token:R.FormBuilder},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Or,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="renameKeysConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.rename-keys-in</div>\n <div class="fx-centered">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="renameIn" appearance="fill">\n <tb-toggle-option *ngFor="let data of renameIn" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n labelText="{{ translation.get(renameKeysConfigForm.get(\'renameIn\').value) | translate }} {{\'tb.rulenode.keys-mapping\' | translate}}"\n formControlName="renameKeysMapping"\n uniqueKeyValuePairValidator\n requiredText="{{\'tb.rulenode.attr-mapping-required\' | translate}}"\n keyText="{{\'tb.rulenode.current-key-name\' | translate}}"\n keyRequiredText="{{\'tb.rulenode.key-name-required\' | translate}}"\n valText="{{\'tb.rulenode.new-key-name\' | translate}}"\n valRequiredText="{{\'tb.rulenode.new-key-name-required\' | translate}}">\n </tb-kv-map-config>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}:host .fx-centered{display:flex;width:100%;justify-content:space-around}\n"],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Ae.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Me.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:Pn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Or,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'<section [formGroup]="renameKeysConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.rename-keys-in</div>\n <div class="fx-centered">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="renameIn" appearance="fill">\n <tb-toggle-option *ngFor="let data of renameIn" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n labelText="{{ translation.get(renameKeysConfigForm.get(\'renameIn\').value) | translate }} {{\'tb.rulenode.keys-mapping\' | translate}}"\n formControlName="renameKeysMapping"\n uniqueKeyValuePairValidator\n requiredText="{{\'tb.rulenode.attr-mapping-required\' | translate}}"\n keyText="{{\'tb.rulenode.current-key-name\' | translate}}"\n keyRequiredText="{{\'tb.rulenode.key-name-required\' | translate}}"\n valText="{{\'tb.rulenode.new-key-name\' | translate}}"\n valRequiredText="{{\'tb.rulenode.new-key-name-required\' | translate}}">\n </tb-kv-map-config>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}:host .fx-centered{display:flex;width:100%;justify-content:space-around}\n"]}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder},{type:Z.TranslateService}]}});class _r extends g{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,[O.required]]})}}e("NodeJsonPathConfigComponent",_r),_r.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:_r,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),_r.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:_r,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"<section [formGroup]=\"jsonPathConfigForm\">\n <mat-form-field subscriptSizing=\"dynamic\" class=\"mat-block\">\n <mat-label>{{ 'tb.rulenode.json-path-expression' | translate }}</mat-label>\n <input matInput formControlName=\"jsonPath\" required/>\n <mat-hint>{{ 'tb.rulenode.json-path-expression-hint' | translate }}</mat-hint>\n <mat-error *ngIf=\"jsonPathConfigForm.get('jsonPath').hasError('required')\">{{ 'tb.rulenode.json-path-expression-required' | translate }}</mat-error>\n </mat-form-field>\n</section>\n",dependencies:[{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:_r,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"<section [formGroup]=\"jsonPathConfigForm\">\n <mat-form-field subscriptSizing=\"dynamic\" class=\"mat-block\">\n <mat-label>{{ 'tb.rulenode.json-path-expression' | translate }}</mat-label>\n <input matInput formControlName=\"jsonPath\" required/>\n <mat-hint>{{ 'tb.rulenode.json-path-expression-hint' | translate }}</mat-hint>\n <mat-error *ngIf=\"jsonPathConfigForm.get('jsonPath').hasError('required')\">{{ 'tb.rulenode.json-path-expression-required' | translate }}</mat-error>\n </mat-form-field>\n</section>\n"}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class Br extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.deleteFrom=[],this.translation=mn;for(const e of this.translation.keys())this.deleteFrom.push({value:e,name:this.translate.instant(this.translation.get(e))})}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({deleteFrom:[e.deleteFrom,[O.required]],keys:[e?e.keys:null,[O.required]]})}prepareInputConfig(e){let t;return t=fe(e?.fromMetadata)?e.fromMetadata?ln.METADATA:ln.DATA:fe(e?.deleteFrom)?e?.deleteFrom:ln.DATA,{keys:fe(e?.keys)?e.keys:null,deleteFrom:t}}configForm(){return this.deleteKeysConfigForm}}e("DeleteKeysConfigComponent",Br),Br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Br,deps:[{token:P.Store},{token:R.FormBuilder},{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Br,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deleteKeysConfigForm" class="tb-form-panel no-border no-padding">\n <tb-msg-metadata-chip\n [labelText]="(\'tb.key-val.delete-key-values-from\' | translate)"\n formControlName="deleteFrom">\n </tb-msg-metadata-chip>\n <tb-string-items-list class="mat-block"\n required\n [label]="\'tb.rulenode.keys\' | translate"\n [placeholder]="\'tb.rulenode.add-key\' | translate"\n [requiredText]="\'tb.key-val.at-least-one-key-error\' | translate"\n formControlName="keys">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.use-regular-expression-delete-hint\' | translate }}">\n help\n </mat-icon>\n </tb-string-items-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:et.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Br,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'<section [formGroup]="deleteKeysConfigForm" class="tb-form-panel no-border no-padding">\n <tb-msg-metadata-chip\n [labelText]="(\'tb.key-val.delete-key-values-from\' | translate)"\n formControlName="deleteFrom">\n </tb-msg-metadata-chip>\n <tb-string-items-list class="mat-block"\n required\n [label]="\'tb.rulenode.keys\' | translate"\n [placeholder]="\'tb.rulenode.add-key\' | translate"\n [requiredText]="\'tb.key-val.at-least-one-key-error\' | translate"\n formControlName="keys">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.use-regular-expression-delete-hint\' | translate }}">\n help\n </mat-icon>\n </tb-string-items-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder},{type:Z.TranslateService}]}});class Kr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.deduplicationStrategie=Ot,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=_t}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[fe(e?.interval)?e.interval:null,[O.required,O.min(1)]],strategy:[fe(e?.strategy)?e.strategy:null,[O.required]],outMsgType:[fe(e?.outMsgType)?e.outMsgType:null,[O.required]],maxPendingMsgs:[fe(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[O.required,O.min(1),O.max(1e3)]],maxRetries:[fe(e?.maxRetries)?e.maxRetries:null,[O.required,O.min(0),O.max(100)]]})}prepareInputConfig(e){return e||(e={}),e.outMsgType||(e.outMsgType="POST_TELEMETRY_REQUEST"),super.prepareInputConfig(e)}updateValidators(e){this.deduplicationConfigForm.get("strategy").value===this.deduplicationStrategie.ALL?this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}):this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("outMsgType").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["strategy"]}}e("DeduplicationConfigComponent",Kr),Kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Kr,deps:[{token:P.Store},{token:R.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Kr,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deduplicationConfigForm">\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.interval\' | translate}}</mat-label>\n <input type=\'number\' required matInput formControlName="interval">\n <mat-error *ngIf="deduplicationConfigForm.get(\'interval\').hasError(\'required\')">\n {{\'tb.rulenode.interval-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'interval\').hasError(\'min\')">\n {{\'tb.rulenode.interval-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.interval-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <div class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.strategy</div>\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="strategy" appearance="fill">\n <tb-toggle-option *ngFor="let strategy of deduplicationStrategies" [value]="strategy">\n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-all-hint\' | translate"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'ALL\'">\n </tb-example-hint>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-first-hint\' | translate"\n textAlign="\'center\'"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'FIRST\'">\n </tb-example-hint>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-last-hint\' | translate"\n textAlign="\'center\'"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'LAST\'">\n </tb-example-hint>\n <div *ngIf="deduplicationConfigForm.get(\'strategy\').value === deduplicationStrategie.ALL">\n <tb-output-message-type-autocomplete\n required\n formControlName="outMsgType">\n </tb-output-message-type-autocomplete>\n </div>\n </div>\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{\'tb.rulenode.max-pending-msgs\' | translate}}</mat-label>\n <input type = \'number\' required matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{\'tb.rulenode.max-pending-msgs-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{\'tb.rulenode.max-pending-msgs-max-error\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{\'tb.rulenode.max-pending-msgs-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.max-pending-msgs-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{\'tb.rulenode.max-retries\' | translate}}</mat-label>\n <input type = \'number\' required matInput formControlName="maxRetries">\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'required\')">\n {{\'tb.rulenode.max-retries-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'max\')">\n {{\'tb.rulenode.max-retries-max-error\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'min\')">\n {{\'tb.rulenode.max-retries-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.max-retries-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n </div>\n </mat-expansion-panel>\n </section>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:U.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:U.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:J.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Q.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Q.MatLabel,selector:"mat-label"},{kind:"directive",type:Q.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Q.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:re.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:oe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:oe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:oe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:R.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:R.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:Z.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Ae.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Me.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:Kn,selector:"tb-output-message-type-autocomplete",inputs:["subscriptSizing","disabled","required"]},{kind:"component",type:xt,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Kr,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:'<section [formGroup]="deduplicationConfigForm">\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.interval\' | translate}}</mat-label>\n <input type=\'number\' required matInput formControlName="interval">\n <mat-error *ngIf="deduplicationConfigForm.get(\'interval\').hasError(\'required\')">\n {{\'tb.rulenode.interval-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'interval\').hasError(\'min\')">\n {{\'tb.rulenode.interval-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.interval-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <div class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.strategy</div>\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="strategy" appearance="fill">\n <tb-toggle-option *ngFor="let strategy of deduplicationStrategies" [value]="strategy">\n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-all-hint\' | translate"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'ALL\'">\n </tb-example-hint>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-first-hint\' | translate"\n textAlign="\'center\'"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'FIRST\'">\n </tb-example-hint>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-last-hint\' | translate"\n textAlign="\'center\'"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'LAST\'">\n </tb-example-hint>\n <div *ngIf="deduplicationConfigForm.get(\'strategy\').value === deduplicationStrategie.ALL">\n <tb-output-message-type-autocomplete\n required\n formControlName="outMsgType">\n </tb-output-message-type-autocomplete>\n </div>\n </div>\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{\'tb.rulenode.max-pending-msgs\' | translate}}</mat-label>\n <input type = \'number\' required matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{\'tb.rulenode.max-pending-msgs-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{\'tb.rulenode.max-pending-msgs-max-error\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{\'tb.rulenode.max-pending-msgs-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.max-pending-msgs-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{\'tb.rulenode.max-retries\' | translate}}</mat-label>\n <input type = \'number\' required matInput formControlName="maxRetries">\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'required\')">\n {{\'tb.rulenode.max-retries-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'max\')">\n {{\'tb.rulenode.max-retries-max-error\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'min\')">\n {{\'tb.rulenode.max-retries-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.max-retries-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n </div>\n </mat-expansion-panel>\n </section>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:P.Store},{type:R.FormBuilder}]}});class zr{}e("RulenodeCoreConfigTransformModule",zr),zr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:zr,declarations:[Ar,Mr,Pr,Rr,Or,_r,Br,Kr],imports:[$,M,Jn],exports:[Ar,Mr,Pr,Rr,Or,_r,Br,Kr]}),zr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zr,imports:[$,M,Jn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zr,decorators:[{type:d,args:[{declarations:[Ar,Mr,Pr,Rr,Or,_r,Br,Kr],imports:[$,M,Jn],exports:[Ar,Mr,Pr,Rr,Or,_r,Br,Kr]}]}]});class Hr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=C}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({forwardMsgToDefaultRuleChain:[!!e&&e?.forwardMsgToDefaultRuleChain,[]],ruleChainId:[e?e.ruleChainId:null,[O.required]]})}}e("RuleChainInputComponent",Hr),Hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Hr,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Hr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="ruleChainInputConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.forward-msg-default-rule-chain-tooltip\' | translate }}"\n class="tb-form-row no-border">\n <mat-slide-toggle class="mat-slide" formControlName="forwardMsgToDefaultRuleChain">\n {{ \'tb.rulenode.forward-msg-default-rule-chain\' | translate }}\n </mat-slide-toggle>\n </div>\n <tb-entity-autocomplete required\n [excludeEntityIds]="[ruleChainId]"\n [entityType]="entityType.RULE_CHAIN"\n [entitySubtype]="ruleChainType"\n formControlName="ruleChainId">\n </tb-entity-autocomplete>\n </div>\n</section>\n',dependencies:[{kind:"component",type:lt.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:Y.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:R.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:pe.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Hr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'<section [formGroup]="ruleChainInputConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.forward-msg-default-rule-chain-tooltip\' | translate }}"\n class="tb-form-row no-border">\n <mat-slide-toggle class="mat-slide" formControlName="forwardMsgToDefaultRuleChain">\n {{ \'tb.rulenode.forward-msg-default-rule-chain\' | translate }}\n </mat-slide-toggle>\n </div>\n <tb-entity-autocomplete required\n [excludeEntityIds]="[ruleChainId]"\n [entityType]="entityType.RULE_CHAIN"\n [entitySubtype]="ruleChainType"\n formControlName="ruleChainId">\n </tb-entity-autocomplete>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class Ur extends g{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.10",ngImport:t,type:Ur,deps:[{token:P.Store},{token:R.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ur,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="ruleChainOutputConfigForm" fxLayout="column">\n <div innerHTML="{{ \'tb.rulenode.output-node-name-hint\' | translate }}"></div>\n</section>\n',dependencies:[{kind:"directive",type:W.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:R.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:R.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:Z.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ur,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'<section [formGroup]="ruleChainOutputConfigForm" fxLayout="column">\n <div innerHTML="{{ \'tb.rulenode.output-node-name-hint\' | translate }}"></div>\n</section>\n'}]}],ctorParameters:function(){return[{type:P.Store},{type:R.UntypedFormBuilder}]}});class jr{}e("RuleNodeCoreConfigFlowModule",jr),jr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:jr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),jr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:jr,declarations:[Hr,Ur],imports:[$,M,Jn],exports:[Hr,Ur]}),jr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:jr,imports:[$,M,Jn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:jr,decorators:[{type:d,args:[{declarations:[Hr,Ur],imports:[$,M,Jn],exports:[Hr,Ur]}]}]});class $r{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{id:"Id","additional-info":"Additional Info","advanced-settings":"Advanced settings","create-entity-if-not-exists":"Create new entity if it doesn't exist","create-entity-if-not-exists-hint":"If enabled, a new entity with specified parameters will be created unless it already exists. Existing entities will be used as is for relation.","select-device-connectivity-event":"Select device connectivity event","entity-name-pattern":"Name pattern","device-name-pattern":"Device name","asset-name-pattern":"Asset name","entity-view-name-pattern":"Entity view name","customer-title-pattern":"Customer title","dashboard-name-pattern":"Dashboard title","user-name-pattern":"User email","edge-name-pattern":"Edge name","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","copy-message-type":"Copy message type","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","message-type-value":"Message type value","message-type-value-required":"Message type value is required","message-type-value-max-length":"Message type value should be less than 256","output-message-type":"Output message type","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 title","customer-name-pattern-required":"Customer title is required","customer-name-pattern-hint":"Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","create-customer-if-not-exists":"Create new customer if it doesn't exist","unassign-from-customer":"Unassign from specific customer if originator is dashboard","unassign-from-customer-tooltip":"Only dashboards can be assigned to multiple customers at once. \nIf the message originator is a dashboard, you need to explicitly specify the customer's title to unassign from.","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":"Allowing range from 1 to 2147483647.","start-interval-value-required":"Interval start is required.","end-interval-value-required":"Interval end is required.",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","add-message-type":"Add message type","select-message-types-required":"At least one message type should be selected.","select-message-types":"Select message types","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","attributes-scope":"Attributes scope","attributes-scope-value":"Attributes scope value","attributes-scope-value-copy":"Copy attributes scope value","attributes-scope-hint":"Use the 'scope' metadata key to dynamically set the attribute scope per message. If provided, this overrides the scope set in the configuration.","notify-device":"Force notification to the 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.","update-attributes-only-on-value-change":"Save attributes only if the value changes","update-attributes-only-on-value-change-hint":"Updates the attributes on every incoming message disregarding if their value has changed. Increases API usage and reduces performance.","update-attributes-only-on-value-change-hint-enabled":"Updates the attributes only if their value has changed. If the value is not changed, no update to the attribute timestamp nor attribute change notification will be sent.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-on-update-hint":"If enabled, force notification to the device about shared attributes update. If disabled, the notification behavior is controlled by the 'notifyDevice' parameter from the incoming message metadata. To turn off the notification, the message metadata must contain the 'notifyDevice' parameter set to 'false'. Any other case will trigger the notification to the device.","notify-device-on-delete-hint":"If enabled, force notification to the device about shared attributes removal. If disabled, the notification behavior is controlled by the 'notifyDevice' parameter from the incoming message metadata. To turn on the notification, the message metadata must contain the 'notifyDevice' parameter set to 'true'. In any other case, the notification will not be triggered to the device.","latest-timeseries":"Latest time series data keys","timeseries-keys":"Time series keys","timeseries-keys-required":"At least one time series key should be selected.","add-timeseries-key":"Add time series key","add-message-field":"Add message field","relation-search-parameters":"Relation search parameters","relation-parameters":"Relation parameters","add-metadata-field":"Add metadata field","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":"Use regular expression to copy keys by pattern.\n\nTips & tricks:\nPress 'Enter' to complete field name input.\nPress 'Backspace' to delete field name. Multiple field names supported.",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","current-key-name":"Current 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":"Value 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.\n\nTips & tricks:\nPress 'Enter' to complete field name input.\nPress 'Backspace' to delete field name.\nMultiple field names supported.","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","relations-query-config-direction-suffix":"originator","profile-name":"Profile name","fetch-circle-parameter-info-from-metadata-hint":'Metadata field \'{{perimeterKeyName}}\' should be defined in next format: {"latitude":48.196, "longitude":24.6532, "radius":100.0, "radiusUnit":"METER"}',"fetch-poligon-parameter-info-from-metadata-hint":"Metadata field '{{perimeterKeyName}}' should be defined in next format: [[48.19736,24.65235],[48.19800,24.65060],...,[48.19849,24.65420]]","short-templatization-tooltip":"Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","fields-mapping-required":"At least one field mapping should be specified.","at-least-one-field-required":"At least one input field must have a value(s) provided.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","new-originator":"New originator","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related entity","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity by name pattern","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","default-ttl-hint":"Rule node will fetch Time-to-Live (TTL) value from the message metadata. If no value is present, it defaults to the TTL specified in the configuration. If the value is set to 0, the TTL from the tenant profile configuration will be applied.","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","select-entity-types":"Select entity types","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","from-template-required":"From is required","message-to-metadata":"Message to metadata","metadata-to-message":"Metadata to message","from-message":"From message","from-metadata":"From metadata","to-template":"To","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> for value from message body',"cc-template":"Cc","bcc-template":"Bcc","subject-template":"Subject","subject-template-required":"Subject Template is required","body-template":"Body","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","body-type-template":"Body type template","reply-routing-configuration":"Reply Routing Configuration","reply-routing-configuration-hint":"These configuration parameters specify the metadata key names used to identify the service and request for sending a reply back.","request-id-metadata-attribute":"Request Id","service-id-metadata-attribute":"Service Id","session-id-metadata-attribute":"Session Id","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","parse-to-plain-text":"Parse to plain text","parse-to-plain-text-hint":'If selected, request body message payload will be transformed from JSON string to plain text, e.g. msg = "Hello,\\t\\"world\\"" will be parsed to Hello, "world"',"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 <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> 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":"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 <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> 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":'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":'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 and ${metadataKey} to extract value from the 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-to-specific-entity-tooltip":"If enabled, checks the presence of relation with a specific entity otherwise, checks the presence of relation with any entity. In both cases, relation lookup is based on configured direction and type.","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-with-specific-entity":"Delete relation with specific entity","delete-relation-with-specific-entity-hint":"If enabled, will delete the relation with just one specific entity. Otherwise, the relation will be removed with all matching entities.","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 <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> 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 time series key prefix","output-timeseries-key-prefix-required":"Output time series key prefix required.","separator-hint":'Press "Enter" to complete field input.',"select-details":"Select 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","email-sender":"Email sender","fields-to-check":"Fields to check","add-detail":"Add detail","check-all-keys-tooltip":"If enabled, checks the presence of all fields listed in the message and metadata field names within the incoming message and its metadata.","fields-to-check-hint":'Press "Enter" to complete field name input. Multiple field names supported.',"entity-details-list-empty":"At least one detail should be selected.","alarm-status":"Alarm status","alarm-required":"At least one alarm status should be 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-field-name":"Latitude field name","longitude-field-name":"Longitude field name","latitude-field-name-required":"Latitude field name is required.","longitude-field-name-required":"Longitude field name is required.","fetch-perimeter-info-from-metadata":"Fetch perimeter information from metadata","fetch-perimeter-info-from-metadata-tooltip":"If perimeter type is set to 'Polygon' the value of metadata field '{{perimeterKeyName}}' will be set as perimeter definition without additional parsing of the value. Otherwise, if perimeter type is set to 'Circle' the value of '{{perimeterKeyName}}' metadata field will be parsed to extract 'latitude', 'longitude', 'radius', 'radiusUnit' fields that uses for circle perimeter definition.","perimeter-key-name":"Perimeter key name","perimeter-key-name-hint":"Metadata field name that includes perimeter information.","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-units-required":"Range units is required.",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"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": "&#123;"ts":1574329385897, "value":42&#125;"',"ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","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.","device-profile-node-hint":"Useful if you have duration or repeating conditions to ensure continuity of alarm state evaluation.","persist-alarm-rules":"Persist state of alarm rules","persist-alarm-rules-hint":"If enabled, the rule node will store the state of processing to the database.","fetch-alarm-rules":"Fetch state of alarm rules","fetch-alarm-rules-hint":"If enabled, the rule node will restore the state of processing on initialization and ensure that alarms are raised even after server restarts. Otherwise, the state will be restored when the first message from the device arrives.","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-caching":"Use caching","use-caching-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":'Use <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The <b>rule node name</b> corresponds to the <b>relation type</b> 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","skip-latest-persistence-hint":"Rule node will not update values for incoming keys for the latest time series data. Useful for highly loaded use-cases to decrease the pressure on the DB.","use-server-ts":"Use server ts","use-server-ts-hint":"Rule node will use the timestamp of 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 and ${metadataKey} to extract value from the metadata.","kv-map-single-pattern-hint":"Input field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the 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","message-metadata-type":"Metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-source-field-input":"Source","argument-source-field-input-required":"Argument source 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","add-entity-type":"Add entity type","add-device-profile":"Add device profile","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Use <i>0</i> to convert result to integer","add-to-message-field-input":"Add to message","add-to-metadata-field-input":"Add to metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Specify a mathematical expression to evaluate. Default expression demonstrates how to transform Fahrenheit to Celsius","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-types":"Clear selected types","clear-selected-details":"Clear selected details","clear-selected-fields":"Clear selected fields","clear-selected-keys":"Clear selected keys","geofence-configuration":"Geofence configuration","coordinate-field-names":"Coordinate field names","coordinate-field-hint":"Rule node tries to retrieve the specified fields from the message. If they are not present, it will look them up in the metadata.","presence-monitoring-strategy":"Presence monitoring strategy","presence-monitoring-strategy-on-first-message":"On first message","presence-monitoring-strategy-on-each-message":"On each message","presence-monitoring-strategy-on-first-message-hint":"Reports presence status 'Inside' or 'Outside' on the first message after the configured minimal duration has passed since previous presence status 'Entered' or 'Left' update.","presence-monitoring-strategy-on-each-message-hint":"Reports presence status 'Inside' or 'Outside' on each message after presence status 'Entered' or 'Left' update.","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 metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell failure if any of the attributes are missing","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time","chip-help":"Press 'Enter' to complete {{inputName}} input. \nPress 'Backspace' to delete {{inputName}}. \nMultiple values supported.",detail:"detail","field-name":"field name","device-profile":"device profile","entity-type":"entity type","message-type":"message type","timeseries-key":"time series key",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 metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch time series from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch time series 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 metadata 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","map-fields-required":"All mapping fields are required.",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","keys-mapping":"keys mapping","add-key":"Add key",recipients:"Recipients","message-subject-and-content":"Message subject and content","template-rules-hint":"Both input fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the message metadata.","originator-customer-desc":"Use customer of incoming message originator as new originator.","originator-tenant-desc":"Use current tenant as new originator.","originator-related-entity-desc":"Use related entity as new originator. Lookup based on configured relation type and direction.","originator-alarm-originator-desc":"Use alarm originator as new originator. Only if incoming message originator is alarm entity.","originator-entity-by-name-pattern-desc":"Use entity fetched from DB as new originator. Lookup based on entity type and specified name pattern.","email-from-template-hint":"Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","recipients-block-main-hint":"Comma-separated address list. All input fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","forward-msg-default-rule-chain":"Forward message to the originator's default rule chain","forward-msg-default-rule-chain-tooltip":"If enabled, message will be forwarded to the originator's default rule chain, or rule chain from configuration, if originator has no default rule chain defined in the entity profile.","exclude-zero-deltas":"Exclude zero deltas from outbound message","exclude-zero-deltas-hint":'If enabled, the "{{outputValueKey}}" output key will be added to the outbound message if its value is not zero.',"exclude-zero-deltas-time-difference-hint":'If enabled, the "{{outputValueKey}}" and "{{periodValueKey}}" output keys will be added to the outbound message only if the "{{outputValueKey}}" value is not zero.',"search-direction-from":"From originator to target entity","search-direction-to":"From target entity to originator","del-relation-direction-from":"From originator","del-relation-direction-to":"To originator","target-entity":"Target entity","function-configuration":"Function configuration","function-name":"Function name","function-name-required":"Function name is required.",qualifier:"Qualifier","qualifier-hint":'If the qualifier is not specified, the default qualifier "$LATEST" will be used.',"aws-credentials":"AWS Credentials","connection-timeout":"Connection timeout","connection-timeout-required":"Connection timeout is required.","connection-timeout-min":"Min connection timeout is 0.","connection-timeout-hint":"Rule node forces failure of message processing if AWS Lambda function execution raises exception.","request-timeout":"Request timeout","request-timeout-required":"Request timeout is required","request-timeout-min":"Min request timeout is 0","request-timeout-hint":"The amount of time to wait in seconds for the request to complete before giving up and timing out. A value of 0 means infinity, and is not recommended.","tell-failure-aws-lambda":"Tell Failure if AWS Lambda function execution raises exception","tell-failure-aws-lambda-hint":"Rule node forces failure of message processing if AWS Lambda function execution raises exception."},"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","add-entry":"Add entry","copy-key-values-from":"Copy key-values from","delete-key-values":"Delete key-values","delete-key-values-from":"Delete key-values from","at-least-one-key-error":"At least one key should be selected.","unique-key-value-pair-error":"'{{keyText}}' must be different from the '{{valText}}'!"},"mail-body-type":{"plain-text":"Plain text",html:"HTML",dynamic:"Dynamic","use-body-type-template":"Use body type template","plain-text-description":"Simple, unformatted text with no special styling or formating.","html-text-description":"Allows you to use HTML tags for formatting, links and images in your mai body.","dynamic-text-description":"Allows to use Plain Text or HTML body type dynamically based on templatization feature.","after-template-evaluation-hint":"After template evaluation value should be true for HTML, and false for Plain text."}}},!0)}(e)}}e("RuleNodeCoreConfigModule",$r),$r.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$r,deps:[{token:Z.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),$r.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:$r,declarations:[dt],imports:[$,M],exports:[Qn,qr,ir,vr,zr,jr,dt]}),$r.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$r,imports:[$,M,Qn,qr,ir,vr,zr,jr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$r,decorators:[{type:d,args:[{declarations:[dt],imports:[$,M],exports:[Qn,qr,ir,vr,zr,jr,dt]}]}],ctorParameters:function(){return[{type:Z.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/input","@angular/material/form-field","@angular/material/slide-toggle","@angular/flex-layout/flex","@ngx-translate/core","@angular/material/button","@angular/material/icon","@angular/material/select","@angular/material/core","@angular/material/tooltip","@angular/material/expansion","rxjs","@shared/components/hint-tooltip-icon.component","@shared/components/help-popup.component","@shared/pipe/safe.pipe","@core/public-api","@shared/components/js-func.component","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/checkbox","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/relation/relation-type-autocomplete.component","@shared/components/entity/entity-select.component","@shared/components/toggle-header.component","@shared/components/toggle-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","@home/components/public-api","tslib","@shared/components/entity/entity-subtype-list.component","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@shared/components/string-items-list.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","@angular/cdk/platform"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,p,d,u,c,g,f,y,b,x,h,v,C,F,k,T,L,I,S,N,q,A,M,E,w,G,D,V,P,R,O,_,B,K,H,z,U,j,$,J,Q,Y,W,Z,X,ee,te,ne,re,oe,ae,ie,le,se,me,pe,de,ue,ce,ge,fe,ye,be,xe,he,ve,Ce,Fe,ke,Te,Le,Ie,Se,Ne,qe,Ae,Me,Ee,we,Ge,De,Ve,Pe,Re,Oe,_e,Be,Ke,He,ze,Ue,je,$e,Je,Qe,Ye,We,Ze,Xe,et,tt,nt,rt,ot,at,it,lt,st,mt,pt,dt;return{setters:[function(e){t=e,n=e.Component,r=e.InjectionToken,o=e.Injectable,a=e.Inject,i=e.Optional,l=e.EventEmitter,s=e.Directive,m=e.Input,p=e.Output,d=e.NgModule,u=e.ViewChild,c=e.forwardRef},function(e){g=e.RuleNodeConfigurationComponent,f=e.AttributeScope,y=e.telemetryTypeTranslations,b=e.ScriptLanguage,x=e.AlarmSeverity,h=e.alarmSeverityTranslations,v=e.EntitySearchDirection,C=e.EntityType,F=e.AliasEntityType,k=e.entityFields,T=e.PageComponent,L=e.messageTypeNames,I=e.MessageType,S=e.coerceBoolean,N=e.entitySearchDirectionTranslations,q=e,A=e.AlarmStatus,M=e.alarmStatusTranslations,E=e.SharedModule,w=e.AggregationType,G=e.aggregationTranslations,D=e.NotificationType,V=e.SlackChanelType,P=e.SlackChanelTypesTranslateMap},function(e){R=e},function(e){O=e,_=e.Validators,B=e.NgControl,K=e.NG_VALUE_ACCESSOR,H=e.NG_VALIDATORS,z=e.FormArray,U=e.FormGroup},function(e){j=e,$=e.DOCUMENT,J=e.CommonModule},function(e){Q=e},function(e){Y=e},function(e){W=e},function(e){Z=e},function(e){X=e},function(e){ee=e},function(e){te=e},function(e){ne=e},function(e){re=e},function(e){oe=e},function(e){ae=e},function(e){ie=e.Subject,le=e.takeUntil,se=e.of,me=e.EMPTY,pe=e.fromEvent},function(e){de=e},function(e){ue=e},function(e){ce=e},function(e){ge=e.getCurrentAuthState,fe=e,ye=e.isDefinedAndNotNull,be=e.isEqual,xe=e.deepTrim,he=e.isObject,ve=e.isNotEmptyStr},function(e){Ce=e},function(e){Fe=e},function(e){ke=e.ENTER,Te=e.COMMA,Le=e.SEMICOLON},function(e){Ie=e},function(e){Se=e},function(e){Ne=e},function(e){qe=e},function(e){Ae=e},function(e){Me=e},function(e){Ee=e},function(e){we=e.coerceBooleanProperty,Ge=e.coerceElement,De=e.coerceNumberProperty},function(e){Ve=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e},function(e){_e=e.tap,Be=e.map,Ke=e.startWith,He=e.mergeMap,ze=e.share,Ue=e.takeUntil,je=e.auditTime},function(e){$e=e},function(e){Je=e},function(e){Qe=e.HomeComponentsModule},function(e){Ye=e.__decorate},function(e){We=e},function(e){Ze=e},function(e){Xe=e},function(e){et=e},function(e){tt=e},function(e){nt=e},function(e){rt=e},function(e){ot=e},function(e){at=e},function(e){it=e},function(e){lt=e},function(e){st=e},function(e){mt=e},function(e){pt=e.normalizePassiveListenerOptions,dt=e}],execute:function(){class ut extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",ut),ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ut,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ut,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"<div></div>",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ut,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"<div></div>"}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class ct extends g{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,[_.required,_.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",ct),ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ct,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ct,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="assignCustomerConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\') ||\n assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.customer-name-pattern-hint</mat-hint>\n </mat-form-field>\n <div class="tb-form-row">\n <mat-slide-toggle class="mat-slide" formControlName="createCustomerIfNotExists">\n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:W.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ct,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'<section [formGroup]="assignCustomerConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\') ||\n assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.customer-name-pattern-hint</mat-hint>\n </mat-form-field>\n <div class="tb-form-row">\n <mat-slide-toggle class="mat-slide" formControlName="createCustomerIfNotExists">\n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});const gt=new r("WindowToken","undefined"!=typeof window&&window.document?{providedIn:"root",factory:()=>window}:{providedIn:"root",factory:()=>{}});class ft{constructor(e,t,n){this.ngZone=e,this.document=t,this.window=n,this.copySubject=new ie,this.copyResponse$=this.copySubject.asObservable(),this.config={}}configure(e){this.config=e}copy(e){if(!this.isSupported||!e)return this.pushCopyResponse({isSuccess:!1,content:e});const t=this.copyFromContent(e);return t?this.pushCopyResponse({content:e,isSuccess:t}):this.pushCopyResponse({isSuccess:!1,content:e})}get isSupported(){return!!this.document.queryCommandSupported&&!!this.document.queryCommandSupported("copy")&&!!this.window}isTargetValid(e){if(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement){if(e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');return!0}throw new Error("Target should be input or textarea")}copyFromInputElement(e,t=!0){try{this.selectTarget(e);const n=this.copyText();return this.clearSelection(t?e:void 0,this.window),n&&this.isCopySuccessInIE11()}catch(e){return!1}}isCopySuccessInIE11(){const e=this.window.clipboardData;return!(e&&e.getData&&!e.getData("Text"))}copyFromContent(e,t=this.document.body){if(this.tempTextArea&&!t.contains(this.tempTextArea)&&this.destroy(this.tempTextArea.parentElement||void 0),!this.tempTextArea){this.tempTextArea=this.createTempTextArea(this.document,this.window);try{t.appendChild(this.tempTextArea)}catch(e){throw new Error("Container should be a Dom element")}}this.tempTextArea.value=e;const n=this.copyFromInputElement(this.tempTextArea,!1);return this.config.cleanUpAfterCopy&&this.destroy(this.tempTextArea.parentElement||void 0),n}destroy(e=this.document.body){this.tempTextArea&&(e.removeChild(this.tempTextArea),this.tempTextArea=void 0)}selectTarget(e){return e.select(),e.setSelectionRange(0,e.value.length),e.value.length}copyText(){return this.document.execCommand("copy")}clearSelection(e,t){e&&e.focus(),t.getSelection()?.removeAllRanges()}createTempTextArea(e,t){const n="rtl"===e.documentElement.getAttribute("dir");let r;r=e.createElement("textarea"),r.style.fontSize="12pt",r.style.border="0",r.style.padding="0",r.style.margin="0",r.style.position="absolute",r.style[n?"right":"left"]="-9999px";const o=t.pageYOffset||e.documentElement.scrollTop;return r.style.top=o+"px",r.setAttribute("readonly",""),r}pushCopyResponse(e){this.copySubject.observers.length>0&&this.ngZone.run((()=>{this.copySubject.next(e)}))}pushCopyReponse(e){this.pushCopyResponse(e)}}ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:ft,deps:[{token:t.NgZone},{token:$},{token:gt,optional:!0}],target:t.ɵɵFactoryTarget.Injectable}),ft.ɵprov=t.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:ft,providedIn:"root"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:ft,decorators:[{type:o,args:[{providedIn:"root"}]}],ctorParameters:function(){return[{type:t.NgZone},{type:void 0,decorators:[{type:a,args:[$]}]},{type:void 0,decorators:[{type:i},{type:a,args:[gt]}]}]}});class yt{constructor(e,t,n,r){this.ngZone=e,this.host=t,this.renderer=n,this.clipboardSrv=r,this.cbOnSuccess=new l,this.cbOnError=new l,this.onClick=e=>{this.clipboardSrv.isSupported?this.targetElm&&this.clipboardSrv.isTargetValid(this.targetElm)?this.handleResult(this.clipboardSrv.copyFromInputElement(this.targetElm),this.targetElm.value,e):this.cbContent&&this.handleResult(this.clipboardSrv.copyFromContent(this.cbContent,this.container),this.cbContent,e):this.handleResult(!1,void 0,e)}}ngOnInit(){this.ngZone.runOutsideAngular((()=>{this.clickListener=this.renderer.listen(this.host.nativeElement,"click",this.onClick)}))}ngOnDestroy(){this.clickListener&&this.clickListener(),this.clipboardSrv.destroy(this.container)}handleResult(e,t,n){let r={isSuccess:e,content:t,successMessage:this.cbSuccessMsg,event:n};e?this.cbOnSuccess.observed&&this.ngZone.run((()=>{this.cbOnSuccess.emit(r)})):this.cbOnError.observed&&this.ngZone.run((()=>{this.cbOnError.emit(r)})),this.clipboardSrv.pushCopyResponse(r)}}yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:yt,deps:[{token:t.NgZone},{token:t.ElementRef},{token:t.Renderer2},{token:ft}],target:t.ɵɵFactoryTarget.Directive}),yt.ɵdir=t.ɵɵngDeclareDirective({minVersion:"12.0.0",version:"13.0.1",type:yt,selector:"[ngxClipboard]",inputs:{targetElm:["ngxClipboard","targetElm"],container:"container",cbContent:"cbContent",cbSuccessMsg:"cbSuccessMsg"},outputs:{cbOnSuccess:"cbOnSuccess",cbOnError:"cbOnError"},ngImport:t}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:yt,decorators:[{type:s,args:[{selector:"[ngxClipboard]"}]}],ctorParameters:function(){return[{type:t.NgZone},{type:t.ElementRef},{type:t.Renderer2},{type:ft}]},propDecorators:{targetElm:[{type:m,args:["ngxClipboard"]}],container:[{type:m}],cbContent:[{type:m}],cbSuccessMsg:[{type:m}],cbOnSuccess:[{type:p}],cbOnError:[{type:p}]}});class bt{constructor(e,t,n){this._clipboardService=e,this._viewContainerRef=t,this._templateRef=n}ngOnInit(){this._clipboardService.isSupported&&this._viewContainerRef.createEmbeddedView(this._templateRef)}}bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:bt,deps:[{token:ft},{token:t.ViewContainerRef},{token:t.TemplateRef}],target:t.ɵɵFactoryTarget.Directive}),bt.ɵdir=t.ɵɵngDeclareDirective({minVersion:"12.0.0",version:"13.0.1",type:bt,selector:"[ngxClipboardIfSupported]",ngImport:t}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:bt,decorators:[{type:s,args:[{selector:"[ngxClipboardIfSupported]"}]}],ctorParameters:function(){return[{type:ft},{type:t.ViewContainerRef},{type:t.TemplateRef}]}});class xt{}xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:xt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),xt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:xt,declarations:[yt,bt],imports:[J],exports:[yt,bt]}),xt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:xt,imports:[[J]]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"13.0.1",ngImport:t,type:xt,decorators:[{type:d,args:[{imports:[J],declarations:[yt,bt],exports:[yt,bt]}]}]});class ht{constructor(){this.textAlign="left"}}e("ExampleHintComponent",ht),ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ht,deps:[],target:t.ɵɵFactoryTarget.Component}),ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ht,selector:"tb-example-hint",inputs:{hintText:"hintText",popupHelpLink:"popupHelpLink",textAlign:"textAlign"},ngImport:t,template:'<div [hidden]="!hintText" class="tb-form-hint tb-primary-fill space-between">\n <div [innerHTML]=" hintText | translate | safe: \'html\'"\n [style.text-align]="textAlign"\n class="hint-text"></div>\n <div *ngIf="popupHelpLink" class="see-example" tb-help-popup="{{ popupHelpLink }}"\n hintMode\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}">\n </div>\n</div>\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}:host .hint-text{width:100%}\n"],dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.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","hintMode"]},{kind:"pipe",type:ce.SafePipe,name:"safe"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ht,decorators:[{type:n,args:[{selector:"tb-example-hint",template:'<div [hidden]="!hintText" class="tb-form-hint tb-primary-fill space-between">\n <div [innerHTML]=" hintText | translate | safe: \'html\'"\n [style.text-align]="textAlign"\n class="hint-text"></div>\n <div *ngIf="popupHelpLink" class="see-example" tb-help-popup="{{ popupHelpLink }}"\n hintMode\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}">\n </div>\n</div>\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}:host .hint-text{width:100%}\n"]}]}],propDecorators:{hintText:[{type:m}],popupHelpLink:[{type:m}],textAlign:[{type:m}]}});class vt extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=f,this.attributeScopes=Object.keys(f),this.telemetryTypeTranslationsMap=y}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[_.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]],updateAttributesOnlyOnValueChange:[!!e&&e.updateAttributesOnlyOnValueChange,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==f.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===f.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1}),this.attributesConfigForm.get("updateAttributesOnlyOnValueChange").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",vt),vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vt,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:vt,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="attributesConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="attributesConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="attributesConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div tb-hint-tooltip-icon="{{ (attributesConfigForm.get(\'updateAttributesOnlyOnValueChange\').value\n ? \'tb.rulenode.update-attributes-only-on-value-change-hint-enabled\'\n : \'tb.rulenode.update-attributes-only-on-value-change-hint\') | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="updateAttributesOnlyOnValueChange">\n {{ \'tb.rulenode.update-attributes-only-on-value-change\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.send-attributes-updated-notification-hint\' | translate }}"\n *ngIf="attributesConfigForm.get(\'scope\').value !== attributeScopeMap.CLIENT_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="sendAttributesUpdatedNotification">\n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.notify-device-on-update-hint\' | translate }}"\n *ngIf="attributesConfigForm.get(\'scope\').value === attributeScopeMap.SHARED_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="notifyDevice">\n {{ \'tb.rulenode.notify-device\' | translate }}\n </mat-slide-toggle>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"component",type:ae.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:ae.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:ae.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:yt,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vt,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'<section [formGroup]="attributesConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="attributesConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="attributesConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div tb-hint-tooltip-icon="{{ (attributesConfigForm.get(\'updateAttributesOnlyOnValueChange\').value\n ? \'tb.rulenode.update-attributes-only-on-value-change-hint-enabled\'\n : \'tb.rulenode.update-attributes-only-on-value-change-hint\') | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="updateAttributesOnlyOnValueChange">\n {{ \'tb.rulenode.update-attributes-only-on-value-change\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.send-attributes-updated-notification-hint\' | translate }}"\n *ngIf="attributesConfigForm.get(\'scope\').value !== attributeScopeMap.CLIENT_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="sendAttributesUpdatedNotification">\n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.notify-device-on-update-hint\' | translate }}"\n *ngIf="attributesConfigForm.get(\'scope\').value === attributeScopeMap.SHARED_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="notifyDevice">\n {{ \'tb.rulenode.notify-device\' | translate }}\n </mat-slide-toggle>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Ct extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ge(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,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:b.JS,[_.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[_.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===b.JS?[_.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===b.TBEL?[_.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),e}testScript(e){const t=this.clearAlarmConfigForm.get("scriptLang").value,n=t===b.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Ct),Ct.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ct,deps:[{token:R.Store},{token:O.UntypedFormBuilder},{token:fe.NodeScriptTestService},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ct.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ct,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:'<section [formGroup]="clearAlarmConfigForm" fxLayout="column">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="clearAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/clear_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="clearAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="alarmDetailsBuildTbel"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/clear_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="clearAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ce.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","propertyHighlightRules","objectHighlightRules","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:oe.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Fe.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ct,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'<section [formGroup]="clearAlarmConfigForm" fxLayout="column">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="clearAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/clear_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="clearAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="alarmDetailsBuildTbel"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/clear_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="clearAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder},{type:fe.NodeScriptTestService},{type:X.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class Ft extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(x),this.alarmSeverityTranslationMap=h,this.separatorKeysCodes=[ke,Te,Le],this.tbelEnabled=ge(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,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:b.JS,[_.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([_.required]),this.createAlarmConfigForm.get("severity").setValidators([_.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==b.TBEL||this.tbelEnabled||(r=b.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===b.JS?[_.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===b.TBEL?[_.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),e}testScript(e){const t=this.createAlarmConfigForm.get("scriptLang").value,n=t===b.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",Ft),Ft.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ft,deps:[{token:R.Store},{token:O.UntypedFormBuilder},{token:fe.NodeScriptTestService},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ft.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ft,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:'<section [formGroup]="createAlarmConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMessageAlarmData">\n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="overwriteAlarmDetails" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === true">\n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false ||\n createAlarmConfigForm.get(\'overwriteAlarmDetails\').value === true">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="createAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/create_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="createAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="alarmDetailsBuildTbel"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/create_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n </section>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false">\n <mat-form-field fxFlex subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="createAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="dynamicSeverity">\n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n </mat-checkbox>\n <mat-form-field fxFlex *ngIf="!createAlarmConfigForm.get(\'dynamicSeverity\').value">\n <mat-label translate>tb.rulenode.alarm-severity</mat-label>\n <mat-select formControlName="severity" required>\n <mat-option *ngFor="let severity of alarmSeverities" [value]="severity">\n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex *ngIf="createAlarmConfigForm.get(\'dynamicSeverity\').value" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-severity-pattern</mat-label>\n <input matInput formControlName="severity" required>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n <mat-hint [innerHTML]="\'tb.rulenode.alarm-severity-pattern-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="propagate">\n {{ \'tb.rulenode.propagate\' | translate }}\n </mat-checkbox>\n <section *ngIf="createAlarmConfigForm.get(\'propagate\').value === true">\n <mat-form-field floatLabel="always" class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.relation-types-list</mat-label>\n <mat-chip-grid #relationTypesChipList>\n <mat-chip-row\n *ngFor="let key of createAlarmConfigForm.get(\'relationTypes\').value;"\n (removed)="removeKey(key, \'relationTypes\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text" placeholder="{{\'tb.rulenode.relation-types-list\' | translate}}"\n [matChipInputFor]="relationTypesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'relationTypes\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-grid>\n <mat-hint translate>tb.rulenode.relation-types-list-hint</mat-hint>\n </mat-form-field>\n </section>\n <mat-checkbox formControlName="propagateToOwner">\n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="propagateToTenant">\n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n </mat-checkbox>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ce.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","propertyHighlightRules","objectHighlightRules","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.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.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Fe.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:ce.SafePipe,name:"safe"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ft,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'<section [formGroup]="createAlarmConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMessageAlarmData">\n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="overwriteAlarmDetails" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === true">\n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false ||\n createAlarmConfigForm.get(\'overwriteAlarmDetails\').value === true">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="createAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/create_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="createAlarmConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="alarmDetailsBuildTbel"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/create_alarm_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n </section>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false">\n <mat-form-field fxFlex subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="createAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="dynamicSeverity">\n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n </mat-checkbox>\n <mat-form-field fxFlex *ngIf="!createAlarmConfigForm.get(\'dynamicSeverity\').value">\n <mat-label translate>tb.rulenode.alarm-severity</mat-label>\n <mat-select formControlName="severity" required>\n <mat-option *ngFor="let severity of alarmSeverities" [value]="severity">\n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex *ngIf="createAlarmConfigForm.get(\'dynamicSeverity\').value" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.alarm-severity-pattern</mat-label>\n <input matInput formControlName="severity" required>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n <mat-hint [innerHTML]="\'tb.rulenode.alarm-severity-pattern-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="propagate">\n {{ \'tb.rulenode.propagate\' | translate }}\n </mat-checkbox>\n <section *ngIf="createAlarmConfigForm.get(\'propagate\').value === true">\n <mat-form-field floatLabel="always" class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.relation-types-list</mat-label>\n <mat-chip-grid #relationTypesChipList>\n <mat-chip-row\n *ngFor="let key of createAlarmConfigForm.get(\'relationTypes\').value;"\n (removed)="removeKey(key, \'relationTypes\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text" placeholder="{{\'tb.rulenode.relation-types-list\' | translate}}"\n [matChipInputFor]="relationTypesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'relationTypes\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-grid>\n <mat-hint translate>tb.rulenode.relation-types-list-hint</mat-hint>\n </mat-form-field>\n </section>\n <mat-checkbox formControlName="propagateToOwner">\n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="propagateToTenant">\n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n </mat-checkbox>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder},{type:fe.NodeScriptTestService},{type:X.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class kt extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(v),this.directionTypeTranslations=new Map([[v.FROM,"tb.rulenode.search-direction-from"],[v.TO,"tb.rulenode.search-direction-to"]]),this.entityType=C,this.entityTypeNamePatternTranslation=new Map([[C.DEVICE,"tb.rulenode.device-name-pattern"],[C.ASSET,"tb.rulenode.asset-name-pattern"],[C.ENTITY_VIEW,"tb.rulenode.entity-view-name-pattern"],[C.CUSTOMER,"tb.rulenode.customer-title-pattern"],[C.USER,"tb.rulenode.user-name-pattern"],[C.DASHBOARD,"tb.rulenode.dashboard-name-pattern"],[C.EDGE,"tb.rulenode.edge-name-pattern"]]),this.allowedEntityTypes=[C.DEVICE,C.ASSET,C.ENTITY_VIEW,C.TENANT,C.CUSTOMER,C.USER,C.DASHBOARD,C.EDGE]}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[_.required]],entityType:[e?e.entityType:null,[_.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[_.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]]})}validatorTriggers(){return["entityType","createEntityIfNotExists"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;if(t?this.createRelationConfigForm.get("entityNamePattern").setValidators([_.required,_.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==C.DEVICE&&t!==C.ASSET)this.createRelationConfigForm.get("entityTypePattern").setValidators([]);else{const e=[_.pattern(/.*\S.*/)];this.createRelationConfigForm.get("createEntityIfNotExists").value&&e.push(_.required),this.createRelationConfigForm.get("entityTypePattern").setValidators(e)}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",kt),kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kt,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:kt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="createRelationConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n </div>\n </div>\n\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.target-entity</div>\n <div fxLayout="row" fxLayoutGap="16px">\n <tb-entity-type-select\n fxFlex\n showLabel\n required\n [allowedEntityTypes]="allowedEntityTypes"\n formControlName="entityType">\n </tb-entity-type-select>\n\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value &&\n createRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n fxFlex class="mat-block">\n <mat-label>{{ entityTypeNamePatternTranslation.get(createRelationConfigForm.get(\'entityType\').value) | translate }}</mat-label>\n <input required matInput formControlName="entityNamePattern">\n </mat-form-field>\n\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.profile-name</mat-label>\n <input matInput formControlName="entityTypePattern">\n </mat-form-field>\n </div>\n\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"></tb-example-hint>\n\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.create-entity-if-not-exists-hint\' | translate }}"\n *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n style="margin-bottom: 18px"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="createEntityIfNotExists">\n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n <section class="tb-form-panel stroked no-padding">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header style="padding: 16px">\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-panel no-border no-padding-top">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.remove-current-relations-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="removeCurrentRelations">\n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.change-originator-to-related-entity-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="changeOriginatorToRelatedEntity">\n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ne.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled","additionEntityTypes"]},{kind:"component",type:qe.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"component",type:ae.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:ae.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:ae.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kt,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'<section [formGroup]="createRelationConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n </div>\n </div>\n\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.target-entity</div>\n <div fxLayout="row" fxLayoutGap="16px">\n <tb-entity-type-select\n fxFlex\n showLabel\n required\n [allowedEntityTypes]="allowedEntityTypes"\n formControlName="entityType">\n </tb-entity-type-select>\n\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value &&\n createRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n fxFlex class="mat-block">\n <mat-label>{{ entityTypeNamePatternTranslation.get(createRelationConfigForm.get(\'entityType\').value) | translate }}</mat-label>\n <input required matInput formControlName="entityNamePattern">\n </mat-form-field>\n\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.profile-name</mat-label>\n <input matInput formControlName="entityTypePattern">\n </mat-form-field>\n </div>\n\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"></tb-example-hint>\n\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.create-entity-if-not-exists-hint\' | translate }}"\n *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n style="margin-bottom: 18px"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="createEntityIfNotExists">\n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n <section class="tb-form-panel stroked no-padding">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header style="padding: 16px">\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-panel no-border no-padding-top">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.remove-current-relations-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="removeCurrentRelations">\n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.change-originator-to-related-entity-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="changeOriginatorToRelatedEntity">\n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Tt extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(v),this.directionTypeTranslations=new Map([[v.FROM,"tb.rulenode.del-relation-direction-from"],[v.TO,"tb.rulenode.del-relation-direction-to"]]),this.entityTypeNamePatternTranslation=new Map([[C.DEVICE,"tb.rulenode.device-name-pattern"],[C.ASSET,"tb.rulenode.asset-name-pattern"],[C.ENTITY_VIEW,"tb.rulenode.entity-view-name-pattern"],[C.CUSTOMER,"tb.rulenode.customer-title-pattern"],[C.USER,"tb.rulenode.user-name-pattern"],[C.DASHBOARD,"tb.rulenode.dashboard-name-pattern"],[C.EDGE,"tb.rulenode.edge-name-pattern"]]),this.entityType=C,this.allowedEntityTypes=[C.DEVICE,C.ASSET,C.ENTITY_VIEW,C.TENANT,C.CUSTOMER,C.USER,C.DASHBOARD,C.EDGE]}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[_.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[_.required]]})}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([_.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n&&n!==C.TENANT?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([_.required,_.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.10",ngImport:t,type:Tt,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Tt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deleteRelationConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.delete-relation-with-specific-entity-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="deleteForSingleEntity">\n {{ \'tb.rulenode.delete-relation-with-specific-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n <div *ngIf="deleteRelationConfigForm.get(\'deleteForSingleEntity\').value">\n <div fxLayout="row" fxLayoutGap="10px">\n <tb-entity-type-select\n fxFlex\n showLabel\n required\n [allowedEntityTypes]="allowedEntityTypes"\n formControlName="entityType">\n </tb-entity-type-select>\n <mat-form-field *ngIf="deleteRelationConfigForm.get(\'entityType\').value && deleteRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n fxFlex class="mat-block">\n <mat-label>{{ entityTypeNamePatternTranslation.get(deleteRelationConfigForm.get(\'entityType\').value) | translate }}</mat-label>\n <input required matInput formControlName="entityNamePattern">\n </mat-form-field>\n </div>\n <tb-example-hint *ngIf="deleteRelationConfigForm.get(\'entityType\').value && deleteRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n [hintText]="\'tb.rulenode.kv-map-single-pattern-hint\'"></tb-example-hint>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ne.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled","additionEntityTypes"]},{kind:"component",type:qe.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:W.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: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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'<section [formGroup]="deleteRelationConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.delete-relation-with-specific-entity-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="deleteForSingleEntity">\n {{ \'tb.rulenode.delete-relation-with-specific-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n <div *ngIf="deleteRelationConfigForm.get(\'deleteForSingleEntity\').value">\n <div fxLayout="row" fxLayoutGap="10px">\n <tb-entity-type-select\n fxFlex\n showLabel\n required\n [allowedEntityTypes]="allowedEntityTypes"\n formControlName="entityType">\n </tb-entity-type-select>\n <mat-form-field *ngIf="deleteRelationConfigForm.get(\'entityType\').value && deleteRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n fxFlex class="mat-block">\n <mat-label>{{ entityTypeNamePatternTranslation.get(deleteRelationConfigForm.get(\'entityType\').value) | translate }}</mat-label>\n <input required matInput formControlName="entityNamePattern">\n </mat-form-field>\n </div>\n <tb-example-hint *ngIf="deleteRelationConfigForm.get(\'entityType\').value && deleteRelationConfigForm.get(\'entityType\').value !== entityType.TENANT"\n [hintText]="\'tb.rulenode.kv-map-single-pattern-hint\'"></tb-example-hint>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Lt extends g{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],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart]})}validatorTriggers(){return["persistAlarmRulesState"]}updateValidators(e){this.deviceProfile.get("persistAlarmRulesState").value?this.deviceProfile.get("fetchAlarmRulesStateOnStart").enable({emitEvent:!1}):(this.deviceProfile.get("fetchAlarmRulesStateOnStart").setValue(!1,{emitEvent:!1}),this.deviceProfile.get("fetchAlarmRulesStateOnStart").disable({emitEvent:!1})),this.deviceProfile.get("fetchAlarmRulesStateOnStart").updateValueAndValidity({emitEvent:e})}}e("DeviceProfileConfigComponent",Lt),Lt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Lt,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Lt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Lt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deviceProfile" class="tb-form-panel stroked">\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.device-profile-node-hint</div>\n <div tb-hint-tooltip-icon="{{\'tb.rulenode.persist-alarm-rules-hint\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="persistAlarmRulesState">\n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{\'tb.rulenode.fetch-alarm-rules-hint\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchAlarmRulesStateOnStart">\n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',dependencies:[{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Lt,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'<section [formGroup]="deviceProfile" class="tb-form-panel stroked">\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.device-profile-node-hint</div>\n <div tb-hint-tooltip-icon="{{\'tb.rulenode.persist-alarm-rules-hint\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="persistAlarmRulesState">\n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{\'tb.rulenode.fetch-alarm-rules-hint\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchAlarmRulesStateOnStart">\n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class It extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ge(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,this.allowedEntityTypes=[C.DEVICE,C.ASSET,C.ENTITY_VIEW,C.CUSTOMER,C.USER,C.DASHBOARD,F.CURRENT_TENANT],this.additionEntityTypes={CURRENT_RULE_NODE:this.translate.instant("tb.rulenode.current-rule-node")},this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-generator-function"}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[_.required,_.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[_.required,_.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:b.JS,[_.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===b.JS?[_.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===b.TBEL?[_.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.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===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}var St;e("GeneratorConfigComponent",It),It.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:It,deps:[{token:R.Store},{token:O.UntypedFormBuilder},{token:fe.NodeScriptTestService},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),It.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:It,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:'<section [formGroup]="generatorConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel no-padding-bottom stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.generation-parameters</div>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.message-count</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="msgCount">\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'required\')">\n {{ \'tb.rulenode.message-count-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'min\')">\n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n\n <div class="tb-form-panel no-padding-bottom stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.originator</div>\n <tb-entity-select fxFlex\n required="true"\n useAliasEntityTypes="true"\n [allowedEntityTypes]="allowedEntityTypes"\n [additionEntityTypes]="additionEntityTypes"\n formControlName="originator">\n </tb-entity-select>\n </div>\n <div class="tb-form-panel no-padding-bottom stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.generator-function</div>\n <tb-js-func *ngIf="generatorConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n helpId="rulenode/generator_node_script_fn"\n noValidate="true">\n <tb-toggle-select toolbarPrefixButton formControlName="scriptLang" appearance="fill" *ngIf="tbelEnabled">\n <tb-toggle-option [value]="scriptLanguage.TBEL">\n {{ \'tb.rulenode.script-lang-tbel\' | translate }}\n </tb-toggle-option>\n <tb-toggle-option [value]="scriptLanguage.JS">\n {{ \'tb.rulenode.script-lang-js\' | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="generatorConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/generator_node_script_fn"\n noValidate="true">\n <tb-toggle-select toolbarPrefixButton formControlName="scriptLang" appearance="fill">\n <tb-toggle-option [value]="scriptLanguage.TBEL">\n {{ \'tb.rulenode.script-lang-tbel\' | translate }}\n </tb-toggle-option>\n <tb-toggle-option [value]="scriptLanguage.JS">\n {{ \'tb.rulenode.script-lang-js\' | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n </div>\n</section>\n',styles:[":host ::ng-deep .mat-button-toggle-group{min-width:120px;height:24px!important}:host ::ng-deep .mat-button-toggle-group .mat-button-toggle{font-size:0}:host ::ng-deep .mat-button-toggle-group .mat-button-toggle .mat-button-toggle-button{height:20px!important;line-height:20px!important;border:none!important}:host ::ng-deep .mat-button-toggle-group .mat-button-toggle .mat-button-toggle-button .mat-button-toggle-label-content{font-size:14px!important;line-height:20px!important}@media screen and (min-width: 599px){:host ::ng-deep .tb-entity-select{display:flex;flex-direction:row;gap:16px}}:host ::ng-deep .tb-entity-select tb-entity-type-select{flex:1}:host ::ng-deep .tb-entity-select tb-entity-autocomplete{flex:1}:host ::ng-deep .tb-entity-select tb-entity-autocomplete mat-form-field{width:100%!important}\n"],dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled","additionEntityTypes"]},{kind:"component",type:Ce.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","propertyHighlightRules","objectHighlightRules","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:oe.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.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Me.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Ee.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination","fillHeight","extraPadding","primaryBackground"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:It,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'<section [formGroup]="generatorConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel no-padding-bottom stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.generation-parameters</div>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.message-count</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="msgCount">\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'required\')">\n {{ \'tb.rulenode.message-count-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'min\')">\n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n\n <div class="tb-form-panel no-padding-bottom stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.originator</div>\n <tb-entity-select fxFlex\n required="true"\n useAliasEntityTypes="true"\n [allowedEntityTypes]="allowedEntityTypes"\n [additionEntityTypes]="additionEntityTypes"\n formControlName="originator">\n </tb-entity-select>\n </div>\n <div class="tb-form-panel no-padding-bottom stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.generator-function</div>\n <tb-js-func *ngIf="generatorConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n helpId="rulenode/generator_node_script_fn"\n noValidate="true">\n <tb-toggle-select toolbarPrefixButton formControlName="scriptLang" appearance="fill" *ngIf="tbelEnabled">\n <tb-toggle-option [value]="scriptLanguage.TBEL">\n {{ \'tb.rulenode.script-lang-tbel\' | translate }}\n </tb-toggle-option>\n <tb-toggle-option [value]="scriptLanguage.JS">\n {{ \'tb.rulenode.script-lang-js\' | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="generatorConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/generator_node_script_fn"\n noValidate="true">\n <tb-toggle-select toolbarPrefixButton formControlName="scriptLang" appearance="fill">\n <tb-toggle-option [value]="scriptLanguage.TBEL">\n {{ \'tb.rulenode.script-lang-tbel\' | translate }}\n </tb-toggle-option>\n <tb-toggle-option [value]="scriptLanguage.JS">\n {{ \'tb.rulenode.script-lang-js\' | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n </div>\n</section>\n',styles:[":host ::ng-deep .mat-button-toggle-group{min-width:120px;height:24px!important}:host ::ng-deep .mat-button-toggle-group .mat-button-toggle{font-size:0}:host ::ng-deep .mat-button-toggle-group .mat-button-toggle .mat-button-toggle-button{height:20px!important;line-height:20px!important;border:none!important}:host ::ng-deep .mat-button-toggle-group .mat-button-toggle .mat-button-toggle-button .mat-button-toggle-label-content{font-size:14px!important;line-height:20px!important}@media screen and (min-width: 599px){:host ::ng-deep .tb-entity-select{display:flex;flex-direction:row;gap:16px}}:host ::ng-deep .tb-entity-select tb-entity-type-select{flex:1}:host ::ng-deep .tb-entity-select tb-entity-autocomplete{flex:1}:host ::ng-deep .tb-entity-select tb-entity-autocomplete mat-form-field{width:100%!important}\n"]}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder},{type:fe.NodeScriptTestService},{type:X.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(St||(St={}));const Nt=new Map([[St.CUSTOMER,"tb.rulenode.originator-customer"],[St.TENANT,"tb.rulenode.originator-tenant"],[St.RELATED,"tb.rulenode.originator-related"],[St.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[St.ENTITY,"tb.rulenode.originator-entity"]]),qt=new Map([[St.CUSTOMER,"tb.rulenode.originator-customer-desc"],[St.TENANT,"tb.rulenode.originator-tenant-desc"],[St.RELATED,"tb.rulenode.originator-related-entity-desc"],[St.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator-desc"],[St.ENTITY,"tb.rulenode.originator-entity-by-name-pattern-desc"]]),At=[k.createdTime,k.name,{value:"type",name:"tb.rulenode.profile-name",keyName:"originatorProfileName"},k.firstName,k.lastName,k.email,k.title,k.country,k.state,k.city,k.address,k.address2,k.zip,k.phone,k.label,{value:"id",name:"tb.rulenode.id",keyName:"id"},{value:"additionalInfo",name:"tb.rulenode.additional-info",keyName:"additionalInfo"}],Mt=new Map([["type","profileName"],["createdTime","createdTime"],["name","name"],["firstName","firstName"],["lastName","lastName"],["email","email"],["title","title"],["country","country"],["state","state"],["city","city"],["address","address"],["address2","address2"],["zip","zip"],["phone","phone"],["label","label"],["id","id"],["additionalInfo","additionalInfo"]]);var Et;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(Et||(Et={}));const wt=new Map([[Et.CIRCLE,"tb.rulenode.perimeter-circle"],[Et.POLYGON,"tb.rulenode.perimeter-polygon"]]);var Gt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(Gt||(Gt={}));const Dt=new Map([[Gt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[Gt.SECONDS,"tb.rulenode.time-unit-seconds"],[Gt.MINUTES,"tb.rulenode.time-unit-minutes"],[Gt.HOURS,"tb.rulenode.time-unit-hours"],[Gt.DAYS,"tb.rulenode.time-unit-days"]]);var Vt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(Vt||(Vt={}));const Pt=new Map([[Vt.METER,"tb.rulenode.range-unit-meter"],[Vt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[Vt.FOOT,"tb.rulenode.range-unit-foot"],[Vt.MILE,"tb.rulenode.range-unit-mile"],[Vt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var Rt;!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"}(Rt||(Rt={}));const Ot=new Map([[Rt.ID,"tb.rulenode.entity-details-id"],[Rt.TITLE,"tb.rulenode.entity-details-title"],[Rt.COUNTRY,"tb.rulenode.entity-details-country"],[Rt.STATE,"tb.rulenode.entity-details-state"],[Rt.CITY,"tb.rulenode.entity-details-city"],[Rt.ZIP,"tb.rulenode.entity-details-zip"],[Rt.ADDRESS,"tb.rulenode.entity-details-address"],[Rt.ADDRESS2,"tb.rulenode.entity-details-address2"],[Rt.PHONE,"tb.rulenode.entity-details-phone"],[Rt.EMAIL,"tb.rulenode.entity-details-email"],[Rt.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var _t;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(_t||(_t={}));const Bt=new Map([[_t.FIRST,"tb.rulenode.first"],[_t.LAST,"tb.rulenode.last"],[_t.ALL,"tb.rulenode.all"]]),Kt=new Map([[_t.FIRST,"tb.rulenode.first-mode-hint"],[_t.LAST,"tb.rulenode.last-mode-hint"],[_t.ALL,"tb.rulenode.all-mode-hint"]]);var Ht,zt;!function(e){e.ASC="ASC",e.DESC="DESC"}(Ht||(Ht={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(zt||(zt={}));const Ut=new Map([[zt.ATTRIBUTES,"tb.rulenode.attributes"],[zt.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[zt.FIELDS,"tb.rulenode.fields"]]),jt=new Map([[zt.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[zt.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[zt.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),$t=new Map([[Ht.ASC,"tb.rulenode.ascending"],[Ht.DESC,"tb.rulenode.descending"]]);var Jt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Jt||(Jt={}));const Qt=new Map([[Jt.STANDARD,"tb.rulenode.sqs-queue-standard"],[Jt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Yt=["anonymous","basic","cert.PEM"],Wt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Zt=["sas","cert.PEM"],Xt=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var en;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(en||(en={}));const tn=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],nn=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 rn;!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"}(rn||(rn={}));const on=new Map([[rn.CUSTOM,{value:rn.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[rn.ADD,{value:rn.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[rn.SUB,{value:rn.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[rn.MULT,{value:rn.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[rn.DIV,{value:rn.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[rn.SIN,{value:rn.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[rn.SINH,{value:rn.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[rn.COS,{value:rn.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[rn.COSH,{value:rn.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[rn.TAN,{value:rn.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[rn.TANH,{value:rn.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[rn.ACOS,{value:rn.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[rn.ASIN,{value:rn.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[rn.ATAN,{value:rn.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[rn.ATAN2,{value:rn.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}],[rn.EXP,{value:rn.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[rn.EXPM1,{value:rn.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[rn.SQRT,{value:rn.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[rn.CBRT,{value:rn.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[rn.GET_EXP,{value:rn.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[rn.HYPOT,{value:rn.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[rn.LOG,{value:rn.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[rn.LOG10,{value:rn.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[rn.LOG1P,{value:rn.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[rn.CEIL,{value:rn.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[rn.FLOOR,{value:rn.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[rn.FLOOR_DIV,{value:rn.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[rn.FLOOR_MOD,{value:rn.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[rn.ABS,{value:rn.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[rn.MIN,{value:rn.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[rn.MAX,{value:rn.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[rn.POW,{value:rn.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}],[rn.SIGNUM,{value:rn.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[rn.RAD,{value:rn.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[rn.DEG,{value:rn.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var an,ln,sn;!function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT"}(an||(an={})),function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES"}(ln||(ln={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(sn||(sn={}));const mn=new Map([[sn.DATA,"tb.rulenode.message-to-metadata"],[sn.METADATA,"tb.rulenode.metadata-to-message"]]),pn=(new Map([[sn.DATA,"tb.rulenode.from-message"],[sn.METADATA,"tb.rulenode.from-metadata"]]),new Map([[sn.DATA,"tb.rulenode.message"],[sn.METADATA,"tb.rulenode.metadata"]])),dn=new Map([[sn.DATA,"tb.rulenode.message"],[sn.METADATA,"tb.rulenode.message-metadata"]]),un=new Map([[an.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Fetch argument value from incoming message"}],[an.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Fetch argument value from incoming message metadata"}],[an.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Fetch attribute value from database"}],[an.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Fetch latest time-series value from database"}],[an.CONSTANT,{name:"tb.rulenode.constant-type",description:"Define constant value"}]]),cn=new Map([[ln.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Add result to the outgoing message"}],[ln.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Add result to the outgoing message metadata"}],[ln.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Store result as an entity attribute in the database"}],[ln.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Store result as an entity time-series in the database"}]]),gn=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var fn,yn;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(fn||(fn={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(yn||(yn={}));const bn=new Map([[fn.SHARED_SCOPE,"tb.rulenode.shared-scope"],[fn.SERVER_SCOPE,"tb.rulenode.server-scope"],[fn.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);var xn;!function(e){e.ON_FIRST_MESSAGE="ON_FIRST_MESSAGE",e.ON_EACH_MESSAGE="ON_EACH_MESSAGE"}(xn||(xn={}));const hn=new Map([[xn.ON_EACH_MESSAGE,{value:!0,name:"tb.rulenode.presence-monitoring-strategy-on-each-message"}],[xn.ON_FIRST_MESSAGE,{value:!1,name:"tb.rulenode.presence-monitoring-strategy-on-first-message"}]]);class vn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Et,this.perimeterTypes=Object.keys(Et),this.perimeterTypeTranslationMap=wt,this.rangeUnits=Object.keys(Vt),this.rangeUnitTranslationMap=Pt,this.presenceMonitoringStrategies=hn,this.presenceMonitoringStrategyKeys=Array.from(this.presenceMonitoringStrategies.keys()),this.timeUnits=Object.keys(Gt),this.timeUnitsTranslationMap=Dt,this.defaultPaddingEnable=!0}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({reportPresenceStatusOnEachMessage:[!e||e.reportPresenceStatusOnEachMessage,[_.required]],latitudeKeyName:[e?e.latitudeKeyName:null,[_.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[_.required]],perimeterType:[e?e.perimeterType:null,[_.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,[_.required,_.min(1),_.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[_.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[_.required,_.min(1),_.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[_.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([_.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==Et.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([]),this.defaultPaddingEnable=!0):(this.geoActionConfigForm.get("centerLatitude").setValidators([_.required,_.min(-90),_.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([_.required,_.min(-180),_.max(180)]),this.geoActionConfigForm.get("range").setValidators([_.required,_.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([_.required]),this.defaultPaddingEnable=!1),t||n!==Et.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([_.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",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vn,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:vn,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="geoActionConfigForm" class="tb-form-panel no-border no-padding">\n <section class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.coordinate-field-names</div>\n <section>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.latitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.longitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.coordinate-field-hint</div>\n </section>\n </section>\n <section class="tb-form-panel stroked" [class.no-padding-bottom]="!defaultPaddingEnable">\n <div class="tb-form-panel-title" translate>tb.rulenode.geofence-configuration</div>\n <section fxLayout="column">\n <mat-form-field fxFlex class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.perimeter-type\' | translate }}</mat-label>\n <mat-select formControlName="perimeterType">\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div tb-hint-tooltip-icon="{{ geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE\n ? (\'tb.rulenode.fetch-circle-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoActionConfigForm.get(\'perimeterKeyName\').valid\n ? geoActionConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'})\n : (\'tb.rulenode.fetch-poligon-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoActionConfigForm.get(\'perimeterKeyName\').valid\n ? geoActionConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'}) }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchPerimeterInfoFromMessageMetadata">\n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field *ngIf="geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value" class="mat-block">\n <mat-label>{{ \'tb.rulenode.perimeter-key-name\' | translate }}</mat-label>\n <input matInput formControlName="perimeterKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'perimeterKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n </mat-error>\n <mat-hint>{{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}</mat-hint>\n </mat-form-field>\n <div fxLayout="column"\n *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-latitude\' | translate }}</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-longitude\' | translate }}</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range\' | translate }}</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range-units\' | translate }}</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="geoActionConfigForm.get(\'rangeUnit\').hasError(\'required\')">\n {{ \'tb.rulenode.range-units-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <div fxLayout="column" *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.polygon-definition</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-icon matSuffix class="margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.polygon-definition-hint\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="geoActionConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </section>\n </section>\n <section class="tb-form-panel stroked no-padding-bottom">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.lt-md="16px" fxLayoutAlign="space-between">\n <div class="tb-form-panel-title">{{ \'tb.rulenode.presence-monitoring-strategy\' | translate }}</div>\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="reportPresenceStatusOnEachMessage" appearance="fill" >\n <tb-toggle-option *ngFor="let strategy of presenceMonitoringStrategyKeys" [value]="presenceMonitoringStrategies.get(strategy).value">\n {{ presenceMonitoringStrategies.get(strategy).name | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n <div class="tb-form-hint tb-primary-fill"> {{ geoActionConfigForm.get(\'reportPresenceStatusOnEachMessage\').value === false ?\n (\'tb.rulenode.presence-monitoring-strategy-on-first-message-hint\' | translate) :\n (\'tb.rulenode.presence-monitoring-strategy-on-each-message-hint\' | translate) }}\n </div>\n <section fxLayout="column">\n <div *ngIf="geoActionConfigForm.get(\'reportPresenceStatusOnEachMessage\').value === false">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minInsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration-time-unit</mat-label>\n <mat-select formControlName="minInsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minOutsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration-time-unit</mat-label>\n <mat-select formControlName="minOutsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n </section>\n </section>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:W.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: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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Me.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Ee.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination","fillHeight","extraPadding","primaryBackground"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vn,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'<section [formGroup]="geoActionConfigForm" class="tb-form-panel no-border no-padding">\n <section class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.coordinate-field-names</div>\n <section>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.latitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.longitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.coordinate-field-hint</div>\n </section>\n </section>\n <section class="tb-form-panel stroked" [class.no-padding-bottom]="!defaultPaddingEnable">\n <div class="tb-form-panel-title" translate>tb.rulenode.geofence-configuration</div>\n <section fxLayout="column">\n <mat-form-field fxFlex class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.perimeter-type\' | translate }}</mat-label>\n <mat-select formControlName="perimeterType">\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div tb-hint-tooltip-icon="{{ geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE\n ? (\'tb.rulenode.fetch-circle-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoActionConfigForm.get(\'perimeterKeyName\').valid\n ? geoActionConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'})\n : (\'tb.rulenode.fetch-poligon-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoActionConfigForm.get(\'perimeterKeyName\').valid\n ? geoActionConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'}) }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchPerimeterInfoFromMessageMetadata">\n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field *ngIf="geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value" class="mat-block">\n <mat-label>{{ \'tb.rulenode.perimeter-key-name\' | translate }}</mat-label>\n <input matInput formControlName="perimeterKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'perimeterKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n </mat-error>\n <mat-hint>{{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}</mat-hint>\n </mat-form-field>\n <div fxLayout="column"\n *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-latitude\' | translate }}</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-longitude\' | translate }}</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range\' | translate }}</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range-units\' | translate }}</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="geoActionConfigForm.get(\'rangeUnit\').hasError(\'required\')">\n {{ \'tb.rulenode.range-units-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <div fxLayout="column" *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.polygon-definition</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-icon matSuffix class="margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.polygon-definition-hint\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="geoActionConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </section>\n </section>\n <section class="tb-form-panel stroked no-padding-bottom">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.lt-md="16px" fxLayoutAlign="space-between">\n <div class="tb-form-panel-title">{{ \'tb.rulenode.presence-monitoring-strategy\' | translate }}</div>\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="reportPresenceStatusOnEachMessage" appearance="fill" >\n <tb-toggle-option *ngFor="let strategy of presenceMonitoringStrategyKeys" [value]="presenceMonitoringStrategies.get(strategy).value">\n {{ presenceMonitoringStrategies.get(strategy).name | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n <div class="tb-form-hint tb-primary-fill"> {{ geoActionConfigForm.get(\'reportPresenceStatusOnEachMessage\').value === false ?\n (\'tb.rulenode.presence-monitoring-strategy-on-first-message-hint\' | translate) :\n (\'tb.rulenode.presence-monitoring-strategy-on-each-message-hint\' | translate) }}\n </div>\n <section fxLayout="column">\n <div *ngIf="geoActionConfigForm.get(\'reportPresenceStatusOnEachMessage\').value === false">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minInsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration-time-unit</mat-label>\n <mat-select formControlName="minInsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minOutsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration-time-unit</mat-label>\n <mat-select formControlName="minOutsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n </section>\n </section>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Cn extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ge(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,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:b.JS,[_.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===b.JS?[_.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===b.TBEL?[_.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),e}testScript(e){const t=this.logConfigForm.get("scriptLang").value,n=t===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Cn,deps:[{token:R.Store},{token:O.UntypedFormBuilder},{token:fe.NodeScriptTestService},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Cn,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:'<section [formGroup]="logConfigForm" fxLayout="column">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="logConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/log_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="logConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/log_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ce.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","propertyHighlightRules","objectHighlightRules","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:oe.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:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Fe.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Cn,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'<section [formGroup]="logConfigForm" fxLayout="column">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="logConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/log_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="logConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/log_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder},{type:fe.NodeScriptTestService},{type:X.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class Fn extends g{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,[_.required,_.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[_.required]]})}}e("MsgCountConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Fn,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Fn,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="msgCountConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.interval-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="interval">\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'required\')">\n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'min\')">\n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.output-timeseries-key-prefix</mat-label>\n <input required matInput formControlName="telemetryPrefix">\n <mat-error *ngIf="msgCountConfigForm.get(\'telemetryPrefix\').hasError(\'required\')">\n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'<section [formGroup]="msgCountConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.interval-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="interval">\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'required\')">\n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'min\')">\n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.output-timeseries-key-prefix</mat-label>\n <input required matInput formControlName="telemetryPrefix">\n <mat-error *ngIf="msgCountConfigForm.get(\'telemetryPrefix\').hasError(\'required\')">\n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class kn extends g{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,[_.required,_.min(1),_.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([_.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([_.required,_.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kn,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:kn,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="msgDelayConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMetadataPeriodInSecondsPatterns">\n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.use-metadata-period-in-seconds-patterns-hint</div>\n <mat-form-field *ngIf="msgDelayConfigForm.get(\'useMetadataPeriodInSecondsPatterns\').value !== true; else periodInSecondsPattern"\n class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <ng-template #periodInSecondsPattern>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.period-in-seconds-pattern</mat-label>\n <input required matInput formControlName="periodInSecondsPattern">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSecondsPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n </ng-template>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.max-pending-messages</mat-label>\n <input required type="number" min="1" max="100000" step="1" matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'<section [formGroup]="msgDelayConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMetadataPeriodInSecondsPatterns">\n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.use-metadata-period-in-seconds-patterns-hint</div>\n <mat-form-field *ngIf="msgDelayConfigForm.get(\'useMetadataPeriodInSecondsPatterns\').value !== true; else periodInSecondsPattern"\n class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <ng-template #periodInSecondsPattern>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.period-in-seconds-pattern</mat-label>\n <input required matInput formControlName="periodInSecondsPattern">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSecondsPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n </ng-template>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.max-pending-messages</mat-label>\n <input required type="number" min="1" max="100000" step="1" matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Tn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(f),this.telemetryTypeTranslationsMap=y}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[_.required]]})}}e("PushToCloudConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tn,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Tn,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="pushToCloudConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="pushToCloudConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="pushToCloudConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:yt,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'<section [formGroup]="pushToCloudConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="pushToCloudConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="pushToCloudConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Ln extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(f),this.telemetryTypeTranslationsMap=y}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[_.required]]})}}e("PushToEdgeConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ln,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ln,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="pushToEdgeConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="pushToEdgeConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="pushToEdgeConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:yt,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'<section [formGroup]="pushToEdgeConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="pushToEdgeConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="pushToEdgeConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class In extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({serviceIdMetaDataAttribute:[e?e.serviceIdMetaDataAttribute:null,[]],sessionIdMetaDataAttribute:[e?e.sessionIdMetaDataAttribute:null,[]],requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:In,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:In,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="rpcReplyConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.reply-routing-configuration</div>\n <tb-example-hint [hintText]="\'tb.rulenode.rpc-reply-routing-configuration-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.service-id-metadata-attribute</mat-label>\n <input matInput formControlName="serviceIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.session-id-metadata-attribute</mat-label>\n <input matInput formControlName="sessionIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'<section [formGroup]="rpcReplyConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.reply-routing-configuration</div>\n <tb-example-hint [hintText]="\'tb.rulenode.rpc-reply-routing-configuration-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.service-id-metadata-attribute</mat-label>\n <input matInput formControlName="serviceIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.session-id-metadata-attribute</mat-label>\n <input matInput formControlName="sessionIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Sn extends g{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,[_.required,_.min(0)]]})}}e("RpcRequestConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Sn,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Sn,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="rpcRequestConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.timeout-sec</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="timeoutInSeconds" required>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'<section [formGroup]="rpcRequestConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.timeout-sec</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="timeoutInSeconds" required>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Nn extends T{get required(){return this.requiredValue}set required(e){this.requiredValue=we(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(B),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,[_.required]],value:[e[n],[_.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:["",[_.required]],value:["",[_.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",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Nn,deps:[{token:R.Store},{token:X.TranslateService},{token:t.Injector},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Nn,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:K,useExisting:c((()=>Nn)),multi:!0},{provide:H,useExisting:c((()=>Nn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section fxLayout="column" class="tb-kv-map-config" [formGroup]="kvListFormGroup">\n <div class="header" fxFlex fxLayout="row" fxLayoutGap="8px">\n <span class="cell tb-required" fxFlex>{{ keyText | translate }}</span>\n <span class="cell tb-required" fxFlex>{{ valText | translate }}</span>\n <span [fxShow]="!disabled" style="width: 52px;" innerHTML="&nbsp"></span>\n </div>\n <div class="body">\n <div class="row" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"\n formArrayName="keyVals"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index">\n <mat-form-field fxFlex class="cell mat-block">\n <input [formControl]="keyValControl.get(\'key\')" matInput required\n placeholder="{{ keyText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'key\').hasError(\'required\')">\n {{ keyRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="cell mat-block">\n <input [formControl]="keyValControl.get(\'value\')" matInput required\n placeholder="{{ valText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'value\').hasError(\'required\')">\n {{ valRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <button mat-icon-button color="primary"\n [fxShow]="!disabled"\n type="button"\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n <div *ngIf="hintText" class="tb-hint" [innerHTML]="hintText | translate | safe: \'html\'"></div>\n </div>\n <tb-error [error]="ngControl.hasError(\'kvMapRequired\') || ngControl.hasError(\'uniqueKeyValuePair\') ?\n (ngControl.hasError(\'kvMapRequired\') ? translate.instant(requiredText) :\n translate.instant(\'tb.key-val.unique-key-value-pair-error\', {keyText: translate.instant(keyText),\n valText: translate.instant(valText)})) : \'\'"></tb-error>\n <div style="margin-top: 16px;">\n <button mat-button mat-raised-button color="primary"\n [fxShow]="!disabled"\n [disabled]="isLoading$ | async"\n (click)="addKeyVal()"\n type="button"\n matTooltip="{{ \'tb.key-val.add-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n </div>\n</section>\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 .header .tb-required:after{color:#757575;font-size:12px;font-weight:700}: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",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ve.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:oe.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:Pe.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:j.AsyncPipe,name:"async"},{kind:"pipe",type:ce.SafePipe,name:"safe"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:K,useExisting:c((()=>Nn)),multi:!0},{provide:H,useExisting:c((()=>Nn)),multi:!0}],template:'<section fxLayout="column" class="tb-kv-map-config" [formGroup]="kvListFormGroup">\n <div class="header" fxFlex fxLayout="row" fxLayoutGap="8px">\n <span class="cell tb-required" fxFlex>{{ keyText | translate }}</span>\n <span class="cell tb-required" fxFlex>{{ valText | translate }}</span>\n <span [fxShow]="!disabled" style="width: 52px;" innerHTML="&nbsp"></span>\n </div>\n <div class="body">\n <div class="row" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"\n formArrayName="keyVals"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index">\n <mat-form-field fxFlex class="cell mat-block">\n <input [formControl]="keyValControl.get(\'key\')" matInput required\n placeholder="{{ keyText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'key\').hasError(\'required\')">\n {{ keyRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="cell mat-block">\n <input [formControl]="keyValControl.get(\'value\')" matInput required\n placeholder="{{ valText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'value\').hasError(\'required\')">\n {{ valRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <button mat-icon-button color="primary"\n [fxShow]="!disabled"\n type="button"\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n <div *ngIf="hintText" class="tb-hint" [innerHTML]="hintText | translate | safe: \'html\'"></div>\n </div>\n <tb-error [error]="ngControl.hasError(\'kvMapRequired\') || ngControl.hasError(\'uniqueKeyValuePair\') ?\n (ngControl.hasError(\'kvMapRequired\') ? translate.instant(requiredText) :\n translate.instant(\'tb.key-val.unique-key-value-pair-error\', {keyText: translate.instant(keyText),\n valText: translate.instant(valText)})) : \'\'"></tb-error>\n <div style="margin-top: 16px;">\n <button mat-button mat-raised-button color="primary"\n [fxShow]="!disabled"\n [disabled]="isLoading$ | async"\n (click)="addKeyVal()"\n type="button"\n matTooltip="{{ \'tb.key-val.add-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n </div>\n</section>\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 .header .tb-required:after{color:#757575;font-size:12px;font-weight:700}: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",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:X.TranslateService},{type:t.Injector},{type:O.FormBuilder}]},propDecorators:{disabled:[{type:m}],uniqueKeyValuePairValidator:[{type:m}],requiredText:[{type:m}],keyText:[{type:m}],keyRequiredText:[{type:m}],valText:[{type:m}],valRequiredText:[{type:m}],hintText:[{type:m}],required:[{type:m}]}});class qn extends g{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,[_.required,_.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[_.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:qn,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:qn,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="saveToCustomTableConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.custom-table-name</mat-label>\n <input required matInput formControlName="tableName">\n <mat-error *ngIf="saveToCustomTableConfigForm.get(\'tableName\').hasError(\'required\') ||\n saveToCustomTableConfigForm.get(\'tableName\').hasError(\'pattern\')">\n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.custom-table-hint</mat-hint>\n </mat-form-field>\n <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label>\n <tb-kv-map-config-old\n required\n formControlName="fieldsMapping"\n requiredText="tb.rulenode.fields-mapping-required"\n keyText="tb.rulenode.message-field"\n keyRequiredText="tb.rulenode.message-field-required"\n valText="tb.rulenode.table-col"\n valRequiredText="tb.rulenode.table-col-required">\n </tb-kv-map-config-old>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'<section [formGroup]="saveToCustomTableConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.custom-table-name</mat-label>\n <input required matInput formControlName="tableName">\n <mat-error *ngIf="saveToCustomTableConfigForm.get(\'tableName\').hasError(\'required\') ||\n saveToCustomTableConfigForm.get(\'tableName\').hasError(\'pattern\')">\n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.custom-table-hint</mat-hint>\n </mat-form-field>\n <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label>\n <tb-kv-map-config-old\n required\n formControlName="fieldsMapping"\n requiredText="tb.rulenode.fields-mapping-required"\n keyText="tb.rulenode.message-field"\n keyRequiredText="tb.rulenode.message-field-required"\n valText="tb.rulenode.table-col"\n valRequiredText="tb.rulenode.table-col-required">\n </tb-kv-map-config-old>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class An extends g{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,[_.required,_.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:An,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:An,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="timeseriesConfigForm" class="tb-form-panel no-border no-padding">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.default-ttl</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="defaultTTL" required>\n <mat-icon class="help-icon margin-8 cursor-pointer"\n aria-hidden="false"\n aria-label="help-icon"\n matSuffix\n matTooltip="{{ \'tb.rulenode.default-ttl-hint\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'required\')">\n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'min\')">\n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <div class="tb-form-panel stroked">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.use-server-ts-hint\' | translate}}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="useServerTs">\n {{ \'tb.rulenode.use-server-ts\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.skip-latest-persistence-hint\' | translate}}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="skipLatestPersistence">\n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'<section [formGroup]="timeseriesConfigForm" class="tb-form-panel no-border no-padding">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.default-ttl</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="defaultTTL" required>\n <mat-icon class="help-icon margin-8 cursor-pointer"\n aria-hidden="false"\n aria-label="help-icon"\n matSuffix\n matTooltip="{{ \'tb.rulenode.default-ttl-hint\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'required\')">\n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'min\')">\n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <div class="tb-form-panel stroked">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.use-server-ts-hint\' | translate}}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="useServerTs">\n {{ \'tb.rulenode.use-server-ts\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.skip-latest-persistence-hint\' | translate}}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="skipLatestPersistence">\n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Mn extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}prepareInputConfig(e){return{customerNamePattern:ye(e?.customerNamePattern)?e.customerNamePattern:null,unassignFromCustomer:ye(e?.customerNamePattern)}}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e.customerNamePattern,[]],unassignFromCustomer:[e.unassignFromCustomer,[]]})}validatorTriggers(){return["unassignFromCustomer"]}updateValidators(e){this.unassignCustomerConfigForm.get("unassignFromCustomer").value?this.unassignCustomerConfigForm.get("customerNamePattern").setValidators([_.required,_.pattern(/.*\S.*/)]):this.unassignCustomerConfigForm.get("customerNamePattern").setValidators([]),this.unassignCustomerConfigForm.get("customerNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return{customerNamePattern:e.unassignFromCustomer?e.customerNamePattern.trim():null}}}e("UnassignCustomerConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Mn,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Mn,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="unassignCustomerConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n\n <div class="tb-form-panel stroked" [class.no-padding-bottom]="unassignCustomerConfigForm.get(\'unassignFromCustomer\').value">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.unassign-from-customer-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="unassignFromCustomer">\n {{ \'tb.rulenode.unassign-from-customer\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic" *ngIf="unassignCustomerConfigForm.get(\'unassignFromCustomer\').value">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\') ||\n unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.customer-name-pattern-hint</mat-hint>\n </mat-form-field>\n </div>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:W.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'<section [formGroup]="unassignCustomerConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n\n <div class="tb-form-panel stroked" [class.no-padding-bottom]="unassignCustomerConfigForm.get(\'unassignFromCustomer\').value">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.unassign-from-customer-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="unassignFromCustomer">\n {{ \'tb.rulenode.unassign-from-customer\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic" *ngIf="unassignCustomerConfigForm.get(\'unassignFromCustomer\').value">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\') ||\n unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.customer-name-pattern-hint</mat-hint>\n </mat-form-field>\n </div>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class En extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendRestApiCallReplyConfigForm}onConfigurationSet(e){this.sendRestApiCallReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]],serviceIdMetaDataAttribute:[e?e.serviceIdMetaDataAttribute:null,[]]})}}e("SendRestApiCallReplyConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:En,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:En,selector:"tb-action-node-send-rest-api-call-reply-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="sendRestApiCallReplyConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.reply-routing-configuration</div>\n <tb-example-hint [hintText]="\'tb.rulenode.reply-routing-configuration-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.service-id-metadata-attribute</mat-label>\n <input matInput formControlName="serviceIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-action-node-send-rest-api-call-reply-config",template:'<section [formGroup]="sendRestApiCallReplyConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.reply-routing-configuration</div>\n <tb-example-hint [hintText]="\'tb.rulenode.reply-routing-configuration-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields column-xs">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.service-id-metadata-attribute</mat-label>\n <input matInput formControlName="serviceIdMetaDataAttribute">\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class wn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=f,this.attributeScopes=Object.keys(f),this.telemetryTypeTranslationsMap=y,this.separatorKeysCodes=[ke,Te,Le]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[_.required]],keys:[e?e.keys:null,[_.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==f.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",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:wn,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:wn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deleteAttributesConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="deleteAttributesConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="deleteAttributesConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label>{{ \'tb.rulenode.attributes-keys\' | translate }}</mat-label>\n <mat-chip-grid formControlName="keys" #attributeChipList>\n <mat-chip-row\n *ngFor="let key of deleteAttributesConfigForm.get(\'keys\').value;"\n (removed)="removeKey(key)">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text"\n [matChipInputFor]="attributeChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event)"\n [matChipInputAddOnBlur]="true">\n </mat-chip-grid>\n <mat-error *ngIf="deleteAttributesConfigForm.get(\'keys\').hasError(\'required\')">{{ \'tb.rulenode.attributes-keys-required\' | translate }}</mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.send-attributes-deleted-notification-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="sendAttributesDeletedNotification">\n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.notify-device-on-delete-hint\' | translate }}"\n *ngIf="deleteAttributesConfigForm.get(\'scope\').value === attributeScopeMap.SHARED_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="notifyDevice">\n {{ \'tb.rulenode.notify-device\' | translate }}\n </mat-slide-toggle>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"component",type:ae.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:ae.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:ae.MatExpansionPanelTitle,selector:"mat-panel-title"},{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:yt,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'<section [formGroup]="deleteAttributesConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <tb-example-hint [hintText]="\'tb.rulenode.attributes-scope-hint\'">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope\' | translate }}</mat-label>\n <mat-select required\n class="tb-entity-type-select" matInput formControlName="scope">\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{ \'tb.rulenode.attributes-scope-value\' | translate }}</mat-label>\n <input type="text" matInput readonly disabled [ngModel]="deleteAttributesConfigForm.get(\'scope\').value" [ngModelOptions]="{standalone: true}">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n ngxClipboard\n [cbContent]="deleteAttributesConfigForm.get(\'scope\').value"\n matTooltip="{{ \'tb.rulenode.attributes-scope-value-copy\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label>{{ \'tb.rulenode.attributes-keys\' | translate }}</mat-label>\n <mat-chip-grid formControlName="keys" #attributeChipList>\n <mat-chip-row\n *ngFor="let key of deleteAttributesConfigForm.get(\'keys\').value;"\n (removed)="removeKey(key)">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text"\n [matChipInputFor]="attributeChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event)"\n [matChipInputAddOnBlur]="true">\n </mat-chip-grid>\n <mat-error *ngIf="deleteAttributesConfigForm.get(\'keys\').hasError(\'required\')">{{ \'tb.rulenode.attributes-keys-required\' | translate }}</mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.send-attributes-deleted-notification-hint\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="sendAttributesDeletedNotification">\n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.notify-device-on-delete-hint\' | translate }}"\n *ngIf="deleteAttributesConfigForm.get(\'scope\').value === attributeScopeMap.SHARED_SCOPE"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="notifyDevice">\n {{ \'tb.rulenode.notify-device\' | translate }}\n </mat-slide-toggle>\n </div>\n </mat-expansion-panel>\n </section>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:u,args:["attributeChipList"]}]}});class Gn extends T{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t){super(e),this.store=e,this.fb=t,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=on,this.ArgumentType=an,this.attributeScopeMap=bn,this.argumentTypeMap=un,this.arguments=Object.values(an),this.attributeScope=Object.values(fn),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){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()}get 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.argumentsFormArray.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.argumentsFormArray.removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormArray,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===rn.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([_.minLength(this.minArgs),_.maxLength(this.maxArgs)]);this.argumentsFormArray.length>this.maxArgs;)this.removeArgument(this.maxArgs-1);for(;this.argumentsFormArray.length<this.minArgs;)this.addArgument(e);this.argumentsFormGroup.get("arguments").updateValueAndValidity({emitEvent:!1})}}createArgumentControl(e,t){const n=this.fb.group({type:[e?.type,[_.required]],key:[e?.key,[_.required]],name:[gn[t],[_.required]],attributeScope:[e?.attributeScope??fn.SERVER_SCOPE,[_.required]],defaultValue:[e?.defaultValue?e?.defaultValue:null]});return this.updateArgumentControlValidators(n),this.valueChangeSubscription.push(n.get("type").valueChanges.subscribe((()=>{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===an.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==an.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormArray.controls.forEach(((e,t)=>{e.get("name").setValue(gn[t])}))}updateModel(){const e=this.argumentsFormArray.value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Gn,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Gn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:K,useExisting:c((()=>Gn)),multi:!0},{provide:H,useExisting:c((()=>Gn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section fxLayout="column">\n\n <div [ngClass]="{\'tb-readonly\': disabled}"\n style="max-height: 500px; overflow: auto;">\n <mat-list class="tb-drop-list arguments-list" cdkDropList cdkDropListOrientation="vertical"\n [formGroup]="argumentsFormGroup"\n (cdkDropListDropped)="onDrop($event)"\n [cdkDropListDisabled]="disabled">\n <mat-list-item *ngFor="let argumentControl of argumentsFormArray.controls; let $index = index"\n formArrayName="arguments"\n cdkDrag class="tb-argument tb-draggable"\n [cdkDragDisabled]="disabled"\n style="height: 100%">\n <div fxFlex fxLayout="row" fxLayoutAlign="start center">\n <button *ngIf="!disabled" mat-icon-button color="primary"\n cdkDragHandle\n class="tb-drag-handle handle"\n style="min-width: 40px; margin: 0"\n matTooltip="{{ \'action.drag\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>drag_handle</mat-icon>\n </button>\n <div fxFlex fxLAyout="row" fxLayoutAlign="start center" fxLayoutGap="16px">\n <span *ngIf="displayArgumentName"\n style="padding: 0 10px; min-width: 20px;">{{argumentControl.get(\'name\').value}}.</span>\n <div fxFlex fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.argument-source-field-input</mat-label>\n <mat-select [formControl]="argumentControl.get(\'type\')" required>\n <mat-select-trigger>\n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n </mat-select-trigger>\n <mat-option *ngFor="let argument of arguments" [value]="argument"\n style="border-bottom: 1px solid #eee;">\n {{ argumentTypeMap.get(argument).name | translate }}\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ argumentTypeMap.get(argument).description }}\n </small>\n </mat-option>\n </mat-select>\n <mat-error *ngIf="argumentControl.get(\'type\').hasError(\'required\')" translate>\n tb.rulenode.argument-source-field-input-required\n </mat-error>\n </mat-form-field>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block"\n *ngIf="argumentControl.get(\'type\').value && argumentControl.get(\'type\').value !== ArgumentType.CONSTANT">\n <mat-label translate>tb.rulenode.argument-key-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'key\')" matInput required/>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.math-templatization-tooltip\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="argumentControl.get(\'key\').hasError(\'required\')" translate>\n tb.rulenode.argument-key-field-input-required\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block"\n *ngIf="argumentControl.get(\'type\').value === ArgumentType.CONSTANT">\n <mat-label translate>tb.rulenode.constant-value-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'key\')"\n matInput\n required\n step="1" min="0"\n type="number"/>\n <mat-error *ngIf="argumentControl.get(\'key\').hasError(\'required\')" translate>\n tb.rulenode.constant-value-field-input-required\n </mat-error>\n </mat-form-field>\n <mat-form-field *ngIf="argumentControl.get(\'type\').value && argumentControl.get(\'type\').value !== ArgumentType.CONSTANT"\n fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.default-value-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'defaultValue\')" matInput step="1" type="number"/>\n </mat-form-field>\n </div>\n <mat-form-field *ngIf="argumentControl.get(\'type\').value === ArgumentType.ATTRIBUTE" class="mat-block">\n <mat-label translate>tb.rulenode.attribute-scope-field-input</mat-label>\n <mat-select required [formControl]="argumentControl.get(\'attributeScope\')">\n <mat-option *ngFor="let scope of attributeScope" [value]="scope">\n {{ attributeScopeMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="argumentControl.get(\'attributeScope\').hasError(\'required\')" translate>\n tb.rulenode.attribute-scope-field-input-required\n </mat-error>\n </mat-form-field>\n </div>\n <button *ngIf="!disabled" mat-icon-button color="primary" style="min-width: 40px;"\n (click)="removeArgument($index)"\n matTooltip="{{ \'action.remove\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </mat-list-item>\n </mat-list>\n </div>\n <div *ngIf="!argumentsFormArray.length">\n <span translate fxLayoutAlign="center center"\n class="tb-prompt">tb.rulenode.no-arguments-prompt</span>\n </div>\n <button mat-button mat-raised-button color="primary"\n [disabled]="argumentsFormArray.length >= maxArgs"\n (click)="addArgument()"\n type="button"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n</section>\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:j.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:ne.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Re.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:Re.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:Oe.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:Oe.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:Oe.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:Pe.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Gn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:K,useExisting:c((()=>Gn)),multi:!0},{provide:H,useExisting:c((()=>Gn)),multi:!0}],template:'<section fxLayout="column">\n\n <div [ngClass]="{\'tb-readonly\': disabled}"\n style="max-height: 500px; overflow: auto;">\n <mat-list class="tb-drop-list arguments-list" cdkDropList cdkDropListOrientation="vertical"\n [formGroup]="argumentsFormGroup"\n (cdkDropListDropped)="onDrop($event)"\n [cdkDropListDisabled]="disabled">\n <mat-list-item *ngFor="let argumentControl of argumentsFormArray.controls; let $index = index"\n formArrayName="arguments"\n cdkDrag class="tb-argument tb-draggable"\n [cdkDragDisabled]="disabled"\n style="height: 100%">\n <div fxFlex fxLayout="row" fxLayoutAlign="start center">\n <button *ngIf="!disabled" mat-icon-button color="primary"\n cdkDragHandle\n class="tb-drag-handle handle"\n style="min-width: 40px; margin: 0"\n matTooltip="{{ \'action.drag\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>drag_handle</mat-icon>\n </button>\n <div fxFlex fxLAyout="row" fxLayoutAlign="start center" fxLayoutGap="16px">\n <span *ngIf="displayArgumentName"\n style="padding: 0 10px; min-width: 20px;">{{argumentControl.get(\'name\').value}}.</span>\n <div fxFlex fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.argument-source-field-input</mat-label>\n <mat-select [formControl]="argumentControl.get(\'type\')" required>\n <mat-select-trigger>\n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n </mat-select-trigger>\n <mat-option *ngFor="let argument of arguments" [value]="argument"\n style="border-bottom: 1px solid #eee;">\n {{ argumentTypeMap.get(argument).name | translate }}\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ argumentTypeMap.get(argument).description }}\n </small>\n </mat-option>\n </mat-select>\n <mat-error *ngIf="argumentControl.get(\'type\').hasError(\'required\')" translate>\n tb.rulenode.argument-source-field-input-required\n </mat-error>\n </mat-form-field>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block"\n *ngIf="argumentControl.get(\'type\').value && argumentControl.get(\'type\').value !== ArgumentType.CONSTANT">\n <mat-label translate>tb.rulenode.argument-key-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'key\')" matInput required/>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.math-templatization-tooltip\' | translate }}">\n help\n </mat-icon>\n <mat-error *ngIf="argumentControl.get(\'key\').hasError(\'required\')" translate>\n tb.rulenode.argument-key-field-input-required\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block"\n *ngIf="argumentControl.get(\'type\').value === ArgumentType.CONSTANT">\n <mat-label translate>tb.rulenode.constant-value-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'key\')"\n matInput\n required\n step="1" min="0"\n type="number"/>\n <mat-error *ngIf="argumentControl.get(\'key\').hasError(\'required\')" translate>\n tb.rulenode.constant-value-field-input-required\n </mat-error>\n </mat-form-field>\n <mat-form-field *ngIf="argumentControl.get(\'type\').value && argumentControl.get(\'type\').value !== ArgumentType.CONSTANT"\n fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.default-value-field-input</mat-label>\n <input [formControl]="argumentControl.get(\'defaultValue\')" matInput step="1" type="number"/>\n </mat-form-field>\n </div>\n <mat-form-field *ngIf="argumentControl.get(\'type\').value === ArgumentType.ATTRIBUTE" class="mat-block">\n <mat-label translate>tb.rulenode.attribute-scope-field-input</mat-label>\n <mat-select required [formControl]="argumentControl.get(\'attributeScope\')">\n <mat-option *ngFor="let scope of attributeScope" [value]="scope">\n {{ attributeScopeMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="argumentControl.get(\'attributeScope\').hasError(\'required\')" translate>\n tb.rulenode.attribute-scope-field-input-required\n </mat-error>\n </mat-form-field>\n </div>\n <button *ngIf="!disabled" mat-icon-button color="primary" style="min-width: 40px;"\n (click)="removeArgument($index)"\n matTooltip="{{ \'action.remove\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </mat-list-item>\n </mat-list>\n </div>\n <div *ngIf="!argumentsFormArray.length">\n <span translate fxLayoutAlign="center center"\n class="tb-prompt">tb.rulenode.no-arguments-prompt</span>\n </div>\n <button mat-button mat-raised-button color="primary"\n [disabled]="argumentsFormArray.length >= maxArgs"\n (click)="addArgument()"\n type="button"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n</section>\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:R.Store},{type:O.FormBuilder}]},propDecorators:{disabled:[{type:m}],function:[{type:m}]}});class Dn extends T{get required(){return this.requiredValue}set required(e){this.requiredValue=we(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=[...on.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(_e((e=>{let t;t="string"==typeof e&&rn[e]?rn[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=on.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",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Dn,deps:[{token:R.Store},{token:X.TranslateService},{token:t.Injector},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Dn,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:K,useExisting:c((()=>Dn)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'<mat-form-field [formGroup]="mathFunctionForm" class="mat-block">\n <mat-label translate>tb.rulenode.functions-field-input</mat-label>\n <input [required]="required"\n (focusin)="onFocus()"\n type="text"\n #operationInput matInput\n formControlName="operation"\n [matAutocomplete]="auto">\n <button *ngIf="mathFunctionForm.get(\'operation\').value"\n type="button"\n matSuffix mat-icon-button aria-label="Clear"\n (click)="clear()">\n <mat-icon class="material-icons">close</mat-icon>\n </button>\n <mat-autocomplete #auto="matAutocomplete" class="tb-autocomplete" [displayWith]="mathFunctionDisplayFn">\n <mat-option *ngFor="let option of filteredOptions | async" [value]="option.value">\n <span [innerHTML]="option.value + \' | \' + option.name | highlight:searchText"></span>\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ option.description }}\n </small>\n </mat-option>\n <mat-option *ngIf="!(filteredOptions | async)?.length" [value]="null">\n <span translate>tb.rulenode.no-option-found</span>\n </mat-option>\n </mat-autocomplete>\n</mat-form-field>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:$e.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:$e.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.AsyncPipe,name:"async"},{kind:"pipe",type:Je.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:K,useExisting:c((()=>Dn)),multi:!0}],template:'<mat-form-field [formGroup]="mathFunctionForm" class="mat-block">\n <mat-label translate>tb.rulenode.functions-field-input</mat-label>\n <input [required]="required"\n (focusin)="onFocus()"\n type="text"\n #operationInput matInput\n formControlName="operation"\n [matAutocomplete]="auto">\n <button *ngIf="mathFunctionForm.get(\'operation\').value"\n type="button"\n matSuffix mat-icon-button aria-label="Clear"\n (click)="clear()">\n <mat-icon class="material-icons">close</mat-icon>\n </button>\n <mat-autocomplete #auto="matAutocomplete" class="tb-autocomplete" [displayWith]="mathFunctionDisplayFn">\n <mat-option *ngFor="let option of filteredOptions | async" [value]="option.value">\n <span [innerHTML]="option.value + \' | \' + option.name | highlight:searchText"></span>\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ option.description }}\n </small>\n </mat-option>\n <mat-option *ngIf="!(filteredOptions | async)?.length" [value]="null">\n <span translate>tb.rulenode.no-option-found</span>\n </mat-option>\n </mat-autocomplete>\n</mat-form-field>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:X.TranslateService},{type:t.Injector},{type:O.UntypedFormBuilder}]},propDecorators:{required:[{type:m}],disabled:[{type:m}],operationInput:[{type:u,args:["operationInput",{static:!0}]}]}});class Vn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=rn,this.ArgumentTypeResult=ln,this.argumentTypeResultMap=cn,this.attributeScopeMap=bn,this.argumentsResult=Object.values(ln),this.attributeScopeResult=Object.values(yn)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[_.required]],arguments:[e?e.arguments:null,[_.required]],customFunction:[e?e.customFunction:"",[_.required]],result:this.fb.group({type:[e?e.result.type:null,[_.required]],attributeScope:[e?e.result.attributeScope:null,[_.required]],key:[e?e.result.key:"",[_.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===rn.CUSTOM?(this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}),null===this.mathFunctionConfigForm.get("customFunction").value&&this.mathFunctionConfigForm.get("customFunction").patchValue("(x - 32) / 1.8",{emitEvent:!1})):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===ln.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",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Vn,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Vn,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="mathFunctionConfigForm" fxLayout="column">\n <tb-math-function-autocomplete\n fxFlex="30" fxFlex.md fxFlex.xs\n required\n formControlName="operation">\n </tb-math-function-autocomplete>\n <fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title" translate>tb.rulenode.argument-tile</legend>\n <tb-arguments-map-config formControlName="arguments"\n [function]="mathFunctionConfigForm.get(\'operation\').value">\n </tb-arguments-map-config>\n </fieldset>\n <fieldset *ngIf="mathFunctionConfigForm.get(\'operation\').value === MathFunction.CUSTOM"\n class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title">{{\'tb.rulenode.custom-expression-field-input\' | translate }} *</legend>\n <mat-form-field fxFlex class="mat-block no-margin-top" subscriptSizing="dynamic">\n <input matInput formControlName="customFunction" required/>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'customFunction\').hasError(\'required\')" translate>\n tb.rulenode.custom-expression-field-input-required\n </mat-error>\n <mat-hint translate>tb.rulenode.custom-expression-field-input-hint</mat-hint>\n </mat-form-field>\n </fieldset>\n <fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title" translate>tb.rulenode.result-title</legend>\n <div formGroupName="result">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.type-field-input</mat-label>\n <mat-select formControlName="type" required>\n <mat-select-trigger>\n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n </mat-select-trigger>\n <mat-option *ngFor="let argument of argumentsResult" [value]="argument"\n style="border-bottom: 1px solid #eee;">\n {{ argumentTypeResultMap.get(argument).name | translate }}\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ argumentTypeResultMap.get(argument).description }}\n </small>\n </mat-option>\n </mat-select>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'result.type\').hasError(\'required\')" translate>\n tb.rulenode.type-field-input-required\n </mat-error>\n </mat-form-field>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex class="mat-block" *ngIf="mathFunctionConfigForm.get(\'result\').get(\'type\').value === ArgumentTypeResult.ATTRIBUTE">\n <mat-label translate>tb.rulenode.attribute-scope-field-input</mat-label>\n <mat-select required formControlName="attributeScope">\n <mat-option *ngFor="let scope of attributeScopeResult" [value]="scope">\n {{ attributeScopeMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.key-field-input</mat-label>\n <input matInput formControlName="key" required/>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.math-templatization-tooltip\' | translate }}">help</mat-icon>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'result.key\').hasError(\'required\')" translate>\n tb.rulenode.key-field-input-required\n </mat-error>\n </mat-form-field>\n </div>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex floatLabel="always" class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.number-floating-point-field-input</mat-label>\n <input formControlName="resultValuePrecision"\n matInput\n step="1" min="0"\n type="number"/>\n <mat-hint [innerHTML]="\'tb.rulenode.number-floating-point-field-input-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n </div>\n <div *ngIf="[ArgumentTypeResult.ATTRIBUTE, ArgumentTypeResult.TIME_SERIES].includes(mathFunctionConfigForm.get(\'result\').get(\'type\').value)"\n fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start" fxLayoutGap.gt-xs="16px" style="padding-top: 16px;">\n <mat-checkbox formControlName="addToBody">\n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="addToMetadata">\n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n </mat-checkbox>\n </div>\n </div>\n </fieldset>\n</section>\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:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:ne.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:O.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Gn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:Dn,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:ce.SafePipe,name:"safe"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'<section [formGroup]="mathFunctionConfigForm" fxLayout="column">\n <tb-math-function-autocomplete\n fxFlex="30" fxFlex.md fxFlex.xs\n required\n formControlName="operation">\n </tb-math-function-autocomplete>\n <fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title" translate>tb.rulenode.argument-tile</legend>\n <tb-arguments-map-config formControlName="arguments"\n [function]="mathFunctionConfigForm.get(\'operation\').value">\n </tb-arguments-map-config>\n </fieldset>\n <fieldset *ngIf="mathFunctionConfigForm.get(\'operation\').value === MathFunction.CUSTOM"\n class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title">{{\'tb.rulenode.custom-expression-field-input\' | translate }} *</legend>\n <mat-form-field fxFlex class="mat-block no-margin-top" subscriptSizing="dynamic">\n <input matInput formControlName="customFunction" required/>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'customFunction\').hasError(\'required\')" translate>\n tb.rulenode.custom-expression-field-input-required\n </mat-error>\n <mat-hint translate>tb.rulenode.custom-expression-field-input-hint</mat-hint>\n </mat-form-field>\n </fieldset>\n <fieldset class="fields-group" fxLayout="column" fxLayoutGap="8px">\n <legend class="group-title" translate>tb.rulenode.result-title</legend>\n <div formGroupName="result">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.type-field-input</mat-label>\n <mat-select formControlName="type" required>\n <mat-select-trigger>\n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n </mat-select-trigger>\n <mat-option *ngFor="let argument of argumentsResult" [value]="argument"\n style="border-bottom: 1px solid #eee;">\n {{ argumentTypeResultMap.get(argument).name | translate }}\n <small style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">\n {{ argumentTypeResultMap.get(argument).description }}\n </small>\n </mat-option>\n </mat-select>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'result.type\').hasError(\'required\')" translate>\n tb.rulenode.type-field-input-required\n </mat-error>\n </mat-form-field>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex class="mat-block" *ngIf="mathFunctionConfigForm.get(\'result\').get(\'type\').value === ArgumentTypeResult.ATTRIBUTE">\n <mat-label translate>tb.rulenode.attribute-scope-field-input</mat-label>\n <mat-select required formControlName="attributeScope">\n <mat-option *ngFor="let scope of attributeScopeResult" [value]="scope">\n {{ attributeScopeMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.key-field-input</mat-label>\n <input matInput formControlName="key" required/>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.math-templatization-tooltip\' | translate }}">help</mat-icon>\n <mat-error *ngIf="mathFunctionConfigForm.get(\'result.key\').hasError(\'required\')" translate>\n tb.rulenode.key-field-input-required\n </mat-error>\n </mat-form-field>\n </div>\n <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="16px">\n <mat-form-field fxFlex floatLabel="always" class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.number-floating-point-field-input</mat-label>\n <input formControlName="resultValuePrecision"\n matInput\n step="1" min="0"\n type="number"/>\n <mat-hint [innerHTML]="\'tb.rulenode.number-floating-point-field-input-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n </div>\n <div *ngIf="[ArgumentTypeResult.ATTRIBUTE, ArgumentTypeResult.TIME_SERIES].includes(mathFunctionConfigForm.get(\'result\').get(\'type\').value)"\n fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start" fxLayoutGap.gt-xs="16px" style="padding-top: 16px;">\n <mat-checkbox formControlName="addToBody">\n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="addToMetadata">\n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n </mat-checkbox>\n </div>\n </div>\n </fieldset>\n</section>\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:R.Store},{type:O.UntypedFormBuilder}]}});class Pn extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageTypeNames=L,this.eventOptions=[I.CONNECT_EVENT,I.ACTIVITY_EVENT,I.DISCONNECT_EVENT,I.INACTIVITY_EVENT]}configForm(){return this.deviceState}prepareInputConfig(e){return{event:ye(e?.event)?e.event:I.ACTIVITY_EVENT}}onConfigurationSet(e){this.deviceState=this.fb.group({event:[e.event,[_.required]]})}}e("DeviceStateConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Pn,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Pn,selector:"tb-action-node-device-state-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deviceState">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label>{{ \'tb.rulenode.select-device-connectivity-event\' | translate }}</mat-label>\n <mat-select formControlName="event">\n <mat-option *ngFor="let eventOption of eventOptions" [value]="eventOption">\n {{ messageTypeNames.get(eventOption) }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-action-node-device-state-config",template:'<section [formGroup]="deviceState">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label>{{ \'tb.rulenode.select-device-connectivity-event\' | translate }}</mat-label>\n <mat-select formControlName="event">\n <mat-option *ngFor="let eventOption of eventOptions" [value]="eventOption">\n {{ messageTypeNames.get(eventOption) }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class Rn{constructor(e,t){this.injector=e,this.fb=t,this.propagateChange=()=>{},this.destroy$=new ie,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1,this.duplicateValuesValidator=e=>e.controls.key.value===e.controls.value.value&&e.controls.key.value&&e.controls.value.value?{uniqueKeyValuePair:!0}:null,this.oneMapRequiredValidator=e=>e.get("keyVals").value.length,this.propagateNestedErrors=e=>{if(this.kvListFormGroup&&this.kvListFormGroup.get("keyVals")&&"VALID"===this.kvListFormGroup.get("keyVals")?.status)return null;const t={};if(this.kvListFormGroup&&this.kvListFormGroup.setErrors(null),e instanceof z||e instanceof U){if(e.errors)for(const n of Object.keys(e.errors))t[n]=!0;for(const n of Object.keys(e.controls)){const r=this.propagateNestedErrors(e.controls[n]);if(r&&Object.keys(r).length)for(const e of Object.keys(r))t[e]=!0}return t}if(e.errors)for(const n of Object.keys(e.errors))t[n]=!0;return be(t,{})?null:t}}ngOnInit(){this.ngControl=this.injector.get(B),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({keyVals:this.fb.array([])},{validators:[this.propagateNestedErrors,this.oneMapRequiredValidator]}),this.kvListFormGroup.valueChanges.pipe(le(this.destroy$)).subscribe((()=>{this.updateModel()}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}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){const t=Object.keys(e).map((t=>({key:t,value:e[t]})));if(this.keyValsFormArray().length===t.length)this.keyValsFormArray().patchValue(t,{emitEvent:!1});else{const e=[];t.forEach((t=>{e.push(this.fb.group({key:[t.key,[_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[t.value,[_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]},{validators:this.uniqueKeyValuePairValidator?[this.duplicateValuesValidator]:[]}))})),this.kvListFormGroup.setControl("keyVals",this.fb.array(e,this.propagateNestedErrors),{emitEvent:!1})}}removeKeyVal(e){this.keyValsFormArray().removeAt(e)}addKeyVal(){this.keyValsFormArray().push(this.fb.group({key:["",[_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]},{validators:this.uniqueKeyValuePairValidator?[this.duplicateValuesValidator]:[]}))}validate(){const e=this.kvListFormGroup.get("keyVals").value;if(!e.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const t of e)if(t.key===t.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",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Rn,deps:[{token:t.Injector},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Rn,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:K,useExisting:c((()=>Rn)),multi:!0},{provide:H,useExisting:c((()=>Rn)),multi:!0}],ngImport:t,template:'<section [formGroup]="kvListFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title">{{ labelText }}</div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'kvMapRequired\')">\n {{ requiredText }}\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'required\')">\n tb.rulenode.map-fields-required\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'uniqueKeyValuePair\')">\n {{ \'tb.key-val.unique-key-value-pair-error\' | translate:\n {\n valText: valText,\n keyText: keyText\n } }}\n </div>\n </div>\n <div class="tb-form-panel no-border no-padding">\n <div class="tb-form-table">\n <div class="tb-form-table-header">\n <div class="tb-form-table-header-cell field-space">{{ keyText }}</div>\n <div class="tb-form-table-header-cell field-space">{{ valText }}</div>\n <div class="tb-form-table-header-cell actions-header"></div>\n </div>\n <div class="tb-form-table-body">\n <div class="tb-form-table-row"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index;">\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="keyText+\'*\'" [formControl]="keyValControl.get(\'key\')" matInput/>\n </mat-form-field>\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="valText+\'*\'" [formControl]="keyValControl.get(\'value\')" matInput/>\n </mat-form-field>\n <div class="tb-form-table-row-cell-buttons">\n <button [class.tb-hidden]="keyValsFormArray().controls.length === 1"\n type="button"\n mat-icon-button\n (click)="removeKeyVal($index)"\n [disabled]="disabled"\n matTooltip="{{ \'tb.key-val.remove-mapping-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div>\n <button type="button" mat-stroked-button color="primary" (click)="addKeyVal()">\n {{ \'tb.key-val.add-mapping-entry\' | translate }}\n </button>\n </div>\n <tb-example-hint [hintText]="hintText" [popupHelpLink]="popupHelpLink" *ngIf="popupHelpLink || hintText"></tb-example-hint>\n</section>\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),Ye([S()],Rn.prototype,"disabled",void 0),Ye([S()],Rn.prototype,"uniqueKeyValuePairValidator",void 0),Ye([S()],Rn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:K,useExisting:c((()=>Rn)),multi:!0},{provide:H,useExisting:c((()=>Rn)),multi:!0}],template:'<section [formGroup]="kvListFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title">{{ labelText }}</div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'kvMapRequired\')">\n {{ requiredText }}\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'required\')">\n tb.rulenode.map-fields-required\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="kvListFormGroup.hasError(\'uniqueKeyValuePair\')">\n {{ \'tb.key-val.unique-key-value-pair-error\' | translate:\n {\n valText: valText,\n keyText: keyText\n } }}\n </div>\n </div>\n <div class="tb-form-panel no-border no-padding">\n <div class="tb-form-table">\n <div class="tb-form-table-header">\n <div class="tb-form-table-header-cell field-space">{{ keyText }}</div>\n <div class="tb-form-table-header-cell field-space">{{ valText }}</div>\n <div class="tb-form-table-header-cell actions-header"></div>\n </div>\n <div class="tb-form-table-body">\n <div class="tb-form-table-row"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index;">\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="keyText+\'*\'" [formControl]="keyValControl.get(\'key\')" matInput/>\n </mat-form-field>\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="valText+\'*\'" [formControl]="keyValControl.get(\'value\')" matInput/>\n </mat-form-field>\n <div class="tb-form-table-row-cell-buttons">\n <button [class.tb-hidden]="keyValsFormArray().controls.length === 1"\n type="button"\n mat-icon-button\n (click)="removeKeyVal($index)"\n [disabled]="disabled"\n matTooltip="{{ \'tb.key-val.remove-mapping-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div>\n <button type="button" mat-stroked-button color="primary" (click)="addKeyVal()">\n {{ \'tb.key-val.add-mapping-entry\' | translate }}\n </button>\n </div>\n <tb-example-hint [hintText]="hintText" [popupHelpLink]="popupHelpLink" *ngIf="popupHelpLink || hintText"></tb-example-hint>\n</section>\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:t.Injector},{type:O.FormBuilder}]},propDecorators:{disabled:[{type:m}],uniqueKeyValuePairValidator:[{type:m}],labelText:[{type:m}],requiredText:[{type:m}],keyText:[{type:m}],keyRequiredText:[{type:m}],valText:[{type:m}],valRequiredText:[{type:m}],hintText:[{type:m}],popupHelpLink:[{type:m}],required:[{type:m}]}});class On extends T{get required(){return this.requiredValue}set required(e){this.requiredValue=we(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(v),this.directionTypeTranslations=N,this.entityType=C,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[_.required]],maxLevel:[null,[_.min(1)]],relationType:[null],deviceTypes:[null,[_.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",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:On,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:On,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:K,useExisting:c((()=>On)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section fxLayout="column" [formGroup]="deviceRelationsQueryFormGroup">\n <div fxLayoutGap="22px" fxLayout="row">\n <mat-form-field class="mat-block" subscriptSizing="dynamic" fxFlex="50" style="min-width: 100px;" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n <mat-error *ngIf="deviceRelationsQueryFormGroup.get(\'maxLevel\').hasError(\'min\')">\n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.last-level-device-relation-tooltip\' | translate }}"\n *ngIf="deviceRelationsQueryFormGroup.get(\'maxLevel\').value > 1"\n class="tb-form-row no-border no-padding last-level-slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-slide-toggle>\n </div>\n <tb-relation-type-autocomplete\n fxFlex\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <tb-entity-subtype-list\n required\n [label]="\'tb.rulenode.device-profiles\' | translate"\n [entityType]="entityType.DEVICE"\n [emptyInputPlaceholder]="\'tb.rulenode.add-device-profile\' | translate"\n [filledInputPlaceholder]="\'tb.rulenode.add-device-profile\' | translate"\n formControlName="deviceTypes">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.device-profile\' | translate } }}">help</mat-icon>\n </tb-entity-subtype-list>\n</section>\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:We.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","floatLabel","label","disabled","entityType","emptyInputPlaceholder","filledInputPlaceholder","appearance","subscriptSizing","additionalClasses"]},{kind:"component",type:qe.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:W.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: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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:K,useExisting:c((()=>On)),multi:!0}],template:'<section fxLayout="column" [formGroup]="deviceRelationsQueryFormGroup">\n <div fxLayoutGap="22px" fxLayout="row">\n <mat-form-field class="mat-block" subscriptSizing="dynamic" fxFlex="50" style="min-width: 100px;" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n <mat-error *ngIf="deviceRelationsQueryFormGroup.get(\'maxLevel\').hasError(\'min\')">\n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.last-level-device-relation-tooltip\' | translate }}"\n *ngIf="deviceRelationsQueryFormGroup.get(\'maxLevel\').value > 1"\n class="tb-form-row no-border no-padding last-level-slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-slide-toggle>\n </div>\n <tb-relation-type-autocomplete\n fxFlex\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <tb-entity-subtype-list\n required\n [label]="\'tb.rulenode.device-profiles\' | translate"\n [entityType]="entityType.DEVICE"\n [emptyInputPlaceholder]="\'tb.rulenode.add-device-profile\' | translate"\n [filledInputPlaceholder]="\'tb.rulenode.add-device-profile\' | translate"\n formControlName="deviceTypes">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.device-profile\' | translate } }}">help</mat-icon>\n </tb-entity-subtype-list>\n</section>\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]},propDecorators:{disabled:[{type:m}],required:[{type:m}]}});class _n extends T{get required(){return this.requiredValue}set required(e){this.requiredValue=we(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(v),this.directionTypeTranslations=N,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[_.required]],maxLevel:[null,[_.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",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:_n,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:_n,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:K,useExisting:c((()=>_n)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section [formGroup]="relationsQueryFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.relations-query</div>\n <section>\n <div fxLayoutGap="16px" fxLayout="row">\n <mat-form-field fxFlex="50" class="mat-block" style="min-width: 100px;" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n <mat-error *ngIf="relationsQueryFormGroup.get(\'maxLevel\').hasError(\'min\')">\n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.last-level-relation-tooltip\' | translate }}"\n *ngIf="relationsQueryFormGroup.get(\'maxLevel\').value > 1"\n class="tb-form-row no-border no-padding last-level-slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-slide-toggle>\n </div>\n </section>\n <section [formGroup]="relationsQueryFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters">\n </tb-relation-filters>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:W.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: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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:Ze.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes","enableNotOption"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:K,useExisting:c((()=>_n)),multi:!0}],template:'<section [formGroup]="relationsQueryFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.relations-query</div>\n <section>\n <div fxLayoutGap="16px" fxLayout="row">\n <mat-form-field fxFlex="50" class="mat-block" style="min-width: 100px;" hideRequiredMarker>\n <mat-label translate>relation.direction</mat-label>\n <mat-select required formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex="50" floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n <mat-error *ngIf="relationsQueryFormGroup.get(\'maxLevel\').hasError(\'min\')">\n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.last-level-relation-tooltip\' | translate }}"\n *ngIf="relationsQueryFormGroup.get(\'maxLevel\').value > 1"\n class="tb-form-row no-border no-padding last-level-slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-slide-toggle>\n </div>\n </section>\n <section [formGroup]="relationsQueryFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters">\n </tb-relation-filters>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]},propDecorators:{disabled:[{type:m}],required:[{type:m}]}});class Bn extends T{get required(){return this.requiredValue}set required(e){this.requiredValue=we(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.add-message-type",this.separatorKeysCodes=[ke,Te,Le],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(I))this.messageTypesList.push({name:L.get(I[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Ke(""),Be((e=>e||"")),He((e=>this.fetchMessageTypes(e))),ze())}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&&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;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",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Bn,deps:[{token:R.Store},{token:X.TranslateService},{token:q.TruncatePipe},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Bn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:K,useExisting:c((()=>Bn)),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:'<mat-form-field [formGroup]="messageTypeConfigForm" style="width: 100%;">\n <mat-label *ngIf="label">{{ label }}</mat-label>\n <mat-chip-grid #chipList [required]="required">\n <mat-chip-row\n *ngFor="let messageType of messageTypes"\n [removable]="true"\n (removed)="remove(messageType)">\n {{messageType.name}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text" placeholder="{{ placeholder | translate }}"\n #messageTypeInput\n (focusin)="onFocus()"\n formControlName="messageType"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="messageTypeAutocomplete"\n [matChipInputFor]="chipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="add($event)">\n </mat-chip-grid>\n <mat-autocomplete #messageTypeAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="selected($event)"\n [displayWith]="displayMessageTypeFn">\n <mat-option *ngFor="let messageType of filteredMessageTypes | async" [value]="messageType">\n <span [innerHTML]="messageType.name | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredMessageTypes | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty">\n <span translate>tb.rulenode.no-message-types-found</span>\n </div>\n <ng-template #searchNotEmpty>\n <span>\n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, &apos;...&apos;)}\n }}\n </span>\n </ng-template>\n <span>\n <a translate (click)="createMessageType($event, searchText)">tb.rulenode.create-new-message-type</a>\n </span>\n </div>\n </mat-option>\n </mat-autocomplete>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.message-type\' | translate } }}">help</mat-icon>\n <mat-error *ngIf="chipList.errorState">\n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n </mat-error>\n</mat-form-field>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:$e.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:$e.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:$e.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.AsyncPipe,name:"async"},{kind:"pipe",type:Je.HighlightPipe,name:"highlight"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:K,useExisting:c((()=>Bn)),multi:!0}],template:'<mat-form-field [formGroup]="messageTypeConfigForm" style="width: 100%;">\n <mat-label *ngIf="label">{{ label }}</mat-label>\n <mat-chip-grid #chipList [required]="required">\n <mat-chip-row\n *ngFor="let messageType of messageTypes"\n [removable]="true"\n (removed)="remove(messageType)">\n {{messageType.name}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip-row>\n <input matInput type="text" placeholder="{{ placeholder | translate }}"\n #messageTypeInput\n (focusin)="onFocus()"\n formControlName="messageType"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="messageTypeAutocomplete"\n [matChipInputFor]="chipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="add($event)">\n </mat-chip-grid>\n <mat-autocomplete #messageTypeAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="selected($event)"\n [displayWith]="displayMessageTypeFn">\n <mat-option *ngFor="let messageType of filteredMessageTypes | async" [value]="messageType">\n <span [innerHTML]="messageType.name | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredMessageTypes | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty">\n <span translate>tb.rulenode.no-message-types-found</span>\n </div>\n <ng-template #searchNotEmpty>\n <span>\n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, &apos;...&apos;)}\n }}\n </span>\n </ng-template>\n <span>\n <a translate (click)="createMessageType($event, searchText)">tb.rulenode.create-new-message-type</a>\n </span>\n </div>\n </mat-option>\n </mat-autocomplete>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" matSuffix\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.message-type\' | translate } }}">help</mat-icon>\n <mat-error *ngIf="chipList.errorState">\n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n </mat-error>\n</mat-form-field>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:X.TranslateService},{type:q.TruncatePipe},{type:O.FormBuilder}]},propDecorators:{required:[{type:m}],label:[{type:m}],placeholder:[{type:m}],disabled:[{type:m}],chipList:[{type:u,args:["chipList",{static:!1}]}],matAutocomplete:[{type:u,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:u,args:["messageTypeInput",{static:!1}]}]}});class Kn extends T{get required(){return this.requiredValue}set required(e){this.requiredValue=we(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=Yt,this.credentialsTypeTranslationsMap=Wt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[_.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){ye(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([_.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[_.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(_.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",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Kn,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Kn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:K,useExisting:c((()=>Kn)),multi:!0},{provide:H,useExisting:c((()=>Kn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'<section [formGroup]="credentialsConfigFormGroup" fxLayout="column">\n <mat-expansion-panel class="tb-credentials-config-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allCredentialsTypes" [value]="credentialsType"\n [disabled]="credentialsType === \'cert.PEM\' && disableCertPemCredentials">\n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="credentialsConfigFormGroup.get(\'type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="basic">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input required matInput formControlName="username">\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'username\').hasError(\'required\')">\n {{ \'tb.rulenode.username-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" [required]="passwordFieldRequired" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'password\').hasError(\'required\')">\n {{ \'tb.rulenode.password-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <div class="tb-hint">{{ \'tb.rulenode.credentials-pem-hint\' | translate }}</div>\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'caCertFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'certFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'certFileName\').setValue($event)"\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'privateKeyFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'privateKeyFileName\').setValue($event)"\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </ng-template>\n </section>\n </ng-template>\n </mat-expansion-panel>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:j.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:j.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ae.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:ae.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:ae.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:ae.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:ae.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Xe.FileInputComponent,selector:"tb-file-input",inputs:["label","hint","accept","noFileText","inputId","allowedExtensions","dropLabel","maxSizeByte","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:et.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:K,useExisting:c((()=>Kn)),multi:!0},{provide:H,useExisting:c((()=>Kn)),multi:!0}],template:'<section [formGroup]="credentialsConfigFormGroup" fxLayout="column">\n <mat-expansion-panel class="tb-credentials-config-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allCredentialsTypes" [value]="credentialsType"\n [disabled]="credentialsType === \'cert.PEM\' && disableCertPemCredentials">\n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="credentialsConfigFormGroup.get(\'type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="basic">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input required matInput formControlName="username">\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'username\').hasError(\'required\')">\n {{ \'tb.rulenode.username-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" [required]="passwordFieldRequired" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n <mat-error *ngIf="credentialsConfigFormGroup.get(\'password\').hasError(\'required\')">\n {{ \'tb.rulenode.password-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <div class="tb-hint">{{ \'tb.rulenode.credentials-pem-hint\' | translate }}</div>\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'caCertFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'certFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'certFileName\').setValue($event)"\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="credentialsConfigFormGroup.get(\'privateKeyFileName\').value"\n (fileNameChanged)="credentialsConfigFormGroup.get(\'privateKeyFileName\').setValue($event)"\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </ng-template>\n </section>\n </ng-template>\n </mat-expansion-panel>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]},propDecorators:{required:[{type:m}],disableCertPemCredentials:[{type:m}],passwordFieldRequired:[{type:m}]}});class Hn{set required(e){this.requiredValue!==e&&(this.requiredValue=e,this.updateValidators())}get required(){return this.requiredValue}constructor(e){this.fb=e,this.subscriptSizing="fixed",this.messageTypes=[{name:"Post attributes",value:"POST_ATTRIBUTES_REQUEST"},{name:"Post telemetry",value:"POST_TELEMETRY_REQUEST"},{name:"Custom",value:""}],this.propagateChange=()=>{},this.destroy$=new ie,this.messageTypeFormGroup=this.fb.group({messageTypeAlias:[null,[_.required]],messageType:[{value:null,disabled:!0},[_.maxLength(255)]]}),this.messageTypeFormGroup.get("messageTypeAlias").valueChanges.pipe(le(this.destroy$)).subscribe((e=>this.updateMessageTypeValue(e))),this.messageTypeFormGroup.valueChanges.pipe(le(this.destroy$)).subscribe((()=>this.updateView()))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnTouched(e){}registerOnChange(e){this.propagateChange=e}writeValue(e){this.modelValue=e;let t=this.messageTypes.find((t=>t.value===e));t||(t=this.messageTypes.find((e=>""===e.value))),this.messageTypeFormGroup.get("messageTypeAlias").patchValue(t,{emitEvent:!1}),this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1})}validate(){return this.messageTypeFormGroup.valid?null:{messageTypeInvalid:!0}}setDisabledState(e){this.disabled=e,e?this.messageTypeFormGroup.disable({emitEvent:!1}):(this.messageTypeFormGroup.enable({emitEvent:!1}),"Custom"!==this.messageTypeFormGroup.get("messageTypeAlias").value?.name&&this.messageTypeFormGroup.get("messageType").disable({emitEvent:!1}))}updateView(){const e=this.messageTypeFormGroup.getRawValue().messageType;this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}updateValidators(){this.messageTypeFormGroup.get("messageType").setValidators(this.required?[_.required,_.maxLength(255)]:[_.maxLength(255)]),this.messageTypeFormGroup.get("messageType").updateValueAndValidity({emitEvent:!1})}updateMessageTypeValue(e){"Custom"!==e?.name?this.messageTypeFormGroup.get("messageType").disable({emitEvent:!1}):this.messageTypeFormGroup.get("messageType").enable({emitEvent:!1}),this.messageTypeFormGroup.get("messageType").patchValue(e.value??null)}}e("OutputMessageTypeAutocompleteComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Hn,deps:[{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Hn,selector:"tb-output-message-type-autocomplete",inputs:{subscriptSizing:"subscriptSizing",disabled:"disabled",required:"required"},providers:[{provide:K,useExisting:c((()=>Hn)),multi:!0},{provide:H,useExisting:c((()=>Hn)),multi:!0}],ngImport:t,template:'<section class="tb-form-row no-border no-padding tb-standard-fields column-xs" [formGroup]="messageTypeFormGroup">\n <mat-form-field class="flex" subscriptSizing="{{ subscriptSizing }}" hideRequiredMarker>\n <mat-label>{{\'tb.rulenode.output-message-type\' | translate}}</mat-label>\n <mat-select formControlName="messageTypeAlias">\n <mat-option *ngFor="let msgType of messageTypes" [value]="msgType">\n {{msgType.name}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex" subscriptSizing="{{ subscriptSizing }}" [hideRequiredMarker]="messageTypeFormGroup.get(\'messageType\').disabled">\n <mat-label>{{\'tb.rulenode.message-type-value\' | translate}}</mat-label>\n <input matInput type="text" formControlName="messageType">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n *ngIf="messageTypeFormGroup.get(\'messageType\').value"\n ngxClipboard\n [cbContent]="messageTypeFormGroup.get(\'messageType\').value"\n matTooltip="{{ \'tb.rulenode.copy-message-type\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n <mat-error *ngIf="messageTypeFormGroup.get(\'messageType\').hasError(\'required\')">\n {{ \'tb.rulenode.message-type-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="messageTypeFormGroup.get(\'messageType\').hasError(\'maxlength\')">\n {{ \'tb.rulenode.message-type-value-max-length\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:yt,selector:"[ngxClipboard]",inputs:["ngxClipboard","container","cbContent","cbSuccessMsg"],outputs:["cbOnSuccess","cbOnError"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),Ye([S()],Hn.prototype,"disabled",void 0),Ye([S()],Hn.prototype,"required",null),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:K,useExisting:c((()=>Hn)),multi:!0},{provide:H,useExisting:c((()=>Hn)),multi:!0}],template:'<section class="tb-form-row no-border no-padding tb-standard-fields column-xs" [formGroup]="messageTypeFormGroup">\n <mat-form-field class="flex" subscriptSizing="{{ subscriptSizing }}" hideRequiredMarker>\n <mat-label>{{\'tb.rulenode.output-message-type\' | translate}}</mat-label>\n <mat-select formControlName="messageTypeAlias">\n <mat-option *ngFor="let msgType of messageTypes" [value]="msgType">\n {{msgType.name}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="flex" subscriptSizing="{{ subscriptSizing }}" [hideRequiredMarker]="messageTypeFormGroup.get(\'messageType\').disabled">\n <mat-label>{{\'tb.rulenode.message-type-value\' | translate}}</mat-label>\n <input matInput type="text" formControlName="messageType">\n <button type="button"\n matSuffix\n mat-icon-button\n aria-label="Copy"\n *ngIf="messageTypeFormGroup.get(\'messageType\').value"\n ngxClipboard\n [cbContent]="messageTypeFormGroup.get(\'messageType\').value"\n matTooltip="{{ \'tb.rulenode.copy-message-type\' | translate }}">\n <mat-icon aria-hidden="false"\n aria-label="help-icon">content_copy\n </mat-icon>\n </button>\n <mat-error *ngIf="messageTypeFormGroup.get(\'messageType\').hasError(\'required\')">\n {{ \'tb.rulenode.message-type-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="messageTypeFormGroup.get(\'messageType\').hasError(\'maxlength\')">\n {{ \'tb.rulenode.message-type-value-max-length\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n\n'}]}],ctorParameters:function(){return[{type:O.FormBuilder}]},propDecorators:{subscriptSizing:[{type:m}],disabled:[{type:m}],required:[{type:m}]}});class zn{constructor(e,t){this.fb=e,this.translate=t,this.translation=pn,this.propagateChange=()=>{},this.destroy$=new ie,this.selectOptions=[]}ngOnInit(){this.initOptions(),this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Ue(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}initOptions(){for(const e of this.translation.keys())this.selectOptions.push({value:e,name:this.translate.instant(this.translation.get(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})}}e("MsgMetadataChipComponent",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zn,deps:[{token:O.FormBuilder},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:zn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText",translation:"translation"},providers:[{provide:K,useExisting:c((()=>zn)),multi:!0}],ngImport:t,template:'<div [formGroup]="chipControlGroup" class="tb-form-row space-between">\n <div class="fixed-title-width">{{ labelText }}</div>\n <mat-chip-listbox formControlName="chipControl">\n <mat-chip-option *ngFor="let option of selectOptions"\n selectable="{{ chipControlGroup.get(\'chipControl\').value !== option.value }}"\n color="primary"\n [value]="option.value">{{ option.name }}</mat-chip-option>\n </mat-chip-listbox>\n</div>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{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:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:K,useExisting:c((()=>zn)),multi:!0}],template:'<div [formGroup]="chipControlGroup" class="tb-form-row space-between">\n <div class="fixed-title-width">{{ labelText }}</div>\n <mat-chip-listbox formControlName="chipControl">\n <mat-chip-option *ngFor="let option of selectOptions"\n selectable="{{ chipControlGroup.get(\'chipControl\').value !== option.value }}"\n color="primary"\n [value]="option.value">{{ option.name }}</mat-chip-option>\n </mat-chip-listbox>\n</div>\n'}]}],ctorParameters:function(){return[{type:O.FormBuilder},{type:X.TranslateService}]},propDecorators:{labelText:[{type:m}],translation:[{type:m}]}});class Un extends T{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new ie,this.sourceFieldSubcritption=[],this.propagateChange=null,this.disabled=!1,this.required=!1,this.oneMapRequiredValidator=e=>e.get("keyVals").value.length,this.propagateNestedErrors=e=>{if(this.svListFormGroup&&this.svListFormGroup.get("keyVals")&&"VALID"===this.svListFormGroup.get("keyVals")?.status)return null;const t={};if(this.svListFormGroup&&this.svListFormGroup.setErrors(null),e instanceof z||e instanceof U){if(e.errors)for(const n of Object.keys(e.errors))t[n]=!0;for(const n of Object.keys(e.controls)){const r=this.propagateNestedErrors(e.controls[n]);if(r&&Object.keys(r).length)for(const e of Object.keys(r))t[e]=!0}return t}if(e.errors)for(const n of Object.keys(e.errors))t[n]=!0;return be(t,{})?null:t}}ngOnInit(){this.ngControl=this.injector.get(B),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({keyVals:this.fb.array([])},{validators:[this.propagateNestedErrors,this.oneMapRequiredValidator]}),this.svListFormGroup.valueChanges.pipe(Ue(this.destroy$)).subscribe((()=>{this.updateModel()}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}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){const t=Object.keys(e).map((t=>({key:t,value:e[t]})));if(this.keyValsFormArray().length===t.length)this.keyValsFormArray().patchValue(t,{emitEvent:!1});else{const e=[];t.forEach((t=>{e.push(this.fb.group({key:[t.key,[_.required]],value:[t.value,[_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))})),this.svListFormGroup.setControl("keyVals",this.fb.array(e,this.propagateNestedErrors),{emitEvent:!1});for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e)}}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)ye(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.keyValsFormArray().removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){this.keyValsFormArray().push(this.fb.group({key:["",[_.required]],value:["",[_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(this.keyValsFormArray().at(this.keyValsFormArray().length-1))}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Ue(this.destroy$)).subscribe((t=>{const n=Mt.get(t);e.get("value").patchValue(this.targetKeyPrefix+n[0].toUpperCase()+n.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",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Un,deps:[{token:R.Store},{token:X.TranslateService},{token:t.Injector},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Un,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:K,useExisting:c((()=>Un)),multi:!0},{provide:H,useExisting:c((()=>Un)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section [formGroup]="svListFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title">{{ labelText }}</div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="svListFormGroup.hasError(\'required\')">\n tb.rulenode.map-fields-required\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="svListFormGroup.hasError(\'svMapRequired\')">\n {{ requiredText }}\n </div>\n </div>\n <div class="tb-form-panel no-border no-padding">\n <div class="tb-form-table">\n <div class="tb-form-table-header">\n <div class="tb-form-table-header-cell field-space">{{ selectText }}</div>\n <div class="tb-form-table-header-cell field-space">{{ valText }}</div>\n <div class="tb-form-table-header-cell actions-header"></div>\n </div>\n <div class="tb-form-table-body">\n <div class="tb-form-table-row"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index;">\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <mat-select [placeholder]="selectText" [formControl]="keyValControl.get(\'key\')" required>\n <mat-option *ngFor="let option of filterSelectOptions(keyValControl)" [value]="option.value">\n {{option.name}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="valText" [formControl]="keyValControl.get(\'value\')" matInput/>\n </mat-form-field>\n <div class="tb-form-table-row-cell-buttons">\n <button [ngClass]="{\'tb-hidden\': keyValsFormArray().controls.length === 1}"\n type="button"\n mat-icon-button\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-mapping-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div>\n <button [disabled]="(isLoading$ | async) || keyValsFormArray().length >= selectOptions.length"\n type="button" mat-stroked-button color="primary" (click)="addKeyVal()">\n {{ \'tb.key-val.add-mapping-entry\' | translate }}\n </button>\n </div>\n <tb-example-hint [hintText]="hintText" [popupHelpLink]="popupHelpLink"></tb-example-hint>\n</section>\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:Pe.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:j.AsyncPipe,name:"async"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),Ye([S()],Un.prototype,"disabled",void 0),Ye([S()],Un.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:K,useExisting:c((()=>Un)),multi:!0},{provide:H,useExisting:c((()=>Un)),multi:!0}],template:'<section [formGroup]="svListFormGroup" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title">{{ labelText }}</div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="svListFormGroup.hasError(\'required\')">\n tb.rulenode.map-fields-required\n </div>\n <div class="tb-form-panel-hint tb-error" translate *ngIf="svListFormGroup.hasError(\'svMapRequired\')">\n {{ requiredText }}\n </div>\n </div>\n <div class="tb-form-panel no-border no-padding">\n <div class="tb-form-table">\n <div class="tb-form-table-header">\n <div class="tb-form-table-header-cell field-space">{{ selectText }}</div>\n <div class="tb-form-table-header-cell field-space">{{ valText }}</div>\n <div class="tb-form-table-header-cell actions-header"></div>\n </div>\n <div class="tb-form-table-body">\n <div class="tb-form-table-row"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index;">\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <mat-select [placeholder]="selectText" [formControl]="keyValControl.get(\'key\')" required>\n <mat-option *ngFor="let option of filterSelectOptions(keyValControl)" [value]="option.value">\n {{option.name}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="tb-inline-field field-space" appearance="outline" subscriptSizing="dynamic">\n <input [placeholder]="valText" [formControl]="keyValControl.get(\'value\')" matInput/>\n </mat-form-field>\n <div class="tb-form-table-row-cell-buttons">\n <button [ngClass]="{\'tb-hidden\': keyValsFormArray().controls.length === 1}"\n type="button"\n mat-icon-button\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-mapping-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div>\n <button [disabled]="(isLoading$ | async) || keyValsFormArray().length >= selectOptions.length"\n type="button" mat-stroked-button color="primary" (click)="addKeyVal()">\n {{ \'tb.key-val.add-mapping-entry\' | translate }}\n </button>\n </div>\n <tb-example-hint [hintText]="hintText" [popupHelpLink]="popupHelpLink"></tb-example-hint>\n</section>\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:X.TranslateService},{type:t.Injector},{type:O.FormBuilder}]},propDecorators:{selectOptions:[{type:m}],disabled:[{type:m}],labelText:[{type:m}],requiredText:[{type:m}],targetKeyPrefix:[{type:m}],selectText:[{type:m}],selectRequiredText:[{type:m}],valText:[{type:m}],valRequiredText:[{type:m}],hintText:[{type:m}],popupHelpLink:[{type:m}],required:[{type:m}]}});class jn extends T{get required(){return this.requiredValue}set required(e){this.requiredValue=we(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(v),this.directionTypeTranslations=N,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[_.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",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:jn,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:jn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:K,useExisting:c((()=>jn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section fxLayout="column" [formGroup]="relationsQueryFormGroup">\n <mat-checkbox formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-checkbox>\n <div fxLayoutGap="8px" fxLayout="row">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n </mat-form-field>\n </div>\n <div class="mat-caption" style="color: #6e6e6e;" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters"\n ></tb-relation-filters>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ze.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes","enableNotOption"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:K,useExisting:c((()=>jn)),multi:!0}],template:'<section fxLayout="column" [formGroup]="relationsQueryFormGroup">\n <mat-checkbox formControlName="fetchLastLevelOnly">\n {{ \'alias.last-level-relation\' | translate }}\n </mat-checkbox>\n <div fxLayoutGap="8px" fxLayout="row">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n </mat-form-field>\n </div>\n <div class="mat-caption" style="color: #6e6e6e;" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters"\n ></tb-relation-filters>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]},propDecorators:{disabled:[{type:m}],required:[{type:m}]}});class $n{constructor(e,t){this.translate=e,this.fb=t,this.propagateChange=e=>{},this.destroy$=new ie,this.separatorKeysCodes=[ke,Te,Le],this.onTouched=()=>{}}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[[],[]],sharedAttributeNames:[[],[]],serverAttributeNames:[[],[]],latestTsKeyNames:[[],[]],getLatestValueWithTs:[!1,[]]},{validators:this.atLeastOne(_.required,["clientAttributeNames","sharedAttributeNames","serverAttributeNames","latestTsKeyNames"])}),this.attributeControlGroup.valueChanges.pipe(Ue(this.destroy$)).subscribe((e=>{this.propagateChange(this.preparePropagateValue(e))}))}preparePropagateValue(e){const t={};for(const n in e)t[n]="getLatestValueWithTs"===n||ye(e[n])?e[n]:[];return t}validate(){return this.attributeControlGroup.valid?null:{atLeastOneRequired:!0}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}writeValue(e){this.attributeControlGroup.setValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){this.onTouched=e}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SelectAttributesComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$n,deps:[{token:X.TranslateService},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:$n,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:K,useExisting:c((()=>$n)),multi:!0},{provide:H,useExisting:$n,multi:!0}],ngImport:t,template:'<div class="tb-form-panel no-padding no-border" [formGroup]="attributeControlGroup">\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\' | translate"\n [popupHelpLink]="popupHelpLink"></tb-example-hint>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.client-attributes\' | translate" formControlName="clientAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.shared-attributes\' | translate" formControlName="sharedAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.server-attributes\' | translate" formControlName="serverAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" editable class="mat-block"\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-telemetry-key\' | translate"\n [label]="\'tb.rulenode.latest-telemetry\' | translate" formControlName="latestTsKeyNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp-tooltip\' | translate:\n { latestTsKeyName: attributeControlGroup.get(\'latestTsKeyNames\').value[0]} }}"\n *ngIf="attributeControlGroup.get(\'latestTsKeyNames\').value?.length > 0"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="getLatestValueWithTs">\n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n </mat-slide-toggle>\n </div>\n</div>\n\n<ng-template #helpIcon>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n</ng-template>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:j.NgTemplateOutlet,selector:"[ngTemplateOutlet]",inputs:["ngTemplateOutletContext","ngTemplateOutlet","ngTemplateOutletInjector"]},{kind:"component",type:tt.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:K,useExisting:c((()=>$n)),multi:!0},{provide:H,useExisting:$n,multi:!0}],template:'<div class="tb-form-panel no-padding no-border" [formGroup]="attributeControlGroup">\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\' | translate"\n [popupHelpLink]="popupHelpLink"></tb-example-hint>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.client-attributes\' | translate" formControlName="clientAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.shared-attributes\' | translate" formControlName="sharedAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" class="mat-block" editable\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-attribute-key\' | translate"\n [label]="\'tb.rulenode.server-attributes\' | translate" formControlName="serverAttributeNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <tb-string-items-list subscriptSizing="dynamic" editable class="mat-block"\n (focusout)="onTouched()"\n [placeholder]="\'tb.rulenode.add-telemetry-key\' | translate"\n [label]="\'tb.rulenode.latest-telemetry\' | translate" formControlName="latestTsKeyNames">\n <ng-container matSuffix *ngTemplateOutlet="helpIcon"></ng-container>\n </tb-string-items-list>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp-tooltip\' | translate:\n { latestTsKeyName: attributeControlGroup.get(\'latestTsKeyNames\').value[0]} }}"\n *ngIf="attributeControlGroup.get(\'latestTsKeyNames\').value?.length > 0"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="getLatestValueWithTs">\n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n </mat-slide-toggle>\n </div>\n</div>\n\n<ng-template #helpIcon>\n <mat-icon class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n</ng-template>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:X.TranslateService},{type:O.FormBuilder}]},propDecorators:{popupHelpLink:[{type:m}]}});class Jn extends T{constructor(e,t){super(e),this.store=e,this.fb=t,this.propagateChange=null,this.destroy$=new ie,this.alarmStatus=A,this.alarmStatusTranslations=M}ngOnInit(){this.alarmStatusGroup=this.fb.group({alarmStatus:[null,[]]}),this.alarmStatusGroup.get("alarmStatus").valueChanges.pipe(Ue(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}setDisabledState(e){e?this.alarmStatusGroup.disable({emitEvent:!1}):this.alarmStatusGroup.enable({emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}writeValue(e){this.alarmStatusGroup.get("alarmStatus").patchValue(e,{emitEvent:!1})}}e("AlarmStatusSelectComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Jn,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Jn,selector:"tb-alarm-status-select",providers:[{provide:K,useExisting:c((()=>Jn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'<section [formGroup]="alarmStatusGroup" fxLayout="column" fxLayoutAlign="center center">\n <mat-chip-listbox multiple formControlName="alarmStatus" class="chip-listbox" fxLayout="column">\n <div class="toggle-column">\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.ACTIVE_UNACK">\n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n </mat-chip-option>\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.ACTIVE_ACK">\n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n </mat-chip-option>\n </div>\n <div class="toggle-column">\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.CLEARED_UNACK">\n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n </mat-chip-option>\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.CLEARED_ACK">\n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_ACK) | translate }}\n </mat-chip-option>\n </div>\n </mat-chip-listbox>\n</section>\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\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: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:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-alarm-status-select",providers:[{provide:K,useExisting:c((()=>Jn)),multi:!0}],template:'<section [formGroup]="alarmStatusGroup" fxLayout="column" fxLayoutAlign="center center">\n <mat-chip-listbox multiple formControlName="alarmStatus" class="chip-listbox" fxLayout="column">\n <div class="toggle-column">\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.ACTIVE_UNACK">\n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n </mat-chip-option>\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.ACTIVE_ACK">\n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n </mat-chip-option>\n </div>\n <div class="toggle-column">\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.CLEARED_UNACK">\n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n </mat-chip-option>\n <mat-chip-option fxFlex class="option" [value]="alarmStatus.CLEARED_ACK">\n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_ACK) | translate }}\n </mat-chip-option>\n </div>\n </mat-chip-listbox>\n</section>\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"]}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class Qn{}e("RulenodeCoreConfigCommonModule",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Qn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Qn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:Qn,declarations:[Rn,On,_n,Bn,Kn,Gn,Dn,Hn,Nn,zn,Un,jn,$n,Jn,ht],imports:[J,E,Qe],exports:[Rn,On,_n,Bn,Kn,Gn,Dn,Hn,Nn,zn,Un,jn,$n,Jn,ht]}),Qn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Qn,imports:[J,E,Qe]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Qn,decorators:[{type:d,args:[{declarations:[Rn,On,_n,Bn,Kn,Gn,Dn,Hn,Nn,zn,Un,jn,$n,Jn,ht],imports:[J,E,Qe],exports:[Rn,On,_n,Bn,Kn,Gn,Dn,Hn,Nn,zn,Un,jn,$n,Jn,ht]}]}]});class Yn{}e("RuleNodeCoreConfigActionModule",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Yn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Yn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:Yn,declarations:[wn,vt,An,Sn,Cn,ct,Ct,Ft,kt,kn,Tt,It,vn,Fn,In,qn,Mn,En,Lt,Ln,Tn,Vn,Pn],imports:[J,E,Qe,Qn],exports:[wn,vt,An,Sn,Cn,ct,Ct,Ft,kt,kn,Tt,It,vn,Fn,In,qn,Mn,En,Lt,Ln,Tn,Vn,Pn]}),Yn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Yn,imports:[J,E,Qe,Qn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Yn,decorators:[{type:d,args:[{declarations:[wn,vt,An,Sn,Cn,ct,Ct,Ft,kt,kn,Tt,It,vn,Fn,In,qn,Mn,En,Lt,Ln,Tn,Vn,Pn],imports:[J,E,Qe,Qn],exports:[wn,vt,An,Sn,Cn,ct,Ct,Ft,kt,kn,Tt,It,vn,Fn,In,qn,Mn,En,Lt,Ln,Tn,Vn,Pn]}]}]});class Wn extends g{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[ke,Te,Le]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[_.min(0),_.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]],excludeZeroDeltas:[e.excludeZeroDeltas,[]]})}prepareInputConfig(e){return{inputValueKey:ye(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:ye(e?.outputValueKey)?e.outputValueKey:null,useCache:!ye(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!ye(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:ye(e?.periodValueKey)?e.periodValueKey:null,round:ye(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!ye(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative,excludeZeroDeltas:!!ye(e?.excludeZeroDeltas)&&e.excludeZeroDeltas}}prepareOutputConfig(e){return xe(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([_.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Wn,deps:[{token:R.Store},{token:X.TranslateService},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Wn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"<section [formGroup]=\"calculateDeltaConfigForm\">\n <div fxLayout.gt-sm=\"row\" fxLayoutGap.gt-sm=\"22px\">\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.input-value-key' | translate }}</mat-label>\n <input matInput formControlName=\"inputValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('inputValueKey').hasError('required') ||\n calculateDeltaConfigForm.get('inputValueKey').hasError('pattern')\">\n {{ 'tb.rulenode.input-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.output-value-key' | translate }}</mat-label>\n <input matInput formControlName=\"outputValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('outputValueKey').hasError('required') ||\n calculateDeltaConfigForm.get('outputValueKey').hasError('pattern')\">\n {{ 'tb.rulenode.output-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}</mat-label>\n <input type=\"number\" min=\"0\" max=\"15\" step=\"1\" matInput formControlName=\"round\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('round').hasError('min')\">\n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n </mat-error>\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('round').hasError('max')\">\n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n </mat-error>\n </mat-form-field>\n <div class=\"tb-form-panel no-padding no-border\">\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.failure-if-delta-negative-tooltip' | translate }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"tellFailureIfDeltaIsNegative\">\n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.use-caching-tooltip' | translate :\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"useCache\">\n {{ 'tb.rulenode.use-caching' | translate }}\n </mat-slide-toggle>\n </div>\n <div class=\"tb-form-panel stroked\" [class.no-padding-bottom]=\"calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value\">\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.add-time-difference-between-readings-tooltip' | translate:\n { periodValueKey: (calculateDeltaConfigForm.get('periodValueKey').valid &&\n calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value) ? calculateDeltaConfigForm.get('periodValueKey').value :\n 'periodInMs' } }}\"\n class=\"tb-form-row no-border no-padding\">\n <mat-slide-toggle class=\"mat-slide\" formControlName=\"addPeriodBetweenMsgs\">\n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n </mat-slide-toggle>\n </div>\n <mat-form-field class=\"mat-block\" *ngIf=\"calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value\">\n <mat-label>{{ 'tb.rulenode.period-value-key' | translate }}</mat-label>\n <input required matInput formControlName=\"periodValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('periodValueKey').hasError('required')\">\n {{ 'tb.rulenode.period-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon=\"{{ calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value ? ('tb.rulenode.exclude-zero-deltas-time-difference-hint' | translate :{\n outputValueKey: calculateDeltaConfigForm.get('outputValueKey').valid ? calculateDeltaConfigForm.get('outputValueKey').value : 'tb.rulenode.output-value-key' | translate,\n periodValueKey: calculateDeltaConfigForm.get('periodValueKey').valid ? calculateDeltaConfigForm.get('periodValueKey').value : 'tb.rulenode.period-value-key' | translate\n }) : ('tb.rulenode.exclude-zero-deltas-hint' | translate :{ outputValueKey: calculateDeltaConfigForm.get('outputValueKey').valid ? calculateDeltaConfigForm.get('outputValueKey').value : 'tb.rulenode.output-value-key' | translate }) }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"excludeZeroDeltas\">\n {{ 'tb.rulenode.exclude-zero-deltas' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n",dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:W.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: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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"<section [formGroup]=\"calculateDeltaConfigForm\">\n <div fxLayout.gt-sm=\"row\" fxLayoutGap.gt-sm=\"22px\">\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.input-value-key' | translate }}</mat-label>\n <input matInput formControlName=\"inputValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('inputValueKey').hasError('required') ||\n calculateDeltaConfigForm.get('inputValueKey').hasError('pattern')\">\n {{ 'tb.rulenode.input-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.output-value-key' | translate }}</mat-label>\n <input matInput formControlName=\"outputValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('outputValueKey').hasError('required') ||\n calculateDeltaConfigForm.get('outputValueKey').hasError('pattern')\">\n {{ 'tb.rulenode.output-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class=\"mat-block\" fxFlex>\n <mat-label>{{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}</mat-label>\n <input type=\"number\" min=\"0\" max=\"15\" step=\"1\" matInput formControlName=\"round\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('round').hasError('min')\">\n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n </mat-error>\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('round').hasError('max')\">\n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n </mat-error>\n </mat-form-field>\n <div class=\"tb-form-panel no-padding no-border\">\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.failure-if-delta-negative-tooltip' | translate }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"tellFailureIfDeltaIsNegative\">\n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n </mat-slide-toggle>\n </div>\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.use-caching-tooltip' | translate :\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"useCache\">\n {{ 'tb.rulenode.use-caching' | translate }}\n </mat-slide-toggle>\n </div>\n <div class=\"tb-form-panel stroked\" [class.no-padding-bottom]=\"calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value\">\n <div tb-hint-tooltip-icon=\"{{ 'tb.rulenode.add-time-difference-between-readings-tooltip' | translate:\n { periodValueKey: (calculateDeltaConfigForm.get('periodValueKey').valid &&\n calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value) ? calculateDeltaConfigForm.get('periodValueKey').value :\n 'periodInMs' } }}\"\n class=\"tb-form-row no-border no-padding\">\n <mat-slide-toggle class=\"mat-slide\" formControlName=\"addPeriodBetweenMsgs\">\n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n </mat-slide-toggle>\n </div>\n <mat-form-field class=\"mat-block\" *ngIf=\"calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value\">\n <mat-label>{{ 'tb.rulenode.period-value-key' | translate }}</mat-label>\n <input required matInput formControlName=\"periodValueKey\">\n <mat-error *ngIf=\"calculateDeltaConfigForm.get('periodValueKey').hasError('required')\">\n {{ 'tb.rulenode.period-value-key-required' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon=\"{{ calculateDeltaConfigForm.get('addPeriodBetweenMsgs').value ? ('tb.rulenode.exclude-zero-deltas-time-difference-hint' | translate :{\n outputValueKey: calculateDeltaConfigForm.get('outputValueKey').valid ? calculateDeltaConfigForm.get('outputValueKey').value : 'tb.rulenode.output-value-key' | translate,\n periodValueKey: calculateDeltaConfigForm.get('periodValueKey').valid ? calculateDeltaConfigForm.get('periodValueKey').value : 'tb.rulenode.period-value-key' | translate\n }) : ('tb.rulenode.exclude-zero-deltas-hint' | translate :{ outputValueKey: calculateDeltaConfigForm.get('outputValueKey').valid ? calculateDeltaConfigForm.get('outputValueKey').value : 'tb.rulenode.output-value-key' | translate }) }}\"\n class=\"tb-form-row same-padding\">\n <mat-slide-toggle class=\"mat-slide margin\" formControlName=\"excludeZeroDeltas\">\n {{ 'tb.rulenode.exclude-zero-deltas' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n</section>\n"}]}],ctorParameters:function(){return[{type:R.Store},{type:X.TranslateService},{type:O.FormBuilder}]}});class Zn extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=zt;for(const e of Ut.keys())e!==zt.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ut.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,xe(e)}prepareInputConfig(e){let t,n;return t=ye(e?.telemetry)?e.telemetry?zt.LATEST_TELEMETRY:zt.ATTRIBUTES:ye(e?.dataToFetch)?e.dataToFetch:zt.ATTRIBUTES,n=ye(e?.attrMapping)?e.attrMapping:ye(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:ye(e?.fetchTo)?e.fetchTo:sn.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===zt.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[_.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Zn,deps:[{token:R.Store},{token:O.FormBuilder},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Zn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="customerAttributesConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.mapping-of-customers</div>\n <div fxFlex fxLayoutAlign="center center">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\',\'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\',\'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\',\'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/customer_attributes_node_fields_templatization">\n </tb-kv-map-config>\n <tb-msg-metadata-chip\n [labelText]="customerAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.LATEST_TELEMETRY ?\n (\'tb.rulenode.add-mapped-latest-telemetry-to\' | translate) : (\'tb.rulenode.add-mapped-attribute-to\' | translate)"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{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:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Me.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Ee.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination","fillHeight","extraPadding","primaryBackground"]},{kind:"component",type:Rn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'<section [formGroup]="customerAttributesConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.mapping-of-customers</div>\n <div fxFlex fxLayoutAlign="center center">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\',\'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\',\'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\',\'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/customer_attributes_node_fields_templatization">\n </tb-kv-map-config>\n <tb-msg-metadata-chip\n [labelText]="customerAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.LATEST_TELEMETRY ?\n (\'tb.rulenode.add-mapped-latest-telemetry-to\' | translate) : (\'tb.rulenode.add-mapped-attribute-to\' | translate)"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder},{type:X.TranslateService}]}});class Xn extends g{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,[_.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return he(e)&&(e.attributesControl={clientAttributeNames:ye(e?.clientAttributeNames)?e.clientAttributeNames:[],latestTsKeyNames:ye(e?.latestTsKeyNames)?e.latestTsKeyNames:[],serverAttributeNames:ye(e?.serverAttributeNames)?e.serverAttributeNames:[],sharedAttributeNames:ye(e?.sharedAttributeNames)?e.sharedAttributeNames:[],getLatestValueWithTs:!!ye(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:ye(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!ye(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:ye(e?.fetchTo)?e.fetchTo:sn.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",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Xn,deps:[{token:R.Store},{token:X.TranslateService},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Xn,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deviceAttributesConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.device-relations-query</div>\n <tb-device-relations-query-config\n required\n formControlName="deviceRelationsQuery">\n </tb-device-relations-query-config>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.related-device-attributes</div>\n <div class="tb-form-panel-hint tb-error" translate\n [hidden]="!(deviceAttributesConfigForm.get(\'attributesControl\').touched &&\n deviceAttributesConfigForm.get(\'attributesControl\').hasError(\'atLeastOneRequired\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-select-attributes formControlName="attributesControl"\n popupHelpLink="rulenode/related_device_attributes_node_fields_templatization"></tb-select-attributes>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="\'tb.rulenode.add-selected-attributes-to\' | translate"></tb-msg-metadata-chip>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-tooltip\' | translate }}"\n class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="tellFailureIfAbsent">\n {{ \'tb.rulenode.tell-failure\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:On,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"component",type:$n,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'<section [formGroup]="deviceAttributesConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.device-relations-query</div>\n <tb-device-relations-query-config\n required\n formControlName="deviceRelationsQuery">\n </tb-device-relations-query-config>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.related-device-attributes</div>\n <div class="tb-form-panel-hint tb-error" translate\n [hidden]="!(deviceAttributesConfigForm.get(\'attributesControl\').touched &&\n deviceAttributesConfigForm.get(\'attributesControl\').hasError(\'atLeastOneRequired\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-select-attributes formControlName="attributesControl"\n popupHelpLink="rulenode/related_device_attributes_node_fields_templatization"></tb-select-attributes>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="\'tb.rulenode.add-selected-attributes-to\' | translate"></tb-msg-metadata-chip>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-tooltip\' | translate }}"\n class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="tellFailureIfAbsent">\n {{ \'tb.rulenode.tell-failure\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:X.TranslateService},{type:O.FormBuilder}]}});class er extends g{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.predefinedValues=[];for(const e of Object.keys(Rt))this.predefinedValues.push({value:Rt[e],name:this.translate.instant(Ot.get(Rt[e]))})}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return t=ye(e?.addToMetadata)?e.addToMetadata?sn.METADATA:sn.DATA:e?.fetchTo?e.fetchTo:sn.DATA,{detailsList:ye(e?.detailsList)?e.detailsList:null,fetchTo:t}}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[_.required]],fetchTo:[e.fetchTo,[]]})}}e("EntityDetailsConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:er,deps:[{token:R.Store},{token:X.TranslateService},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:er,selector:"tb-enrichment-node-entity-details-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="entityDetailsConfigForm">\n <tb-string-items-list [predefinedValues]="predefinedValues"\n class="mat-block" required\n [label]="\'tb.rulenode.select-details\' | translate"\n [placeholder]="\'tb.rulenode.add-detail\' | translate"\n [requiredText]="\'tb.rulenode.entity-details-list-empty\' | translate"\n formControlName="detailsList">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.detail\' | translate } }}">\n help\n </mat-icon>\n </tb-string-items-list>\n <tb-msg-metadata-chip\n [labelText]="\'tb.rulenode.add-selected-details-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:tt.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:er,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'<section [formGroup]="entityDetailsConfigForm">\n <tb-string-items-list [predefinedValues]="predefinedValues"\n class="mat-block" required\n [label]="\'tb.rulenode.select-details\' | translate"\n [placeholder]="\'tb.rulenode.add-detail\' | translate"\n [requiredText]="\'tb.rulenode.entity-details-list-empty\' | translate"\n formControlName="detailsList">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.detail\' | translate } }}">\n help\n </mat-icon>\n </tb-string-items-list>\n <tb-msg-metadata-chip\n [labelText]="\'tb.rulenode.add-selected-details-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:X.TranslateService},{type:O.FormBuilder}]}});class tr extends g{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[ke,Te,Le],this.aggregationTypes=w,this.aggregations=Object.values(w),this.aggregationTypesTranslations=G,this.fetchMode=_t,this.samplingOrders=Object.values(Ht),this.samplingOrdersTranslate=$t,this.timeUnits=Object.values(Gt),this.timeUnitsTranslationMap=Dt,this.deduplicationStrategiesHintTranslations=Kt,this.headerOptions=[],this.timeUnitMap={[Gt.MILLISECONDS]:1,[Gt.SECONDS]:1e3,[Gt.MINUTES]:6e4,[Gt.HOURS]:36e5,[Gt.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 Bt.keys())this.headerOptions.push({value:e,name:this.translate.instant(Bt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[_.required]],aggregation:[e.aggregation,[_.required]],fetchMode:[e.fetchMode,[_.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,xe(e)}prepareInputConfig(e){return he(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:ye(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:ye(e?.aggregation)?e.aggregation:w.NONE,fetchMode:ye(e?.fetchMode)?e.fetchMode:_t.FIRST,orderBy:ye(e?.orderBy)?e.orderBy:Ht.ASC,limit:ye(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!ye(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:ye(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:ye(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:Gt.MINUTES,endInterval:ye(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:ye(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:Gt.MINUTES},startIntervalPattern:ye(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:ye(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===_t.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([_.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([_.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([_.required,_.min(2),_.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([_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([_.required,_.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([_.required,_.min(1),_.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([_.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([_.required,_.min(1),_.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([_.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="")}defaultPaddingEnable(){return this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value===_t.ALL&&this.getTelemetryFromDatabaseConfigForm.get("aggregation").value===w.NONE}}e("GetTelemetryFromDatabaseConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:tr,deps:[{token:R.Store},{token:X.TranslateService},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:tr,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="getTelemetryFromDatabaseConfigForm" class="tb-form-panel no-padding no-border">\n <tb-string-items-list class="mat-block" editable [placeholder]="\'tb.rulenode.add-timeseries-key\' | translate"\n subscriptSizing="dynamic" required\n [requiredText]="\'tb.rulenode.timeseries-keys-required\' | translate"\n [label]="\'tb.rulenode.timeseries-keys\' | translate" formControlName="latestTsKeyNames"\n [hint]="\'tb.rulenode.general-pattern-hint\' | translate">\n <div matHintEnd class="see-example" tb-help-popup="{{\'rulenode/originator_telemetry_node_fields_templatization\'}}"\n hintMode\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}"></div>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.timeseries-key\' | translate } }}">help\n </mat-icon>\n </tb-string-items-list>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.fetch-interval</div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.use-metadata-dynamic-interval-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="useMetadataIntervalPatterns">\n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n </mat-slide-toggle>\n </div>\n <div formGroupName="interval" fxLayout="column"\n *ngIf="getTelemetryFromDatabaseConfigForm.get(\'useMetadataIntervalPatterns\').value === false; else intervalPattern">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="0" fxLayoutGap.gt-sm="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.interval-start\' | translate }}</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="startInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.time-unit\' | translate }}</mat-label>\n <mat-select formControlName="startIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="0" fxLayoutGap.gt-sm="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.interval-end\' | translate }}</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="endInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.time-unit\' | translate }}</mat-label>\n <mat-select formControlName="endIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class="description-block tb-primary-fill" [class.error]="getTelemetryFromDatabaseConfigForm.get(\'interval\').invalid">\n <mat-icon class="description-icon">error_outline</mat-icon>\n <div class="description-text">\n <ng-container *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval\').valid; else invalidText">\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 </ng-container>\n <ng-template #invalidText>\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n </ng-template>\n </div>\n </div>\n </div>\n <ng-template #intervalPattern>\n <div fxLayout="column" class="input-block">\n <mat-form-field fxFlex class="mat-block">\n <mat-label>{{ \'tb.rulenode.start-interval\' | translate }}</mat-label>\n <input matInput formControlName="startIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'required\') ||\n getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.start-interval-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label>{{ \'tb.rulenode.end-interval\' | translate }}</mat-label>\n <input matInput formControlName="endIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'required\') ||\n getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.end-interval-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-example-hint [hintText]="\'tb.rulenode.metadata-dynamic-interval-hint\' | translate"\n popupHelpLink="rulenode/originator_telemetry_node_fields_templatization">\n </tb-example-hint>\n </div>\n </ng-template>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.fetch-strategy</div>\n <div class="tb-form-panel no-border no-padding item-center">\n <div class="fetch-mod-toggle">\n <tb-toggle-select formControlName="fetchMode" appearance="fill">\n <tb-toggle-option *ngFor="let data of headerOptions" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n <div class="tb-form-hint tb-primary-fill hint-container">\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n </div>\n </div>\n <div *ngIf="getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value === fetchMode.ALL">\n <mat-form-field class="mat-block" hideRequiredMarker\n [subscriptSizing]="defaultPaddingEnable() ? \'fixed\' : \'dynamic\'">\n <mat-label>{{ \'aggregation.function\' | translate }}</mat-label>\n <mat-select formControlName="aggregation" required>\n <mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">\n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div *ngIf="getTelemetryFromDatabaseConfigForm.get(\'aggregation\').value === aggregationTypes.NONE">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label> {{ "tb.rulenode.order-by-timestamp" | translate }} </mat-label>\n <mat-select formControlName="orderBy" required>\n <mat-option *ngFor="let order of samplingOrders" [value]="order">\n {{ samplingOrdersTranslate.get(order) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label>{{ "tb.rulenode.limit" | translate }}</mat-label>\n <input type="number" min="2" max="1000" step="1" matInput formControlName="limit" required>\n <mat-hint>{{ "tb.rulenode.limit-hint" | translate }}</mat-hint>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'required\')">\n {{ \'tb.rulenode.limit-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'min\')">\n {{ \'tb.rulenode.limit-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'max\')">\n {{ \'tb.rulenode.limit-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n </div>\n</section>\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{width:100%}:host .hint-container{width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.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","hintMode"]},{kind:"component",type:tt.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:W.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: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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:O.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Me.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Ee.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination","fillHeight","extraPadding","primaryBackground"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'<section [formGroup]="getTelemetryFromDatabaseConfigForm" class="tb-form-panel no-padding no-border">\n <tb-string-items-list class="mat-block" editable [placeholder]="\'tb.rulenode.add-timeseries-key\' | translate"\n subscriptSizing="dynamic" required\n [requiredText]="\'tb.rulenode.timeseries-keys-required\' | translate"\n [label]="\'tb.rulenode.timeseries-keys\' | translate" formControlName="latestTsKeyNames"\n [hint]="\'tb.rulenode.general-pattern-hint\' | translate">\n <div matHintEnd class="see-example" tb-help-popup="{{\'rulenode/originator_telemetry_node_fields_templatization\'}}"\n hintMode\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}"></div>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon" color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.timeseries-key\' | translate } }}">help\n </mat-icon>\n </tb-string-items-list>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.fetch-interval</div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.use-metadata-dynamic-interval-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="useMetadataIntervalPatterns">\n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n </mat-slide-toggle>\n </div>\n <div formGroupName="interval" fxLayout="column"\n *ngIf="getTelemetryFromDatabaseConfigForm.get(\'useMetadataIntervalPatterns\').value === false; else intervalPattern">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="0" fxLayoutGap.gt-sm="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.interval-start\' | translate }}</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="startInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.time-unit\' | translate }}</mat-label>\n <mat-select formControlName="startIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="0" fxLayoutGap.gt-sm="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.interval-end\' | translate }}</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="endInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.time-unit\' | translate }}</mat-label>\n <mat-select formControlName="endIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class="description-block tb-primary-fill" [class.error]="getTelemetryFromDatabaseConfigForm.get(\'interval\').invalid">\n <mat-icon class="description-icon">error_outline</mat-icon>\n <div class="description-text">\n <ng-container *ngIf="getTelemetryFromDatabaseConfigForm.get(\'interval\').valid; else invalidText">\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 </ng-container>\n <ng-template #invalidText>\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n </ng-template>\n </div>\n </div>\n </div>\n <ng-template #intervalPattern>\n <div fxLayout="column" class="input-block">\n <mat-form-field fxFlex class="mat-block">\n <mat-label>{{ \'tb.rulenode.start-interval\' | translate }}</mat-label>\n <input matInput formControlName="startIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'required\') ||\n getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.start-interval-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label>{{ \'tb.rulenode.end-interval\' | translate }}</mat-label>\n <input matInput formControlName="endIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'required\') ||\n getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.end-interval-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-example-hint [hintText]="\'tb.rulenode.metadata-dynamic-interval-hint\' | translate"\n popupHelpLink="rulenode/originator_telemetry_node_fields_templatization">\n </tb-example-hint>\n </div>\n </ng-template>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.fetch-strategy</div>\n <div class="tb-form-panel no-border no-padding item-center">\n <div class="fetch-mod-toggle">\n <tb-toggle-select formControlName="fetchMode" appearance="fill">\n <tb-toggle-option *ngFor="let data of headerOptions" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n <div class="tb-form-hint tb-primary-fill hint-container">\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n </div>\n </div>\n <div *ngIf="getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value === fetchMode.ALL">\n <mat-form-field class="mat-block" hideRequiredMarker\n [subscriptSizing]="defaultPaddingEnable() ? \'fixed\' : \'dynamic\'">\n <mat-label>{{ \'aggregation.function\' | translate }}</mat-label>\n <mat-select formControlName="aggregation" required>\n <mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">\n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div *ngIf="getTelemetryFromDatabaseConfigForm.get(\'aggregation\').value === aggregationTypes.NONE">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label> {{ "tb.rulenode.order-by-timestamp" | translate }} </mat-label>\n <mat-select formControlName="orderBy" required>\n <mat-option *ngFor="let order of samplingOrders" [value]="order">\n {{ samplingOrdersTranslate.get(order) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label>{{ "tb.rulenode.limit" | translate }}</mat-label>\n <input type="number" min="2" max="1000" step="1" matInput formControlName="limit" required>\n <mat-hint>{{ "tb.rulenode.limit-hint" | translate }}</mat-hint>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'required\')">\n {{ \'tb.rulenode.limit-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'min\')">\n {{ \'tb.rulenode.limit-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'limit\').hasError(\'max\')">\n {{ \'tb.rulenode.limit-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n </div>\n</section>\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{width:100%}:host .hint-container{width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:X.TranslateService},{type:O.FormBuilder}]}});class nr extends g{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 he(e)&&(e.attributesControl={clientAttributeNames:ye(e?.clientAttributeNames)?e.clientAttributeNames:[],latestTsKeyNames:ye(e?.latestTsKeyNames)?e.latestTsKeyNames:[],serverAttributeNames:ye(e?.serverAttributeNames)?e.serverAttributeNames:[],sharedAttributeNames:ye(e?.sharedAttributeNames)?e.sharedAttributeNames:[],getLatestValueWithTs:!!ye(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:ye(e?.fetchTo)?e.fetchTo:sn.METADATA,tellFailureIfAbsent:!!ye(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:ye(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",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:nr,deps:[{token:R.Store},{token:X.TranslateService},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:nr,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'<section class="tb-form-panel no-padding no-border" [formGroup]="originatorAttributesConfigForm">\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.originator-attributes</div>\n <div class="tb-form-panel-hint tb-error" translate\n [hidden]="!(originatorAttributesConfigForm.get(\'attributesControl\').touched &&\n originatorAttributesConfigForm.get(\'attributesControl\').hasError(\'atLeastOneRequired\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-select-attributes formControlName="attributesControl"\n popupHelpLink="rulenode/originator_attributes_node_fields_templatization">\n </tb-select-attributes>\n <tb-msg-metadata-chip [labelText]="\'tb.rulenode.add-originator-attributes-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-tooltip\' | translate }}" class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="tellFailureIfAbsent">\n {{ \'tb.rulenode.tell-failure\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"component",type:$n,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'<section class="tb-form-panel no-padding no-border" [formGroup]="originatorAttributesConfigForm">\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.originator-attributes</div>\n <div class="tb-form-panel-hint tb-error" translate\n [hidden]="!(originatorAttributesConfigForm.get(\'attributesControl\').touched &&\n originatorAttributesConfigForm.get(\'attributesControl\').hasError(\'atLeastOneRequired\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-select-attributes formControlName="attributesControl"\n popupHelpLink="rulenode/originator_attributes_node_fields_templatization">\n </tb-select-attributes>\n <tb-msg-metadata-chip [labelText]="\'tb.rulenode.add-originator-attributes-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-tooltip\' | translate }}" class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="tellFailureIfAbsent">\n {{ \'tb.rulenode.tell-failure\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:X.TranslateService},{type:O.FormBuilder}]}});class rr extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of At)this.originatorFields.push({value:e.value,name:this.translate.instant(e.name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return xe(e)}prepareInputConfig(e){return{dataMapping:ye(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:ye(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:ye(e?.fetchTo)?e.fetchTo:sn.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[_.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:rr,deps:[{token:R.Store},{token:O.FormBuilder},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:rr,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="originatorFieldsConfigForm" class="tb-form-panel no-padding no-border">\n <tb-sv-map-config\n required\n [selectOptions]="originatorFields"\n targetKeyPrefix="originator"\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="\'tb.rulenode.originator-fields-mapping\' | translate"\n [selectText]="\'tb.rulenode.source-field\' | translate"\n [selectRequiredText]="\'tb.rulenode.source-field-required\' | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.originator-fields-sv-map-hint\' | translate"\n popupHelpLink="rulenode/originator_fields_node_fields_templatization">\n </tb-sv-map-config>\n <tb-msg-metadata-chip [labelText]="\'tb.rulenode.add-mapped-originator-fields-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.skip-empty-fields-tooltip\' | translate }}" class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="ignoreNullStrings">\n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',dependencies:[{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"component",type:Un,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'<section [formGroup]="originatorFieldsConfigForm" class="tb-form-panel no-padding no-border">\n <tb-sv-map-config\n required\n [selectOptions]="originatorFields"\n targetKeyPrefix="originator"\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="\'tb.rulenode.originator-fields-mapping\' | translate"\n [selectText]="\'tb.rulenode.source-field\' | translate"\n [selectRequiredText]="\'tb.rulenode.source-field-required\' | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.originator-fields-sv-map-hint\' | translate"\n popupHelpLink="rulenode/originator_fields_node_fields_templatization">\n </tb-sv-map-config>\n <tb-msg-metadata-chip [labelText]="\'tb.rulenode.add-mapped-originator-fields-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.skip-empty-fields-tooltip\' | translate }}" class="tb-form-row same-padding">\n <mat-slide-toggle class="mat-slide margin" formControlName="ignoreNullStrings">\n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder},{type:X.TranslateService}]}});class or extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=zt,this.msgMetadataLabelTranslations=jt,this.originatorFields=[],this.fetchToData=[];for(const e of Object.keys(At))this.originatorFields.push({value:At[e].value,name:this.translate.instant(At[e].name)});for(const e of Ut.keys())this.fetchToData.push({value:e,name:this.translate.instant(Ut.get(e))})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){e.dataToFetch===zt.FIELDS?(e.dataMapping=e.svMap,delete e.svMap):(e.dataMapping=e.kvMap,delete e.kvMap);const t={};if(e&&e.dataMapping)for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,delete e.svMap,delete e.kvMap,xe(e)}prepareInputConfig(e){let t,n,r={[k.name.value]:`relatedEntity${this.translate.instant(k.name.name)}`},o={serialNumber:"sn"};return t=ye(e?.telemetry)?e.telemetry?zt.LATEST_TELEMETRY:zt.ATTRIBUTES:ye(e?.dataToFetch)?e.dataToFetch:zt.ATTRIBUTES,n=ye(e?.attrMapping)?e.attrMapping:ye(e?.dataMapping)?e.dataMapping:null,t===zt.FIELDS?r=n:o=n,{relationsQuery:ye(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:t,svMap:r,kvMap:o,fetchTo:ye(e?.fetchTo)?e.fetchTo:sn.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===zt.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[_.required]],dataToFetch:[e.dataToFetch,[]],kvMap:[e.kvMap,[_.required]],svMap:[e.svMap,[_.required]],fetchTo:[e.fetchTo,[]]})}validatorTriggers(){return["dataToFetch"]}updateValidators(e){this.relatedAttributesConfigForm.get("dataToFetch").value===zt.FIELDS?(this.relatedAttributesConfigForm.get("svMap").enable({emitEvent:!1}),this.relatedAttributesConfigForm.get("kvMap").disable({emitEvent:!1}),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity()):(this.relatedAttributesConfigForm.get("svMap").disable({emitEvent:!1}),this.relatedAttributesConfigForm.get("kvMap").enable({emitEvent:!1}),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity())}}e("RelatedAttributesConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:or,deps:[{token:R.Store},{token:O.FormBuilder},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:or,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="relatedAttributesConfigForm" class="tb-form-panel no-padding no-border">\n <tb-relations-query-config\n required\n formControlName="relationsQuery">\n </tb-relations-query-config>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.data-to-fetch</div>\n <tb-toggle-select formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n <tb-kv-map-config\n [hidden]="relatedAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.FIELDS"\n required\n formControlName="kvMap"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\',\'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\',\'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\',\'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/related_entity_data_node_fields_templatization">\n </tb-kv-map-config>\n <tb-sv-map-config\n [hidden]="relatedAttributesConfigForm.get(\'dataToFetch\').value !== DataToFetch.FIELDS"\n required\n [labelText]="\'tb.rulenode.fields-mapping\' | translate"\n targetKeyPrefix="relatedEntity"\n [selectOptions]="originatorFields"\n formControlName="svMap"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [selectText]="\'tb.rulenode.source-field\' | translate"\n [selectRequiredText]="\'tb.rulenode.source-field-required\' | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.sv-map-hint\' | translate"\n popupHelpLink="rulenode/related_entity_data_node_fields_templatization">\n </tb-sv-map-config>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="msgMetadataLabelTranslations.get(relatedAttributesConfigForm.get(\'dataToFetch\').value) | translate">\n </tb-msg-metadata-chip>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Me.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Ee.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination","fillHeight","extraPadding","primaryBackground"]},{kind:"component",type:Rn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:_n,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"component",type:Un,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'<section [formGroup]="relatedAttributesConfigForm" class="tb-form-panel no-padding no-border">\n <tb-relations-query-config\n required\n formControlName="relationsQuery">\n </tb-relations-query-config>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.data-to-fetch</div>\n <tb-toggle-select formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n <tb-kv-map-config\n [hidden]="relatedAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.FIELDS"\n required\n formControlName="kvMap"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\',\'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\',\'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\',\'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/related_entity_data_node_fields_templatization">\n </tb-kv-map-config>\n <tb-sv-map-config\n [hidden]="relatedAttributesConfigForm.get(\'dataToFetch\').value !== DataToFetch.FIELDS"\n required\n [labelText]="\'tb.rulenode.fields-mapping\' | translate"\n targetKeyPrefix="relatedEntity"\n [selectOptions]="originatorFields"\n formControlName="svMap"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [selectText]="\'tb.rulenode.source-field\' | translate"\n [selectRequiredText]="\'tb.rulenode.source-field-required\' | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.sv-map-hint\' | translate"\n popupHelpLink="rulenode/related_entity_data_node_fields_templatization">\n </tb-sv-map-config>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="msgMetadataLabelTranslations.get(relatedAttributesConfigForm.get(\'dataToFetch\').value) | translate">\n </tb-msg-metadata-chip>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder},{type:X.TranslateService}]}});class ar extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=zt;for(const e of Ut.keys())e!==zt.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ut.get(e))})}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=ye(e?.telemetry)?e.telemetry?zt.LATEST_TELEMETRY:zt.ATTRIBUTES:ye(e?.dataToFetch)?e.dataToFetch:zt.ATTRIBUTES,n=ye(e?.attrMapping)?e.attrMapping:ye(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:ye(e?.fetchTo)?e.fetchTo:sn.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===zt.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[_.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ar,deps:[{token:R.Store},{token:O.FormBuilder},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ar,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="tenantAttributesConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.mapping-of-tenant</div>\n <div fxFlex fxLayoutAlign="center center">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\', \'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\', \'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\', \'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/tenant_attributes_node_fields_templatization">\n </tb-kv-map-config>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="tenantAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.LATEST_TELEMETRY ?\n (\'tb.rulenode.add-mapped-latest-telemetry-to\' | translate) : (\'tb.rulenode.add-mapped-attribute-to\' | translate)">\n </tb-msg-metadata-chip>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{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:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Me.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Ee.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination","fillHeight","extraPadding","primaryBackground"]},{kind:"component",type:Rn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'<section [formGroup]="tenantAttributesConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.mapping-of-tenant</div>\n <div fxFlex fxLayoutAlign="center center">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="dataToFetch" appearance="fill">\n <tb-toggle-option *ngFor="let data of fetchToData" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n formControlName="dataMapping"\n [requiredText]="\'tb.rulenode.attr-mapping-required\' | translate"\n [labelText]="selectTranslation(\'tb.rulenode.latest-telemetry-mapping\', \'tb.rulenode.attributes-mapping\') | translate"\n [keyText]="selectTranslation(\'tb.rulenode.source-telemetry\', \'tb.rulenode.source-attribute\') | translate"\n [keyRequiredText]="selectTranslation(\'tb.rulenode.source-telemetry-required\', \'tb.rulenode.source-attribute-required\') | translate"\n [valText]="\'tb.rulenode.target-key\' | translate"\n [valRequiredText]="\'tb.rulenode.target-key-required\' | translate"\n [hintText]="\'tb.rulenode.kv-map-pattern-hint\'"\n popupHelpLink="rulenode/tenant_attributes_node_fields_templatization">\n </tb-kv-map-config>\n <tb-msg-metadata-chip formControlName="fetchTo"\n [labelText]="tenantAttributesConfigForm.get(\'dataToFetch\').value === DataToFetch.LATEST_TELEMETRY ?\n (\'tb.rulenode.add-mapped-latest-telemetry-to\' | translate) : (\'tb.rulenode.add-mapped-attribute-to\' | translate)">\n </tb-msg-metadata-chip>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder},{type:X.TranslateService}]}});class ir extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:ye(e?.fetchTo)?e.fetchTo:sn.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ir,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ir,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="fetchDeviceCredentialsConfigForm">\n <tb-msg-metadata-chip\n [labelText]="\'tb.rulenode.fetch-credentials-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n',dependencies:[{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'<section [formGroup]="fetchDeviceCredentialsConfigForm">\n <tb-msg-metadata-chip\n [labelText]="\'tb.rulenode.fetch-credentials-to\' | translate"\n formControlName="fetchTo">\n </tb-msg-metadata-chip>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class lr{}e("RulenodeCoreConfigEnrichmentModule",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:lr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),lr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:lr,declarations:[Zn,er,Xn,nr,rr,tr,or,ar,Wn,ir],imports:[J,E,Qn],exports:[Zn,er,Xn,nr,rr,tr,or,ar,Wn,ir]}),lr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:lr,imports:[J,E,Qn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:lr,decorators:[{type:d,args:[{declarations:[Zn,er,Xn,nr,rr,tr,or,ar,Wn,ir],imports:[J,E,Qn],exports:[Zn,er,Xn,nr,rr,tr,or,ar,Wn,ir]}]}]});class sr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Zt,this.azureIotHubCredentialsTypeTranslationsMap=Xt}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[_.required]],host:[e?e.host:null,[_.required]],port:[e?e.port:null,[_.required,_.min(1),_.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[_.required,_.min(1),_.max(200)]],clientId:[e?e.clientId:null,[_.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[_.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([_.required]);break;case"cert.PEM":t.get("privateKey").setValidators([_.required]),t.get("privateKeyFileName").setValidators([_.required]),t.get("cert").setValidators([_.required]),t.get("certFileName").setValidators([_.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",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:sr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:sr,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="azureIotHubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.hostname</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.hostname-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.device-id</mat-label>\n <input required matInput formControlName="clientId" autocomplete="new-clientId">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'clientId\').hasError(\'required\')">\n {{ \'tb.rulenode.device-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-accordion>\n <mat-expansion-panel class="tb-mqtt-credentials-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title class="tb-required" translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <section formGroupName="credentials" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allAzureIotHubCredentialsTypes" [value]="credentialsType">\n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="azureIotHubConfigForm.get(\'credentials.type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="azureIotHubConfigForm.get(\'credentials.type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="sas">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.sas-key</mat-label>\n <input type="password" required matInput formControlName="sasKey" autocomplete="new-password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n <mat-error *ngIf="azureIotHubConfigForm.get(\'credentials.sasKey\').hasError(\'required\')">\n {{ \'tb.rulenode.sas-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.caCertFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.azure-ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.caCertFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.azure-ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.certFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.certFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.privateKeyFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.privateKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password" autocomplete="new-password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </ng-template>\n </section>\n </section>\n </mat-expansion-panel>\n </mat-accordion>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:j.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:j.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:ae.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:ae.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:ae.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:ae.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:O.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Xe.FileInputComponent,selector:"tb-file-input",inputs:["label","hint","accept","noFileText","inputId","allowedExtensions","dropLabel","maxSizeByte","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:et.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:sr,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'<section [formGroup]="azureIotHubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.hostname</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.hostname-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.device-id</mat-label>\n <input required matInput formControlName="clientId" autocomplete="new-clientId">\n <mat-error *ngIf="azureIotHubConfigForm.get(\'clientId\').hasError(\'required\')">\n {{ \'tb.rulenode.device-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-accordion>\n <mat-expansion-panel class="tb-mqtt-credentials-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title class="tb-required" translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <section formGroupName="credentials" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allAzureIotHubCredentialsTypes" [value]="credentialsType">\n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="azureIotHubConfigForm.get(\'credentials.type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="azureIotHubConfigForm.get(\'credentials.type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="sas">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.sas-key</mat-label>\n <input type="password" required matInput formControlName="sasKey" autocomplete="new-password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n <mat-error *ngIf="azureIotHubConfigForm.get(\'credentials.sasKey\').hasError(\'required\')">\n {{ \'tb.rulenode.sas-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.caCertFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.azure-ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.caCertFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.caCertFileName\').setValue($event)"\n label="{{\'tb.rulenode.azure-ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.certFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.certFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="azureIotHubConfigForm.get(\'credentials.privateKeyFileName\').value"\n (fileNameChanged)="azureIotHubConfigForm.get(\'credentials.privateKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password" autocomplete="new-password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </ng-template>\n </section>\n </section>\n </mat-expansion-panel>\n </mat-accordion>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class mr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=tn,this.ToByteStandartCharsetTypeTranslationMap=nn}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[_.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[_.required]],retries:[e?e.retries:null,[_.min(0)]],batchSize:[e?e.batchSize:null,[_.min(0)]],linger:[e?e.linger:null,[_.min(0)]],bufferMemory:[e?e.bufferMemory:null,[_.min(0)]],acks:[e?e.acks:null,[_.required]],keySerializer:[e?e.keySerializer:null,[_.required]],valueSerializer:[e?e.valueSerializer:null,[_.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([_.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:mr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:mr,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="kafkaConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="kafkaConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.key-pattern</mat-label>\n <input matInput formControlName="keyPattern">\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <div class="tb-hint" translate>tb.rulenode.key-pattern-hint</div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.bootstrap-servers</mat-label>\n <input required matInput formControlName="bootstrapServers">\n <mat-error *ngIf="kafkaConfigForm.get(\'bootstrapServers\').hasError(\'required\')">\n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.retries</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="retries">\n <mat-error *ngIf="kafkaConfigForm.get(\'retries\').hasError(\'min\')">\n {{ \'tb.rulenode.min-retries-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.batch-size-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="batchSize">\n <mat-error *ngIf="kafkaConfigForm.get(\'batchSize\').hasError(\'min\')">\n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.linger-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="linger">\n <mat-error *ngIf="kafkaConfigForm.get(\'linger\').hasError(\'min\')">\n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.buffer-memory-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="bufferMemory">\n <mat-error *ngIf="kafkaConfigForm.get(\'bufferMemory\').hasError(\'min\')">\n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.acks</mat-label>\n <mat-select formControlName="acks" required>\n <mat-option *ngFor="let ackValue of ackValues" [value]="ackValue">\n {{ ackValue }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.key-serializer</mat-label>\n <input required matInput formControlName="keySerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'keySerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.value-serializer</mat-label>\n <input required matInput formControlName="valueSerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'valueSerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.other-properties</label>\n <tb-kv-map-config-old\n required="false"\n formControlName="otherProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <mat-checkbox fxFlex formControlName="addMetadataKeyValuesAsKafkaHeaders">\n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.add-metadata-key-values-as-kafka-headers-hint</div>\n <mat-form-field fxFlex class="mat-block" *ngIf="kafkaConfigForm.get(\'addMetadataKeyValuesAsKafkaHeaders\').value">\n <mat-label translate>tb.rulenode.charset-encoding</mat-label>\n <mat-select formControlName="kafkaHeadersCharset" required>\n <mat-option *ngFor="let charset of ToByteStandartCharsetTypesValues" [value]="charset">\n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'<section [formGroup]="kafkaConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="kafkaConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.key-pattern</mat-label>\n <input matInput formControlName="keyPattern">\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <div class="tb-hint" translate>tb.rulenode.key-pattern-hint</div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.bootstrap-servers</mat-label>\n <input required matInput formControlName="bootstrapServers">\n <mat-error *ngIf="kafkaConfigForm.get(\'bootstrapServers\').hasError(\'required\')">\n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.retries</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="retries">\n <mat-error *ngIf="kafkaConfigForm.get(\'retries\').hasError(\'min\')">\n {{ \'tb.rulenode.min-retries-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.batch-size-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="batchSize">\n <mat-error *ngIf="kafkaConfigForm.get(\'batchSize\').hasError(\'min\')">\n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.linger-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="linger">\n <mat-error *ngIf="kafkaConfigForm.get(\'linger\').hasError(\'min\')">\n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.buffer-memory-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="bufferMemory">\n <mat-error *ngIf="kafkaConfigForm.get(\'bufferMemory\').hasError(\'min\')">\n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.acks</mat-label>\n <mat-select formControlName="acks" required>\n <mat-option *ngFor="let ackValue of ackValues" [value]="ackValue">\n {{ ackValue }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.key-serializer</mat-label>\n <input required matInput formControlName="keySerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'keySerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.value-serializer</mat-label>\n <input required matInput formControlName="valueSerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'valueSerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.other-properties</label>\n <tb-kv-map-config-old\n required="false"\n formControlName="otherProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <mat-checkbox fxFlex formControlName="addMetadataKeyValuesAsKafkaHeaders">\n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.add-metadata-key-values-as-kafka-headers-hint</div>\n <mat-form-field fxFlex class="mat-block" *ngIf="kafkaConfigForm.get(\'addMetadataKeyValuesAsKafkaHeaders\').value">\n <mat-label translate>tb.rulenode.charset-encoding</mat-label>\n <mat-select formControlName="kafkaHeadersCharset" required>\n <mat-option *ngFor="let charset of ToByteStandartCharsetTypesValues" [value]="charset">\n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class pr extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[_.required]],host:[e?e.host:null,[_.required]],port:[e?e.port:null,[_.required,_.min(1),_.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[_.required,_.min(1),_.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&ve(e.clientId))},[]],parseToPlainText:[!!e&&e.parseToPlainText,[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})}updateValidators(e){ve(this.mqttConfigForm.get("clientId").value)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1}),this.mqttConfigForm.get("appendClientIdSuffix").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["clientId"]}}e("MqttConfigComponent",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:pr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:pr,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="mqttConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="mqttConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <div fxFlex fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="mqttConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.connect-timeout</mat-label>\n <input required type="number" step="1" min="1" max="200" matInput formControlName="connectTimeoutSec">\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'required\')">\n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'min\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'max\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.client-id</mat-label>\n <input matInput formControlName="clientId">\n <mat-hint>{{\'tb.rulenode.client-id-hint\' | translate}}</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="appendClientIdSuffix">\n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n </mat-checkbox>\n <div class="tb-hint">{{ "tb.rulenode.client-id-suffix-hint" | translate }}</div>\n <mat-checkbox formControlName="parseToPlainText">\n {{ \'tb.rulenode.parse-to-plain-text\' | translate }}\n </mat-checkbox>\n <div class="tb-hint">{{ "tb.rulenode.parse-to-plain-text-hint" | translate }}</div>\n <mat-checkbox formControlName="cleanSession">\n {{ \'tb.rulenode.clean-session\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="retainedMessage">\n {{ "tb.rulenode.retained-message" | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="ssl">\n {{ \'tb.rulenode.enable-ssl\' | translate }}\n </mat-checkbox>\n <tb-credentials-config formControlName="credentials" [passwordFieldRequired]="false"></tb-credentials-config>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Kn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:pr,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'<section [formGroup]="mqttConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="mqttConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <div fxFlex fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="mqttConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.connect-timeout</mat-label>\n <input required type="number" step="1" min="1" max="200" matInput formControlName="connectTimeoutSec">\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'required\')">\n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'min\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'max\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.client-id</mat-label>\n <input matInput formControlName="clientId">\n <mat-hint>{{\'tb.rulenode.client-id-hint\' | translate}}</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="appendClientIdSuffix">\n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n </mat-checkbox>\n <div class="tb-hint">{{ "tb.rulenode.client-id-suffix-hint" | translate }}</div>\n <mat-checkbox formControlName="parseToPlainText">\n {{ \'tb.rulenode.parse-to-plain-text\' | translate }}\n </mat-checkbox>\n <div class="tb-hint">{{ "tb.rulenode.parse-to-plain-text-hint" | translate }}</div>\n <mat-checkbox formControlName="cleanSession">\n {{ \'tb.rulenode.clean-session\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="retainedMessage">\n {{ "tb.rulenode.retained-message" | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="ssl">\n {{ \'tb.rulenode.enable-ssl\' | translate }}\n </mat-checkbox>\n <tb-credentials-config formControlName="credentials" [passwordFieldRequired]="false"></tb-credentials-config>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class dr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=D,this.entityType=C}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[_.required]],targets:[e?e.targets:[],[_.required]]})}}e("NotificationConfigComponent",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:dr,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:dr,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="notificationConfigForm" fxLayout="column">\n <tb-template-autocomplete\n required\n allowCreate\n formControlName="templateId"\n [notificationTypes]="notificationType.RULE_NODE">\n </tb-template-autocomplete>\n <tb-entity-list\n required\n formControlName="targets"\n labelText="{{ \'notification.recipients\' | translate }}"\n placeholderText="{{ \'notification.recipient\' | translate }}"\n requiredText="{{ \'notification.recipients-required\' | translate }}"\n entityType="{{ entityType.NOTIFICATION_TARGET }}"\n subType="{{ notificationType.RULE_NODE }}">\n </tb-entity-list>\n</section>\n',dependencies:[{kind:"component",type:nt.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint","syncIdsWithDB"]},{kind:"directive",type:Z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:rt.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:dr,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'<section [formGroup]="notificationConfigForm" fxLayout="column">\n <tb-template-autocomplete\n required\n allowCreate\n formControlName="templateId"\n [notificationTypes]="notificationType.RULE_NODE">\n </tb-template-autocomplete>\n <tb-entity-list\n required\n formControlName="targets"\n labelText="{{ \'notification.recipients\' | translate }}"\n placeholderText="{{ \'notification.recipient\' | translate }}"\n requiredText="{{ \'notification.recipients-required\' | translate }}"\n entityType="{{ entityType.NOTIFICATION_TARGET }}"\n subType="{{ notificationType.RULE_NODE }}">\n </tb-entity-list>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class ur extends g{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,[_.required]],topicName:[e?e.topicName:null,[_.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[_.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[_.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ur,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:ur,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="pubSubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.gcp-project-id</mat-label>\n <input required matInput formControlName="projectId">\n <mat-error *ngIf="pubSubConfigForm.get(\'projectId\').hasError(\'required\')">\n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.pubsub-topic-name</mat-label>\n <input required matInput formControlName="topicName">\n <mat-error *ngIf="pubSubConfigForm.get(\'topicName\').hasError(\'required\')">\n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input style="padding-bottom: 24px;"\n formControlName="serviceAccountKey"\n [existingFileName]="pubSubConfigForm.get(\'serviceAccountKeyFileName\').value"\n (fileNameChanged)="pubSubConfigForm.get(\'serviceAccountKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.gcp-service-account-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.message-attributes-hint\' | translate | safe: \'html\'"></div>\n <tb-kv-map-config-old\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Xe.FileInputComponent,selector:"tb-file-input",inputs:["label","hint","accept","noFileText","inputId","allowedExtensions","dropLabel","maxSizeByte","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:ce.SafePipe,name:"safe"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:ur,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'<section [formGroup]="pubSubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.gcp-project-id</mat-label>\n <input required matInput formControlName="projectId">\n <mat-error *ngIf="pubSubConfigForm.get(\'projectId\').hasError(\'required\')">\n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.pubsub-topic-name</mat-label>\n <input required matInput formControlName="topicName">\n <mat-error *ngIf="pubSubConfigForm.get(\'topicName\').hasError(\'required\')">\n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input style="padding-bottom: 24px;"\n formControlName="serviceAccountKey"\n [existingFileName]="pubSubConfigForm.get(\'serviceAccountKeyFileName\').value"\n (fileNameChanged)="pubSubConfigForm.get(\'serviceAccountKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.gcp-service-account-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.message-attributes-hint\' | translate | safe: \'html\'"></div>\n <tb-kv-map-config-old\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class cr extends g{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,[_.required]],port:[e?e.port:null,[_.required,_.min(1),_.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,[_.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[_.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",cr),cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:cr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),cr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:cr,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="rabbitMqConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.exchange-name-pattern</mat-label>\n <input matInput formControlName="exchangeNamePattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.routing-key-pattern</mat-label>\n <input matInput formControlName="routingKeyPattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-properties</mat-label>\n <mat-select formControlName="messageProperties">\n <mat-option *ngFor="let property of messageProperties" [value]="property">\n {{ property }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.virtual-host</mat-label>\n <input matInput formControlName="virtualHost">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n <mat-checkbox formControlName="automaticRecoveryEnabled">\n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.connection-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.handshake-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="handshakeTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'handshakeTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.client-properties</label>\n <tb-kv-map-config-old\n required="false"\n formControlName="clientProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:et.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:cr,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'<section [formGroup]="rabbitMqConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.exchange-name-pattern</mat-label>\n <input matInput formControlName="exchangeNamePattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.routing-key-pattern</mat-label>\n <input matInput formControlName="routingKeyPattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-properties</mat-label>\n <mat-select formControlName="messageProperties">\n <mat-option *ngFor="let property of messageProperties" [value]="property">\n {{ property }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.virtual-host</mat-label>\n <input matInput formControlName="virtualHost">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" matInput formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n <mat-checkbox formControlName="automaticRecoveryEnabled">\n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.connection-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.handshake-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="handshakeTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'handshakeTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.client-properties</label>\n <tb-kv-map-config-old\n required="false"\n formControlName="clientProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class gr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(en)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[_.required]],requestMethod:[e?e.requestMethod:null,[_.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],parseToPlainText:[!!e&&e.parseToPlainText,[]],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,[_.min(0)]],headers:[e?e.headers:null,[]],credentials:[e?e.credentials:null,[]],maxInMemoryBufferSizeInKb:[e?e.maxInMemoryBufferSizeInKb:null,[_.min(1)]]})}validatorTriggers(){return["useSimpleClientHttpFactory","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("enableProxy").value,r=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!r?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[_.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[_.required,_.min(1),_.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([_.min(0)])),this.restApiCallConfigForm.get("readTimeoutMs").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",gr),gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:gr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),gr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:gr,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="restApiCallConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.endpoint-url-pattern</mat-label>\n <input required matInput formControlName="restEndpointUrlPattern">\n <mat-error *ngIf="restApiCallConfigForm.get(\'restEndpointUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.request-method</mat-label>\n <mat-select formControlName="requestMethod">\n <mat-option *ngFor="let requestType of httpRequestTypes" [value]="requestType">\n {{ requestType }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName="enableProxy">\n {{ \'tb.rulenode.enable-proxy\' | translate }}\n </mat-checkbox>\n <mat-checkbox *ngIf="!restApiCallConfigForm.get(\'enableProxy\').value" formControlName="useSimpleClientHttpFactory">\n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="parseToPlainText">\n {{ \'tb.rulenode.parse-to-plain-text\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 5px;" translate>tb.rulenode.parse-to-plain-text-hint</div>\n <mat-checkbox formControlName="ignoreRequestBody">\n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n </mat-checkbox>\n <div *ngIf="restApiCallConfigForm.get(\'enableProxy\').value">\n <mat-checkbox formControlName="useSystemProxyProperties">\n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n </mat-checkbox>\n <div *ngIf="!restApiCallConfigForm.get(\'useSystemProxyProperties\').value">\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="10">\n <mat-label translate>tb.rulenode.proxy-scheme</mat-label>\n <mat-select formControlName="proxyScheme">\n <mat-option *ngFor="let proxyScheme of proxySchemes" [value]="proxyScheme">\n {{ proxyScheme }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="md-block" fxFlex="100" fxFlex.gt-sm="50">\n <mat-label translate>tb.rulenode.proxy-host</mat-label>\n <input matInput required formControlName="proxyHost">\n <mat-error *ngIf="restApiCallConfigForm.get(\'proxyHost\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="40">\n <mat-label translate>tb.rulenode.proxy-port</mat-label>\n <input matInput required formControlName="proxyPort" type="number" step="1">\n <mat-error *ngIf="restApiCallConfigForm.get(\'proxyPort\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n </mat-error>\n <mat-error\n *ngIf="restApiCallConfigForm.get(\'proxyPort\').hasError(\'min\') || restApiCallConfigForm.get(\'proxyPort\').hasError(\'max\')">\n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-user</mat-label>\n <input matInput formControlName="proxyUser">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-password</mat-label>\n <input matInput formControlName="proxyPassword">\n </mat-form-field>\n </div>\n </div>\n <mat-form-field *ngIf="!restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value || restApiCallConfigForm.get(\'enableProxy\').value" class="mat-block"\n subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.read-timeout</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="readTimeoutMs">\n <mat-hint translate>tb.rulenode.read-timeout-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.max-parallel-requests-count</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="maxParallelRequestsCount">\n <mat-hint translate>tb.rulenode.max-parallel-requests-count-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.max-response-size</mat-label>\n <input type="number" step="1" min="1" matInput formControlName="maxInMemoryBufferSizeInKb">\n <mat-hint translate>tb.rulenode.max-response-size-hint</mat-hint>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.headers</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.headers-hint\' | translate | safe: \'html\'"> </div>\n <tb-kv-map-config-old\n required="false"\n formControlName="headers"\n keyText="tb.rulenode.header"\n keyRequiredText="tb.rulenode.header-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <tb-credentials-config formControlName="credentials" [disableCertPemCredentials]="restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value"></tb-credentials-config>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Kn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:ce.SafePipe,name:"safe"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:gr,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'<section [formGroup]="restApiCallConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.endpoint-url-pattern</mat-label>\n <input required matInput formControlName="restEndpointUrlPattern">\n <mat-error *ngIf="restApiCallConfigForm.get(\'restEndpointUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.request-method</mat-label>\n <mat-select formControlName="requestMethod">\n <mat-option *ngFor="let requestType of httpRequestTypes" [value]="requestType">\n {{ requestType }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName="enableProxy">\n {{ \'tb.rulenode.enable-proxy\' | translate }}\n </mat-checkbox>\n <mat-checkbox *ngIf="!restApiCallConfigForm.get(\'enableProxy\').value" formControlName="useSimpleClientHttpFactory">\n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="parseToPlainText">\n {{ \'tb.rulenode.parse-to-plain-text\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 5px;" translate>tb.rulenode.parse-to-plain-text-hint</div>\n <mat-checkbox formControlName="ignoreRequestBody">\n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n </mat-checkbox>\n <div *ngIf="restApiCallConfigForm.get(\'enableProxy\').value">\n <mat-checkbox formControlName="useSystemProxyProperties">\n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n </mat-checkbox>\n <div *ngIf="!restApiCallConfigForm.get(\'useSystemProxyProperties\').value">\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="10">\n <mat-label translate>tb.rulenode.proxy-scheme</mat-label>\n <mat-select formControlName="proxyScheme">\n <mat-option *ngFor="let proxyScheme of proxySchemes" [value]="proxyScheme">\n {{ proxyScheme }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="md-block" fxFlex="100" fxFlex.gt-sm="50">\n <mat-label translate>tb.rulenode.proxy-host</mat-label>\n <input matInput required formControlName="proxyHost">\n <mat-error *ngIf="restApiCallConfigForm.get(\'proxyHost\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="40">\n <mat-label translate>tb.rulenode.proxy-port</mat-label>\n <input matInput required formControlName="proxyPort" type="number" step="1">\n <mat-error *ngIf="restApiCallConfigForm.get(\'proxyPort\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n </mat-error>\n <mat-error\n *ngIf="restApiCallConfigForm.get(\'proxyPort\').hasError(\'min\') || restApiCallConfigForm.get(\'proxyPort\').hasError(\'max\')">\n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-user</mat-label>\n <input matInput formControlName="proxyUser">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-password</mat-label>\n <input matInput formControlName="proxyPassword">\n </mat-form-field>\n </div>\n </div>\n <mat-form-field *ngIf="!restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value || restApiCallConfigForm.get(\'enableProxy\').value" class="mat-block"\n subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.read-timeout</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="readTimeoutMs">\n <mat-hint translate>tb.rulenode.read-timeout-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.max-parallel-requests-count</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="maxParallelRequestsCount">\n <mat-hint translate>tb.rulenode.max-parallel-requests-count-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.max-response-size</mat-label>\n <input type="number" step="1" min="1" matInput formControlName="maxInMemoryBufferSizeInKb">\n <mat-hint translate>tb.rulenode.max-response-size-hint</mat-hint>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.headers</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.headers-hint\' | translate | safe: \'html\'"> </div>\n <tb-kv-map-config-old\n required="false"\n formControlName="headers"\n keyText="tb.rulenode.header"\n keyRequiredText="tb.rulenode.header-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <tb-credentials-config formControlName="credentials" [disableCertPemCredentials]="restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value"></tb-credentials-config>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class fr extends g{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([_.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([_.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([_.required,_.min(1),_.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([_.required,_.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[_.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[_.required,_.min(1),_.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",fr),fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:fr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:fr,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="sendEmailConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useSystemSmtpSettings">\n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="sendEmailConfigForm.get(\'useSystemSmtpSettings\').value === false">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.smtp-protocol</mat-label>\n <mat-select formControlName="smtpProtocol">\n <mat-option *ngFor="let smtpProtocol of smtpProtocols" [value]="smtpProtocol">\n {{ smtpProtocol.toUpperCase() }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-host</mat-label>\n <input required matInput formControlName="smtpHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpHost\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="smtpPort">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'min\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'max\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.timeout-msec</mat-label>\n <input required type="number" step="1" min="0" matInput formControlName="timeout">\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox formControlName="enableTls">\n {{ \'tb.rulenode.enable-tls\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block" *ngIf="sendEmailConfigForm.get(\'enableTls\').value === true">\n <mat-label translate>tb.rulenode.tls-version</mat-label>\n <mat-select formControlName="tlsVersion">\n <mat-option *ngFor="let tlsVersion of tlsVersions" [value]="tlsVersion">\n {{ tlsVersion }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-checkbox formControlName="enableProxy">\n {{ \'tb.rulenode.enable-proxy\' | translate }}\n </tb-checkbox>\n <div *ngIf="sendEmailConfigForm.get(\'enableProxy\').value">\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="60">\n <mat-label translate>tb.rulenode.proxy-host</mat-label>\n <input matInput required formControlName="proxyHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyHost\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="40">\n <mat-label translate>tb.rulenode.proxy-port</mat-label>\n <input matInput required formControlName="proxyPort" type="number" step="1" min="1" max="65535">\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyPort\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyPort\').hasError(\'min\') || sendEmailConfigForm.get(\'proxyPort\').hasError(\'max\')">\n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-user</mat-label>\n <input matInput formControlName="proxyUser">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-password</mat-label>\n <input matInput formControlName="proxyPassword">\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput placeholder="{{ \'tb.rulenode.enter-username\' | translate }}" formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input matInput type="password" placeholder="{{ \'tb.rulenode.enter-password\' | translate }}" formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </section>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ot.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:et.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:fr,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'<section [formGroup]="sendEmailConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useSystemSmtpSettings">\n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="sendEmailConfigForm.get(\'useSystemSmtpSettings\').value === false">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.smtp-protocol</mat-label>\n <mat-select formControlName="smtpProtocol">\n <mat-option *ngFor="let smtpProtocol of smtpProtocols" [value]="smtpProtocol">\n {{ smtpProtocol.toUpperCase() }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-host</mat-label>\n <input required matInput formControlName="smtpHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpHost\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="smtpPort">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'min\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'max\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.timeout-msec</mat-label>\n <input required type="number" step="1" min="0" matInput formControlName="timeout">\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox formControlName="enableTls">\n {{ \'tb.rulenode.enable-tls\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block" *ngIf="sendEmailConfigForm.get(\'enableTls\').value === true">\n <mat-label translate>tb.rulenode.tls-version</mat-label>\n <mat-select formControlName="tlsVersion">\n <mat-option *ngFor="let tlsVersion of tlsVersions" [value]="tlsVersion">\n {{ tlsVersion }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-checkbox formControlName="enableProxy">\n {{ \'tb.rulenode.enable-proxy\' | translate }}\n </tb-checkbox>\n <div *ngIf="sendEmailConfigForm.get(\'enableProxy\').value">\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="60">\n <mat-label translate>tb.rulenode.proxy-host</mat-label>\n <input matInput required formControlName="proxyHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyHost\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block" fxFlex="100" fxFlex.gt-sm="40">\n <mat-label translate>tb.rulenode.proxy-port</mat-label>\n <input matInput required formControlName="proxyPort" type="number" step="1" min="1" max="65535">\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyPort\').hasError(\'required\')">\n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'proxyPort\').hasError(\'min\') || sendEmailConfigForm.get(\'proxyPort\').hasError(\'max\')">\n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-user</mat-label>\n <input matInput formControlName="proxyUser">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.proxy-password</mat-label>\n <input matInput formControlName="proxyPassword">\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput placeholder="{{ \'tb.rulenode.enter-username\' | translate }}" formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input matInput type="password" placeholder="{{ \'tb.rulenode.enter-password\' | translate }}" formControlName="password">\n <tb-toggle-password matSuffix></tb-toggle-password>\n </mat-form-field>\n </section>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class yr extends g{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,[_.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[_.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([_.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",yr),yr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:yr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),yr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:yr,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="sendSmsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.numbers-to-template</mat-label>\n <input required matInput formControlName="numbersToTemplate">\n <mat-error *ngIf="sendSmsConfigForm.get(\'numbersToTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n </mat-error>\n <mat-hint [innerHTML]="\'tb.rulenode.numbers-to-template-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.sms-message-template</mat-label>\n <textarea required matInput formControlName="smsMessageTemplate" rows="6"></textarea>\n <mat-error *ngIf="sendSmsConfigForm.get(\'smsMessageTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="useSystemSmsSettings">\n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n </mat-checkbox>\n <tb-sms-provider-configuration\n *ngIf="sendSmsConfigForm.get(\'useSystemSmsSettings\').value === false"\n formControlName="smsProviderConfiguration"\n required>\n </tb-sms-provider-configuration>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:at.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:ce.SafePipe,name:"safe"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:yr,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'<section [formGroup]="sendSmsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.numbers-to-template</mat-label>\n <input required matInput formControlName="numbersToTemplate">\n <mat-error *ngIf="sendSmsConfigForm.get(\'numbersToTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n </mat-error>\n <mat-hint [innerHTML]="\'tb.rulenode.numbers-to-template-hint\' | translate | safe: \'html\'"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.sms-message-template</mat-label>\n <textarea required matInput formControlName="smsMessageTemplate" rows="6"></textarea>\n <mat-error *ngIf="sendSmsConfigForm.get(\'smsMessageTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="useSystemSmsSettings">\n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n </mat-checkbox>\n <tb-sms-provider-configuration\n *ngIf="sendSmsConfigForm.get(\'useSystemSmsSettings\').value === false"\n formControlName="smsProviderConfiguration"\n required>\n </tb-sms-provider-configuration>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class br extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(V),this.slackChanelTypesTranslateMap=P}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,[_.required]],conversationType:[e?e.conversationType:null,[_.required]],conversation:[e?e.conversation:null,[_.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([_.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",br),br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:br,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:br,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="slackConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.message-template</mat-label>\n <input required matInput formControlName="messageTemplate">\n <mat-error *ngIf="slackConfigForm.get(\'messageTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.message-template-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="useSystemSettings">\n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n </mat-checkbox>\n <mat-form-field *ngIf="!slackConfigForm.get(\'useSystemSettings\').value" class="mat-block">\n <mat-label translate>tb.rulenode.slack-api-token</mat-label>\n <input required matInput formControlName="botToken">\n <mat-error *ngIf="slackConfigForm.get(\'botToken\').hasError(\'required\')">\n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label class="tb-title">{{ \'notification.slack-chanel-type\' | translate }}</label>\n <mat-radio-group formControlName="conversationType">\n <mat-radio-button *ngFor="let slackChanelType of slackChanelTypes" [value]="slackChanelType">\n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n </mat-radio-button>\n </mat-radio-group>\n <tb-slack-conversation-autocomplete\n formControlName="conversation"\n required\n [token]="slackConfigForm.get(\'useSystemSettings\').value ? \'\' : slackConfigForm.get(\'botToken\').value"\n [slackChanelType]="slackConfigForm.get(\'conversationType\').value">\n </tb-slack-conversation-autocomplete>\n</section>\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:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ie.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:it.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:it.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:lt.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:br,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'<section [formGroup]="slackConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.message-template</mat-label>\n <input required matInput formControlName="messageTemplate">\n <mat-error *ngIf="slackConfigForm.get(\'messageTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.message-template-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-checkbox formControlName="useSystemSettings">\n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n </mat-checkbox>\n <mat-form-field *ngIf="!slackConfigForm.get(\'useSystemSettings\').value" class="mat-block">\n <mat-label translate>tb.rulenode.slack-api-token</mat-label>\n <input required matInput formControlName="botToken">\n <mat-error *ngIf="slackConfigForm.get(\'botToken\').hasError(\'required\')">\n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label class="tb-title">{{ \'notification.slack-chanel-type\' | translate }}</label>\n <mat-radio-group formControlName="conversationType">\n <mat-radio-button *ngFor="let slackChanelType of slackChanelTypes" [value]="slackChanelType">\n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n </mat-radio-button>\n </mat-radio-group>\n <tb-slack-conversation-autocomplete\n formControlName="conversation"\n required\n [token]="slackConfigForm.get(\'useSystemSettings\').value ? \'\' : slackConfigForm.get(\'botToken\').value"\n [slackChanelType]="slackConfigForm.get(\'conversationType\').value">\n </tb-slack-conversation-autocomplete>\n</section>\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:R.Store},{type:O.FormBuilder}]}});class xr extends g{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,[_.required]],accessKeyId:[e?e.accessKeyId:null,[_.required]],secretAccessKey:[e?e.secretAccessKey:null,[_.required]],region:[e?e.region:null,[_.required]]})}}e("SnsConfigComponent",xr),xr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:xr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),xr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:xr,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="snsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-arn-pattern</mat-label>\n <input required matInput formControlName="topicArnPattern">\n <mat-error *ngIf="snsConfigForm.get(\'topicArnPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="snsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="snsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="snsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:xr,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'<section [formGroup]="snsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.topic-arn-pattern</mat-label>\n <input required matInput formControlName="topicArnPattern">\n <mat-error *ngIf="snsConfigForm.get(\'topicArnPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="snsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="snsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="snsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class hr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Jt,this.sqsQueueTypes=Object.keys(Jt),this.sqsQueueTypeTranslationsMap=Qt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[_.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[_.required]],delaySeconds:[e?e.delaySeconds:null,[_.min(0),_.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[_.required]],secretAccessKey:[e?e.secretAccessKey:null,[_.required]],region:[e?e.region:null,[_.required]]})}}e("SqsConfigComponent",hr),hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:hr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),hr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:hr,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="sqsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.queue-type</mat-label>\n <mat-select formControlName="queueType" required>\n <mat-option *ngFor="let type of sqsQueueTypes" [value]="type">\n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.queue-url-pattern</mat-label>\n <input required matInput formControlName="queueUrlPattern">\n <mat-error *ngIf="sqsConfigForm.get(\'queueUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field *ngIf="sqsConfigForm.get(\'queueType\').value === sqsQueueType.STANDARD" class="mat-block">\n <mat-label translate>tb.rulenode.delay-seconds</mat-label>\n <input required type="number" min="0" max="900" step="1" matInput formControlName="delaySeconds">\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n </mat-error>\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'max\')">\n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.message-attributes-hint\' | translate | safe: \'html\'"></div>\n <tb-kv-map-config-old\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="sqsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="sqsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="sqsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Nn,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:ce.SafePipe,name:"safe"},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:hr,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'<section [formGroup]="sqsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.queue-type</mat-label>\n <mat-select formControlName="queueType" required>\n <mat-option *ngFor="let type of sqsQueueTypes" [value]="type">\n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.queue-url-pattern</mat-label>\n <input required matInput formControlName="queueUrlPattern">\n <mat-error *ngIf="sqsConfigForm.get(\'queueUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint translate>tb.rulenode.general-pattern-hint</mat-hint>\n </mat-form-field>\n <mat-form-field *ngIf="sqsConfigForm.get(\'queueType\').value === sqsQueueType.STANDARD" class="mat-block">\n <mat-label translate>tb.rulenode.delay-seconds</mat-label>\n <input required type="number" min="0" max="900" step="1" matInput formControlName="delaySeconds">\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n </mat-error>\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'max\')">\n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" [innerHTML]="\'tb.rulenode.message-attributes-hint\' | translate | safe: \'html\'"></div>\n <tb-kv-map-config-old\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config-old>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="sqsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="sqsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="sqsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class vr extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.lambdaConfigForm}onConfigurationSet(e){this.lambdaConfigForm=this.fb.group({functionName:[e?e.functionName:null,[_.required]],qualifier:[e?e.qualifier:null,[]],accessKey:[e?e.accessKey:null,[_.required]],secretKey:[e?e.secretKey:null,[_.required]],region:[e?e.region:null,[_.required]],connectionTimeout:[e?e.connectionTimeout:null,[_.required,_.min(0)]],requestTimeout:[e?e.requestTimeout:null,[_.required,_.min(0)]],tellFailureIfFuncThrowsExc:[!!e&&e.tellFailureIfFuncThrowsExc,[]]})}}e("LambdaConfigComponent",vr),vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),vr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:vr,selector:"tb-external-node-lambda-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="lambdaConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.function-configuration</div>\n </div>\n <tb-example-hint [hintText]="\'tb.rulenode.template-rules-hint\'"\n popupHelpLink="rulenode/node-templatization-doc">\n </tb-example-hint>\n <div class="tb-standard-fields">\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.function-name\' | translate}}</mat-label>\n <input required matInput formControlName="functionName">\n <mat-error *ngIf="lambdaConfigForm.get(\'functionName\').hasError(\'required\')">\n {{\'tb.rulenode.function-name-required\' | translate}}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.qualifier\' | translate}}</mat-label>\n <input matInput formControlName="qualifier">\n <mat-hint translate>tb.rulenode.qualifier-hint</mat-hint>\n </mat-form-field>\n </div>\n </div>\n\n <div class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings" expanded>\n <mat-expansion-panel-header>\n <mat-panel-title class="tb-form-panel-title tb-required" translate>tb.rulenode.aws-credentials</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-standard-fields">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKey">\n <mat-error *ngIf="lambdaConfigForm.get(\'accessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretKey">\n <mat-error *ngIf="lambdaConfigForm.get(\'secretKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="lambdaConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </mat-expansion-panel>\n </div>\n <div class="tb-form-panel stroked no-padding">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header style="padding: 16px">\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-panel no-border no-padding no-gap" style="margin-top: 0">\n <div class="tb-form-row no-border same-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.connection-timeout</mat-label>\n <input type="number" required min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="lambdaConfigForm.get(\'connectionTimeout\').hasError(\'required\')">\n {{ \'tb.rulenode.connection-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="lambdaConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.connection-timeout-min\' | translate }}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.connection-timeout-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-timeout</mat-label>\n <input type="number" required min="0" matInput formControlName="requestTimeout">\n <mat-error *ngIf="lambdaConfigForm.get(\'requestTimeout\').hasError(\'required\')">\n {{ \'tb.rulenode.request-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="lambdaConfigForm.get(\'requestTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.request-timeout-min\' | translate }}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.request-timeout-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-aws-lambda-hint\' | translate }}"\n class="tb-form-row no-border" style="margin-bottom: 16px">\n <mat-slide-toggle class="mat-slide" formControlName="tellFailureIfFuncThrowsExc">\n {{ \'tb.rulenode.tell-failure-aws-lambda\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n </mat-expansion-panel>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"component",type:ae.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:ae.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:ae.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:vr,decorators:[{type:n,args:[{selector:"tb-external-node-lambda-config",template:'<section [formGroup]="lambdaConfigForm" class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.function-configuration</div>\n </div>\n <tb-example-hint [hintText]="\'tb.rulenode.template-rules-hint\'"\n popupHelpLink="rulenode/node-templatization-doc">\n </tb-example-hint>\n <div class="tb-standard-fields">\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.function-name\' | translate}}</mat-label>\n <input required matInput formControlName="functionName">\n <mat-error *ngIf="lambdaConfigForm.get(\'functionName\').hasError(\'required\')">\n {{\'tb.rulenode.function-name-required\' | translate}}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.qualifier\' | translate}}</mat-label>\n <input matInput formControlName="qualifier">\n <mat-hint translate>tb.rulenode.qualifier-hint</mat-hint>\n </mat-form-field>\n </div>\n </div>\n\n <div class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings" expanded>\n <mat-expansion-panel-header>\n <mat-panel-title class="tb-form-panel-title tb-required" translate>tb.rulenode.aws-credentials</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-standard-fields">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKey">\n <mat-error *ngIf="lambdaConfigForm.get(\'accessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretKey">\n <mat-error *ngIf="lambdaConfigForm.get(\'secretKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="lambdaConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </mat-expansion-panel>\n </div>\n <div class="tb-form-panel stroked no-padding">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header style="padding: 16px">\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-panel no-border no-padding no-gap" style="margin-top: 0">\n <div class="tb-form-row no-border same-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.connection-timeout</mat-label>\n <input type="number" required min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="lambdaConfigForm.get(\'connectionTimeout\').hasError(\'required\')">\n {{ \'tb.rulenode.connection-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="lambdaConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.connection-timeout-min\' | translate }}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.connection-timeout-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.request-timeout</mat-label>\n <input type="number" required min="0" matInput formControlName="requestTimeout">\n <mat-error *ngIf="lambdaConfigForm.get(\'requestTimeout\').hasError(\'required\')">\n {{ \'tb.rulenode.request-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="lambdaConfigForm.get(\'requestTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.request-timeout-min\' | translate }}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.request-timeout-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n </div>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.tell-failure-aws-lambda-hint\' | translate }}"\n class="tb-form-row no-border" style="margin-bottom: 16px">\n <mat-slide-toggle class="mat-slide" formControlName="tellFailureIfFuncThrowsExc">\n {{ \'tb.rulenode.tell-failure-aws-lambda\' | translate }}\n </mat-slide-toggle>\n </div>\n </div>\n </mat-expansion-panel>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Cr{}e("RulenodeCoreConfigExternalModule",Cr),Cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Cr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:Cr,declarations:[xr,hr,vr,ur,mr,pr,dr,cr,gr,fr,sr,yr,br],imports:[J,E,Qe,Qn],exports:[xr,hr,vr,ur,mr,pr,dr,cr,gr,fr,sr,yr,br]}),Cr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Cr,imports:[J,E,Qe,Qn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Cr,decorators:[{type:d,args:[{declarations:[xr,hr,vr,ur,mr,pr,dr,cr,gr,fr,sr,yr,br],imports:[J,E,Qe,Qn],exports:[xr,hr,vr,ur,mr,pr,dr,cr,gr,fr,sr,yr,br]}]}]});class Fr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.searchText=""}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return{alarmStatusList:ye(e?.alarmStatusList)?e.alarmStatusList:null}}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e.alarmStatusList,[_.required]]})}}e("CheckAlarmStatusComponent",Fr),Fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Fr,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Fr,selector:"tb-filter-node-check-alarm-status-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="alarmStatusConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.alarm-status</div>\n <div class="tb-form-panel-hint tb-error" translate [hidden]="alarmStatusConfigForm.get(\'alarmStatusList\').valid">\n tb.rulenode.alarm-required\n </div>\n </div>\n <tb-alarm-status-select formControlName="alarmStatusList"></tb-alarm-status-select>\n</section>\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Jn,selector:"tb-alarm-status-select"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Fr,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'<section [formGroup]="alarmStatusConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.alarm-status</div>\n <div class="tb-form-panel-hint tb-error" translate [hidden]="alarmStatusConfigForm.get(\'alarmStatusList\').valid">\n tb.rulenode.alarm-required\n </div>\n </div>\n <tb-alarm-status-select formControlName="alarmStatusList"></tb-alarm-status-select>\n</section>\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class kr extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.checkMessageConfigForm}prepareInputConfig(e){return{messageNames:ye(e?.messageNames)?e.messageNames:[],metadataNames:ye(e?.metadataNames)?e.metadataNames:[],checkAllKeys:!!ye(e?.checkAllKeys)&&e.checkAllKeys}}prepareOutputConfig(e){return{messageNames:ye(e?.messageNames)?e.messageNames:[],metadataNames:ye(e?.metadataNames)?e.metadataNames:[],checkAllKeys:e.checkAllKeys}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e.messageNames,[]],metadataNames:[e.metadataNames,[]],checkAllKeys:[e.checkAllKeys,[]]},{validators:this.atLeastOne(_.required,["messageNames","metadataNames"])})}get touchedValidationControl(){return["messageNames","metadataNames"].some((e=>this.checkMessageConfigForm.get(e).touched))}}e("CheckMessageConfigComponent",kr),kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kr,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:kr,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="checkMessageConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.fields-to-check</div>\n <div class="tb-form-panel-hint tb-error" translate [hidden]="!(touchedValidationControl && checkMessageConfigForm.hasError(\'atLeastOne\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-string-items-list editable subscriptSizing="dynamic"\n [label]="\'tb.rulenode.data-keys\' | translate"\n [placeholder]="\'tb.rulenode.add-message-field\' | translate"\n formControlName="messageNames">\n <mat-icon matSuffix color="primary" class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n </tb-string-items-list>\n <tb-string-items-list editable subscriptSizing="dynamic"\n [label]="\'tb.rulenode.metadata-keys\' | translate"\n [placeholder]="\'tb.rulenode.add-metadata-field\' | translate"\n formControlName="metadataNames">\n <mat-icon matSuffix color="primary" class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n </tb-string-items-list>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.check-all-keys-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="checkAllKeys">\n {{ \'tb.rulenode.check-all-keys\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:tt.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:W.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:kr,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'<section [formGroup]="checkMessageConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-row no-padding no-border space-between">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.fields-to-check</div>\n <div class="tb-form-panel-hint tb-error" translate [hidden]="!(touchedValidationControl && checkMessageConfigForm.hasError(\'atLeastOne\'))">\n tb.rulenode.at-least-one-field-required\n </div>\n </div>\n <tb-string-items-list editable subscriptSizing="dynamic"\n [label]="\'tb.rulenode.data-keys\' | translate"\n [placeholder]="\'tb.rulenode.add-message-field\' | translate"\n formControlName="messageNames">\n <mat-icon matSuffix color="primary" class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n </tb-string-items-list>\n <tb-string-items-list editable subscriptSizing="dynamic"\n [label]="\'tb.rulenode.metadata-keys\' | translate"\n [placeholder]="\'tb.rulenode.add-metadata-field\' | translate"\n formControlName="metadataNames">\n <mat-icon matSuffix color="primary" class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.field-name\' | translate } }}">help</mat-icon>\n </tb-string-items-list>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.check-all-keys-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding">\n <mat-slide-toggle class="mat-slide" formControlName="checkAllKeys">\n {{ \'tb.rulenode.check-all-keys\' | translate }}\n </mat-slide-toggle>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class Tr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.values(v),this.entitySearchDirectionTranslationsMap=N}configForm(){return this.checkRelationConfigForm}prepareInputConfig(e){return{checkForSingleEntity:!!ye(e?.checkForSingleEntity)&&e.checkForSingleEntity,direction:ye(e?.direction)?e.direction:null,entityType:ye(e?.entityType)?e.entityType:null,entityId:ye(e?.entityId)?e.entityId:null,relationType:ye(e?.relationType)?e.relationType:null}}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[e.checkForSingleEntity,[]],direction:[e.direction,[]],entityType:[e.entityType,e&&e.checkForSingleEntity?[_.required]:[]],entityId:[e.entityId,e&&e.checkForSingleEntity?[_.required]:[]],relationType:[e.relationType,[_.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[_.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[_.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",Tr),Tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Tr,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="checkRelationConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-search-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'relation.direction\' | translate }}</mat-label>\n <mat-select formControlName="direction" required>\n <mat-option *ngFor="let direction of entitySearchDirection" [value]="direction">\n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.check-relation-to-specific-entity-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="checkForSingleEntity">\n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n <div *ngIf="checkRelationConfigForm.get(\'checkForSingleEntity\').value" class="same-width-component-row">\n <tb-entity-type-select\n style="min-width: 100px; flex: 1;"\n showLabel\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <tb-entity-autocomplete\n fxFlex\n required\n *ngIf="checkRelationConfigForm.get(\'entityType\').value"\n [entityType]="checkRelationConfigForm.get(\'entityType\').value"\n formControlName="entityId">\n </tb-entity-autocomplete>\n </div>\n </div>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:st.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:Ne.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled","additionEntityTypes"]},{kind:"component",type:qe.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:W.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: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:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Tr,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'<section [formGroup]="checkRelationConfigForm" class="tb-form-panel stroked no-padding-bottom">\n <div class="tb-form-panel-title" translate>tb.rulenode.relation-search-parameters</div>\n <div fxLayout="column">\n <mat-form-field class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'relation.direction\' | translate }}</mat-label>\n <mat-select formControlName="direction" required>\n <mat-option *ngFor="let direction of entitySearchDirection" [value]="direction">\n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }} <span translate>tb.rulenode.relations-query-config-direction-suffix</span>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.check-relation-to-specific-entity-tooltip\' | translate }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="checkForSingleEntity">\n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n </mat-slide-toggle>\n </div>\n <div *ngIf="checkRelationConfigForm.get(\'checkForSingleEntity\').value" class="same-width-component-row">\n <tb-entity-type-select\n style="min-width: 100px; flex: 1;"\n showLabel\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <tb-entity-autocomplete\n fxFlex\n required\n *ngIf="checkRelationConfigForm.get(\'entityType\').value"\n [entityType]="checkRelationConfigForm.get(\'entityType\').value"\n formControlName="entityId">\n </tb-entity-autocomplete>\n </div>\n </div>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Lr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=Et,this.perimeterTypes=Object.values(Et),this.perimeterTypeTranslationMap=wt,this.rangeUnits=Object.values(Vt),this.rangeUnitTranslationMap=Pt,this.defaultPaddingEnable=!0}configForm(){return this.geoFilterConfigForm}prepareInputConfig(e){return{latitudeKeyName:ye(e?.latitudeKeyName)?e.latitudeKeyName:null,longitudeKeyName:ye(e?.longitudeKeyName)?e.longitudeKeyName:null,perimeterType:ye(e?.perimeterType)?e.perimeterType:null,fetchPerimeterInfoFromMessageMetadata:!!ye(e?.fetchPerimeterInfoFromMessageMetadata)&&e.fetchPerimeterInfoFromMessageMetadata,perimeterKeyName:ye(e?.perimeterKeyName)?e.perimeterKeyName:null,centerLatitude:ye(e?.centerLatitude)?e.centerLatitude:null,centerLongitude:ye(e?.centerLongitude)?e.centerLongitude:null,range:ye(e?.range)?e.range:null,rangeUnit:ye(e?.rangeUnit)?e.rangeUnit:null,polygonsDefinition:ye(e?.polygonsDefinition)?e.polygonsDefinition:null}}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e.latitudeKeyName,[_.required]],longitudeKeyName:[e.longitudeKeyName,[_.required]],perimeterType:[e.perimeterType,[_.required]],fetchPerimeterInfoFromMessageMetadata:[e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e.perimeterKeyName,[]],centerLatitude:[e.centerLatitude,[]],centerLongitude:[e.centerLongitude,[]],range:[e.range,[]],rangeUnit:[e.rangeUnit,[]],polygonsDefinition:[e.polygonsDefinition,[]]})}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([_.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==Et.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([]),this.defaultPaddingEnable=!0):(this.geoFilterConfigForm.get("centerLatitude").setValidators([_.required,_.min(-90),_.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([_.required,_.min(-180),_.max(180)]),this.geoFilterConfigForm.get("range").setValidators([_.required,_.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([_.required]),this.defaultPaddingEnable=!1),t||n!==Et.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([_.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",Lr),Lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Lr,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Lr,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="geoFilterConfigForm" class="tb-form-panel no-border no-padding">\n <section class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.coordinate-field-names</div>\n <section>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.latitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.longitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.coordinate-field-hint</div>\n </section>\n </section>\n <section class="tb-form-panel stroked" [class.no-padding-bottom]="!defaultPaddingEnable">\n <div class="tb-form-panel-title" translate>tb.rulenode.geofence-configuration</div>\n <section fxLayout="column">\n <mat-form-field fxFlex class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.perimeter-type\' | translate }}</mat-label>\n <mat-select formControlName="perimeterType">\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div tb-hint-tooltip-icon="{{ geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE\n ? (\'tb.rulenode.fetch-circle-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoFilterConfigForm.get(\'perimeterKeyName\').valid\n ? geoFilterConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'})\n : (\'tb.rulenode.fetch-poligon-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoFilterConfigForm.get(\'perimeterKeyName\').valid\n ? geoFilterConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'}) }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchPerimeterInfoFromMessageMetadata">\n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field *ngIf="geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value" class="mat-block">\n <mat-label>{{ \'tb.rulenode.perimeter-key-name\' | translate }}</mat-label>\n <input matInput formControlName="perimeterKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'perimeterKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n </mat-error>\n <mat-hint>{{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}</mat-hint>\n </mat-form-field>\n <div fxLayout="column"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-latitude\' | translate }}</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-longitude\' | translate }}</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range\' | translate }}</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range-units\' | translate }}</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="geoFilterConfigForm.get(\'rangeUnit\').hasError(\'required\')">\n {{ \'tb.rulenode.range-units-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-label>{{ \'tb.rulenode.polygon-definition\' | translate }}</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-hint>{{ \'tb.rulenode.polygon-definition-hint\' | translate }}</mat-hint>\n <mat-error *ngIf="geoFilterConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n </section>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:W.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: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:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:O.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Lr,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'<section [formGroup]="geoFilterConfigForm" class="tb-form-panel no-border no-padding">\n <section class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.coordinate-field-names</div>\n <section>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.latitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="50" class="mat-block">\n <mat-label>{{ \'tb.rulenode.longitude-field-name\' | translate }}</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div class="tb-form-hint tb-primary-fill" translate>tb.rulenode.coordinate-field-hint</div>\n </section>\n </section>\n <section class="tb-form-panel stroked" [class.no-padding-bottom]="!defaultPaddingEnable">\n <div class="tb-form-panel-title" translate>tb.rulenode.geofence-configuration</div>\n <section fxLayout="column">\n <mat-form-field fxFlex class="mat-block" hideRequiredMarker>\n <mat-label>{{ \'tb.rulenode.perimeter-type\' | translate }}</mat-label>\n <mat-select formControlName="perimeterType">\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div tb-hint-tooltip-icon="{{ geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE\n ? (\'tb.rulenode.fetch-circle-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoFilterConfigForm.get(\'perimeterKeyName\').valid\n ? geoFilterConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'})\n : (\'tb.rulenode.fetch-poligon-parameter-info-from-metadata-hint\'\n | translate : { perimeterKeyName: geoFilterConfigForm.get(\'perimeterKeyName\').valid\n ? geoFilterConfigForm.get(\'perimeterKeyName\').value\n : \'ss_perimeter\'}) }}"\n class="tb-form-row no-border no-padding slide-toggle">\n <mat-slide-toggle class="mat-slide" formControlName="fetchPerimeterInfoFromMessageMetadata">\n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n </mat-slide-toggle>\n </div>\n <mat-form-field *ngIf="geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value" class="mat-block">\n <mat-label>{{ \'tb.rulenode.perimeter-key-name\' | translate }}</mat-label>\n <input matInput formControlName="perimeterKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'perimeterKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n </mat-error>\n <mat-hint>{{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}</mat-hint>\n </mat-form-field>\n <div fxLayout="column"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-latitude\' | translate }}</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.circle-center-longitude\' | translate }}</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="16px">\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range\' | translate }}</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label>{{ \'tb.rulenode.range-units\' | translate }}</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="geoFilterConfigForm.get(\'rangeUnit\').hasError(\'required\')">\n {{ \'tb.rulenode.range-units-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <mat-form-field class="mat-block" subscriptSizing="dynamic"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-label>{{ \'tb.rulenode.polygon-definition\' | translate }}</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-hint>{{ \'tb.rulenode.polygon-definition-hint\' | translate }}</mat-hint>\n <mat-error *ngIf="geoFilterConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n </section>\n</section>\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class Ir extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}prepareInputConfig(e){return{messageTypes:ye(e?.messageTypes)?e.messageTypes:null}}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e.messageTypes,[_.required]]})}}e("MessageTypeConfigComponent",Ir),Ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ir,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ir,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="messageTypeConfigForm">\n <tb-message-types-config\n required\n [label]="\'tb.rulenode.select-message-types\' | translate"\n formControlName="messageTypes">\n </tb-message-types-config>\n</section>\n',dependencies:[{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Bn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ir,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'<section [formGroup]="messageTypeConfigForm">\n <tb-message-types-config\n required\n [label]="\'tb.rulenode.select-message-types\' | translate"\n formControlName="messageTypes">\n </tb-message-types-config>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Sr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[C.DEVICE,C.ASSET,C.ENTITY_VIEW,C.TENANT,C.CUSTOMER,C.USER,C.DASHBOARD,C.RULE_CHAIN,C.RULE_NODE,C.EDGE]}configForm(){return this.originatorTypeConfigForm}prepareInputConfig(e){return{originatorTypes:ye(e?.originatorTypes)?e.originatorTypes:null}}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e.originatorTypes,[_.required]]})}}e("OriginatorTypeConfigComponent",Sr),Sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Sr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Sr,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="originatorTypeConfigForm">\n <tb-entity-type-list fxFlex\n formControlName="originatorTypes"\n [allowedEntityTypes]="allowedEntityTypes"\n [ignoreAuthorityFilter]="true"\n [emptyInputPlaceholder]="\'tb.rulenode.add-entity-type\' | translate"\n [filledInputPlaceholder]="\'tb.rulenode.add-entity-type\' | translate"\n [label]="\'tb.rulenode.select-entity-types\' | translate"\n required>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.entity-type\' | translate } }}">help</mat-icon>\n </tb-entity-type-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:mt.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","additionalClasses","appearance","label","floatLabel","disabled","subscriptSizing","allowedEntityTypes","emptyInputPlaceholder","filledInputPlaceholder","ignoreAuthorityFilter"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{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:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Sr,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'<section [formGroup]="originatorTypeConfigForm">\n <tb-entity-type-list fxFlex\n formControlName="originatorTypes"\n [allowedEntityTypes]="allowedEntityTypes"\n [ignoreAuthorityFilter]="true"\n [emptyInputPlaceholder]="\'tb.rulenode.add-entity-type\' | translate"\n [filledInputPlaceholder]="\'tb.rulenode.add-entity-type\' | translate"\n [label]="\'tb.rulenode.select-entity-types\' | translate"\n required>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.chip-help\' | translate: { inputName: \'tb.rulenode.entity-type\' | translate } }}">help</mat-icon>\n </tb-entity-type-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class Nr extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ge(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-filter-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e.scriptLang,[_.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===b.JS?[_.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===b.TBEL?[_.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),{scriptLang:ye(e?.scriptLang)?e.scriptLang:b.JS,jsScript:ye(e?.jsScript)?e.jsScript:null,tbelScript:ye(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Nr),Nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Nr,deps:[{token:R.Store},{token:O.UntypedFormBuilder},{token:fe.NodeScriptTestService},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Nr,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:'<section [formGroup]="scriptConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/filter_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/filter_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ce.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","propertyHighlightRules","objectHighlightRules","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Fe.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Nr,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'<section [formGroup]="scriptConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/filter_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/filter_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder},{type:fe.NodeScriptTestService},{type:X.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class qr extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ge(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-switch-function"}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e.scriptLang,[_.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===b.JS?[_.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===b.TBEL?[_.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),{scriptLang:ye(e?.scriptLang)?e.scriptLang:b.JS,jsScript:ye(e?.jsScript)?e.jsScript:null,tbelScript:ye(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.switchConfigForm.get("scriptLang").value,n=t===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",qr),qr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:qr,deps:[{token:R.Store},{token:O.UntypedFormBuilder},{token:fe.NodeScriptTestService},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:qr,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:'<section [formGroup]="switchConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="switchConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/switch_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="switchConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/switch_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ce.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","propertyHighlightRules","objectHighlightRules","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Fe.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:qr,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'<section [formGroup]="switchConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="switchConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n helpId="rulenode/switch_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="switchConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n helpId="rulenode/tbel/switch_node_script_fn"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder},{type:fe.NodeScriptTestService},{type:X.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}});class Ar{}e("RuleNodeCoreConfigFilterModule",Ar),Ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ar,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Ar.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:Ar,declarations:[kr,Tr,Lr,Ir,Sr,Nr,qr,Fr],imports:[J,E,Qn],exports:[kr,Tr,Lr,Ir,Sr,Nr,qr,Fr]}),Ar.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ar,imports:[J,E,Qn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ar,decorators:[{type:d,args:[{declarations:[kr,Tr,Lr,Ir,Sr,Nr,qr,Fr],imports:[J,E,Qn],exports:[kr,Tr,Lr,Ir,Sr,Nr,qr,Fr]}]}]});class Mr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=St,this.originatorSources=Object.keys(St),this.originatorSourceTranslationMap=Nt,this.originatorSourceDescTranslationMap=qt,this.allowedEntityTypes=[C.DEVICE,C.ASSET,C.ENTITY_VIEW,C.USER,C.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[_.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===St.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([_.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===St.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([_.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([_.required,_.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",Mr),Mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Mr,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Mr,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="changeOriginatorConfigForm" class="tb-form-panel no-border no-padding">\n <mat-form-field class="mat-block" subscriptSizing="dynamic" hideRequiredMarker>\n <mat-label translate>tb.rulenode.new-originator</mat-label>\n <mat-select formControlName="originatorSource" required>\n <mat-select-trigger>\n <span *ngIf="originatorSourceTranslationMap.get(changeOriginatorConfigForm.get(\'originatorSource\').value)">\n {{ originatorSourceTranslationMap.get(changeOriginatorConfigForm.get(\'originatorSource\').value) | translate }}\n </span>\n </mat-select-trigger>\n <mat-option *ngFor="let source of originatorSources" [value]="source">\n <span matListItemTitle>\n {{ originatorSourceTranslationMap.get(source) | translate }}\n </span>\n <br>\n <small matListItemMeta style="color: inherit">\n {{ originatorSourceDescTranslationMap.get(source) | translate }}\n </small>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div class="tb-form-panel stroked no-padding-bottom"\n *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === \'ENTITY\'">\n <tb-example-hint [hintText]="\'tb.rulenode.entity-name-pattern-hint\'"\n popupHelpLink="rulenode/change_originator_node_fields_templatization">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <tb-entity-type-select\n showLabel\n required\n [allowedEntityTypes] = "allowedEntityTypes"\n formControlName="entityType"\n class="mat-mdc-form-field flex">\n </tb-entity-type-select>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.entity-name-pattern</mat-label>\n <input required matInput formControlName="entityNamePattern">\n <mat-error *ngIf="changeOriginatorConfigForm.get(\'entityNamePattern\').hasError(\'required\') ||\n changeOriginatorConfigForm.get(\'entityNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <tb-relations-query-config\n required\n *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === originatorSource.RELATED"\n formControlName="relationsQuery">\n </tb-relations-query-config>\n</section>\n',dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ne.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled","additionEntityTypes"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:ne.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Re.MatListItemTitle,selector:"[matListItemTitle]"},{kind:"directive",type:Re.MatListItemMeta,selector:"[matListItemMeta]"},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:_n,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Mr,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'<section [formGroup]="changeOriginatorConfigForm" class="tb-form-panel no-border no-padding">\n <mat-form-field class="mat-block" subscriptSizing="dynamic" hideRequiredMarker>\n <mat-label translate>tb.rulenode.new-originator</mat-label>\n <mat-select formControlName="originatorSource" required>\n <mat-select-trigger>\n <span *ngIf="originatorSourceTranslationMap.get(changeOriginatorConfigForm.get(\'originatorSource\').value)">\n {{ originatorSourceTranslationMap.get(changeOriginatorConfigForm.get(\'originatorSource\').value) | translate }}\n </span>\n </mat-select-trigger>\n <mat-option *ngFor="let source of originatorSources" [value]="source">\n <span matListItemTitle>\n {{ originatorSourceTranslationMap.get(source) | translate }}\n </span>\n <br>\n <small matListItemMeta style="color: inherit">\n {{ originatorSourceDescTranslationMap.get(source) | translate }}\n </small>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div class="tb-form-panel stroked no-padding-bottom"\n *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === \'ENTITY\'">\n <tb-example-hint [hintText]="\'tb.rulenode.entity-name-pattern-hint\'"\n popupHelpLink="rulenode/change_originator_node_fields_templatization">\n </tb-example-hint>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <tb-entity-type-select\n showLabel\n required\n [allowedEntityTypes] = "allowedEntityTypes"\n formControlName="entityType"\n class="mat-mdc-form-field flex">\n </tb-entity-type-select>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.entity-name-pattern</mat-label>\n <input required matInput formControlName="entityNamePattern">\n <mat-error *ngIf="changeOriginatorConfigForm.get(\'entityNamePattern\').hasError(\'required\') ||\n changeOriginatorConfigForm.get(\'entityNamePattern\').hasError(\'pattern\')">\n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <tb-relations-query-config\n required\n *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === originatorSource.RELATED"\n formControlName="relationsQuery">\n </tb-relations-query-config>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class Er extends g{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=ge(this.store).tbelEnabled,this.scriptLanguage=b,this.changeScript=new l,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:b.JS,[_.required]],jsScript:[e?e.jsScript:null,[_.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==b.TBEL||this.tbelEnabled||(t=b.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===b.JS?[_.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===b.TBEL?[_.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=b.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===b.JS?"jsScript":"tbelScript",r=t===b.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===b.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Er),Er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Er,deps:[{token:R.Store},{token:O.FormBuilder},{token:fe.NodeScriptTestService},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Er,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:'<section [formGroup]="scriptConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Transform"\n helpId="rulenode/transformation_node_script_fn"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Transform"\n helpId="rulenode/tbel/transformation_node_script_fn"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n',dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ce.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","propertyHighlightRules","objectHighlightRules","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","hideBrackets","noValidate","required"]},{kind:"component",type:ee.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:ee.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Fe.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Er,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'<section [formGroup]="scriptConfigForm">\n <tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.JS"\n #jsFuncComponent\n formControlName="jsScript"\n functionName="Transform"\n helpId="rulenode/transformation_node_script_fn"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <tb-js-func *ngIf="scriptConfigForm.get(\'scriptLang\').value === scriptLanguage.TBEL"\n #tbelFuncComponent\n formControlName="tbelScript"\n functionName="Transform"\n helpId="rulenode/tbel/transformation_node_script_fn"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n [disableUndefinedCheck]="true"\n [scriptLanguage]="scriptLanguage.TBEL"\n noValidate="true">\n <button toolbarSuffixButton\n mat-icon-button\n matTooltip="{{ testScriptLabel | translate }}"\n matTooltipPosition="above"\n class="tb-mat-32"\n (click)="testScript()">\n <mat-icon class="material-icons" color="primary">bug_report</mat-icon>\n </button>\n </tb-js-func>\n <div>\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ testScriptLabel | translate }}\n </button>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder},{type:fe.NodeScriptTestService},{type:X.TranslateService}]},propDecorators:{jsFuncComponent:[{type:u,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:u,args:["tbelFuncComponent",{static:!1}]}]}}); + /** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + const wr=pt({passive:!0});class Gr{constructor(e,t){this._platform=e,this._ngZone=t,this._monitoredElements=new Map}monitor(e){if(!this._platform.isBrowser)return me;const t=Ge(e),n=this._monitoredElements.get(t);if(n)return n.subject;const r=new ie,o="cdk-text-field-autofilled",a=e=>{"cdk-text-field-autofill-start"!==e.animationName||t.classList.contains(o)?"cdk-text-field-autofill-end"===e.animationName&&t.classList.contains(o)&&(t.classList.remove(o),this._ngZone.run((()=>r.next({target:e.target,isAutofilled:!1})))):(t.classList.add(o),this._ngZone.run((()=>r.next({target:e.target,isAutofilled:!0}))))};return this._ngZone.runOutsideAngular((()=>{t.addEventListener("animationstart",a,wr),t.classList.add("cdk-text-field-autofill-monitored")})),this._monitoredElements.set(t,{subject:r,unlisten:()=>{t.removeEventListener("animationstart",a,wr)}}),r}stopMonitoring(e){const t=Ge(e),n=this._monitoredElements.get(t);n&&(n.unlisten(),n.subject.complete(),t.classList.remove("cdk-text-field-autofill-monitored"),t.classList.remove("cdk-text-field-autofilled"),this._monitoredElements.delete(t))}ngOnDestroy(){this._monitoredElements.forEach(((e,t)=>this.stopMonitoring(t)))}}Gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Gr,deps:[{token:dt.Platform},{token:t.NgZone}],target:t.ɵɵFactoryTarget.Injectable}),Gr.ɵprov=t.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Gr,providedIn:"root"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Gr,decorators:[{type:o,args:[{providedIn:"root"}]}],ctorParameters:function(){return[{type:dt.Platform},{type:t.NgZone}]}});class Dr{constructor(e,t){this._elementRef=e,this._autofillMonitor=t,this.cdkAutofill=new l}ngOnInit(){this._autofillMonitor.monitor(this._elementRef).subscribe((e=>this.cdkAutofill.emit(e)))}ngOnDestroy(){this._autofillMonitor.stopMonitoring(this._elementRef)}}Dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Dr,deps:[{token:t.ElementRef},{token:Gr}],target:t.ɵɵFactoryTarget.Directive}),Dr.ɵdir=t.ɵɵngDeclareDirective({minVersion:"14.0.0",version:"15.2.0-rc.0",type:Dr,selector:"[cdkAutofill]",outputs:{cdkAutofill:"cdkAutofill"},ngImport:t}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Dr,decorators:[{type:s,args:[{selector:"[cdkAutofill]"}]}],ctorParameters:function(){return[{type:t.ElementRef},{type:Gr}]},propDecorators:{cdkAutofill:[{type:p}]}}); + /** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + class Vr{get minRows(){return this._minRows}set minRows(e){this._minRows=De(e),this._setMinHeight()}get maxRows(){return this._maxRows}set maxRows(e){this._maxRows=De(e),this._setMaxHeight()}get enabled(){return this._enabled}set enabled(e){e=we(e),this._enabled!==e&&((this._enabled=e)?this.resizeToFitContent(!0):this.reset())}get placeholder(){return this._textareaElement.placeholder}set placeholder(e){this._cachedPlaceholderHeight=void 0,e?this._textareaElement.setAttribute("placeholder",e):this._textareaElement.removeAttribute("placeholder"),this._cacheTextareaPlaceholderHeight()}constructor(e,t,n,r){this._elementRef=e,this._platform=t,this._ngZone=n,this._destroyed=new ie,this._enabled=!0,this._previousMinRows=-1,this._isViewInited=!1,this._handleFocusEvent=e=>{this._hasFocus="focus"===e.type},this._document=r,this._textareaElement=this._elementRef.nativeElement}_setMinHeight(){const e=this.minRows&&this._cachedLineHeight?this.minRows*this._cachedLineHeight+"px":null;e&&(this._textareaElement.style.minHeight=e)}_setMaxHeight(){const e=this.maxRows&&this._cachedLineHeight?this.maxRows*this._cachedLineHeight+"px":null;e&&(this._textareaElement.style.maxHeight=e)}ngAfterViewInit(){this._platform.isBrowser&&(this._initialHeight=this._textareaElement.style.height,this.resizeToFitContent(),this._ngZone.runOutsideAngular((()=>{const e=this._getWindow();pe(e,"resize").pipe(je(16),Ue(this._destroyed)).subscribe((()=>this.resizeToFitContent(!0))),this._textareaElement.addEventListener("focus",this._handleFocusEvent),this._textareaElement.addEventListener("blur",this._handleFocusEvent)})),this._isViewInited=!0,this.resizeToFitContent(!0))}ngOnDestroy(){this._textareaElement.removeEventListener("focus",this._handleFocusEvent),this._textareaElement.removeEventListener("blur",this._handleFocusEvent),this._destroyed.next(),this._destroyed.complete()}_cacheTextareaLineHeight(){if(this._cachedLineHeight)return;let e=this._textareaElement.cloneNode(!1);e.rows=1,e.style.position="absolute",e.style.visibility="hidden",e.style.border="none",e.style.padding="0",e.style.height="",e.style.minHeight="",e.style.maxHeight="",e.style.overflow="hidden",this._textareaElement.parentNode.appendChild(e),this._cachedLineHeight=e.clientHeight,e.remove(),this._setMinHeight(),this._setMaxHeight()}_measureScrollHeight(){const e=this._textareaElement,t=e.style.marginBottom||"",n=this._platform.FIREFOX,r=n&&this._hasFocus,o=n?"cdk-textarea-autosize-measuring-firefox":"cdk-textarea-autosize-measuring";r&&(e.style.marginBottom=`${e.clientHeight}px`),e.classList.add(o);const a=e.scrollHeight-4;return e.classList.remove(o),r&&(e.style.marginBottom=t),a}_cacheTextareaPlaceholderHeight(){if(!this._isViewInited||null!=this._cachedPlaceholderHeight)return;if(!this.placeholder)return void(this._cachedPlaceholderHeight=0);const e=this._textareaElement.value;this._textareaElement.value=this._textareaElement.placeholder,this._cachedPlaceholderHeight=this._measureScrollHeight(),this._textareaElement.value=e}ngDoCheck(){this._platform.isBrowser&&this.resizeToFitContent()}resizeToFitContent(e=!1){if(!this._enabled)return;if(this._cacheTextareaLineHeight(),this._cacheTextareaPlaceholderHeight(),!this._cachedLineHeight)return;const t=this._elementRef.nativeElement,n=t.value;if(!e&&this._minRows===this._previousMinRows&&n===this._previousValue)return;const r=this._measureScrollHeight(),o=Math.max(r,this._cachedPlaceholderHeight||0);t.style.height=`${o}px`,this._ngZone.runOutsideAngular((()=>{"undefined"!=typeof requestAnimationFrame?requestAnimationFrame((()=>this._scrollToCaretPosition(t))):setTimeout((()=>this._scrollToCaretPosition(t)))})),this._previousValue=n,this._previousMinRows=this._minRows}reset(){void 0!==this._initialHeight&&(this._textareaElement.style.height=this._initialHeight)}_noopInputHandler(){}_getDocument(){return this._document||document}_getWindow(){return this._getDocument().defaultView||window}_scrollToCaretPosition(e){const{selectionStart:t,selectionEnd:n}=e;!this._destroyed.isStopped&&this._hasFocus&&e.setSelectionRange(t,n)}}Vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Vr,deps:[{token:t.ElementRef},{token:dt.Platform},{token:t.NgZone},{token:$,optional:!0}],target:t.ɵɵFactoryTarget.Directive}),Vr.ɵdir=t.ɵɵngDeclareDirective({minVersion:"14.0.0",version:"15.2.0-rc.0",type:Vr,selector:"textarea[cdkTextareaAutosize]",inputs:{minRows:["cdkAutosizeMinRows","minRows"],maxRows:["cdkAutosizeMaxRows","maxRows"],enabled:["cdkTextareaAutosize","enabled"],placeholder:"placeholder"},host:{attributes:{rows:"1"},listeners:{input:"_noopInputHandler()"},classAttribute:"cdk-textarea-autosize"},exportAs:["cdkTextareaAutosize"],ngImport:t}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Vr,decorators:[{type:s,args:[{selector:"textarea[cdkTextareaAutosize]",exportAs:"cdkTextareaAutosize",host:{class:"cdk-textarea-autosize",rows:"1","(input)":"_noopInputHandler()"}}]}],ctorParameters:function(){return[{type:t.ElementRef},{type:dt.Platform},{type:t.NgZone},{type:void 0,decorators:[{type:i},{type:a,args:[$]}]}]},propDecorators:{minRows:[{type:m,args:["cdkAutosizeMinRows"]}],maxRows:[{type:m,args:["cdkAutosizeMaxRows"]}],enabled:[{type:m,args:["cdkTextareaAutosize"]}],placeholder:[{type:m}]}}); + /** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + class Pr{}Pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Pr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.0-rc.0",ngImport:t,type:Pr,declarations:[Dr,Vr],exports:[Dr,Vr]}),Pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Pr}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.0-rc.0",ngImport:t,type:Pr,decorators:[{type:d,args:[{declarations:[Dr,Vr],exports:[Dr,Vr]}]}]});class Rr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",description:"tb.mail-body-type.plain-text-description",value:"false"},{name:"tb.mail-body-type.html",description:"tb.mail-body-type.html-text-description",value:"true"},{name:"tb.mail-body-type.use-body-type-template",description:"tb.mail-body-type.dynamic-text-description",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[_.required]],toTemplate:[e?e.toTemplate:null,[_.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[_.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null,[_.required]],bodyTemplate:[e?e.bodyTemplate:null,[_.required]]})}prepareInputConfig(e){return{fromTemplate:ye(e?.fromTemplate)?e.fromTemplate:null,toTemplate:ye(e?.toTemplate)?e.toTemplate:null,ccTemplate:ye(e?.ccTemplate)?e.ccTemplate:null,bccTemplate:ye(e?.bccTemplate)?e.bccTemplate:null,subjectTemplate:ye(e?.subjectTemplate)?e.subjectTemplate:null,mailBodyType:ye(e?.mailBodyType)?e.mailBodyType:null,isHtmlTemplate:ye(e?.isHtmlTemplate)?e.isHtmlTemplate:null,bodyTemplate:ye(e?.bodyTemplate)?e.bodyTemplate:null}}updateValidators(e){"dynamic"===this.toEmailConfigForm.get("mailBodyType").value?this.toEmailConfigForm.get("isHtmlTemplate").enable({emitEvent:!1}):this.toEmailConfigForm.get("isHtmlTemplate").disable({emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["mailBodyType"]}getBodyTypeName(){return this.mailBodyTypes.find((e=>e.value===this.toEmailConfigForm.get("mailBodyType").value)).name}}e("ToEmailConfigComponent",Rr),Rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Rr,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Rr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="toEmailConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.email-sender</div>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.from-template</mat-label>\n <input required matInput formControlName="fromTemplate">\n <mat-hint align="start">\n {{ \'tb.rulenode.email-from-template-hint\' | translate }}\n </mat-hint>\n <mat-hint align="end">\n <div class="input-bottom-double-hint">\n <div class="see-example"\n hintMode\n tb-help-popup="{{\'rulenode/to_email_node_fields_templatization\'}}"\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px;"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}"></div>\n </div>\n </mat-hint>\n <mat-error *ngIf="toEmailConfigForm.get(\'fromTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.from-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel-title" translate>tb.rulenode.recipients</div>\n <tb-example-hint [hintText]="\'tb.rulenode.recipients-block-main-hint\' | translate"\n popupHelpLink="rulenode/to_email_node_fields_templatization">\n </tb-example-hint>\n </div>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.to-template</mat-label>\n <textarea required\n matInput\n class="tb-enable-vertical-resize"\n formControlName="toTemplate"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'toTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.to-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.cc-template</mat-label>\n <textarea matInput\n formControlName="ccTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.bcc-template</mat-label>\n <textarea matInput\n formControlName="bccTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n </mat-form-field>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.message-subject-and-content</div>\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\' | translate"\n popupHelpLink="rulenode/to_email_node_fields_templatization">\n </tb-example-hint>\n <section>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.subject-template</mat-label>\n <textarea required\n matInput\n formControlName="subjectTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'subjectTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.subject-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.mail-body-type</mat-label>\n <mat-select formControlName="mailBodyType">\n <mat-select-trigger>\n <span *ngIf="toEmailConfigForm.get(\'mailBodyType\').value">\n {{ getBodyTypeName() | translate }}\n </span>\n </mat-select-trigger>\n <mat-option *ngFor="let type of mailBodyTypes" [value]="type.value">\n <span matListItemTitle>\n {{ type.name | translate }}\n </span>\n <br>\n <small matListItemMeta style="color: inherit">\n {{ type.description | translate }}\n </small>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" *ngIf="toEmailConfigForm.get(\'mailBodyType\').value === \'dynamic\'">\n <mat-label translate>tb.rulenode.body-type-template</mat-label>\n <input required matInput formControlName="isHtmlTemplate">\n <mat-hint translate>tb.mail-body-type.after-template-evaluation-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.body-template</mat-label>\n <textarea required\n matInput\n formControlName="bodyTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'bodyTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.body-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n </div>\n</section>\n',styles:[":host .input-bottom-double-hint{display:inline-flex}:host .input-bottom-double-hint .see-example{flex-shrink:0;padding-right:16px}:host textarea.tb-enable-vertical-resize{resize:vertical}\n"],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.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","hintMode"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Vr,selector:"textarea[cdkTextareaAutosize]",inputs:["cdkAutosizeMinRows","cdkAutosizeMaxRows","cdkTextareaAutosize","placeholder"],exportAs:["cdkTextareaAutosize"]},{kind:"component",type:ne.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:ne.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:re.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Re.MatListItemTitle,selector:"[matListItemTitle]"},{kind:"directive",type:Re.MatListItemMeta,selector:"[matListItemMeta]"},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'<section [formGroup]="toEmailConfigForm" class="tb-form-panel no-border no-padding">\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.email-sender</div>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex" subscriptSizing="dynamic">\n <mat-label translate>tb.rulenode.from-template</mat-label>\n <input required matInput formControlName="fromTemplate">\n <mat-hint align="start">\n {{ \'tb.rulenode.email-from-template-hint\' | translate }}\n </mat-hint>\n <mat-hint align="end">\n <div class="input-bottom-double-hint">\n <div class="see-example"\n hintMode\n tb-help-popup="{{\'rulenode/to_email_node_fields_templatization\'}}"\n tb-help-popup-placement="right"\n trigger-style="letter-spacing:0.25px; font-size:12px;"\n [tb-help-popup-style]="{maxWidth: \'820px\'}"\n trigger-text="{{ \'tb.key-val.see-examples\' | translate }}"></div>\n </div>\n </mat-hint>\n <mat-error *ngIf="toEmailConfigForm.get(\'fromTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.from-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel-title" translate>tb.rulenode.recipients</div>\n <tb-example-hint [hintText]="\'tb.rulenode.recipients-block-main-hint\' | translate"\n popupHelpLink="rulenode/to_email_node_fields_templatization">\n </tb-example-hint>\n </div>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.to-template</mat-label>\n <textarea required\n matInput\n class="tb-enable-vertical-resize"\n formControlName="toTemplate"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'toTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.to-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.cc-template</mat-label>\n <textarea matInput\n formControlName="ccTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label translate>tb.rulenode.bcc-template</mat-label>\n <textarea matInput\n formControlName="bccTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n </mat-form-field>\n </div>\n </div>\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.message-subject-and-content</div>\n <tb-example-hint [hintText]="\'tb.rulenode.kv-map-pattern-hint\' | translate"\n popupHelpLink="rulenode/to_email_node_fields_templatization">\n </tb-example-hint>\n <section>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.subject-template</mat-label>\n <textarea required\n matInput\n formControlName="subjectTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="1"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'subjectTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.subject-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.mail-body-type</mat-label>\n <mat-select formControlName="mailBodyType">\n <mat-select-trigger>\n <span *ngIf="toEmailConfigForm.get(\'mailBodyType\').value">\n {{ getBodyTypeName() | translate }}\n </span>\n </mat-select-trigger>\n <mat-option *ngFor="let type of mailBodyTypes" [value]="type.value">\n <span matListItemTitle>\n {{ type.name | translate }}\n </span>\n <br>\n <small matListItemMeta style="color: inherit">\n {{ type.description | translate }}\n </small>\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" *ngIf="toEmailConfigForm.get(\'mailBodyType\').value === \'dynamic\'">\n <mat-label translate>tb.rulenode.body-type-template</mat-label>\n <input required matInput formControlName="isHtmlTemplate">\n <mat-hint translate>tb.mail-body-type.after-template-evaluation-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.body-template</mat-label>\n <textarea required\n matInput\n formControlName="bodyTemplate"\n class="tb-enable-vertical-resize"\n cdkTextareaAutosize\n cdkAutosizeMinRows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'bodyTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.body-template-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n </div>\n</section>\n',styles:[":host .input-bottom-double-hint{display:inline-flex}:host .input-bottom-double-hint .see-example{flex-shrink:0;padding-right:16px}:host textarea.tb-enable-vertical-resize{resize:vertical}\n"]}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class Or extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.copyFrom=[],this.translation=mn;for(const e of this.translation.keys())this.copyFrom.push({value:e,name:this.translate.instant(this.translation.get(e))})}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({copyFrom:[e.copyFrom,[_.required]],keys:[e?e.keys:null,[_.required]]})}configForm(){return this.copyKeysConfigForm}prepareInputConfig(e){let t;return t=ye(e?.fromMetadata)?e.copyFrom?sn.METADATA:sn.DATA:ye(e?.copyFrom)?e.copyFrom:sn.DATA,{keys:ye(e?.keys)?e.keys:null,copyFrom:t}}}e("CopyKeysConfigComponent",Or),Or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Or,deps:[{token:R.Store},{token:O.FormBuilder},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Or,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="copyKeysConfigForm" class="tb-form-panel no-padding no-border">\n <tb-msg-metadata-chip\n [labelText]="(\'tb.key-val.copy-key-values-from\' | translate)"\n [translation]="translation"\n formControlName="copyFrom">\n </tb-msg-metadata-chip>\n <tb-string-items-list class="mat-block"\n required\n [label]="\'tb.rulenode.keys\' | translate"\n [placeholder]="\'tb.rulenode.add-key\' | translate"\n [requiredText]="\'tb.key-val.at-least-one-key-error\' | translate"\n formControlName="keys">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.use-regular-expression-hint\' | translate }}">\n help\n </mat-icon>\n </tb-string-items-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:tt.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Or,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'<section [formGroup]="copyKeysConfigForm" class="tb-form-panel no-padding no-border">\n <tb-msg-metadata-chip\n [labelText]="(\'tb.key-val.copy-key-values-from\' | translate)"\n [translation]="translation"\n formControlName="copyFrom">\n </tb-msg-metadata-chip>\n <tb-string-items-list class="mat-block"\n required\n [label]="\'tb.rulenode.keys\' | translate"\n [placeholder]="\'tb.rulenode.add-key\' | translate"\n [requiredText]="\'tb.key-val.at-least-one-key-error\' | translate"\n formControlName="keys">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.use-regular-expression-hint\' | translate }}">\n help\n </mat-icon>\n </tb-string-items-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder},{type:X.TranslateService}]}});class _r extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.renameIn=[],this.translation=dn;for(const e of this.translation.keys())this.renameIn.push({value:e,name:this.translate.instant(this.translation.get(e))})}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({renameIn:[e?e.renameIn:null,[_.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[_.required]]})}prepareInputConfig(e){let t;return t=ye(e?.fromMetadata)?e.fromMetadata?sn.METADATA:sn.DATA:ye(e?.renameIn)?e?.renameIn:sn.DATA,{renameKeysMapping:ye(e?.renameKeysMapping)?e.renameKeysMapping:null,renameIn:t}}}e("RenameKeysConfigComponent",_r),_r.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:_r,deps:[{token:R.Store},{token:O.FormBuilder},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),_r.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:_r,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="renameKeysConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.rename-keys-in</div>\n <div class="fx-centered">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="renameIn" appearance="fill">\n <tb-toggle-option *ngFor="let data of renameIn" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n labelText="{{ translation.get(renameKeysConfigForm.get(\'renameIn\').value) | translate }} {{\'tb.rulenode.keys-mapping\' | translate}}"\n formControlName="renameKeysMapping"\n uniqueKeyValuePairValidator\n requiredText="{{\'tb.rulenode.attr-mapping-required\' | translate}}"\n keyText="{{\'tb.rulenode.current-key-name\' | translate}}"\n keyRequiredText="{{\'tb.rulenode.key-name-required\' | translate}}"\n valText="{{\'tb.rulenode.new-key-name\' | translate}}"\n valRequiredText="{{\'tb.rulenode.new-key-name-required\' | translate}}">\n </tb-kv-map-config>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}:host .fx-centered{display:flex;width:100%;justify-content:space-around}\n"],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Me.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Ee.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination","fillHeight","extraPadding","primaryBackground"]},{kind:"component",type:Rn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:_r,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'<section [formGroup]="renameKeysConfigForm" class="tb-form-panel stroked">\n <div class="tb-form-panel-title" translate>tb.rulenode.rename-keys-in</div>\n <div class="fx-centered">\n <div class="fetch-to-data-toggle">\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="renameIn" appearance="fill">\n <tb-toggle-option *ngFor="let data of renameIn" [value]="data.value">\n {{ data.name }}\n </tb-toggle-option>\n </tb-toggle-select>\n </div>\n </div>\n <tb-kv-map-config\n required\n labelText="{{ translation.get(renameKeysConfigForm.get(\'renameIn\').value) | translate }} {{\'tb.rulenode.keys-mapping\' | translate}}"\n formControlName="renameKeysMapping"\n uniqueKeyValuePairValidator\n requiredText="{{\'tb.rulenode.attr-mapping-required\' | translate}}"\n keyText="{{\'tb.rulenode.current-key-name\' | translate}}"\n keyRequiredText="{{\'tb.rulenode.key-name-required\' | translate}}"\n valText="{{\'tb.rulenode.new-key-name\' | translate}}"\n valRequiredText="{{\'tb.rulenode.new-key-name-required\' | translate}}">\n </tb-kv-map-config>\n</section>\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}:host .fx-centered{display:flex;width:100%;justify-content:space-around}\n"]}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder},{type:X.TranslateService}]}});class Br extends g{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,[_.required]]})}}e("NodeJsonPathConfigComponent",Br),Br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Br,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Br,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"<section [formGroup]=\"jsonPathConfigForm\">\n <mat-form-field subscriptSizing=\"dynamic\" class=\"mat-block\">\n <mat-label>{{ 'tb.rulenode.json-path-expression' | translate }}</mat-label>\n <input matInput formControlName=\"jsonPath\" required/>\n <mat-hint>{{ 'tb.rulenode.json-path-expression-hint' | translate }}</mat-hint>\n <mat-error *ngIf=\"jsonPathConfigForm.get('jsonPath').hasError('required')\">{{ 'tb.rulenode.json-path-expression-required' | translate }}</mat-error>\n </mat-form-field>\n</section>\n",dependencies:[{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Br,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"<section [formGroup]=\"jsonPathConfigForm\">\n <mat-form-field subscriptSizing=\"dynamic\" class=\"mat-block\">\n <mat-label>{{ 'tb.rulenode.json-path-expression' | translate }}</mat-label>\n <input matInput formControlName=\"jsonPath\" required/>\n <mat-hint>{{ 'tb.rulenode.json-path-expression-hint' | translate }}</mat-hint>\n <mat-error *ngIf=\"jsonPathConfigForm.get('jsonPath').hasError('required')\">{{ 'tb.rulenode.json-path-expression-required' | translate }}</mat-error>\n </mat-form-field>\n</section>\n"}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class Kr extends g{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.deleteFrom=[],this.translation=pn;for(const e of this.translation.keys())this.deleteFrom.push({value:e,name:this.translate.instant(this.translation.get(e))})}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({deleteFrom:[e.deleteFrom,[_.required]],keys:[e?e.keys:null,[_.required]]})}prepareInputConfig(e){let t;return t=ye(e?.fromMetadata)?e.fromMetadata?sn.METADATA:sn.DATA:ye(e?.deleteFrom)?e?.deleteFrom:sn.DATA,{keys:ye(e?.keys)?e.keys:null,deleteFrom:t}}configForm(){return this.deleteKeysConfigForm}}e("DeleteKeysConfigComponent",Kr),Kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Kr,deps:[{token:R.Store},{token:O.FormBuilder},{token:X.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Kr,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deleteKeysConfigForm" class="tb-form-panel no-border no-padding">\n <tb-msg-metadata-chip\n [labelText]="(\'tb.key-val.delete-key-values-from\' | translate)"\n formControlName="deleteFrom">\n </tb-msg-metadata-chip>\n <tb-string-items-list class="mat-block"\n required\n [label]="\'tb.rulenode.keys\' | translate"\n [placeholder]="\'tb.rulenode.add-key\' | translate"\n [requiredText]="\'tb.key-val.at-least-one-key-error\' | translate"\n formControlName="keys">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.use-regular-expression-delete-hint\' | translate }}">\n help\n </mat-icon>\n </tb-string-items-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"component",type:tt.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:zn,selector:"tb-msg-metadata-chip",inputs:["labelText","translation"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Kr,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'<section [formGroup]="deleteKeysConfigForm" class="tb-form-panel no-border no-padding">\n <tb-msg-metadata-chip\n [labelText]="(\'tb.key-val.delete-key-values-from\' | translate)"\n formControlName="deleteFrom">\n </tb-msg-metadata-chip>\n <tb-string-items-list class="mat-block"\n required\n [label]="\'tb.rulenode.keys\' | translate"\n [placeholder]="\'tb.rulenode.add-key\' | translate"\n [requiredText]="\'tb.key-val.at-least-one-key-error\' | translate"\n formControlName="keys">\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.use-regular-expression-delete-hint\' | translate }}">\n help\n </mat-icon>\n </tb-string-items-list>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder},{type:X.TranslateService}]}});class Hr extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.deduplicationStrategie=_t,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=Bt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[ye(e?.interval)?e.interval:null,[_.required,_.min(1)]],strategy:[ye(e?.strategy)?e.strategy:null,[_.required]],outMsgType:[ye(e?.outMsgType)?e.outMsgType:null,[_.required]],maxPendingMsgs:[ye(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[_.required,_.min(1),_.max(1e3)]],maxRetries:[ye(e?.maxRetries)?e.maxRetries:null,[_.required,_.min(0),_.max(100)]]})}prepareInputConfig(e){return e||(e={}),e.outMsgType||(e.outMsgType="POST_TELEMETRY_REQUEST"),super.prepareInputConfig(e)}updateValidators(e){this.deduplicationConfigForm.get("strategy").value===this.deduplicationStrategie.ALL?this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}):this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("outMsgType").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["strategy"]}}e("DeduplicationConfigComponent",Hr),Hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Hr,deps:[{token:R.Store},{token:O.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Hr,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="deduplicationConfigForm">\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.interval\' | translate}}</mat-label>\n <input type=\'number\' required matInput formControlName="interval">\n <mat-error *ngIf="deduplicationConfigForm.get(\'interval\').hasError(\'required\')">\n {{\'tb.rulenode.interval-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'interval\').hasError(\'min\')">\n {{\'tb.rulenode.interval-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.interval-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <div class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.strategy</div>\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="strategy" appearance="fill">\n <tb-toggle-option *ngFor="let strategy of deduplicationStrategies" [value]="strategy">\n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-all-hint\' | translate"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'ALL\'">\n </tb-example-hint>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-first-hint\' | translate"\n textAlign="\'center\'"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'FIRST\'">\n </tb-example-hint>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-last-hint\' | translate"\n textAlign="\'center\'"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'LAST\'">\n </tb-example-hint>\n <div *ngIf="deduplicationConfigForm.get(\'strategy\').value === deduplicationStrategie.ALL">\n <tb-output-message-type-autocomplete\n required\n formControlName="outMsgType">\n </tb-output-message-type-autocomplete>\n </div>\n </div>\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{\'tb.rulenode.max-pending-msgs\' | translate}}</mat-label>\n <input type = \'number\' required matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{\'tb.rulenode.max-pending-msgs-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{\'tb.rulenode.max-pending-msgs-max-error\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{\'tb.rulenode.max-pending-msgs-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.max-pending-msgs-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{\'tb.rulenode.max-retries\' | translate}}</mat-label>\n <input type = \'number\' required matInput formControlName="maxRetries">\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'required\')">\n {{\'tb.rulenode.max-retries-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'max\')">\n {{\'tb.rulenode.max-retries-max-error\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'min\')">\n {{\'tb.rulenode.max-retries-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.max-retries-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n </div>\n </mat-expansion-panel>\n </section>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n'],dependencies:[{kind:"directive",type:j.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:j.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:Q.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:Y.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:Y.MatLabel,selector:"mat-label"},{kind:"directive",type:Y.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Y.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:oe.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ae.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:ae.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:ae.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:O.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:O.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:X.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Me.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Ee.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination","fillHeight","extraPadding","primaryBackground"]},{kind:"component",type:Hn,selector:"tb-output-message-type-autocomplete",inputs:["subscriptSizing","disabled","required"]},{kind:"component",type:ht,selector:"tb-example-hint",inputs:["hintText","popupHelpLink","textAlign"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Hr,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:'<section [formGroup]="deduplicationConfigForm">\n <mat-form-field class="mat-block">\n <mat-label>{{\'tb.rulenode.interval\' | translate}}</mat-label>\n <input type=\'number\' required matInput formControlName="interval">\n <mat-error *ngIf="deduplicationConfigForm.get(\'interval\').hasError(\'required\')">\n {{\'tb.rulenode.interval-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'interval\').hasError(\'min\')">\n {{\'tb.rulenode.interval-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.interval-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <div class="tb-form-panel no-padding no-border">\n <div class="tb-form-panel stroked">\n <div class="tb-form-panel-title tb-required" translate>tb.rulenode.strategy</div>\n <tb-toggle-select class="fetch-to-data-toggle" formControlName="strategy" appearance="fill">\n <tb-toggle-option *ngFor="let strategy of deduplicationStrategies" [value]="strategy">\n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n </tb-toggle-option>\n </tb-toggle-select>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-all-hint\' | translate"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'ALL\'">\n </tb-example-hint>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-first-hint\' | translate"\n textAlign="\'center\'"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'FIRST\'">\n </tb-example-hint>\n <tb-example-hint [hintText]="\'tb.rulenode.strategy-last-hint\' | translate"\n textAlign="\'center\'"\n *ngIf="deduplicationConfigForm.get(\'strategy\').value === \'LAST\'">\n </tb-example-hint>\n <div *ngIf="deduplicationConfigForm.get(\'strategy\').value === deduplicationStrategie.ALL">\n <tb-output-message-type-autocomplete\n required\n formControlName="outMsgType">\n </tb-output-message-type-autocomplete>\n </div>\n </div>\n <section class="tb-form-panel stroked">\n <mat-expansion-panel class="tb-settings">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.advanced-settings</mat-panel-title>\n </mat-expansion-panel-header>\n <div class="tb-form-row no-border no-padding tb-standard-fields">\n <mat-form-field class="flex">\n <mat-label>{{\'tb.rulenode.max-pending-msgs\' | translate}}</mat-label>\n <input type = \'number\' required matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{\'tb.rulenode.max-pending-msgs-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{\'tb.rulenode.max-pending-msgs-max-error\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{\'tb.rulenode.max-pending-msgs-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.max-pending-msgs-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n <mat-form-field class="flex">\n <mat-label>{{\'tb.rulenode.max-retries\' | translate}}</mat-label>\n <input type = \'number\' required matInput formControlName="maxRetries">\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'required\')">\n {{\'tb.rulenode.max-retries-required\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'max\')">\n {{\'tb.rulenode.max-retries-max-error\' | translate}}\n </mat-error>\n <mat-error *ngIf="deduplicationConfigForm.get(\'maxRetries\').hasError(\'min\')">\n {{\'tb.rulenode.max-retries-min-error\' | translate}}\n </mat-error>\n <mat-icon matSuffix class="help-icon margin-8 cursor-pointer" aria-hidden="false" aria-label="help-icon"\n color="primary"\n matTooltip="{{ \'tb.rulenode.max-retries-hint\' | translate }}">help</mat-icon>\n </mat-form-field>\n </div>\n </mat-expansion-panel>\n </section>\n </div>\n</section>\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*";font-size:16px;color:#000000de}:host .help-icon{color:#000;opacity:.38;padding:unset}:host .help-icon:hover{color:#305680;opacity:unset}.same-width-component-row{display:flex;flex-wrap:nowrap;gap:16px}@media screen and (max-width: 599px){.same-width-component-row{gap:8px}}.same-width-component-row>*{flex:1}\n']}]}],ctorParameters:function(){return[{type:R.Store},{type:O.FormBuilder}]}});class zr{}e("RulenodeCoreConfigTransformModule",zr),zr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:zr,declarations:[Mr,Er,Rr,Or,_r,Br,Kr,Hr],imports:[J,E,Qn],exports:[Mr,Er,Rr,Or,_r,Br,Kr,Hr]}),zr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zr,imports:[J,E,Qn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:zr,decorators:[{type:d,args:[{declarations:[Mr,Er,Rr,Or,_r,Br,Kr,Hr],imports:[J,E,Qn],exports:[Mr,Er,Rr,Or,_r,Br,Kr,Hr]}]}]});class Ur extends g{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=C}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({forwardMsgToDefaultRuleChain:[!!e&&e?.forwardMsgToDefaultRuleChain,[]],ruleChainId:[e?e.ruleChainId:null,[_.required]]})}}e("RuleChainInputComponent",Ur),Ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ur,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:Ur,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="ruleChainInputConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.forward-msg-default-rule-chain-tooltip\' | translate }}"\n class="tb-form-row no-border">\n <mat-slide-toggle class="mat-slide" formControlName="forwardMsgToDefaultRuleChain">\n {{ \'tb.rulenode.forward-msg-default-rule-chain\' | translate }}\n </mat-slide-toggle>\n </div>\n <tb-entity-autocomplete required\n [excludeEntityIds]="[ruleChainId]"\n [entityType]="entityType.RULE_CHAIN"\n [entitySubtype]="ruleChainType"\n formControlName="ruleChainId">\n </tb-entity-autocomplete>\n </div>\n</section>\n',dependencies:[{kind:"component",type:st.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:W.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:O.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:O.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:de.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Ur,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'<section [formGroup]="ruleChainInputConfigForm" fxLayout="column">\n <div class="tb-form-panel no-padding no-border">\n <div tb-hint-tooltip-icon="{{ \'tb.rulenode.forward-msg-default-rule-chain-tooltip\' | translate }}"\n class="tb-form-row no-border">\n <mat-slide-toggle class="mat-slide" formControlName="forwardMsgToDefaultRuleChain">\n {{ \'tb.rulenode.forward-msg-default-rule-chain\' | translate }}\n </mat-slide-toggle>\n </div>\n <tb-entity-autocomplete required\n [excludeEntityIds]="[ruleChainId]"\n [entityType]="entityType.RULE_CHAIN"\n [entitySubtype]="ruleChainType"\n formControlName="ruleChainId">\n </tb-entity-autocomplete>\n </div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class jr extends g{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",jr),jr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:jr,deps:[{token:R.Store},{token:O.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.10",type:jr,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'<section [formGroup]="ruleChainOutputConfigForm" fxLayout="column">\n <div innerHTML="{{ \'tb.rulenode.output-node-name-hint\' | translate }}"></div>\n</section>\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:O.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:O.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:X.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:jr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'<section [formGroup]="ruleChainOutputConfigForm" fxLayout="column">\n <div innerHTML="{{ \'tb.rulenode.output-node-name-hint\' | translate }}"></div>\n</section>\n'}]}],ctorParameters:function(){return[{type:R.Store},{type:O.UntypedFormBuilder}]}});class $r{}e("RuleNodeCoreConfigFlowModule",$r),$r.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$r,deps:[],target:t.ɵɵFactoryTarget.NgModule}),$r.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:$r,declarations:[Ur,jr],imports:[J,E,Qn],exports:[Ur,jr]}),$r.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$r,imports:[J,E,Qn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:$r,decorators:[{type:d,args:[{declarations:[Ur,jr],imports:[J,E,Qn],exports:[Ur,jr]}]}]});class Jr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{id:"Id","additional-info":"Additional Info","advanced-settings":"Advanced settings","create-entity-if-not-exists":"Create new entity if it doesn't exist","create-entity-if-not-exists-hint":"If enabled, a new entity with specified parameters will be created unless it already exists. Existing entities will be used as is for relation.","select-device-connectivity-event":"Select device connectivity event","entity-name-pattern":"Name pattern","device-name-pattern":"Device name","asset-name-pattern":"Asset name","entity-view-name-pattern":"Entity view name","customer-title-pattern":"Customer title","dashboard-name-pattern":"Dashboard title","user-name-pattern":"User email","edge-name-pattern":"Edge name","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","copy-message-type":"Copy message type","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","message-type-value":"Message type value","message-type-value-required":"Message type value is required","message-type-value-max-length":"Message type value should be less than 256","output-message-type":"Output message type","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 title","customer-name-pattern-required":"Customer title is required","customer-name-pattern-hint":"Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","create-customer-if-not-exists":"Create new customer if it doesn't exist","unassign-from-customer":"Unassign from specific customer if originator is dashboard","unassign-from-customer-tooltip":"Only dashboards can be assigned to multiple customers at once. \nIf the message originator is a dashboard, you need to explicitly specify the customer's title to unassign from.","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":"Allowing range from 1 to 2147483647.","start-interval-value-required":"Interval start is required.","end-interval-value-required":"Interval end is required.",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","add-message-type":"Add message type","select-message-types-required":"At least one message type should be selected.","select-message-types":"Select message types","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","attributes-scope":"Attributes scope","attributes-scope-value":"Attributes scope value","attributes-scope-value-copy":"Copy attributes scope value","attributes-scope-hint":"Use the 'scope' metadata key to dynamically set the attribute scope per message. If provided, this overrides the scope set in the configuration.","notify-device":"Force notification to the 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.","update-attributes-only-on-value-change":"Save attributes only if the value changes","update-attributes-only-on-value-change-hint":"Updates the attributes on every incoming message disregarding if their value has changed. Increases API usage and reduces performance.","update-attributes-only-on-value-change-hint-enabled":"Updates the attributes only if their value has changed. If the value is not changed, no update to the attribute timestamp nor attribute change notification will be sent.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-on-update-hint":"If enabled, force notification to the device about shared attributes update. If disabled, the notification behavior is controlled by the 'notifyDevice' parameter from the incoming message metadata. To turn off the notification, the message metadata must contain the 'notifyDevice' parameter set to 'false'. Any other case will trigger the notification to the device.","notify-device-on-delete-hint":"If enabled, force notification to the device about shared attributes removal. If disabled, the notification behavior is controlled by the 'notifyDevice' parameter from the incoming message metadata. To turn on the notification, the message metadata must contain the 'notifyDevice' parameter set to 'true'. In any other case, the notification will not be triggered to the device.","latest-timeseries":"Latest time series data keys","timeseries-keys":"Time series keys","timeseries-keys-required":"At least one time series key should be selected.","add-timeseries-key":"Add time series key","add-message-field":"Add message field","relation-search-parameters":"Relation search parameters","relation-parameters":"Relation parameters","add-metadata-field":"Add metadata field","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":"Use regular expression to copy keys by pattern.\n\nTips & tricks:\nPress 'Enter' to complete field name input.\nPress 'Backspace' to delete field name. Multiple field names supported.",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","current-key-name":"Current 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":"Value 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.\n\nTips & tricks:\nPress 'Enter' to complete field name input.\nPress 'Backspace' to delete field name.\nMultiple field names supported.","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","relations-query-config-direction-suffix":"originator","profile-name":"Profile name","fetch-circle-parameter-info-from-metadata-hint":'Metadata field \'{{perimeterKeyName}}\' should be defined in next format: {"latitude":48.196, "longitude":24.6532, "radius":100.0, "radiusUnit":"METER"}',"fetch-poligon-parameter-info-from-metadata-hint":"Metadata field '{{perimeterKeyName}}' should be defined in next format: [[48.19736,24.65235],[48.19800,24.65060],...,[48.19849,24.65420]]","short-templatization-tooltip":"Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","fields-mapping-required":"At least one field mapping should be specified.","at-least-one-field-required":"At least one input field must have a value(s) provided.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","new-originator":"New originator","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related entity","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity by name pattern","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","default-ttl-hint":"Rule node will fetch Time-to-Live (TTL) value from the message metadata. If no value is present, it defaults to the TTL specified in the configuration. If the value is set to 0, the TTL from the tenant profile configuration will be applied.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","generation-parameters":"Generation parameters","message-count":"Generated messages limit (0 - unlimited)","message-count-required":"Generated messages limit is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Generation frequency in seconds","period-seconds-required":"Period is required.","script-lang-tbel":"TBEL","script-lang-js":"JS","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","current-rule-node":"Current Rule Node","generator-function":"Generator function","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","select-entity-types":"Select entity types","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","from-template-required":"From is required","message-to-metadata":"Message to metadata","metadata-to-message":"Metadata to message","from-message":"From message","from-metadata":"From metadata","to-template":"To","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> for value from message body',"cc-template":"Cc","bcc-template":"Bcc","subject-template":"Subject","subject-template-required":"Subject Template is required","body-template":"Body","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","body-type-template":"Body type template","reply-routing-configuration":"Reply Routing Configuration","rpc-reply-routing-configuration-hint":"These configuration parameters specify the metadata key names used to identify the service, session, and request for sending a reply back.","reply-routing-configuration-hint":"These configuration parameters specify the metadata key names used to identify the service and request for sending a reply back.","request-id-metadata-attribute":"Request Id","service-id-metadata-attribute":"Service Id","session-id-metadata-attribute":"Session Id","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","parse-to-plain-text":"Parse to plain text","parse-to-plain-text-hint":'If selected, request body message payload will be transformed from JSON string to plain text, e.g. msg = "Hello,\\t\\"world\\"" will be parsed to Hello, "world"',"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","max-response-size":"Max response size (in KB)","max-response-size-hint":"The maximum amount of memory allocated for buffering data when decoding or encoding HTTP messages, such as JSON or XML payloads",headers:"Headers","headers-hint":'Use <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> 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":"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 <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> 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":'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":'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 and ${metadataKey} to extract value from the 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-to-specific-entity-tooltip":"If enabled, checks the presence of relation with a specific entity otherwise, checks the presence of relation with any entity. In both cases, relation lookup is based on configured direction and type.","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-with-specific-entity":"Delete relation with specific entity","delete-relation-with-specific-entity-hint":"If enabled, will delete the relation with just one specific entity. Otherwise, the relation will be removed with all matching entities.","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 <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> 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 time series key prefix","output-timeseries-key-prefix-required":"Output time series key prefix required.","separator-hint":'Press "Enter" to complete field input.',"select-details":"Select 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","email-sender":"Email sender","fields-to-check":"Fields to check","add-detail":"Add detail","check-all-keys-tooltip":"If enabled, checks the presence of all fields listed in the message and metadata field names within the incoming message and its metadata.","fields-to-check-hint":'Press "Enter" to complete field name input. Multiple field names supported.',"entity-details-list-empty":"At least one detail should be selected.","alarm-status":"Alarm status","alarm-required":"At least one alarm status should be 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-field-name":"Latitude field name","longitude-field-name":"Longitude field name","latitude-field-name-required":"Latitude field name is required.","longitude-field-name-required":"Longitude field name is required.","fetch-perimeter-info-from-metadata":"Fetch perimeter information from metadata","fetch-perimeter-info-from-metadata-tooltip":"If perimeter type is set to 'Polygon' the value of metadata field '{{perimeterKeyName}}' will be set as perimeter definition without additional parsing of the value. Otherwise, if perimeter type is set to 'Circle' the value of '{{perimeterKeyName}}' metadata field will be parsed to extract 'latitude', 'longitude', 'radius', 'radiusUnit' fields that uses for circle perimeter definition.","perimeter-key-name":"Perimeter key name","perimeter-key-name-hint":"Metadata field name that includes perimeter information.","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-units-required":"Range units is required.",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"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": "&#123;"ts":1574329385897, "value":42&#125;"',"ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","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.","device-profile-node-hint":"Useful if you have duration or repeating conditions to ensure continuity of alarm state evaluation.","persist-alarm-rules":"Persist state of alarm rules","persist-alarm-rules-hint":"If enabled, the rule node will store the state of processing to the database.","fetch-alarm-rules":"Fetch state of alarm rules","fetch-alarm-rules-hint":"If enabled, the rule node will restore the state of processing on initialization and ensure that alarms are raised even after server restarts. Otherwise, the state will be restored when the first message from the device arrives.","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-caching":"Use caching","use-caching-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":'Use <code><span style="color: #000;">$&#123;</span>metadataKey<span style="color: #000;">&#125;</span></code> for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The <b>rule node name</b> corresponds to the <b>relation type</b> 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","skip-latest-persistence-hint":"Rule node will not update values for incoming keys for the latest time series data. Useful for highly loaded use-cases to decrease the pressure on the DB.","use-server-ts":"Use server ts","use-server-ts-hint":"Rule node will use the timestamp of 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 and ${metadataKey} to extract value from the metadata.","kv-map-single-pattern-hint":"Input field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the 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","message-metadata-type":"Metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-source-field-input":"Source","argument-source-field-input-required":"Argument source 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","add-entity-type":"Add entity type","add-device-profile":"Add device profile","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Use <i>0</i> to convert result to integer","add-to-message-field-input":"Add to message","add-to-metadata-field-input":"Add to metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Specify a mathematical expression to evaluate. Default expression demonstrates how to transform Fahrenheit to Celsius","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-types":"Clear selected types","clear-selected-details":"Clear selected details","clear-selected-fields":"Clear selected fields","clear-selected-keys":"Clear selected keys","geofence-configuration":"Geofence configuration","coordinate-field-names":"Coordinate field names","coordinate-field-hint":"Rule node tries to retrieve the specified fields from the message. If they are not present, it will look them up in the metadata.","presence-monitoring-strategy":"Presence monitoring strategy","presence-monitoring-strategy-on-first-message":"On first message","presence-monitoring-strategy-on-each-message":"On each message","presence-monitoring-strategy-on-first-message-hint":"Reports presence status 'Inside' or 'Outside' on the first message after the configured minimal duration has passed since previous presence status 'Entered' or 'Left' update.","presence-monitoring-strategy-on-each-message-hint":"Reports presence status 'Inside' or 'Outside' on each message after presence status 'Entered' or 'Left' update.","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 metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell failure if any of the attributes are missing","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time","chip-help":"Press 'Enter' to complete {{inputName}} input. \nPress 'Backspace' to delete {{inputName}}. \nMultiple values supported.",detail:"detail","field-name":"field name","device-profile":"device profile","entity-type":"entity type","message-type":"message type","timeseries-key":"time series key",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 metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch time series from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch time series 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 metadata 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","map-fields-required":"All mapping fields are required.",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","keys-mapping":"keys mapping","add-key":"Add key",recipients:"Recipients","message-subject-and-content":"Message subject and content","template-rules-hint":"Both input fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the message metadata.","originator-customer-desc":"Use customer of incoming message originator as new originator.","originator-tenant-desc":"Use current tenant as new originator.","originator-related-entity-desc":"Use related entity as new originator. Lookup based on configured relation type and direction.","originator-alarm-originator-desc":"Use alarm originator as new originator. Only if incoming message originator is alarm entity.","originator-entity-by-name-pattern-desc":"Use entity fetched from DB as new originator. Lookup based on entity type and specified name pattern.","email-from-template-hint":"Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","recipients-block-main-hint":"Comma-separated address list. All input fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","forward-msg-default-rule-chain":"Forward message to the originator's default rule chain","forward-msg-default-rule-chain-tooltip":"If enabled, message will be forwarded to the originator's default rule chain, or rule chain from configuration, if originator has no default rule chain defined in the entity profile.","exclude-zero-deltas":"Exclude zero deltas from outbound message","exclude-zero-deltas-hint":'If enabled, the "{{outputValueKey}}" output key will be added to the outbound message if its value is not zero.',"exclude-zero-deltas-time-difference-hint":'If enabled, the "{{outputValueKey}}" and "{{periodValueKey}}" output keys will be added to the outbound message only if the "{{outputValueKey}}" value is not zero.',"search-direction-from":"From originator to target entity","search-direction-to":"From target entity to originator","del-relation-direction-from":"From originator","del-relation-direction-to":"To originator","target-entity":"Target entity","function-configuration":"Function configuration","function-name":"Function name","function-name-required":"Function name is required.",qualifier:"Qualifier","qualifier-hint":'If the qualifier is not specified, the default qualifier "$LATEST" will be used.',"aws-credentials":"AWS Credentials","connection-timeout":"Connection timeout","connection-timeout-required":"Connection timeout is required.","connection-timeout-min":"Min connection timeout is 0.","connection-timeout-hint":"The amount of time to wait in seconds when initially establishing a connection before giving up and timing out. A value of 0 means infinity, and is not recommended.","request-timeout":"Request timeout","request-timeout-required":"Request timeout is required","request-timeout-min":"Min request timeout is 0","request-timeout-hint":"The amount of time to wait in seconds for the request to complete before giving up and timing out. A value of 0 means infinity, and is not recommended.","tell-failure-aws-lambda":"Tell Failure if AWS Lambda function execution raises exception","tell-failure-aws-lambda-hint":"Rule node forces failure of message processing if AWS Lambda function execution raises exception."},"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","add-entry":"Add entry","copy-key-values-from":"Copy key-values from","delete-key-values":"Delete key-values","delete-key-values-from":"Delete key-values from","at-least-one-key-error":"At least one key should be selected.","unique-key-value-pair-error":"'{{keyText}}' must be different from the '{{valText}}'!"},"mail-body-type":{"plain-text":"Plain text",html:"HTML",dynamic:"Dynamic","use-body-type-template":"Use body type template","plain-text-description":"Simple, unformatted text with no special styling or formating.","html-text-description":"Allows you to use HTML tags for formatting, links and images in your mai body.","dynamic-text-description":"Allows to use Plain Text or HTML body type dynamically based on templatization feature.","after-template-evaluation-hint":"After template evaluation value should be true for HTML, and false for Plain text."}}},!0)}(e)}}e("RuleNodeCoreConfigModule",Jr),Jr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Jr,deps:[{token:X.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),Jr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.10",ngImport:t,type:Jr,declarations:[ut],imports:[J,E],exports:[Yn,Ar,lr,Cr,zr,$r,ut]}),Jr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Jr,imports:[J,E,Yn,Ar,lr,Cr,zr,$r]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.10",ngImport:t,type:Jr,decorators:[{type:d,args:[{declarations:[ut],imports:[J,E],exports:[Yn,Ar,lr,Cr,zr,$r,ut]}]}],ctorParameters:function(){return[{type:X.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map diff --git a/ui-ngx/src/app/core/api/alias-controller.ts b/ui-ngx/src/app/core/api/alias-controller.ts index bf7399cf6d..83dd4e102f 100644 --- a/ui-ngx/src/app/core/api/alias-controller.ts +++ b/ui-ngx/src/app/core/api/alias-controller.ts @@ -68,10 +68,11 @@ export class AliasController implements IAliasController { private translate: TranslateService, private stateControllerHolder: StateControllerHolder, private origEntityAliases: EntityAliases, - private origFilters: Filters) { + private origFilters: Filters, + private origUserFilters?: Filters) { this.entityAliases = deepClone(this.origEntityAliases) || {}; this.filters = deepClone(this.origFilters) || {}; - this.userFilters = {}; + this.userFilters = deepClone(this.origUserFilters) || {}; } updateEntityAliases(newEntityAliases: EntityAliases) { @@ -166,6 +167,10 @@ export class AliasController implements IAliasController { return this.filters; } + getUserFilters(): Filters { + return this.userFilters; + } + getFilterInfo(filterId: string): FilterInfo { if (this.userFilters[filterId]) { return this.userFilters[filterId]; 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 71bfa32ee6..bca6a05644 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -137,6 +137,7 @@ export interface IAliasController { resolveAlarmSource(alarmSource: Datasource): Observable<Datasource>; getEntityAliases(): EntityAliases; getFilters(): Filters; + getUserFilters(): Filters; getFilterInfo(filterId: string): FilterInfo; getKeyFilters(filterId: string): Array<KeyFilter>; updateCurrentAliasEntity(aliasId: string, currentEntity: EntityInfo): void; diff --git a/ui-ngx/src/app/core/http/ota-package.service.ts b/ui-ngx/src/app/core/http/ota-package.service.ts index 9952dd4916..de062a94ee 100644 --- a/ui-ngx/src/app/core/http/ota-package.service.ts +++ b/ui-ngx/src/app/core/http/ota-package.service.ts @@ -59,7 +59,7 @@ export class OtaPackageService { } public getOtaPackage(otaPackageId: string, config?: RequestConfig): Observable<OtaPackage> { - return this.http.get<OtaPackage>(`/api/otaPackages/${otaPackageId}`, defaultHttpOptionsFromConfig(config)); + return this.http.get<OtaPackage>(`/api/otaPackage/${otaPackageId}`, defaultHttpOptionsFromConfig(config)); } public getOtaPackageInfo(otaPackageId: string, config?: RequestConfig): Observable<OtaPackageInfo> { diff --git a/ui-ngx/src/app/core/http/user.service.ts b/ui-ngx/src/app/core/http/user.service.ts index 1d5ce28998..695bae3cc1 100644 --- a/ui-ngx/src/app/core/http/user.service.ts +++ b/ui-ngx/src/app/core/http/user.service.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; -import { User, UserEmailInfo } from '@shared/models/user.model'; +import { ActivationLinkInfo, User, UserEmailInfo } from '@shared/models/user.model'; import { Observable } from 'rxjs'; import { HttpClient, HttpParams } from '@angular/common/http'; import { PageLink } from '@shared/models/page/page-link'; @@ -77,6 +77,10 @@ export class UserService { {...{responseType: 'text'}, ...defaultHttpOptionsFromConfig(config)}); } + public getActivationLinkInfo(userId: string, config?: RequestConfig): Observable<ActivationLinkInfo> { + return this.http.get<ActivationLinkInfo>(`/api/user/${userId}/activationLinkInfo`, defaultHttpOptionsFromConfig(config)); + } + public sendActivationEmail(email: string, config?: RequestConfig) { const encodeEmail = encodeURIComponent(email); return this.http.post(`/api/user/sendActivationMail?email=${encodeEmail}`, null, defaultHttpOptionsFromConfig(config)); 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 5c2363789d..b31c603814 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -31,7 +31,7 @@ import { DashboardLayoutsInfo, DashboardState, DashboardStateLayouts, - GridSettings, + GridSettings, LayoutType, WidgetLayout } from '@shared/models/dashboard.models'; import { deepClone, isDefined, isDefinedAndNotNull, isNotEmptyStr, isString, isUndefined } from '@core/utils'; @@ -406,6 +406,7 @@ export class DashboardUtilsService { private createDefaultGridSettings(): GridSettings { return { + layoutType: LayoutType.default, backgroundColor: '#eeeeee', columns: 24, margin: 10, @@ -491,12 +492,15 @@ export class DashboardUtilsService { if (!layout.gridSettings) { layout.gridSettings = this.createDefaultGridSettings(); } - if (layout.gridSettings.margins && layout.gridSettings.margins.length === 2) { - layout.gridSettings.margin = layout.gridSettings.margins[0]; - delete layout.gridSettings.margins; + if ((layout.gridSettings as any).margins && (layout.gridSettings as any).margins.length === 2) { + layout.gridSettings.margin = (layout.gridSettings as any).margins[0]; + delete (layout.gridSettings as any).margins; } layout.gridSettings.outerMargin = isDefined(layout.gridSettings.outerMargin) ? layout.gridSettings.outerMargin : true; layout.gridSettings.margin = isDefined(layout.gridSettings.margin) ? layout.gridSettings.margin : 10; + if (!layout.gridSettings.layoutType) { + layout.gridSettings.layoutType = LayoutType.default; + } } public setLayouts(dashboard: Dashboard, targetState: string, newLayouts: DashboardStateLayouts) { 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 8414e6ff0e..1c7150bac3 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 @@ -14,49 +14,17 @@ /// limitations under the License. /// -import { - Compiler, - Component, - Injectable, - Injector, - NgModule, - NgModuleRef, - OnDestroy, - Type, - ɵresetCompiledComponents -} from '@angular/core'; +import { Component, Injectable, Type, ɵComponentDef, ɵNG_COMP_DEF } from '@angular/core'; import { from, Observable, of } from 'rxjs'; import { CommonModule } from '@angular/common'; import { mergeMap } from 'rxjs/operators'; -@NgModule() -export abstract class DynamicComponentModule implements OnDestroy { - - // eslint-disable-next-line @angular-eslint/contextual-lifecycle - ngOnDestroy(): void { - } - -} - -interface DynamicComponentData<T> { - componentType: Type<T>; - componentModuleRef: NgModuleRef<DynamicComponentModule>; -} - -interface DynamicComponentModuleData { - moduleRef: NgModuleRef<DynamicComponentModule>; - moduleType: Type<DynamicComponentModule>; -} - @Injectable({ providedIn: 'root' }) export class DynamicComponentFactoryService { - private dynamicComponentModulesMap = new Map<Type<any>, DynamicComponentModuleData>(); - - constructor(private compiler: Compiler, - private injector: Injector) { + constructor() { } public createDynamicComponent<T>( @@ -64,66 +32,38 @@ export class DynamicComponentFactoryService { template: string, modules?: Type<any>[], preserveWhitespaces?: boolean, - compileAttempt = 1, - styles?: string[]): Observable<DynamicComponentData<T>> { + styles?: string[]): Observable<Type<T>> { return from(import('@angular/compiler')).pipe( mergeMap(() => { - const comp = this._createDynamicComponent(componentType, template, preserveWhitespaces, styles); - let moduleImports: Type<any>[] = [CommonModule]; + let componentImports: Type<any>[] = [CommonModule]; if (modules) { - moduleImports = [...moduleImports, ...modules]; - } - // noinspection AngularInvalidImportedOrDeclaredSymbol - const dynamicComponentInstanceModule = NgModule({ - declarations: [comp], - imports: moduleImports - })(class DynamicComponentInstanceModule extends DynamicComponentModule {}); - try { - const module = this.compiler.compileModuleSync(dynamicComponentInstanceModule); - let moduleRef: NgModuleRef<any>; - try { - moduleRef = module.create(this.injector); - } catch (e) { - this.compiler.clearCacheFor(module.moduleType); - throw e; - } - this.dynamicComponentModulesMap.set(comp, { - moduleRef, - moduleType: module.moduleType - }); - return of( { - componentType: comp, - componentModuleRef: moduleRef - }); - } catch (error) { - if (compileAttempt === 1) { - ɵresetCompiledComponents(); - return this.createDynamicComponent(componentType, template, modules, preserveWhitespaces, ++compileAttempt, styles); - } else { - console.error(error); - throw error; - } + componentImports = [...componentImports, ...modules]; } + const comp = this.createAndCompileDynamicComponent(componentType, template, componentImports, preserveWhitespaces, styles); + return of(comp.type); }) ); } - public destroyDynamicComponent<T>(componentType: Type<T>) { - const moduleData = this.dynamicComponentModulesMap.get(componentType); - if (moduleData) { - moduleData.moduleRef.destroy(); - this.compiler.clearCacheFor(moduleData.moduleType); - this.dynamicComponentModulesMap.delete(componentType); - } + public destroyDynamicComponent<T>(_componentType: Type<T>) { + } + + public getComponentDef<T>(componentType: Type<T>): ɵComponentDef<T> { + return componentType[ɵNG_COMP_DEF]; } - private _createDynamicComponent<T>(componentType: Type<T>, template: string, preserveWhitespaces?: boolean, styles?: string[]): Type<T> { + private createAndCompileDynamicComponent<T>(componentType: Type<T>, template: string, imports: Type<any>[], + preserveWhitespaces?: boolean, styles?: string[]): ɵComponentDef<T> { // noinspection AngularMissingOrInvalidDeclarationInModule - return Component({ + const comp = Component({ template, + imports, preserveWhitespaces, - styles + styles, + standalone: true })(componentType); + // Trigger component compilation + return comp[ɵNG_COMP_DEF]; } } diff --git a/ui-ngx/src/app/core/services/resources.service.ts b/ui-ngx/src/app/core/services/resources.service.ts index 449e950a65..013c3e5d72 100644 --- a/ui-ngx/src/app/core/services/resources.service.ts +++ b/ui-ngx/src/app/core/services/resources.service.ts @@ -21,7 +21,7 @@ import { Injectable, Injector, ModuleWithComponentFactories, - Type + Type, ɵNG_MOD_DEF } from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { forkJoin, Observable, ReplaySubject, throwError } from 'rxjs'; @@ -50,7 +50,6 @@ export class ResourcesService { private loadedJsonResources: { [url: string]: ReplaySubject<any> } = {}; private loadedResources: { [url: string]: ReplaySubject<void> } = {}; - private loadedModules: { [url: string]: ReplaySubject<Type<any>[]> } = {}; private loadedModulesAndFactories: { [url: string]: ReplaySubject<ModulesWithFactories> } = {}; private anchor = this.document.getElementsByTagName('head')[0] || this.document.getElementsByTagName('body')[0]; @@ -201,71 +200,6 @@ export class ResourcesService { ); } - public loadModules(resourceId: string | TbResourceId, modulesMap: IModulesMap): Observable<Type<any>[]> { - const url = this.getDownloadUrl(resourceId); - if (this.loadedModules[url]) { - return this.loadedModules[url].asObservable(); - } - modulesMap.init(); - const meta = this.getMetaInfo(resourceId); - const subject = new ReplaySubject<Type<any>[]>(); - this.loadedModules[url] = subject; - import('@angular/compiler').then( - () => { - System.import(url, undefined, meta).then( - (module) => { - try { - let modules; - try { - modules = this.extractNgModules(module); - } catch (e) { - console.error(e); - } - if (modules && modules.length) { - const tasks: Promise<ModuleWithComponentFactories<any>>[] = []; - for (const m of modules) { - tasks.push(this.compiler.compileModuleAndAllComponentsAsync(m)); - } - forkJoin(tasks).subscribe((compiled) => { - try { - for (const c of compiled) { - c.ngModuleFactory.create(this.injector); - } - this.loadedModules[url].next(modules); - this.loadedModules[url].complete(); - } catch (e) { - this.loadedModules[url].error(new Error(`Unable to init module from url: ${url}`)); - } - }, - (e) => { - this.loadedModules[url].error(new Error(`Unable to compile module from url: ${url}`)); - }); - } else { - this.loadedModules[url].error(new Error(`Module '${url}' doesn't have default export or not NgModule!`)); - } - } catch (e) { - this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); - } - }, - (e) => { - this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); - console.error(`Unable to load module from url: ${url}`, e); - } - ); - } - ); - return subject.asObservable().pipe( - tap({ - next: () => System.delete(url), - error: () => { - delete this.loadedModulesAndFactories[url]; - System.delete(url); - }, - complete: () => System.delete(url) - }) - ); - } - private extractNgModules(module: any, modules: Type<any>[] = []): Type<any>[] { try { let potentialModules = [module]; @@ -274,7 +208,7 @@ export class ResourcesService { while (potentialModules.length && currentScanDepth < 10) { const newPotentialModules = []; for (const potentialModule of potentialModules) { - if (potentialModule && ('ɵmod' in potentialModule)) { + if (potentialModule && (ɵNG_MOD_DEF in potentialModule)) { modules.push(potentialModule); } else { for (const k of Object.keys(potentialModule)) { @@ -349,7 +283,6 @@ export class ResourcesService { } private clearModulesCache() { - this.loadedModules = {}; this.loadedModulesAndFactories = {}; } } 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 0daabc7611..1919bee9b9 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 @@ -522,7 +522,8 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.translate, () => this.dashboardCtx.stateController, this.dashboardConfiguration.entityAliases, - this.dashboardConfiguration.filters); + this.dashboardConfiguration.filters, + this.parentDashboard?.aliasController.getUserFilters()); this.updateDashboardCss(); @@ -1168,8 +1169,6 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.filtersUpdated(); this.updateLayouts(); } - } else if (!this.widgetEditMode) { - this.dashboard.configuration.timewindow = this.dashboardCtx.dashboardTimewindow; } } } @@ -1216,6 +1215,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.setEditMode(false, false); } else { let reInitDashboard = false; + this.dashboard.configuration.timewindow = this.dashboardCtx.dashboardTimewindow; this.dashboardService.saveDashboard(this.dashboard).pipe( catchError((err) => { if (err.status === HttpStatusCode.Conflict) { diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html index 0a1733e851..5137f6128d 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html @@ -119,20 +119,15 @@ </div> <div class="tb-form-row space-between"> <div translate>dashboard.columns-count</div> - <mat-form-field *ngIf="!isScada()" - appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic"> + <mat-form-field *ngIf="!isScada()" appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic" + matTooltipPosition="above" + matTooltipClass="tb-error-tooltip" + [matTooltipDisabled]="!(gridSettingsFormGroup.get('columns').invalid && gridSettingsFormGroup.get('columns').touched)" + [matTooltip]="(gridSettingsFormGroup.get('columns').hasError('required') ? 'dashboard.columns-count-required' : + (gridSettingsFormGroup.get('columns').hasError('min') ? 'dashboard.min-columns-count-message' : 'dashboard.max-columns-count-message')) | translate"> <input matInput formControlName="columns" type="number" min="10" max="1008" step="1" required placeholder="{{ 'widget-config.set' | translate }}"> - <mat-icon matSuffix - matTooltipPosition="above" - matTooltipClass="tb-error-tooltip" - [matTooltip]="(gridSettingsFormGroup.get('columns').hasError('required') ? 'dashboard.columns-count-required' : - (gridSettingsFormGroup.get('columns').hasError('min') ? 'dashboard.min-columns-count-message' : 'dashboard.max-columns-count-message')) | translate" - *ngIf="gridSettingsFormGroup.get('columns').invalid && gridSettingsFormGroup.get('columns').touched" - class="tb-error"> - warning - </mat-icon> </mat-form-field> <mat-form-field *ngIf="isScada()" class="medium-width" appearance="outline" subscriptSizing="dynamic"> @@ -145,37 +140,29 @@ </div> <div class="tb-form-row space-between"> <div translate>dashboard.min-layout-width</div> - <mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic"> + <mat-form-field appearance="outline" class="number medium-width" subscriptSizing="dynamic" + matTooltipPosition="above" + matTooltipClass="tb-error-tooltip" + [matTooltipDisabled]="!(gridSettingsFormGroup.get('minColumns').invalid && gridSettingsFormGroup.get('minColumns').touched)" + [matTooltip]="(gridSettingsFormGroup.get('minColumns').hasError('required') ? 'dashboard.columns-count-required' : + (gridSettingsFormGroup.get('minColumns').hasError('min') ? 'dashboard.min-columns-count-message' : 'dashboard.max-columns-count-message')) | translate"> <input matInput formControlName="minColumns" type="number" min="10" max="1008" step="1" required placeholder="{{ 'widget-config.set' | translate }}"> - <mat-icon matSuffix - matTooltipPosition="above" - matTooltipClass="tb-error-tooltip" - [matTooltip]="(gridSettingsFormGroup.get('minColumns').hasError('required') ? 'dashboard.columns-count-required' : - (gridSettingsFormGroup.get('minColumns').hasError('min') ? 'dashboard.min-columns-count-message' : 'dashboard.max-columns-count-message')) | translate" - *ngIf="gridSettingsFormGroup.get('minColumns').invalid && gridSettingsFormGroup.get('minColumns').touched" - class="tb-error"> - warning - </mat-icon> <span translate matSuffix>dashboard.columns-suffix</span> </mat-form-field> </div> <div *ngIf="!isScada()" class="tb-form-row space-between"> <div translate>dashboard.widgets-margins</div> - <mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic"> + <mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic" + matTooltipPosition="above" + matTooltipClass="tb-error-tooltip" + [matTooltipDisabled]="!(gridSettingsFormGroup.get('margin').invalid && gridSettingsFormGroup.get('margin').touched)" + [matTooltip]="(gridSettingsFormGroup.get('margin').hasError('required') ? 'dashboard.margin-required' : + (gridSettingsFormGroup.get('margin').hasError('min') ? 'dashboard.min-margin-message' : 'dashboard.max-margin-message')) | translate"> <input matInput formControlName="margin" type="number" min="0" max="50" step="any" required placeholder="{{ 'widget-config.set' | translate }}"> - <mat-icon matSuffix - matTooltipPosition="above" - matTooltipClass="tb-error-tooltip" - [matTooltip]="(gridSettingsFormGroup.get('margin').hasError('required') ? 'dashboard.margin-required' : - (gridSettingsFormGroup.get('margin').hasError('min') ? 'dashboard.min-margin-message' : 'dashboard.max-margin-message')) | translate" - *ngIf="gridSettingsFormGroup.get('margin').invalid && gridSettingsFormGroup.get('margin').touched" - class="tb-error"> - warning - </mat-icon> </mat-form-field> </div> <div *ngIf="!isScada()" class="tb-form-row"> @@ -190,20 +177,16 @@ </div> <div *ngIf="isDefaultLayout && !isDefaultBreakpoint" class="tb-form-row space-between"> <div translate>dashboard.row-height</div> - <mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic"> + <mat-form-field appearance="outline" class="number medium-width" subscriptSizing="dynamic" + matTooltipPosition="above" + matTooltipClass="tb-error-tooltip" + [matTooltipDisabled]="!(gridSettingsFormGroup.get('rowHeight').invalid && gridSettingsFormGroup.get('rowHeight').touched)" + [matTooltip]="(gridSettingsFormGroup.get('rowHeight').hasError('required') ? 'dashboard.row-height-required' : + (gridSettingsFormGroup.get('rowHeight').hasError('min') ? + 'dashboard.min-row-height-message' : 'dashboard.max-row-height-message')) | translate"> <input matInput formControlName="rowHeight" type="number" min="5" max="200" step="any" required placeholder="{{ 'widget-config.set' | translate }}"> - <mat-icon matSuffix - matTooltipPosition="above" - matTooltipClass="tb-error-tooltip" - [matTooltip]="(gridSettingsFormGroup.get('rowHeight').hasError('required') ? 'dashboard.row-height-required' : - (gridSettingsFormGroup.get('rowHeight').hasError('min') ? - 'dashboard.min-row-height-message' : 'dashboard.max-row-height-message')) | translate" - *ngIf="gridSettingsFormGroup.get('rowHeight').invalid && gridSettingsFormGroup.get('rowHeight').touched" - class="tb-error"> - warning - </mat-icon> <span matSuffix>px</span> </mat-form-field> </div> @@ -245,20 +228,16 @@ </div> <div *ngIf="!isScada()" class="tb-form-row space-between"> <div translate>dashboard.mobile-row-height</div> - <mat-form-field appearance="outline" class="number medium-width tb-suffix-absolute" subscriptSizing="dynamic"> + <mat-form-field appearance="outline" class="number medium-width" subscriptSizing="dynamic" + matTooltipPosition="above" + matTooltipClass="tb-error-tooltip" + [matTooltipDisabled]="!(gridSettingsFormGroup.get('mobileRowHeight').invalid && gridSettingsFormGroup.get('mobileRowHeight').touched)" + [matTooltip]="(gridSettingsFormGroup.get('mobileRowHeight').hasError('required') ? 'dashboard.mobile-row-height-required' : + (gridSettingsFormGroup.get('mobileRowHeight').hasError('min') ? + 'dashboard.min-mobile-row-height-message' : 'dashboard.max-mobile-row-height-message')) | translate"> <input matInput formControlName="mobileRowHeight" type="number" min="5" max="200" step="any" required placeholder="{{ 'widget-config.set' | translate }}"> - <mat-icon matSuffix - matTooltipPosition="above" - matTooltipClass="tb-error-tooltip" - [matTooltip]="(gridSettingsFormGroup.get('mobileRowHeight').hasError('required') ? 'dashboard.mobile-row-height-required' : - (gridSettingsFormGroup.get('mobileRowHeight').hasError('min') ? - 'dashboard.min-mobile-row-height-message' : 'dashboard.max-mobile-row-height-message')) | translate" - *ngIf="gridSettingsFormGroup.get('mobileRowHeight').invalid && gridSettingsFormGroup.get('mobileRowHeight').touched" - class="tb-error"> - warning - </mat-icon> <span matSuffix>px</span> </mat-form-field> </div> 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 44e288d2e0..c1f0d7e635 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 @@ -126,6 +126,12 @@ <input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}"> </mat-form-field> </div> + <div class="tb-form-row space-between"> + <div>{{ 'widget-config.card-padding' | translate }}</div> + <mat-form-field appearance="outline" subscriptSizing="dynamic"> + <input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}"> + </mat-form-field> + </div> </div> <tb-widget-actions-panel formControlName="actions"> 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 0bffd39ce4..5f14b7569e 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 @@ -144,6 +144,7 @@ export class ValueCardBasicConfigComponent extends BasicWidgetConfigComponent { cardButtons: [this.getCardButtons(configData.config), []], borderRadius: [configData.config.borderRadius, []], + padding: [settings.padding, []], actions: [configData.config.actions || {}, []] }); @@ -183,6 +184,7 @@ export class ValueCardBasicConfigComponent extends BasicWidgetConfigComponent { this.setCardButtons(config.cardButtons, this.widgetConfig.config); this.widgetConfig.config.borderRadius = config.borderRadius; + this.widgetConfig.config.settings.padding = config.padding; this.widgetConfig.config.actions = config.actions; return this.widgetConfig; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/status-widget-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/status-widget-basic-config.component.html index 52563a1b46..e43dd1665a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/status-widget-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/status-widget-basic-config.component.html @@ -94,6 +94,12 @@ <input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}"> </mat-form-field> </div> + <div class="tb-form-row space-between"> + <div>{{ 'widget-config.card-padding' | translate }}</div> + <mat-form-field appearance="outline" subscriptSizing="dynamic"> + <input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}"> + </mat-form-field> + </div> </div> <tb-widget-actions-panel formControlName="actions"> diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/status-widget-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/status-widget-basic-config.component.ts index d2110026f6..0e012cefe7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/status-widget-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/status-widget-basic-config.component.ts @@ -79,6 +79,7 @@ export class StatusWidgetBasicConfigComponent extends BasicWidgetConfigComponent cardButtons: [this.getCardButtons(configData.config), []], borderRadius: [configData.config.borderRadius, []], + padding: [settings.padding, []], actions: [configData.config.actions || {}, []] }); @@ -99,6 +100,7 @@ export class StatusWidgetBasicConfigComponent extends BasicWidgetConfigComponent this.setCardButtons(config.cardButtons, this.widgetConfig.config); this.widgetConfig.config.borderRadius = config.borderRadius; + this.widgetConfig.config.settings.padding = config.padding; this.widgetConfig.config.actions = config.actions; return this.widgetConfig; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/rpc/single-switch-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/rpc/single-switch-basic-config.component.html index 7a638c70f3..9fa2d1b1a5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/rpc/single-switch-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/rpc/single-switch-basic-config.component.html @@ -211,6 +211,12 @@ <tb-background-settings formControlName="background"> </tb-background-settings> </div> + <div class="tb-form-row space-between"> + <div>{{ 'widget-config.card-padding' | translate }}</div> + <mat-form-field appearance="outline" subscriptSizing="dynamic"> + <input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}"> + </mat-form-field> + </div> <div class="tb-form-row space-between column-lt-md"> <div translate>widget-config.show-card-buttons</div> <mat-chip-listbox multiple formControlName="cardButtons"> diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/rpc/single-switch-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/rpc/single-switch-basic-config.component.ts index 75c93bc852..dfdc9e8eb0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/rpc/single-switch-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/rpc/single-switch-basic-config.component.ts @@ -108,6 +108,7 @@ export class SingleSwitchBasicConfigComponent extends BasicWidgetConfigComponent cardButtons: [this.getCardButtons(configData.config), []], borderRadius: [configData.config.borderRadius, []], + padding: [settings.padding, []], actions: [configData.config.actions || {}, []] }); @@ -159,6 +160,7 @@ export class SingleSwitchBasicConfigComponent extends BasicWidgetConfigComponent this.setCardButtons(config.cardButtons, this.widgetConfig.config); this.widgetConfig.config.borderRadius = config.borderRadius; + this.widgetConfig.config.settings.padding = config.padding; this.widgetConfig.config.actions = config.actions; return this.widgetConfig; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.html index 7854a9f3b3..0dd9a2ebd9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.html @@ -208,6 +208,12 @@ <input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}"> </mat-form-field> </div> + <div class="tb-form-row space-between"> + <div>{{ 'widget-config.card-padding' | translate }}</div> + <mat-form-field appearance="outline" subscriptSizing="dynamic"> + <input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}"> + </mat-form-field> + </div> </div> <tb-widget-actions-panel formControlName="actions"> diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts index fca3bd2502..08e7003b65 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts @@ -147,6 +147,7 @@ export class WindSpeedDirectionBasicConfigComponent extends BasicWidgetConfigCom cardButtons: [this.getCardButtons(configData.config), []], borderRadius: [configData.config.borderRadius, []], + padding: [settings.padding, []], actions: [configData.config.actions || {}, []] }); @@ -198,6 +199,7 @@ export class WindSpeedDirectionBasicConfigComponent extends BasicWidgetConfigCom this.setCardButtons(config.cardButtons, this.widgetConfig.config); this.widgetConfig.config.borderRadius = config.borderRadius; + this.widgetConfig.config.settings.padding = config.padding; this.widgetConfig.config.actions = config.actions; return this.widgetConfig; 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 089297427f..889a19a5aa 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 @@ -17,11 +17,12 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Component, - ComponentFactory, - ComponentRef, HostBinding, + ComponentRef, + HostBinding, Inject, - Injector, NgModuleRef, - OnDestroy, Type, + Injector, + OnDestroy, + Type, ViewContainerRef } from '@angular/core'; import { DialogComponent } from '@shared/components/dialog.component'; @@ -35,13 +36,11 @@ 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; customComponentType: Type<CustomDialogComponent>; - customComponentModuleRef: NgModuleRef<DynamicComponentModule>; } @Component({ @@ -80,7 +79,7 @@ export class CustomDialogContainerComponent extends DialogComponent<CustomDialog }); try { this.customComponentRef = this.viewContainerRef.createComponent(this.data.customComponentType, - {index: 0, injector, ngModuleRef: this.data.customComponentModuleRef}); + {index: 0, injector}); } catch (e: any) { let message; if (e.message?.startsWith('NG0')) { diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts index ba3b080936..2705a8902c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog.service.ts @@ -60,11 +60,10 @@ export class CustomDialogService { } return this.dynamicComponentFactoryService.createDynamicComponent( class CustomDialogComponentInstance extends CustomDialogComponent {}, template, modules).pipe( - mergeMap((componentData) => { + mergeMap((componentType) => { const dialogData: CustomDialogContainerData = { controller, - customComponentType: componentData.componentType, - customComponentModuleRef: componentData.componentModuleRef, + customComponentType: componentType, data }; let dialogConfig: MatDialogConfig = { @@ -79,7 +78,7 @@ export class CustomDialogService { CustomDialogContainerComponent, dialogConfig).afterClosed().pipe( tap(() => { - this.dynamicComponentFactoryService.destroyDynamicComponent(componentData.componentType); + this.dynamicComponentFactoryService.destroyDynamicComponent(componentType); }) ); } 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 72598a4cdf..814f9f08d8 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 @@ -15,41 +15,41 @@ limitations under the License. --> -<div #valueCardPanel class="tb-value-card-panel" [class]="this.layout" [style]="backgroundStyle$ | async"> +<div #valueCardPanel class="tb-value-card-panel" [class]="this.layout" [style.padding]="padding" [style]="backgroundStyle$ | async"> <div class="tb-value-card-overlay" [style]="overlayStyle"></div> <div class="tb-value-card-title-panel"> <ng-container *ngTemplateOutlet="widgetTitlePanel"></ng-container> </div> <div #valueCardContent class="tb-value-card-content" [class]="this.layout"> <ng-container [ngSwitch]="layout"> - <ng-template [ngSwitchCase]="valueCardLayout.square"> - <ng-container *ngTemplateOutlet="iconWithLabelTpl"></ng-container> - <ng-container *ngTemplateOutlet="valueTpl"></ng-container> - </ng-template> - <ng-template [ngSwitchCase]="valueCardLayout.vertical"> - <ng-container *ngTemplateOutlet="labelTpl"></ng-container> - <ng-container *ngTemplateOutlet="valueTpl"></ng-container> - <ng-container *ngTemplateOutlet="iconTpl"></ng-container> - </ng-template> - <ng-template [ngSwitchCase]="valueCardLayout.centered"> - <ng-container *ngTemplateOutlet="labelTpl"></ng-container> - <div class="tb-value-card-icon-row"> + <ng-template [ngSwitchCase]="valueCardLayout.square"> + <ng-container *ngTemplateOutlet="iconWithLabelTpl"></ng-container> + <ng-container *ngTemplateOutlet="valueTpl"></ng-container> + </ng-template> + <ng-template [ngSwitchCase]="valueCardLayout.vertical"> + <ng-container *ngTemplateOutlet="labelTpl"></ng-container> + <ng-container *ngTemplateOutlet="valueTpl"></ng-container> <ng-container *ngTemplateOutlet="iconTpl"></ng-container> + </ng-template> + <ng-template [ngSwitchCase]="valueCardLayout.centered"> + <ng-container *ngTemplateOutlet="labelTpl"></ng-container> + <div class="tb-value-card-icon-row"> + <ng-container *ngTemplateOutlet="iconTpl"></ng-container> + <ng-container *ngTemplateOutlet="valueTpl"></ng-container> + </div> + <ng-container *ngTemplateOutlet="dateTpl"></ng-container> + </ng-template> + <ng-template [ngSwitchCase]="valueCardLayout.simplified"> <ng-container *ngTemplateOutlet="valueTpl"></ng-container> - </div> - <ng-container *ngTemplateOutlet="dateTpl"></ng-container> - </ng-template> - <ng-template [ngSwitchCase]="valueCardLayout.simplified"> - <ng-container *ngTemplateOutlet="valueTpl"></ng-container> - <ng-container *ngTemplateOutlet="labelTpl"></ng-container> - </ng-template> - <ng-template [ngSwitchCase]="layout === valueCardLayout.horizontal || - layout === valueCardLayout.horizontal_reversed ? layout : ''"> - <ng-container *ngTemplateOutlet="iconWithLabelTpl"></ng-container> - <div fxFlex></div> - <ng-container *ngTemplateOutlet="valueTpl"></ng-container> - </ng-template> - </ng-container> + <ng-container *ngTemplateOutlet="labelTpl"></ng-container> + </ng-template> + <ng-template [ngSwitchCase]="layout === valueCardLayout.horizontal || + layout === valueCardLayout.horizontal_reversed ? layout : ''"> + <ng-container *ngTemplateOutlet="iconWithLabelTpl"></ng-container> + <div fxFlex></div> + <ng-container *ngTemplateOutlet="valueTpl"></ng-container> + </ng-template> + </ng-container> </div> </div> <ng-template #iconWithLabelTpl> 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 ed361c1e76..96ec634362 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 @@ -38,6 +38,7 @@ import { getSingleTsValue, iconStyle, overlayStyle, + resolveCssSize, textStyle } from '@shared/models/widget-settings.models'; import { valueCardDefaultSettings, ValueCardLayout, ValueCardWidgetSettings } from './value-card-widget.models'; @@ -48,7 +49,6 @@ import { ImagePipe } from '@shared/pipe/image.pipe'; import { DomSanitizer } from '@angular/platform-browser'; const squareLayoutSize = 160; -const squareLayoutPadding = 48; const horizontalLayoutHeight = 80; @Component({ @@ -96,6 +96,7 @@ export class ValueCardWidgetComponent implements OnInit, AfterViewInit, OnDestro backgroundStyle$: Observable<ComponentStyle>; overlayStyle: ComponentStyle = {}; + padding: string; private panelResize$: ResizeObserver; @@ -148,6 +149,7 @@ export class ValueCardWidgetComponent implements OnInit, AfterViewInit, OnDestro this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer); this.overlayStyle = overlayStyle(this.settings.background.overlay); + this.padding = this.settings.background.overlay.enabled ? undefined : this.settings.padding; } public ngAfterViewInit() { @@ -199,8 +201,13 @@ export class ValueCardWidgetComponent implements OnInit, AfterViewInit, OnDestro } private onResize() { - const panelWidth = this.valueCardPanel.nativeElement.getBoundingClientRect().width - squareLayoutPadding; - const panelHeight = this.valueCardPanel.nativeElement.getBoundingClientRect().height - (this.horizontal ? 0 : squareLayoutPadding); + const computedStyle = getComputedStyle(this.valueCardPanel.nativeElement); + const [pLeft, pRight, pTop, pBottom] = ['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom'] + .map(side => resolveCssSize(computedStyle[side])[0]); + + const widgetBoundingClientRect = this.valueCardPanel.nativeElement.getBoundingClientRect(); + const panelWidth = widgetBoundingClientRect.width - (pLeft + pRight); + const panelHeight = widgetBoundingClientRect.height - (pTop + pBottom); let scale: number; if (!this.horizontal) { const size = Math.min(panelWidth, panelHeight); 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 df5fc78e9a..2ca299cb6e 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,10 @@ import { BackgroundType, ColorSettings, constantColor, - cssUnit, DateFormatSettings, - Font, lastUpdateAgoDateFormat + cssUnit, + DateFormatSettings, + Font, + lastUpdateAgoDateFormat } from '@shared/models/widget-settings.models'; export enum ValueCardLayout { @@ -80,6 +82,7 @@ export interface ValueCardWidgetSettings { dateFont: Font; dateColor: ColorSettings; background: BackgroundSettings; + padding: string; } export const valueCardDefaultSettings = (horizontal: boolean): ValueCardWidgetSettings => ({ @@ -128,5 +131,6 @@ export const valueCardDefaultSettings = (horizontal: boolean): ValueCardWidgetSe color: 'rgba(255,255,255,0.72)', blur: 3 } - } + }, + padding: '' }); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts new file mode 100644 index 0000000000..d12e647254 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts @@ -0,0 +1,72 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Directive, inject, Input, OnDestroy, TemplateRef } from '@angular/core'; +import { ControlValueAccessor, FormBuilder, FormGroup, ValidationErrors, Validator } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +@Directive() +export abstract class GatewayConnectorBasicConfigDirective<InputBasicConfig, OutputBasicConfig> + implements ControlValueAccessor, Validator, OnDestroy { + + @Input() generalTabContent: TemplateRef<any>; + + basicFormGroup: FormGroup; + + protected fb = inject(FormBuilder); + protected onChange!: (value: OutputBasicConfig) => void; + protected onTouched!: () => void; + protected destroy$ = new Subject<void>(); + + constructor() { + this.basicFormGroup = this.initBasicFormGroup(); + + this.basicFormGroup.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe((value) => this.onBasicFormGroupChange(value)); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + validate(): ValidationErrors | null { + return this.basicFormGroup.valid ? null : { basicFormGroup: { valid: false } }; + } + + registerOnChange(fn: (value: OutputBasicConfig) => void): void { + this.onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + writeValue(config: OutputBasicConfig): void { + this.basicFormGroup.setValue(this.mapConfigToFormValue(config), { emitEvent: false }); + } + + protected onBasicFormGroupChange(value: InputBasicConfig): void { + this.onChange(this.getMappedValue(value)); + this.onTouched(); + } + + protected abstract mapConfigToFormValue(config: OutputBasicConfig): InputBasicConfig; + protected abstract getMappedValue(config: InputBasicConfig): OutputBasicConfig; + protected abstract initBasicFormGroup(): FormGroup; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts new file mode 100644 index 0000000000..944b5ffe6c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-version-processor.abstract.ts @@ -0,0 +1,61 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { GatewayConnector, GatewayVersion } from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { isNumber, isString } from '@core/utils'; + +export abstract class GatewayConnectorVersionProcessor<BasicConfig> { + gatewayVersion: number; + configVersion: number; + + protected constructor(protected gatewayVersionIn: string | number, protected connector: GatewayConnector<BasicConfig>) { + this.gatewayVersion = this.parseVersion(this.gatewayVersionIn); + this.configVersion = this.parseVersion(connector.configVersion); + } + + getProcessedByVersion(): GatewayConnector<BasicConfig> { + if (this.isVersionUpdateNeeded()) { + return this.isVersionUpgradeNeeded() + ? this.getUpgradedVersion() + : this.getDowngradedVersion(); + } + + return this.connector; + } + + private isVersionUpdateNeeded(): boolean { + if (!this.gatewayVersion) { + return false; + } + + return this.configVersion !== this.gatewayVersion; + } + + private isVersionUpgradeNeeded(): boolean { + return this.gatewayVersionIn === GatewayVersion.Current && (!this.configVersion || this.configVersion < this.gatewayVersion); + } + + private parseVersion(version: string | number): number { + if (isNumber(version)) { + return version as number; + } + + return isString(version) ? parseFloat((version as string).replace(/\./g, '').slice(0, 3)) / 100 : 0; + } + + protected abstract getDowngradedVersion(): GatewayConnector<BasicConfig>; + protected abstract getUpgradedVersion(): GatewayConnector<BasicConfig>; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts new file mode 100644 index 0000000000..6ea8f4516d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract.ts @@ -0,0 +1,68 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + GatewayConnector, + ModbusBasicConfig, + ModbusBasicConfig_v3_5_2, + ModbusLegacyBasicConfig, + ModbusLegacySlave, + ModbusMasterConfig, + ModbusSlave, +} from '../gateway-widget.models'; +import { GatewayConnectorVersionProcessor } from './gateway-connector-version-processor.abstract'; +import { ModbusVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/modbus-version-mapping.util'; + +export class ModbusVersionProcessor extends GatewayConnectorVersionProcessor<any> { + + constructor( + protected gatewayVersionIn: string, + protected connector: GatewayConnector<ModbusBasicConfig> + ) { + super(gatewayVersionIn, connector); + } + + getUpgradedVersion(): GatewayConnector<ModbusBasicConfig_v3_5_2> { + const configurationJson = this.connector.configurationJson; + return { + ...this.connector, + configurationJson: { + master: configurationJson.master + ? ModbusVersionMappingUtil.mapMasterToUpgradedVersion(configurationJson.master) + : {} as ModbusMasterConfig, + slave: configurationJson.slave + ? ModbusVersionMappingUtil.mapSlaveToUpgradedVersion(configurationJson.slave as ModbusLegacySlave) + : {} as ModbusSlave, + }, + configVersion: this.gatewayVersionIn + } as GatewayConnector<ModbusBasicConfig_v3_5_2>; + } + + getDowngradedVersion(): GatewayConnector<ModbusLegacyBasicConfig> { + const configurationJson = this.connector.configurationJson; + return { + ...this.connector, + configurationJson: { + ...configurationJson, + slave: configurationJson.slave + ? ModbusVersionMappingUtil.mapSlaveToDowngradedVersion(configurationJson.slave as ModbusSlave) + : {} as ModbusLegacySlave, + master: configurationJson.master, + }, + configVersion: this.gatewayVersionIn + } as GatewayConnector<ModbusLegacyBasicConfig>; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts new file mode 100644 index 0000000000..351ad76494 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract.ts @@ -0,0 +1,101 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { isEqual } from '@core/utils'; +import { + GatewayConnector, + MQTTBasicConfig, + MQTTBasicConfig_v3_5_2, + MQTTLegacyBasicConfig, + RequestMappingData, + RequestType, +} from '../gateway-widget.models'; +import { MqttVersionMappingUtil } from '../utils/mqtt-version-mapping.util'; +import { GatewayConnectorVersionProcessor } from './gateway-connector-version-processor.abstract'; + +export class MqttVersionProcessor extends GatewayConnectorVersionProcessor<MQTTBasicConfig> { + + private readonly mqttRequestTypeKeys = Object.values(RequestType); + + constructor( + protected gatewayVersionIn: string, + protected connector: GatewayConnector<MQTTBasicConfig> + ) { + super(gatewayVersionIn, connector); + } + + getUpgradedVersion(): GatewayConnector<MQTTBasicConfig_v3_5_2> { + const { + connectRequests, + disconnectRequests, + attributeRequests, + attributeUpdates, + serverSideRpc + } = this.connector.configurationJson as MQTTLegacyBasicConfig; + let configurationJson = { + ...this.connector.configurationJson, + requestsMapping: MqttVersionMappingUtil.mapRequestsToUpgradedVersion({ + connectRequests, + disconnectRequests, + attributeRequests, + attributeUpdates, + serverSideRpc + }), + mapping: MqttVersionMappingUtil.mapMappingToUpgradedVersion((this.connector.configurationJson as MQTTLegacyBasicConfig).mapping), + }; + + this.mqttRequestTypeKeys.forEach((key: RequestType) => { + const { [key]: removedValue, ...rest } = configurationJson as MQTTLegacyBasicConfig; + configurationJson = { ...rest } as any; + }); + + this.cleanUpConfigJson(configurationJson as MQTTBasicConfig_v3_5_2); + + return { + ...this.connector, + configurationJson, + configVersion: this.gatewayVersionIn + } as GatewayConnector<MQTTBasicConfig_v3_5_2>; + } + + getDowngradedVersion(): GatewayConnector<MQTTLegacyBasicConfig> { + const { requestsMapping, mapping, ...restConfig } = this.connector.configurationJson as MQTTBasicConfig_v3_5_2; + + const updatedRequestsMapping = + MqttVersionMappingUtil.mapRequestsToDowngradedVersion(requestsMapping as Record<RequestType, RequestMappingData[]>); + const updatedMapping = MqttVersionMappingUtil.mapMappingToDowngradedVersion(mapping); + + return { + ...this.connector, + configurationJson: { + ...restConfig, + ...updatedRequestsMapping, + mapping: updatedMapping, + }, + configVersion: this.gatewayVersionIn + } as GatewayConnector<MQTTLegacyBasicConfig>; + } + + private cleanUpConfigJson(configurationJson: MQTTBasicConfig_v3_5_2): void { + if (isEqual(configurationJson.requestsMapping, {})) { + delete configurationJson.requestsMapping; + } + + if (isEqual(configurationJson.mapping, [])) { + delete configurationJson.mapping; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts new file mode 100644 index 0000000000..e89c48fc28 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts @@ -0,0 +1,56 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + GatewayConnector, LegacyServerConfig, + OPCBasicConfig, + OPCBasicConfig_v3_5_2, + OPCLegacyBasicConfig, +} from '../gateway-widget.models'; +import { GatewayConnectorVersionProcessor } from './gateway-connector-version-processor.abstract'; +import { OpcVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/opc-version-mapping.util'; + +export class OpcVersionProcessor extends GatewayConnectorVersionProcessor<OPCBasicConfig> { + + constructor( + protected gatewayVersionIn: string, + protected connector: GatewayConnector<OPCBasicConfig> + ) { + super(gatewayVersionIn, connector); + } + + getUpgradedVersion(): GatewayConnector<OPCBasicConfig_v3_5_2> { + const server = this.connector.configurationJson.server as LegacyServerConfig; + return { + ...this.connector, + configurationJson: { + server: server ? OpcVersionMappingUtil.mapServerToUpgradedVersion(server) : {}, + mapping: server.mapping ? OpcVersionMappingUtil.mapMappingToUpgradedVersion(server.mapping) : [], + }, + configVersion: this.gatewayVersionIn + } as GatewayConnector<OPCBasicConfig_v3_5_2>; + } + + getDowngradedVersion(): GatewayConnector<OPCLegacyBasicConfig> { + return { + ...this.connector, + configurationJson: { + server: OpcVersionMappingUtil.mapServerToDowngradedVersion(this.connector.configurationJson as OPCBasicConfig_v3_5_2) + }, + configVersion: this.gatewayVersionIn + } as GatewayConnector<OPCLegacyBasicConfig>; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/basic/gateway-basic-configuration.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/basic/gateway-basic-configuration.component.ts index 4b47dd15c4..e63a60372e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/basic/gateway-basic-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/basic/gateway-basic-configuration.component.ts @@ -43,7 +43,7 @@ import { } from '@home/components/widget/lib/gateway/gateway-remote-configuration-dialog'; import { DeviceService } from '@core/http/device.service'; import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { take, takeUntil } from 'rxjs/operators'; import { DeviceCredentials, DeviceCredentialsType } from '@shared/models/device.models'; import { GatewayLogLevel, @@ -61,7 +61,9 @@ import { CommonModule } from '@angular/common'; import { coerceBoolean } from '@shared/decorators/coercion'; import { GatewayConfigCommand, - GatewayConfigValue, LogConfig + GatewayConfigSecurity, + GatewayConfigValue, + LogConfig } from '@home/components/widget/lib/gateway/configuration/models/gateway-configuration.models'; @Component({ @@ -99,13 +101,14 @@ export class GatewayBasicConfigurationComponent implements OnDestroy, ControlVal initialCredentialsUpdated = new EventEmitter<DeviceCredentials>(); StorageTypes = StorageTypes; - storageTypes = Object.values(StorageTypes) as StorageTypes[]; + storageTypes = Object.values(StorageTypes); storageTypesTranslationMap = StorageTypesTranslationMap; logSavingPeriods = LogSavingPeriodTranslations; localLogsConfigs = Object.keys(LocalLogsConfigs) as LocalLogsConfigs[]; localLogsConfigTranslateMap = LocalLogsConfigTranslateMap; securityTypes = GecurityTypesTranslationsMap; gatewayLogLevel = Object.values(GatewayLogLevel); + logSelector: FormControl; basicFormGroup: FormGroup; @@ -119,6 +122,7 @@ export class GatewayBasicConfigurationComponent implements OnDestroy, ControlVal private cd: ChangeDetectorRef, private dialog: MatDialog) { this.initBasicFormGroup(); + this.observeFormChanges(); this.basicFormGroup.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe(value => { @@ -142,14 +146,12 @@ export class GatewayBasicConfigurationComponent implements OnDestroy, ControlVal writeValue(basicConfig: GatewayConfigValue): void { this.basicFormGroup.patchValue(basicConfig, {emitEvent: false}); - if (basicConfig?.thingsboard?.security) { - this.checkAndFetchCredentials(basicConfig.thingsboard.security); - } + this.checkAndFetchCredentials(basicConfig?.thingsboard?.security ?? {} as GatewayConfigSecurity); if (basicConfig?.grpc) { this.toggleRpcFields(basicConfig.grpc.enabled); } - const commands = basicConfig?.thingsboard?.statistics?.commands || []; - commands.forEach(command => this.addCommand(command, false)); + const commands = basicConfig?.thingsboard?.statistics?.commands ?? []; + commands.forEach((command: GatewayConfigCommand) => this.addCommand(command, false)); } validate(): ValidationErrors | null { @@ -251,7 +253,7 @@ export class GatewayBasicConfigurationComponent implements OnDestroy, ControlVal data: { gatewayName: gateway.name } - }).afterClosed().subscribe( + }).afterClosed().pipe(take(1)).subscribe( (res) => { if (!res) { this.basicFormGroup.get('thingsboard.remoteConfiguration').setValue(true, {emitEvent: false}); @@ -273,214 +275,294 @@ export class GatewayBasicConfigurationComponent implements OnDestroy, ControlVal this.commandFormArray().push(commandFormGroup, { emitEvent }); } - private initBasicFormGroup(): void { this.basicFormGroup = this.fb.group({ - thingsboard: this.fb.group({ - host: [window.location.hostname, [Validators.required, Validators.pattern(/^[^\s]+$/)]], - port: [1883, [Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern(/^-?[0-9]+$/)]], - remoteShell: [false, []], - remoteConfiguration: [true, []], - checkConnectorsConfigurationInSeconds: [60, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - statistics: this.fb.group({ - enable: [true, []], - statsSendPeriodInSeconds: [3600, [Validators.required, Validators.min(60), Validators.pattern(/^-?[0-9]+$/)]], - commands: this.fb.array([], []) - }), - maxPayloadSizeBytes: [8196, [Validators.required, Validators.min(100), Validators.pattern(/^-?[0-9]+$/)]], - minPackSendDelayMS: [50, [Validators.required, Validators.min(10), Validators.pattern(/^-?[0-9]+$/)]], - minPackSizeToSend: [500, [Validators.required, Validators.min(100), Validators.pattern(/^-?[0-9]+$/)]], - handleDeviceRenaming: [true, []], - checkingDeviceActivity: this.fb.group({ - checkDeviceInactivity: [false, []], - inactivityTimeoutSeconds: [200, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - inactivityCheckPeriodSeconds: [500, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]] - }), - security: this.fb.group({ - type: [SecurityTypes.ACCESS_TOKEN, [Validators.required]], - accessToken: [null, [Validators.required, Validators.pattern(/^[^.\s]+$/)]], - clientId: [null, [Validators.pattern(/^[^.\s]+$/)]], - username: [null, [Validators.pattern(/^[^.\s]+$/)]], - password: [null, [Validators.pattern(/^[^.\s]+$/)]], - caCert: [null, []], - cert: [null, []], - privateKey: [null, []], - }), - qos: [1, [Validators.min(0), Validators.max(1), Validators.required, Validators.pattern(/^[^.\s]+$/)]] - }), - storage: this.fb.group({ - type: [StorageTypes.MEMORY, [Validators.required]], - read_records_count: [ - 100, [Validators.min(1), - Validators.pattern(/^-?[0-9]+$/), Validators.required, Validators.pattern(/^[^.\s]+$/)] - ], - max_records_count: [ - 100000, - [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required, Validators.pattern(/^[^.\s]+$/)] - ], - data_folder_path: ['./data/', [Validators.required]], - max_file_count: [10, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - max_read_records_count: [10, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - max_records_per_file: [10000, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - data_file_path: ['./data/data.db', [Validators.required]], - messages_ttl_check_in_hours: [1, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - messages_ttl_in_days: [7, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + thingsboard: this.initThingsboardFormGroup(), + storage: this.initStorageFormGroup(), + grpc: this.initGrpcFormGroup(), + connectors: this.fb.array([]), + logs: this.initLogsFormGroup(), + }); + } + private initThingsboardFormGroup(): FormGroup { + return this.fb.group({ + host: [window.location.hostname, [Validators.required, Validators.pattern(/^[^\s]+$/)]], + port: [1883, [Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern(/^-?[0-9]+$/)]], + remoteShell: [false], + remoteConfiguration: [true], + checkConnectorsConfigurationInSeconds: [60, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + statistics: this.fb.group({ + enable: [true], + statsSendPeriodInSeconds: [3600, [Validators.required, Validators.min(60), Validators.pattern(/^-?[0-9]+$/)]], + commands: this.fb.array([]) }), - grpc: this.fb.group({ - enabled: [false, []], - serverPort: [9595, [Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern(/^-?[0-9]+$/)]], - keepAliveTimeMs: [10000, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - keepAliveTimeoutMs: [5000, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - keepalivePermitWithoutCalls: [true, []], - maxPingsWithoutData: [0, [Validators.required, Validators.min(0), Validators.pattern(/^-?[0-9]+$/)]], - minTimeBetweenPingsMs: [10000, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - minPingIntervalWithoutDataMs: [5000, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + maxPayloadSizeBytes: [8196, [Validators.required, Validators.min(100), Validators.pattern(/^-?[0-9]+$/)]], + minPackSendDelayMS: [50, [Validators.required, Validators.min(10), Validators.pattern(/^-?[0-9]+$/)]], + minPackSizeToSend: [500, [Validators.required, Validators.min(100), Validators.pattern(/^-?[0-9]+$/)]], + handleDeviceRenaming: [true], + checkingDeviceActivity: this.initCheckingDeviceActivityFormGroup(), + security: this.initSecurityFormGroup(), + qos: [1, [Validators.required, Validators.min(0), Validators.max(1), Validators.pattern(/^[^.\s]+$/)]] + }); + } + + private initStorageFormGroup(): FormGroup { + return this.fb.group({ + type: [StorageTypes.MEMORY, [Validators.required]], + read_records_count: [100, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + max_records_count: [100000, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + data_folder_path: ['./data/', [Validators.required]], + max_file_count: [10, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + max_read_records_count: [10, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + max_records_per_file: [10000, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + data_file_path: ['./data/data.db', [Validators.required]], + messages_ttl_check_in_hours: [1, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + messages_ttl_in_days: [7, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]] + }); + } + + private initGrpcFormGroup(): FormGroup { + return this.fb.group({ + enabled: [false], + serverPort: [9595, [Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern(/^-?[0-9]+$/)]], + keepAliveTimeMs: [10000, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + keepAliveTimeoutMs: [5000, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + keepalivePermitWithoutCalls: [true], + maxPingsWithoutData: [0, [Validators.required, Validators.min(0), Validators.pattern(/^-?[0-9]+$/)]], + minTimeBetweenPingsMs: [10000, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + minPingIntervalWithoutDataMs: [5000, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]] + }); + } + + private initLogsFormGroup(): FormGroup { + return this.fb.group({ + dateFormat: ['%Y-%m-%d %H:%M:%S', [Validators.required, Validators.pattern(/^[^\s].*[^\s]$/)]], + logFormat: [ + '%(asctime)s - |%(levelname)s| - [%(filename)s] - %(module)s - %(funcName)s - %(lineno)d - %(message)s', + [Validators.required, Validators.pattern(/^[^\s].*[^\s]$/)] + ], + type: ['remote', [Validators.required]], + remote: this.fb.group({ + enabled: [false], + logLevel: [GatewayLogLevel.INFO, [Validators.required]] }), - connectors: this.fb.array([]), - logs: this.fb.group({ - dateFormat: ['%Y-%m-%d %H:%M:%S', [Validators.required, Validators.pattern(/^[^\s].*[^\s]$/)]], - logFormat: ['%(asctime)s - |%(levelname)s| - [%(filename)s] - %(module)s - %(funcName)s - %(lineno)d - %(message)s', - [Validators.required, Validators.pattern(/^[^\s].*[^\s]$/)]], - type: ['remote', [Validators.required]], - remote: this.fb.group({ - enabled: [false], - logLevel: [GatewayLogLevel.INFO, [Validators.required]], - }), - local: this.fb.group({}) - }) + local: this.fb.group({}) + }); + } + + private initCheckingDeviceActivityFormGroup(): FormGroup { + return this.fb.group({ + checkDeviceInactivity: [false], + inactivityTimeoutSeconds: [200, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + inactivityCheckPeriodSeconds: [500, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]] }); + } - this.basicFormGroup.get('thingsboard.security.password').valueChanges.subscribe(password => { + private initSecurityFormGroup(): FormGroup { + return this.fb.group({ + type: [SecurityTypes.ACCESS_TOKEN, [Validators.required]], + accessToken: [null, [Validators.required, Validators.pattern(/^[^.\s]+$/)]], + clientId: [null, [Validators.pattern(/^[^.\s]+$/)]], + username: [null, [Validators.pattern(/^[^.\s]+$/)]], + password: [null, [Validators.pattern(/^[^.\s]+$/)]], + caCert: [null], + cert: [null], + privateKey: [null] + }); + } + + private observeFormChanges(): void { + this.observeSecurityPasswordChanges(); + this.observeRemoteConfigurationChanges(); + this.observeDeviceActivityChanges(); + this.observeSecurityTypeChanges(); + this.observeStorageTypeChanges(); + } + + private observeSecurityPasswordChanges(): void { + const securityUsername = this.basicFormGroup.get('thingsboard.security.username'); + this.basicFormGroup.get('thingsboard.security.password').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(password => { if (password && password !== '') { - this.basicFormGroup.get('thingsboard.security.username').setValidators([Validators.required]); + securityUsername.setValidators([Validators.required]); } else { - this.basicFormGroup.get('thingsboard.security.username').clearValidators(); + securityUsername.clearValidators(); } - this.basicFormGroup.get('thingsboard.security.username').updateValueAndValidity({emitEvent: false}); + securityUsername.updateValueAndValidity({ emitEvent: false }); }); + } - this.toggleRpcFields(false); - - this.basicFormGroup.get('thingsboard.remoteConfiguration').valueChanges.subscribe(enabled => { + private observeRemoteConfigurationChanges(): void { + this.basicFormGroup.get('thingsboard.remoteConfiguration').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(enabled => { if (!enabled) { this.openConfigurationConfirmDialog(); } }); this.logSelector = this.fb.control(LocalLogsConfigs.service); - - for (const localLogsConfigsKey of Object.keys(LocalLogsConfigs)) { - this.addLocalLogConfig(localLogsConfigsKey, {} as LogConfig); + for (const key of Object.keys(LocalLogsConfigs)) { + this.addLocalLogConfig(key, {} as LogConfig); } + } + private observeDeviceActivityChanges(): void { const checkingDeviceActivityGroup = this.basicFormGroup.get('thingsboard.checkingDeviceActivity') as FormGroup; - checkingDeviceActivityGroup.get('checkDeviceInactivity').valueChanges.subscribe(enabled => { + checkingDeviceActivityGroup.get('checkDeviceInactivity').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(enabled => { checkingDeviceActivityGroup.updateValueAndValidity(); + const validators = [Validators.min(1), Validators.required, Validators.pattern(/^-?[0-9]+$/)]; + if (enabled) { - checkingDeviceActivityGroup.get('inactivityTimeoutSeconds') - .setValidators([Validators.min(1), Validators.required, Validators.pattern(/^-?[0-9]+$/)]); - checkingDeviceActivityGroup.get('inactivityCheckPeriodSeconds') - .setValidators([Validators.min(1), Validators.required, Validators.pattern(/^-?[0-9]+$/)]); + checkingDeviceActivityGroup.get('inactivityTimeoutSeconds').setValidators(validators); + checkingDeviceActivityGroup.get('inactivityCheckPeriodSeconds').setValidators(validators); } else { checkingDeviceActivityGroup.get('inactivityTimeoutSeconds').clearValidators(); checkingDeviceActivityGroup.get('inactivityCheckPeriodSeconds').clearValidators(); } - checkingDeviceActivityGroup.get('inactivityTimeoutSeconds').updateValueAndValidity({emitEvent: false}); - checkingDeviceActivityGroup.get('inactivityCheckPeriodSeconds').updateValueAndValidity({emitEvent: false}); + checkingDeviceActivityGroup.get('inactivityTimeoutSeconds').updateValueAndValidity({ emitEvent: false }); + checkingDeviceActivityGroup.get('inactivityCheckPeriodSeconds').updateValueAndValidity({ emitEvent: false }); }); - this.basicFormGroup.get('grpc.enabled').valueChanges.subscribe(value => { + this.basicFormGroup.get('grpc.enabled').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(value => { this.toggleRpcFields(value); }); + } + private observeSecurityTypeChanges(): void { const securityGroup = this.basicFormGroup.get('thingsboard.security') as FormGroup; - securityGroup.get('type').valueChanges.subscribe(type => { + + securityGroup.get('type').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(type => { this.removeAllSecurityValidators(); - if (type === SecurityTypes.ACCESS_TOKEN) { - securityGroup.get('accessToken').addValidators([Validators.required, Validators.pattern(/^[^.\s]+$/)]); - securityGroup.get('accessToken').updateValueAndValidity(); - } else if (type === SecurityTypes.TLS_PRIVATE_KEY) { - securityGroup.get('caCert').addValidators([Validators.required]); - securityGroup.get('caCert').updateValueAndValidity(); - securityGroup.get('privateKey').addValidators([Validators.required]); - securityGroup.get('privateKey').updateValueAndValidity(); - securityGroup.get('cert').addValidators([Validators.required]); - securityGroup.get('cert').updateValueAndValidity(); - } else if (type === SecurityTypes.TLS_ACCESS_TOKEN) { - securityGroup.get('accessToken').addValidators([Validators.required, Validators.pattern(/^[^.\s]+$/)]); - securityGroup.get('accessToken').updateValueAndValidity(); - securityGroup.get('caCert').addValidators([Validators.required]); - securityGroup.get('caCert').updateValueAndValidity(); - } else if (type === SecurityTypes.USERNAME_PASSWORD) { - securityGroup.addValidators([this.atLeastOneRequired(Validators.required, ['clientId', 'username'])]); + + switch (type) { + case SecurityTypes.ACCESS_TOKEN: + this.addAccessTokenValidators(securityGroup); + break; + case SecurityTypes.TLS_PRIVATE_KEY: + this.addTlsPrivateKeyValidators(securityGroup); + break; + case SecurityTypes.TLS_ACCESS_TOKEN: + this.addTlsAccessTokenValidators(securityGroup); + break; + case SecurityTypes.USERNAME_PASSWORD: + securityGroup.addValidators([this.atLeastOneRequired(Validators.required, ['clientId', 'username'])]); + break; } + securityGroup.updateValueAndValidity(); }); - securityGroup.get('caCert').valueChanges.subscribe(() => this.cd.detectChanges()); - securityGroup.get('privateKey').valueChanges.subscribe(() => this.cd.detectChanges()); - securityGroup.get('cert').valueChanges.subscribe(() => this.cd.detectChanges()); + ['caCert', 'privateKey', 'cert'].forEach(field => { + securityGroup.get(field).valueChanges.pipe(takeUntil(this.destroy$)).subscribe(() => this.cd.detectChanges()); + }); + } + private observeStorageTypeChanges(): void { const storageGroup = this.basicFormGroup.get('storage') as FormGroup; - storageGroup.get('type').valueChanges.subscribe(type => { + + storageGroup.get('type').valueChanges.pipe(takeUntil(this.destroy$)).subscribe(type => { this.removeAllStorageValidators(); - if (type === StorageTypes.MEMORY) { - storageGroup.get('read_records_count').addValidators( - [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]); - storageGroup.get('max_records_count').addValidators( - [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); - storageGroup.get('read_records_count').updateValueAndValidity({emitEvent: false}); - storageGroup.get('max_records_count').updateValueAndValidity({emitEvent: false}); - } else if (type === StorageTypes.FILE) { - storageGroup.get('data_folder_path').addValidators([Validators.required]); - storageGroup.get('max_file_count').addValidators( - [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); - storageGroup.get('max_read_records_count').addValidators( - [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); - storageGroup.get('max_records_per_file').addValidators( - [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); - storageGroup.get('data_folder_path').updateValueAndValidity({emitEvent: false}); - storageGroup.get('max_file_count').updateValueAndValidity({emitEvent: false}); - storageGroup.get('max_read_records_count').updateValueAndValidity({emitEvent: false}); - storageGroup.get('max_records_per_file').updateValueAndValidity({emitEvent: false}); - } else if (type === StorageTypes.SQLITE) { - storageGroup.get('data_file_path').addValidators([Validators.required]); - storageGroup.get('messages_ttl_check_in_hours').addValidators( - [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); - storageGroup.get('messages_ttl_in_days').addValidators( - [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); - storageGroup.get('data_file_path').updateValueAndValidity({emitEvent: false}); - storageGroup.get('messages_ttl_check_in_hours').updateValueAndValidity({emitEvent: false}); - storageGroup.get('messages_ttl_in_days').updateValueAndValidity({emitEvent: false}); + + switch (type) { + case StorageTypes.MEMORY: + this.addMemoryStorageValidators(storageGroup); + break; + case StorageTypes.FILE: + this.addFileStorageValidators(storageGroup); + break; + case StorageTypes.SQLITE: + this.addSqliteStorageValidators(storageGroup); + break; } }); } - private checkAndFetchCredentials(security: any = {}): void { - if (security.type !== SecurityTypes.TLS_PRIVATE_KEY) { - this.deviceService.getDeviceCredentials(this.device.id).subscribe(credentials => { - this.initialCredentialsUpdated.emit(credentials); - if (credentials.credentialsType === DeviceCredentialsType.ACCESS_TOKEN || security.type === SecurityTypes.TLS_ACCESS_TOKEN) { - this.basicFormGroup.get('thingsboard.security.type') - .setValue(security.type === SecurityTypes.TLS_ACCESS_TOKEN - ? SecurityTypes.TLS_ACCESS_TOKEN - : SecurityTypes.ACCESS_TOKEN, {emitEvent: false}); - this.basicFormGroup.get('thingsboard.security.accessToken').setValue(credentials.credentialsId, {emitEvent: false}); - if(security.type === SecurityTypes.TLS_ACCESS_TOKEN) { - this.basicFormGroup.get('thingsboard.security.caCert').setValue(security.caCert, {emitEvent: false}); - } - } else if (credentials.credentialsType === DeviceCredentialsType.MQTT_BASIC) { - const parsedValue = JSON.parse(credentials.credentialsValue); - this.basicFormGroup.get('thingsboard.security.type').setValue(SecurityTypes.USERNAME_PASSWORD, {emitEvent: false}); - this.basicFormGroup.get('thingsboard.security.clientId').setValue(parsedValue.clientId, {emitEvent: false}); - this.basicFormGroup.get('thingsboard.security.username').setValue(parsedValue.userName, {emitEvent: false}); - this.basicFormGroup.get('thingsboard.security.password') - .setValue(parsedValue.password, {emitEvent: false}); - } else if (credentials.credentialsType === DeviceCredentialsType.X509_CERTIFICATE) { - //if sertificate is present set sertificate as present - } - }); + private addAccessTokenValidators(group: FormGroup): void { + group.get('accessToken').addValidators([Validators.required, Validators.pattern(/^[^.\s]+$/)]); + group.get('accessToken').updateValueAndValidity(); + } + + private addTlsPrivateKeyValidators(group: FormGroup): void { + ['caCert', 'privateKey', 'cert'].forEach(field => { + group.get(field).addValidators([Validators.required]); + group.get(field).updateValueAndValidity(); + }); + } + + private addTlsAccessTokenValidators(group: FormGroup): void { + this.addAccessTokenValidators(group); + group.get('caCert').addValidators([Validators.required]); + group.get('caCert').updateValueAndValidity(); + } + + private addMemoryStorageValidators(group: FormGroup): void { + group.get('read_records_count').addValidators([Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]); + group.get('max_records_count').addValidators([Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]); + group.get('read_records_count').updateValueAndValidity({ emitEvent: false }); + group.get('max_records_count').updateValueAndValidity({ emitEvent: false }); + } + + private addFileStorageValidators(group: FormGroup): void { + ['data_folder_path', 'max_file_count', 'max_read_records_count', 'max_records_per_file'].forEach(field => { + group.get(field).addValidators([Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]); + group.get(field).updateValueAndValidity({ emitEvent: false }); + }); + } + + private addSqliteStorageValidators(group: FormGroup): void { + ['data_file_path', 'messages_ttl_check_in_hours', 'messages_ttl_in_days'].forEach(field => { + group.get(field).addValidators([Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]); + group.get(field).updateValueAndValidity({ emitEvent: false }); + }); + } + + private checkAndFetchCredentials(security: GatewayConfigSecurity): void { + if (security.type === SecurityTypes.TLS_PRIVATE_KEY) { + return; + } + + this.deviceService.getDeviceCredentials(this.device.id).pipe(takeUntil(this.destroy$)).subscribe(credentials => { + this.initialCredentialsUpdated.emit(credentials); + this.updateSecurityType(security, credentials); + this.updateCredentials(credentials, security); + }); + } + + private updateSecurityType(security, credentials: DeviceCredentials): void { + const isAccessToken = credentials.credentialsType === DeviceCredentialsType.ACCESS_TOKEN + || security.type === SecurityTypes.TLS_ACCESS_TOKEN; + const securityType = isAccessToken + ? (security.type === SecurityTypes.TLS_ACCESS_TOKEN ? SecurityTypes.TLS_ACCESS_TOKEN : SecurityTypes.ACCESS_TOKEN) + : (credentials.credentialsType === DeviceCredentialsType.MQTT_BASIC ? SecurityTypes.USERNAME_PASSWORD : null); + + if (securityType) { + this.basicFormGroup.get('thingsboard.security.type').setValue(securityType, { emitEvent: false }); } } + + private updateCredentials(credentials: DeviceCredentials, security: GatewayConfigSecurity): void { + switch (credentials.credentialsType) { + case DeviceCredentialsType.ACCESS_TOKEN: + this.updateAccessTokenCredentials(credentials, security); + break; + case DeviceCredentialsType.MQTT_BASIC: + this.updateMqttBasicCredentials(credentials); + break; + case DeviceCredentialsType.X509_CERTIFICATE: + break; + } + } + + private updateAccessTokenCredentials(credentials: DeviceCredentials, security: GatewayConfigSecurity): void { + this.basicFormGroup.get('thingsboard.security.accessToken').setValue(credentials.credentialsId, { emitEvent: false }); + if (security.type === SecurityTypes.TLS_ACCESS_TOKEN) { + this.basicFormGroup.get('thingsboard.security.caCert').setValue(security.caCert, { emitEvent: false }); + } + } + + private updateMqttBasicCredentials(credentials: DeviceCredentials): void { + const parsedValue = JSON.parse(credentials.credentialsValue); + this.basicFormGroup.get('thingsboard.security.clientId').setValue(parsedValue.clientId, { emitEvent: false }); + this.basicFormGroup.get('thingsboard.security.username').setValue(parsedValue.userName, { emitEvent: false }); + this.basicFormGroup.get('thingsboard.security.password').setValue(parsedValue.password, { emitEvent: false }); + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/gateway-configuration.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/gateway-configuration.component.ts index 317b616110..056628dd6a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/gateway-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/gateway-configuration.component.ts @@ -69,8 +69,8 @@ export class GatewayConfigurationComponent implements AfterViewInit, OnDestroy { constructor(private fb: FormBuilder, private attributeService: AttributeService, private deviceService: DeviceService, - private cd: ChangeDetectorRef, - private dialog: MatDialog) { + private cd: ChangeDetectorRef + ) { this.gatewayConfigGroup = this.fb.group({ basicConfig: [], @@ -361,7 +361,7 @@ export class GatewayConfigurationComponent implements AfterViewInit, OnDestroy { } private updateFormControls(thingsboard: GatewayGeneralConfig): void { - const { type, accessToken, ...securityConfig } = thingsboard.security || {}; + const { type, accessToken, ...securityConfig } = thingsboard.security ?? {}; this.initialCredentials = { deviceId: this.device as DeviceId, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts index a23d8e7900..bfdd46997e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts @@ -16,7 +16,9 @@ import { ConfigurationModes, - GatewayConnector, LocalLogsConfigs, LogSavingPeriod, + GatewayConnector, + LocalLogsConfigs, + LogSavingPeriod, SecurityTypes, StorageTypes } from '@home/components/widget/lib/gateway/gateway-widget.models'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table/device-info-table.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table/device-info-table.component.ts index 569f40b185..91432b7353 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table/device-info-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/device-info-table/device-info-table.component.ts @@ -42,8 +42,8 @@ import { import { DeviceInfoType, noLeadTrailSpacesRegex, - OPCUaSourceTypes, - SourceTypes, + OPCUaSourceType, + SourceType, SourceTypeTranslationsMap } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { coerceBoolean } from '@shared/decorators/coercion'; @@ -81,7 +81,7 @@ export class DeviceInfoTableComponent extends PageComponent implements ControlVa required = false; @Input() - sourceTypes: Array<SourceTypes | OPCUaSourceTypes> = Object.values(SourceTypes); + sourceTypes: Array<SourceType | OPCUaSourceType> = Object.values(SourceType); deviceInfoTypeValue: any; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.ts index 7867a7213f..de289dde2e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.ts @@ -42,7 +42,7 @@ import { MappingValueType, mappingValueTypesMap, noLeadTrailSpacesRegex, - OPCUaSourceTypes, + OPCUaSourceType, RpcMethodsMapping, } from '@home/components/widget/lib/gateway/gateway-widget.models'; @@ -73,7 +73,7 @@ export class MappingDataKeysPanelComponent extends PageComponent implements OnIn keysType: MappingKeysType; @Input() - valueTypeKeys: Array<MappingValueType | OPCUaSourceTypes> = Object.values(MappingValueType); + valueTypeKeys: Array<MappingValueType | OPCUaSourceType> = Object.values(MappingValueType); @Input() valueTypeEnum = MappingValueType; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component.ts index 05dcfa88ba..fa8dfa6466 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component.ts @@ -40,17 +40,21 @@ import { Validator, } from '@angular/forms'; import { + AttributeUpdate, ConnectorMapping, + ConnectRequest, ConverterConnectorMapping, ConvertorTypeTranslationsMap, DeviceConnectorMapping, + DisconnectRequest, MappingInfo, MappingType, MappingTypeTranslationsMap, MappingValue, - RequestMappingData, + RequestMappingValue, RequestType, - RequestTypesTranslationsMap + RequestTypesTranslationsMap, + ServerSideRpc } from '@home/components/widget/lib/gateway/gateway-widget.models'; import { MappingDialogComponent } from '@home/components/widget/lib/gateway/dialog/mapping-dialog.component'; import { isDefinedAndNotNull, isUndefinedOrNull } from '@core/utils'; @@ -259,16 +263,17 @@ export class MappingTableComponent implements ControlValueAccessor, Validator, A }; case MappingType.REQUESTS: let details: string; - if ((value as RequestMappingData).requestType === RequestType.ATTRIBUTE_UPDATE) { - details = (value as RequestMappingData).requestValue.attributeFilter; - } else if ((value as RequestMappingData).requestType === RequestType.SERVER_SIDE_RPC) { - details = (value as RequestMappingData).requestValue.methodFilter; + const requestValue = value as RequestMappingValue; + if (requestValue.requestType === RequestType.ATTRIBUTE_UPDATE) { + details = (requestValue.requestValue as AttributeUpdate).attributeFilter; + } else if (requestValue.requestType === RequestType.SERVER_SIDE_RPC) { + details = (requestValue.requestValue as ServerSideRpc).methodFilter; } else { - details = (value as RequestMappingData).requestValue.topicFilter; + details = (requestValue.requestValue as ConnectRequest | DisconnectRequest).topicFilter; } return { - requestType: (value as RequestMappingData).requestType, - type: this.translate.instant(RequestTypesTranslationsMap.get((value as RequestMappingData).requestType)), + requestType: (value as RequestMappingValue).requestType, + type: this.translate.instant(RequestTypesTranslationsMap.get((value as RequestMappingValue).requestType)), details }; case MappingType.OPCUA: diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract.ts new file mode 100644 index 0000000000..9e7be382d2 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract.ts @@ -0,0 +1,81 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Directive } from '@angular/core'; +import { FormControl, FormGroup, ValidationErrors } from '@angular/forms'; +import { takeUntil } from 'rxjs/operators'; +import { isEqual } from '@core/utils'; +import { GatewayConnectorBasicConfigDirective } from '@home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract'; +import { + ModbusBasicConfig, + ModbusBasicConfig_v3_5_2, +} from '@home/components/widget/lib/gateway/gateway-widget.models'; + +@Directive() +export abstract class ModbusBasicConfigDirective<BasicConfig> + extends GatewayConnectorBasicConfigDirective<ModbusBasicConfig_v3_5_2, BasicConfig> { + + enableSlaveControl: FormControl<boolean> = new FormControl(false); + + constructor() { + super(); + + this.enableSlaveControl.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe(enable => { + this.updateSlaveEnabling(enable); + this.basicFormGroup.get('slave').updateValueAndValidity({ emitEvent: !!this.onChange }); + }); + } + + override writeValue(basicConfig: BasicConfig & ModbusBasicConfig): void { + super.writeValue(basicConfig); + this.onEnableSlaveControl(basicConfig); + } + + override validate(): ValidationErrors | null { + const { master, slave } = this.basicFormGroup.value; + const isEmpty = !master?.slaves?.length && (isEqual(slave, {}) || !slave); + if (!this.basicFormGroup.valid || isEmpty) { + return { basicFormGroup: { valid: false } }; + } + return null; + } + + protected override initBasicFormGroup(): FormGroup { + return this.fb.group({ + master: [], + slave: [], + }); + } + + protected override onBasicFormGroupChange(value: ModbusBasicConfig_v3_5_2): void { + super.onBasicFormGroupChange(value); + this.basicFormGroup.get('slave').updateValueAndValidity({ emitEvent: !!this.onChange }); + } + + private updateSlaveEnabling(isEnabled: boolean): void { + if (isEnabled) { + this.basicFormGroup.get('slave').enable({ emitEvent: false }); + } else { + this.basicFormGroup.get('slave').disable({ emitEvent: false }); + } + } + + private onEnableSlaveControl(basicConfig: ModbusBasicConfig): void { + this.enableSlaveControl.setValue(!!basicConfig.slave && !isEqual(basicConfig.slave, {})); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component.ts index aa0424da93..21c37ed147 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component.ts @@ -14,28 +14,21 @@ /// limitations under the License. /// -import { ChangeDetectionStrategy, Component, forwardRef, Input, OnDestroy, TemplateRef } from '@angular/core'; +import { ChangeDetectionStrategy, Component, forwardRef } from '@angular/core'; +import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; import { - ControlValueAccessor, - FormBuilder, - FormControl, - FormGroup, - NG_VALIDATORS, - NG_VALUE_ACCESSOR, - UntypedFormControl, - ValidationErrors, - Validator, -} from '@angular/forms'; -import { ModbusBasicConfig } from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { SharedModule } from '@shared/shared.module'; + ModbusBasicConfig_v3_5_2, + ModbusMasterConfig, + ModbusSlave +} from '@home/components/widget/lib/gateway/gateway-widget.models'; import { CommonModule } from '@angular/common'; -import { takeUntil } from 'rxjs/operators'; -import { Subject } from 'rxjs'; - -import { EllipsisChipListDirective } from '@shared/directives/ellipsis-chip-list.directive'; +import { SharedModule } from '@shared/shared.module'; import { ModbusSlaveConfigComponent } from '../modbus-slave-config/modbus-slave-config.component'; import { ModbusMasterTableComponent } from '../modbus-master-table/modbus-master-table.component'; -import { isEqual } from '@core/utils'; +import { EllipsisChipListDirective } from '@shared/directives/ellipsis-chip-list.directive'; +import { + ModbusBasicConfigDirective +} from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract'; @Component({ selector: 'tb-modbus-basic-config', @@ -63,80 +56,19 @@ import { isEqual } from '@core/utils'; ], styleUrls: ['./modbus-basic-config.component.scss'], }) +export class ModbusBasicConfigComponent extends ModbusBasicConfigDirective<ModbusBasicConfig_v3_5_2> { -export class ModbusBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { - - @Input() generalTabContent: TemplateRef<any>; - - basicFormGroup: FormGroup; - enableSlaveControl: FormControl<boolean>; - - onChange: (value: ModbusBasicConfig) => void; - onTouched: () => void; - - private destroy$ = new Subject<void>(); - - constructor(private fb: FormBuilder) { - this.basicFormGroup = this.fb.group({ - master: [], - slave: [], - }); - this.enableSlaveControl = new FormControl(false); - - this.basicFormGroup.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(({ master, slave }) => { - this.onChange({ master, slave: slave ?? {} }); - this.onTouched(); - }); - - this.enableSlaveControl.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(enable => { - this.updateSlaveEnabling(enable); - this.basicFormGroup.get('slave').updateValueAndValidity({emitEvent: !!this.onChange}); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - registerOnChange(fn: (value: ModbusBasicConfig) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - writeValue(basicConfig: ModbusBasicConfig): void { - const editedBase = { - slave: basicConfig.slave ?? {}, - master: basicConfig.master ?? {}, + protected override mapConfigToFormValue(config: ModbusBasicConfig_v3_5_2): ModbusBasicConfig_v3_5_2 { + return { + master: config.master ?? {} as ModbusMasterConfig, + slave: config.slave ?? {} as ModbusSlave, }; - - this.basicFormGroup.setValue(editedBase, {emitEvent: false}); - this.enableSlaveControl.setValue(!!basicConfig.slave && !isEqual(basicConfig.slave, {})); - } - - validate(basicFormControl: UntypedFormControl): ValidationErrors | null { - const { master, slave } = basicFormControl.value; - const isEmpty = !master?.slaves?.length && (isEqual(slave, {}) || !slave); - if (!this.basicFormGroup.valid || isEmpty) { - return { - basicFormGroup: {valid: false} - }; - } - return null; } - private updateSlaveEnabling(isEnabled: boolean): void { - if (isEnabled) { - this.basicFormGroup.get('slave').enable({emitEvent: false}); - } else { - this.basicFormGroup.get('slave').disable({emitEvent: false}); - } + protected override getMappedValue(value: ModbusBasicConfig_v3_5_2): ModbusBasicConfig_v3_5_2 { + return { + master: value.master, + slave: value.slave, + }; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component.ts new file mode 100644 index 0000000000..50f7d833fa --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component.ts @@ -0,0 +1,76 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ChangeDetectionStrategy, Component, forwardRef } from '@angular/core'; +import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { + ModbusBasicConfig_v3_5_2, + ModbusLegacyBasicConfig, ModbusLegacySlave, + ModbusMasterConfig, + ModbusSlave +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { ModbusSlaveConfigComponent } from '../modbus-slave-config/modbus-slave-config.component'; +import { ModbusMasterTableComponent } from '../modbus-master-table/modbus-master-table.component'; +import { EllipsisChipListDirective } from '@shared/directives/ellipsis-chip-list.directive'; +import { ModbusVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/modbus-version-mapping.util'; +import { + ModbusBasicConfigDirective +} from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.abstract'; + +@Component({ + selector: 'tb-modbus-legacy-basic-config', + templateUrl: './modbus-basic-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ModbusLegacyBasicConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => ModbusLegacyBasicConfigComponent), + multi: true + } + ], + standalone: true, + imports: [ + CommonModule, + SharedModule, + ModbusSlaveConfigComponent, + ModbusMasterTableComponent, + EllipsisChipListDirective, + ], + styleUrls: ['./modbus-basic-config.component.scss'], +}) +export class ModbusLegacyBasicConfigComponent extends ModbusBasicConfigDirective<ModbusLegacyBasicConfig> { + + protected override mapConfigToFormValue(config: ModbusLegacyBasicConfig): ModbusBasicConfig_v3_5_2 { + return { + master: config.master ? ModbusVersionMappingUtil.mapMasterToUpgradedVersion(config.master) : {} as ModbusMasterConfig, + slave: config.slave ? ModbusVersionMappingUtil.mapSlaveToUpgradedVersion(config.slave) : {} as ModbusSlave, + }; + } + + protected override getMappedValue(value: ModbusBasicConfig_v3_5_2): ModbusLegacyBasicConfig { + return { + master: value.master, + slave: value.slave ? ModbusVersionMappingUtil.mapSlaveToDowngradedVersion(value.slave) : {} as ModbusLegacySlave, + }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.ts deleted file mode 100644 index 25f8671201..0000000000 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.ts +++ /dev/null @@ -1,191 +0,0 @@ -/// -/// Copyright © 2016-2024 The Thingsboard Authors -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// - -import { ChangeDetectionStrategy, Component, forwardRef, Input, OnDestroy, TemplateRef } from '@angular/core'; -import { - ControlValueAccessor, - FormBuilder, - FormGroup, - NG_VALIDATORS, - NG_VALUE_ACCESSOR, - ValidationErrors, - Validator, -} from '@angular/forms'; -import { - MappingType, - MQTTBasicConfig, - RequestMappingData, - RequestType, -} from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { SharedModule } from '@shared/shared.module'; -import { CommonModule } from '@angular/common'; -import { takeUntil } from 'rxjs/operators'; -import { Subject } from 'rxjs'; -import { isObject } from 'lodash'; -import { - SecurityConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; -import { - WorkersConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; -import { - BrokerConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component'; -import { - MappingTableComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; -import { isDefinedAndNotNull } from '@core/utils'; - -@Component({ - selector: 'tb-mqtt-basic-config', - templateUrl: './mqtt-basic-config.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MqttBasicConfigComponent), - multi: true - }, - { - provide: NG_VALIDATORS, - useExisting: forwardRef(() => MqttBasicConfigComponent), - multi: true - } - ], - standalone: true, - imports: [ - CommonModule, - SharedModule, - SecurityConfigComponent, - WorkersConfigControlComponent, - BrokerConfigControlComponent, - MappingTableComponent, - ], - styleUrls: ['./mqtt-basic-config.component.scss'] -}) - -export class MqttBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { - - @Input() - generalTabContent: TemplateRef<any>; - - mappingTypes = MappingType; - basicFormGroup: FormGroup; - - private onChange: (value: MQTTBasicConfig) => void; - private onTouched: () => void; - - private destroy$ = new Subject<void>(); - - constructor(private fb: FormBuilder) { - this.basicFormGroup = this.fb.group({ - dataMapping: [], - requestsMapping: [], - broker: [], - workers: [], - }); - - this.basicFormGroup.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(value => { - this.onChange(this.getMappedMQTTConfig(value)); - this.onTouched(); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - registerOnChange(fn: (value: MQTTBasicConfig) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - writeValue(basicConfig: MQTTBasicConfig): void { - const { broker, dataMapping = [], requestsMapping } = basicConfig; - const editedBase = { - workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { - maxNumberOfWorkers: broker.maxNumberOfWorkers, - maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, - } : {}, - dataMapping: dataMapping || [], - broker: broker || {}, - requestsMapping: Array.isArray(requestsMapping) - ? requestsMapping - : this.getRequestDataArray(requestsMapping), - }; - - this.basicFormGroup.setValue(editedBase, {emitEvent: false}); - } - - private getMappedMQTTConfig(basicConfig: MQTTBasicConfig): MQTTBasicConfig { - let { broker, workers, dataMapping, requestsMapping } = basicConfig || {}; - - if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { - broker = { - ...broker, - ...workers, - }; - } - - if ((requestsMapping as RequestMappingData[])?.length) { - requestsMapping = this.getRequestDataObject(requestsMapping as RequestMappingData[]); - } - - return { broker, workers, dataMapping, requestsMapping }; - } - - validate(): ValidationErrors | null { - return this.basicFormGroup.valid ? null : { - basicFormGroup: {valid: false} - }; - } - - private getRequestDataArray(value: Record<RequestType, RequestMappingData[]>): RequestMappingData[] { - const mappingConfigs = []; - - if (isObject(value)) { - Object.keys(value).forEach((configKey: string) => { - for (const mapping of value[configKey]) { - mappingConfigs.push({ - requestType: configKey, - requestValue: mapping - }); - } - }); - } - - return mappingConfigs; - } - - private getRequestDataObject(array: RequestMappingData[]): Record<RequestType, RequestMappingData[]> { - return array.reduce((result, { requestType, requestValue }) => { - result[requestType].push(requestValue); - return result; - }, { - connectRequests: [], - disconnectRequests: [], - attributeRequests: [], - attributeUpdates: [], - serverSideRpc: [], - }); - } -} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts new file mode 100644 index 0000000000..ce87d80a75 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract.ts @@ -0,0 +1,82 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Directive } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { + MappingType, + MQTTBasicConfig, MQTTBasicConfig_v3_5_2, + RequestMappingData, + RequestMappingValue, + RequestType +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { isObject } from '@core/utils'; +import { + GatewayConnectorBasicConfigDirective +} from '@home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract'; + +@Directive() +export abstract class MqttBasicConfigDirective<BasicConfig> + extends GatewayConnectorBasicConfigDirective<MQTTBasicConfig_v3_5_2, BasicConfig> { + + MappingType = MappingType; + + protected override initBasicFormGroup(): FormGroup { + return this.fb.group({ + mapping: [], + requestsMapping: [], + broker: [], + workers: [], + }); + } + + protected getRequestDataArray(value: Record<RequestType, RequestMappingData[]>): RequestMappingData[] { + const mappingConfigs = []; + + if (isObject(value)) { + Object.keys(value).forEach((configKey: string) => { + for (const mapping of value[configKey]) { + mappingConfigs.push({ + requestType: configKey, + requestValue: mapping + }); + } + }); + } + + return mappingConfigs; + } + + protected getRequestDataObject(array: RequestMappingValue[]): Record<RequestType, RequestMappingValue[]> { + return array.reduce((result, { requestType, requestValue }) => { + result[requestType].push(requestValue); + return result; + }, { + connectRequests: [], + disconnectRequests: [], + attributeRequests: [], + attributeUpdates: [], + serverSideRpc: [], + }); + } + + writeValue(basicConfig: BasicConfig): void { + this.basicFormGroup.setValue(this.mapConfigToFormValue(basicConfig), { emitEvent: false }); + } + + protected abstract override mapConfigToFormValue(config: BasicConfig): MQTTBasicConfig_v3_5_2; + protected abstract override getMappedValue(config: MQTTBasicConfig): BasicConfig; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html similarity index 90% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html index 9849923218..b602ba20d4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.html @@ -24,12 +24,12 @@ </mat-tab> <mat-tab label="{{ 'gateway.data-mapping' | translate }}*"> <div class="tb-form-panel no-border no-padding padding-top tb-flex fill-height"> - <tb-mapping-table formControlName="dataMapping" [required]="true" [mappingType]="mappingTypes.DATA"></tb-mapping-table> + <tb-mapping-table formControlName="mapping" [required]="true" [mappingType]="MappingType.DATA"></tb-mapping-table> </div> </mat-tab> <mat-tab label="{{ 'gateway.requests-mapping' | translate }}"> <div class="tb-form-panel no-border no-padding padding-top tb-flex fill-height"> - <tb-mapping-table formControlName="requestsMapping" [mappingType]="mappingTypes.REQUESTS"></tb-mapping-table> + <tb-mapping-table formControlName="requestsMapping" [mappingType]="MappingType.REQUESTS"></tb-mapping-table> </div> </mat-tab> <mat-tab label="{{ 'gateway.workers-settings' | translate }}"> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts new file mode 100644 index 0000000000..9af627352a --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component.ts @@ -0,0 +1,103 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, ChangeDetectionStrategy } from '@angular/core'; +import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; +import { + BrokerConfig, + MQTTBasicConfig_v3_5_2, + RequestMappingData, + RequestMappingValue, + RequestType, WorkersConfig +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { + MqttBasicConfigDirective +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract'; +import { isDefinedAndNotNull } from '@core/utils'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { + SecurityConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; +import { + WorkersConfigControlComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component'; +import { + BrokerConfigControlComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component'; +import { + MappingTableComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; + +@Component({ + selector: 'tb-mqtt-basic-config', + templateUrl: './mqtt-basic-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MqttBasicConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => MqttBasicConfigComponent), + multi: true + } + ], + styleUrls: ['./mqtt-basic-config.component.scss'], + standalone: true, + imports: [ + CommonModule, + SharedModule, + SecurityConfigComponent, + WorkersConfigControlComponent, + BrokerConfigControlComponent, + MappingTableComponent, + ], +}) +export class MqttBasicConfigComponent extends MqttBasicConfigDirective<MQTTBasicConfig_v3_5_2> { + + protected override mapConfigToFormValue(basicConfig: MQTTBasicConfig_v3_5_2): MQTTBasicConfig_v3_5_2 { + const { broker, mapping = [], requestsMapping } = basicConfig; + return{ + workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { + maxNumberOfWorkers: broker.maxNumberOfWorkers, + maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, + } : {} as WorkersConfig, + mapping: mapping ?? [], + broker: broker ?? {} as BrokerConfig, + requestsMapping: this.getRequestDataArray(requestsMapping as Record<RequestType, RequestMappingData[]>), + }; + } + + protected override getMappedValue(basicConfig: MQTTBasicConfig_v3_5_2): MQTTBasicConfig_v3_5_2 { + let { broker, workers, mapping, requestsMapping } = basicConfig || {}; + + if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { + broker = { + ...broker, + ...workers, + }; + } + + if ((requestsMapping as RequestMappingData[])?.length) { + requestsMapping = this.getRequestDataObject(requestsMapping as RequestMappingValue[]); + } + + return { broker, mapping, requestsMapping }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts new file mode 100644 index 0000000000..e4577c653e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component.ts @@ -0,0 +1,124 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, ChangeDetectionStrategy } from '@angular/core'; +import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; +import { + BrokerConfig, + MQTTBasicConfig_v3_5_2, + MQTTLegacyBasicConfig, + RequestMappingData, + RequestMappingValue, + RequestType, WorkersConfig +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { MqttVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/mqtt-version-mapping.util'; +import { + MqttBasicConfigDirective +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.abstract'; +import { isDefinedAndNotNull } from '@core/utils'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { + SecurityConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; +import { + WorkersConfigControlComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component'; +import { + BrokerConfigControlComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component'; +import { + MappingTableComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; + +@Component({ + selector: 'tb-mqtt-legacy-basic-config', + templateUrl: './mqtt-basic-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MqttLegacyBasicConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => MqttLegacyBasicConfigComponent), + multi: true + } + ], + styleUrls: ['./mqtt-basic-config.component.scss'], + standalone: true, + imports: [ + CommonModule, + SharedModule, + SecurityConfigComponent, + WorkersConfigControlComponent, + BrokerConfigControlComponent, + MappingTableComponent, + ], +}) +export class MqttLegacyBasicConfigComponent extends MqttBasicConfigDirective<MQTTLegacyBasicConfig> { + + protected override mapConfigToFormValue(config: MQTTLegacyBasicConfig): MQTTBasicConfig_v3_5_2 { + const { + broker, + mapping = [], + connectRequests = [], + disconnectRequests = [], + attributeRequests = [], + attributeUpdates = [], + serverSideRpc = [] + } = config as MQTTLegacyBasicConfig; + const updatedRequestMapping = MqttVersionMappingUtil.mapRequestsToUpgradedVersion({ + connectRequests, + disconnectRequests, + attributeRequests, + attributeUpdates, + serverSideRpc + }); + return { + workers: broker && (broker.maxNumberOfWorkers || broker.maxMessageNumberPerWorker) ? { + maxNumberOfWorkers: broker.maxNumberOfWorkers, + maxMessageNumberPerWorker: broker.maxMessageNumberPerWorker, + } : {} as WorkersConfig, + mapping: MqttVersionMappingUtil.mapMappingToUpgradedVersion(mapping) || [], + broker: broker || {} as BrokerConfig, + requestsMapping: this.getRequestDataArray(updatedRequestMapping), + }; + } + + protected override getMappedValue(basicConfig: MQTTBasicConfig_v3_5_2): MQTTLegacyBasicConfig { + let { broker, workers, mapping, requestsMapping } = basicConfig || {}; + + if (isDefinedAndNotNull(workers.maxNumberOfWorkers) || isDefinedAndNotNull(workers.maxMessageNumberPerWorker)) { + broker = { + ...broker, + ...workers, + }; + } + + if ((requestsMapping as RequestMappingData[])?.length) { + requestsMapping = this.getRequestDataObject(requestsMapping as RequestMappingValue[]); + } + + return { + broker, + mapping: MqttVersionMappingUtil.mapMappingToDowngradedVersion(mapping), + ...(MqttVersionMappingUtil.mapRequestsToDowngradedVersion(requestsMapping as Record<RequestType, RequestMappingData[]>)) + }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.ts similarity index 97% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.ts index e44506dccc..61c62a49e1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component.ts @@ -36,7 +36,7 @@ import { CommonModule } from '@angular/common'; import { generateSecret } from '@core/utils'; import { Subject } from 'rxjs'; import { GatewayPortTooltipPipe } from '@home/components/widget/lib/gateway/pipes/gateway-port-tooltip.pipe'; -import { SecurityConfigComponent } from '../security-config/security-config.component'; +import { SecurityConfigComponent } from '../../security-config/security-config.component'; @Component({ selector: 'tb-broker-config-control', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts deleted file mode 100644 index 39198c9696..0000000000 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.ts +++ /dev/null @@ -1,134 +0,0 @@ -/// -/// Copyright © 2016-2024 The Thingsboard Authors -/// -/// Licensed under the Apache License, Version 2.0 (the "License"); -/// you may not use this file except in compliance with the License. -/// You may obtain a copy of the License at -/// -/// http://www.apache.org/licenses/LICENSE-2.0 -/// -/// Unless required by applicable law or agreed to in writing, software -/// distributed under the License is distributed on an "AS IS" BASIS, -/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -/// See the License for the specific language governing permissions and -/// limitations under the License. -/// - -import { ChangeDetectionStrategy, Component, forwardRef, Input, OnDestroy, TemplateRef } from '@angular/core'; -import { - ControlValueAccessor, - FormBuilder, - FormGroup, - NG_VALIDATORS, - NG_VALUE_ACCESSOR, - ValidationErrors, - Validator, -} from '@angular/forms'; -import { - ConnectorType, - MappingType, - OPCBasicConfig, -} from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { SharedModule } from '@shared/shared.module'; -import { CommonModule } from '@angular/common'; -import { takeUntil } from 'rxjs/operators'; -import { Subject } from 'rxjs'; -import { - SecurityConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; -import { - WorkersConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; -import { - BrokerConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component'; -import { - MappingTableComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; -import { - OpcServerConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component'; - -@Component({ - selector: 'tb-opc-ua-basic-config', - templateUrl: './opc-ua-basic-config.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => OpcUaBasicConfigComponent), - multi: true - }, - { - provide: NG_VALIDATORS, - useExisting: forwardRef(() => OpcUaBasicConfigComponent), - multi: true - } - ], - standalone: true, - imports: [ - CommonModule, - SharedModule, - SecurityConfigComponent, - WorkersConfigControlComponent, - BrokerConfigControlComponent, - MappingTableComponent, - OpcServerConfigComponent, - ], - styleUrls: ['./opc-ua-basic-config.component.scss'] -}) - -export class OpcUaBasicConfigComponent implements ControlValueAccessor, Validator, OnDestroy { - @Input() generalTabContent: TemplateRef<any>; - - mappingTypes = MappingType; - basicFormGroup: FormGroup; - - onChange!: (value: string) => void; - onTouched!: () => void; - - protected readonly connectorType = ConnectorType; - private destroy$ = new Subject<void>(); - - constructor(private fb: FormBuilder) { - this.basicFormGroup = this.fb.group({ - mapping: [], - server: [], - }); - - this.basicFormGroup.valueChanges - .pipe(takeUntil(this.destroy$)) - .subscribe(value => { - this.onChange(value); - this.onTouched(); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - registerOnChange(fn: (value: string) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - writeValue(basicConfig: OPCBasicConfig): void { - const editedBase = { - server: basicConfig.server || {}, - mapping: basicConfig.mapping || [], - }; - - this.basicFormGroup.setValue(editedBase, {emitEvent: false}); - } - - validate(): ValidationErrors | null { - return this.basicFormGroup.valid ? null : { - basicFormGroup: {valid: false} - }; - } -} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.html similarity index 98% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.html index 584679fa2c..523705d029 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.html @@ -84,7 +84,7 @@ </mat-form-field> </div> </div> - <div class="tb-form-row column-xs" fxLayoutAlign="space-between center"> + <div *ngIf="!hideNewFields" class="tb-form-row column-xs" fxLayoutAlign="space-between center"> <div class="fixed-title-width" tb-hint-tooltip-icon="{{ 'gateway.hints.poll-period' | translate }}"> <div tbTruncateWithTooltip>{{ 'gateway.poll-period' | translate }}</div> </div> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.ts similarity index 90% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.ts index c838121b76..c000139ded 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectionStrategy, Component, forwardRef, OnDestroy } from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, Component, forwardRef, Input, OnDestroy } from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -39,6 +39,7 @@ import { SecurityConfigComponent } from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; import { HOUR } from '@shared/models/time/time.models'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-opc-server-config', @@ -64,7 +65,11 @@ import { HOUR } from '@shared/models/time/time.models'; SecurityConfigComponent, ] }) -export class OpcServerConfigComponent implements ControlValueAccessor, Validator, OnDestroy { +export class OpcServerConfigComponent implements ControlValueAccessor, Validator, AfterViewInit, OnDestroy { + + @Input() + @coerceBoolean() + hideNewFields: boolean = false; securityPolicyTypes = SecurityPolicyTypes; serverConfigFormGroup: UntypedFormGroup; @@ -95,6 +100,12 @@ export class OpcServerConfigComponent implements ControlValueAccessor, Validator }); } + ngAfterViewInit(): void { + if (this.hideNewFields) { + this.serverConfigFormGroup.get('pollPeriodInMillis').disable({emitEvent: false}); + } + } + ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.html similarity index 92% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.html index 5f8b25af9d..2296a472a4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.html @@ -20,7 +20,7 @@ <ng-container [ngTemplateOutlet]="generalTabContent"></ng-container> </mat-tab> <mat-tab label="{{ 'gateway.server' | translate }}*"> - <tb-opc-server-config formControlName="server"></tb-opc-server-config> + <tb-opc-server-config formControlName="server" [hideNewFields]="isLegacy"></tb-opc-server-config> </mat-tab> <mat-tab label="{{ 'gateway.data-mapping' | translate }}*"> <div class="tb-form-panel no-border no-padding padding-top tb-flex fill-height"> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts new file mode 100644 index 0000000000..c45eafcc67 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component.ts @@ -0,0 +1,88 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ChangeDetectionStrategy, Component, forwardRef } from '@angular/core'; +import { FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { + MappingType, + OPCBasicConfig_v3_5_2, + ServerConfig +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { MappingTableComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; +import { + SecurityConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; +import { + OpcServerConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component'; +import { + GatewayConnectorBasicConfigDirective +} from '@home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract'; + +@Component({ + selector: 'tb-opc-ua-basic-config', + templateUrl: './opc-ua-basic-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => OpcUaBasicConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => OpcUaBasicConfigComponent), + multi: true + } + ], + standalone: true, + imports: [ + CommonModule, + SharedModule, + SecurityConfigComponent, + MappingTableComponent, + OpcServerConfigComponent, + ], + styleUrls: ['./opc-ua-basic-config.component.scss'] +}) +export class OpcUaBasicConfigComponent extends GatewayConnectorBasicConfigDirective<OPCBasicConfig_v3_5_2, OPCBasicConfig_v3_5_2> { + + mappingTypes = MappingType; + isLegacy = false; + + protected override initBasicFormGroup(): FormGroup { + return this.fb.group({ + mapping: [], + server: [], + }); + } + + protected override mapConfigToFormValue(config: OPCBasicConfig_v3_5_2): OPCBasicConfig_v3_5_2 { + return { + server: config.server ?? {} as ServerConfig, + mapping: config.mapping ?? [], + }; + } + + protected override getMappedValue(value: OPCBasicConfig_v3_5_2): OPCBasicConfig_v3_5_2 { + return { + server: value.server, + mapping: value.mapping, + }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts new file mode 100644 index 0000000000..9458858cbf --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component.ts @@ -0,0 +1,88 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ChangeDetectionStrategy, Component, forwardRef } from '@angular/core'; +import { FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { + MappingType, + OPCBasicConfig_v3_5_2, + OPCLegacyBasicConfig, ServerConfig, +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { MappingTableComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; +import { + SecurityConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/security-config/security-config.component'; +import { + OpcServerConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component'; +import { + GatewayConnectorBasicConfigDirective +} from '@home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract'; +import { OpcVersionMappingUtil } from '@home/components/widget/lib/gateway/utils/opc-version-mapping.util'; + +@Component({ + selector: 'tb-opc-ua-legacy-basic-config', + templateUrl: './opc-ua-basic-config.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => OpcUaLegacyBasicConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => OpcUaLegacyBasicConfigComponent), + multi: true + } + ], + standalone: true, + imports: [ + CommonModule, + SharedModule, + SecurityConfigComponent, + MappingTableComponent, + OpcServerConfigComponent, + ], + styleUrls: ['./opc-ua-basic-config.component.scss'] +}) +export class OpcUaLegacyBasicConfigComponent extends GatewayConnectorBasicConfigDirective<OPCBasicConfig_v3_5_2, OPCLegacyBasicConfig> { + + mappingTypes = MappingType; + isLegacy = true; + + protected override initBasicFormGroup(): FormGroup { + return this.fb.group({ + mapping: [], + server: [], + }); + } + + protected override mapConfigToFormValue(config: OPCLegacyBasicConfig): OPCBasicConfig_v3_5_2 { + return { + server: config.server ? OpcVersionMappingUtil.mapServerToUpgradedVersion(config.server) : {} as ServerConfig, + mapping: config.server?.mapping ? OpcVersionMappingUtil.mapMappingToUpgradedVersion(config.server.mapping) : [], + }; + } + + protected override getMappedValue(value: OPCBasicConfig_v3_5_2): OPCLegacyBasicConfig { + return { + server: OpcVersionMappingUtil.mapServerToDowngradedVersion(value), + }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts index eca1497d22..c8235cb697 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/add-connector-dialog.component.ts @@ -26,12 +26,14 @@ import { AddConnectorConfigData, ConnectorType, CreatedConnectorConfigData, + GatewayConnector, GatewayConnectorDefaultTypesTranslatesMap, GatewayLogLevel, - getDefaultConfig, + GatewayVersion, + GatewayVersionedDefaultConfig, noLeadTrailSpacesRegex } from '@home/components/widget/lib/gateway/gateway-widget.models'; -import { Subject } from 'rxjs'; +import { Observable, Subject } from 'rxjs'; import { ResourcesService } from '@core/services/resources.service'; import { takeUntil, tap } from 'rxjs/operators'; import { helpBaseUrl } from '@shared/models/constants'; @@ -42,7 +44,8 @@ import { helpBaseUrl } from '@shared/models/constants'; styleUrls: ['./add-connector-dialog.component.scss'], providers: [], }) -export class AddConnectorDialogComponent extends DialogComponent<AddConnectorDialogComponent, BaseData<HasId>> implements OnInit, OnDestroy { +export class AddConnectorDialogComponent + extends DialogComponent<AddConnectorDialogComponent, BaseData<HasId>> implements OnInit, OnDestroy { connectorForm: UntypedFormGroup; @@ -95,8 +98,15 @@ export class AddConnectorDialogComponent extends DialogComponent<AddConnectorDia this.submitted = true; const value = this.connectorForm.getRawValue(); if (value.useDefaults) { - getDefaultConfig(this.resourcesService, value.type).subscribe((defaultConfig) => { - value.configurationJson = defaultConfig; + this.getDefaultConfig(value.type).subscribe((defaultConfig: GatewayVersionedDefaultConfig) => { + const gatewayVersion = this.data.gatewayVersion; + if (gatewayVersion) { + value.configVersion = gatewayVersion; + } + value.configurationJson = (gatewayVersion === GatewayVersion.Current + ? defaultConfig[this.data.gatewayVersion] + : defaultConfig.legacy) + ?? defaultConfig; if (this.connectorForm.valid) { this.dialogRef.close(value); } @@ -130,4 +140,8 @@ export class AddConnectorDialogComponent extends DialogComponent<AddConnectorDia takeUntil(this.destroy$), ).subscribe(); } + + private getDefaultConfig(type: string): Observable<GatewayVersionedDefaultConfig | GatewayConnector> { + return this.resourcesService.loadJsonResource(`/assets/metadata/connector-default-configs/${type}.json`); + }; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts index 9e5a43bc17..ef8d7ed7ce 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/dialog/mapping-dialog.component.ts @@ -43,15 +43,16 @@ import { MappingType, MappingTypeTranslationsMap, noLeadTrailSpacesRegex, - OPCUaSourceTypes, + OPCUaSourceType, QualityTypes, QualityTypeTranslationsMap, + RequestMappingData, RequestMappingFormValue, RequestType, RequestTypesTranslationsMap, RpcMethod, ServerSideRPCType, - SourceTypes, + SourceType, SourceTypeTranslationsMap, Timeseries } from '@home/components/widget/lib/gateway/gateway-widget.models'; @@ -82,10 +83,10 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone ConvertorTypeEnum = ConvertorType; ConvertorTypeTranslationsMap = ConvertorTypeTranslationsMap; - sourceTypes: SourceTypes[] = Object.values(SourceTypes); - OPCUaSourceTypes = Object.values(OPCUaSourceTypes) as Array<OPCUaSourceTypes>; - OPCUaSourceTypesEnum = OPCUaSourceTypes; - sourceTypesEnum = SourceTypes; + sourceTypes: SourceType[] = Object.values(SourceType); + OPCUaSourceTypes = Object.values(OPCUaSourceType) as Array<OPCUaSourceType>; + OPCUaSourceTypesEnum = OPCUaSourceType; + sourceTypesEnum = SourceType; SourceTypeTranslationsMap = SourceTypeTranslationsMap; requestTypes: RequestType[] = Object.values(RequestType); @@ -230,8 +231,8 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone noKeysText: MappingKeysNoKeysTextTranslationsMap.get(keysType) }; if (this.data.mappingType === MappingType.OPCUA) { - ctx.valueTypeKeys = Object.values(OPCUaSourceTypes); - ctx.valueTypeEnum = OPCUaSourceTypes; + ctx.valueTypeKeys = Object.values(OPCUaSourceType); + ctx.valueTypeEnum = OPCUaSourceType; ctx.valueTypes = SourceTypeTranslationsMap; } this.keysPopupClosed = false; @@ -293,8 +294,8 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone requestType: this.data.value.requestType, requestValue: { [this.data.value.requestType]: this.data.value.requestValue - } - } as RequestMappingFormValue; + } as Record<RequestType, RequestMappingData> + }; default: return this.data.value as DeviceConnectorMapping; } @@ -349,10 +350,10 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone attributeRequests: this.fb.group({ topicFilter: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], deviceInfo: this.fb.group({ - deviceNameExpressionSource: [SourceTypes.MSG, []], + deviceNameExpressionSource: [SourceType.MSG, []], deviceNameExpression: ['', [Validators.required]], }), - attributeNameExpressionSource: [SourceTypes.MSG, []], + attributeNameExpressionSource: [SourceType.MSG, []], attributeNameExpression: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], topicExpression: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], valueExpression: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], @@ -407,7 +408,7 @@ export class MappingDialogComponent extends DialogComponent<MappingDialogCompone private createOPCUAMappingForm(): void { this.mappingForm = this.fb.group({ - deviceNodeSource: [OPCUaSourceTypes.PATH, []], + deviceNodeSource: [OPCUaSourceType.PATH, []], deviceNodePattern: ['', [Validators.required]], deviceInfo: [{}, []], attributes: [[], []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html index e6391f1782..7c495d34f1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html @@ -156,6 +156,7 @@ <div class="tb-form-panel-title"> {{ initialConnector?.type ? GatewayConnectorTypesTranslatesMap.get(initialConnector.type) : '' }} {{ 'gateway.configuration' | translate }} + <span class="version-placeholder" *ngIf="connectorForm.get('configVersion').value">v{{connectorForm.get('configVersion').value}}</span> </div> <tb-toggle-select *ngIf="initialConnector && allowBasicConfig.has(initialConnector.type)" formControlName="mode" appearance="fill"> @@ -175,18 +176,36 @@ <section class="tb-form-panel section-container no-border no-padding tb-flex space-between" *ngIf="initialConnector"> <ng-container *ngIf="connectorForm.get('mode')?.value === ConnectorConfigurationModes.BASIC else defaultConfig"> <ng-container [ngSwitch]="initialConnector.type"> - <tb-mqtt-basic-config *ngSwitchCase="ConnectorType.MQTT" - formControlName="basicConfig" - [generalTabContent]="generalTabContent"> - </tb-mqtt-basic-config> - <tb-opc-ua-basic-config *ngSwitchCase="ConnectorType.OPCUA" - formControlName="basicConfig" - [generalTabContent]="generalTabContent"> - </tb-opc-ua-basic-config> - <tb-modbus-basic-config *ngSwitchCase="ConnectorType.MODBUS" - formControlName="basicConfig" - [generalTabContent]="generalTabContent"> - </tb-modbus-basic-config> + <ng-container *ngSwitchCase="ConnectorType.MQTT"> + <tb-mqtt-basic-config + *ngIf="connectorForm.get('configVersion').value === GatewayVersion.Current else legacy" + formControlName="basicConfig" + [generalTabContent]="generalTabContent" + /> + <ng-template #legacy> + <tb-mqtt-legacy-basic-config formControlName="basicConfig" [generalTabContent]="generalTabContent"/> + </ng-template> + </ng-container> + <ng-container *ngSwitchCase="ConnectorType.OPCUA"> + <tb-opc-ua-basic-config + *ngIf="connectorForm.get('configVersion').value === GatewayVersion.Current else legacy" + formControlName="basicConfig" + [generalTabContent]="generalTabContent" + /> + <ng-template #legacy> + <tb-opc-ua-legacy-basic-config formControlName="basicConfig" [generalTabContent]="generalTabContent"/> + </ng-template> + </ng-container> + <ng-container *ngSwitchCase="ConnectorType.MODBUS"> + <tb-modbus-basic-config + *ngIf="connectorForm.get('configVersion').value === GatewayVersion.Current else legacy" + formControlName="basicConfig" + [generalTabContent]="generalTabContent" + /> + <ng-template #legacy> + <tb-modbus-legacy-basic-config formControlName="basicConfig" [generalTabContent]="generalTabContent"/> + </ng-template> + </ng-container> </ng-container> </ng-container> <ng-template #defaultConfig> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss index f151887c92..5d8c6aad5b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss @@ -22,6 +22,11 @@ overflow-x: auto; padding: 0; + .version-placeholder { + color: gray; + font-size: 12px + } + .connector-container { height: 100%; width: 100%; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index c4cbf9d698..03765613da 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -59,12 +59,16 @@ import { GatewayConnectorDefaultTypesTranslatesMap, GatewayLogLevel, noLeadTrailSpacesRegex, + GatewayVersion, } from './gateway-widget.models'; import { MatDialog } from '@angular/material/dialog'; import { AddConnectorDialogComponent } from '@home/components/widget/lib/gateway/dialog/add-connector-dialog.component'; import { debounceTime, filter, switchMap, take, takeUntil, tap } from 'rxjs/operators'; import { ErrorStateMatcher } from '@angular/material/core'; import { PageData } from '@shared/models/page/page-data'; +import { + GatewayConnectorVersionMappingUtil +} from '@home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util'; export class ForceErrorStateMatcher implements ErrorStateMatcher { isErrorState(control: FormControl | null): boolean { @@ -98,6 +102,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie readonly displayedColumns = ['enabled', 'key', 'type', 'syncStatus', 'errors', 'actions']; readonly GatewayConnectorTypesTranslatesMap = GatewayConnectorDefaultTypesTranslatesMap; readonly ConnectorConfigurationModes = ConfigurationModes; + readonly GatewayVersion = GatewayVersion; pageLink: PageLink; dataSource: MatTableDataSource<GatewayAttributeData>; @@ -106,6 +111,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie mode: ConfigurationModes = this.ConnectorConfigurationModes.BASIC; initialConnector: GatewayConnector; + private gatewayVersion: string; private inactiveConnectors: Array<string>; private attributeDataSource: AttributeDatasource; private inactiveConnectorsDataSource: AttributeDatasource; @@ -239,6 +245,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie delete value.class; } + if (this.gatewayVersion && !value.configVersion) { + value.configVersion = this.gatewayVersion; + } + value.ts = Date.now(); return value; @@ -263,7 +273,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie }); } - isConnectorSynced(attribute: GatewayAttributeData) { + isConnectorSynced(attribute: GatewayAttributeData): boolean { const connectorData = attribute.value; if (!connectorData.ts || attribute.skipSync) { return false; @@ -340,7 +350,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie class: '', configuration: '', configurationJson: {}, - basicConfig: {} + basicConfig: {}, + configVersion: '' }, {emitEvent: false}); this.connectorForm.markAsPristine(); } @@ -483,7 +494,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie return this.dialog.open<AddConnectorDialogComponent, AddConnectorConfigData>(AddConnectorDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], - data: { dataSourceData: this.dataSource.data } + data: { + dataSourceData: this.dataSource.data, + gatewayVersion: this.gatewayVersion, + } }).afterClosed(); } @@ -526,7 +540,8 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie class: [''], configuration: [''], configurationJson: [{}, [Validators.required]], - basicConfig: [{}] + basicConfig: [{}], + configVersion: [''], }); this.connectorForm.disable(); } @@ -560,10 +575,12 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie forkJoin([ this.attributeService.getEntityAttributes(this.device, AttributeScope.SHARED_SCOPE, ['active_connectors']), - this.attributeService.getEntityAttributes(this.device, AttributeScope.SERVER_SCOPE, ['inactive_connectors']) + this.attributeService.getEntityAttributes(this.device, AttributeScope.SERVER_SCOPE, ['inactive_connectors']), + this.attributeService.getEntityAttributes(this.device, AttributeScope.CLIENT_SCOPE, ['Version']) ]).pipe(takeUntil(this.destroy$)).subscribe(attributes => { this.activeConnectors = this.parseConnectors(attributes[0]); this.inactiveConnectors = this.parseConnectors(attributes[1]); + this.gatewayVersion = attributes[2][0]?.value; this.updateData(true); }); @@ -721,12 +738,12 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.connectorForm.enable(); } - const connectorState = { + const connectorState = GatewayConnectorVersionMappingUtil.getConfig({ configuration: '', key: 'auto', configurationJson: {} as ConnectorBaseConfig, ...connector, - }; + }, this.gatewayVersion); connectorState.basicConfig = connectorState.configurationJson; this.initialConnector = connectorState; @@ -739,6 +756,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie case ConnectorType.OPCUA: case ConnectorType.MODBUS: this.connectorForm.get('mode').setValue(connector.mode || ConfigurationModes.BASIC, {emitEvent: false}); + this.connectorForm.get('configVersion').setValue(connector.configVersion, {emitEvent: false}); setTimeout(() => { this.connectorForm.patchValue(connector, {emitEvent: false}); this.connectorForm.markAsPristine(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index 74ea647b14..0f940e28ff 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -14,8 +14,6 @@ /// limitations under the License. /// -import { ResourcesService } from '@core/services/resources.service'; -import { Observable } from 'rxjs'; import { helpBaseUrl, ValueTypeData } from '@shared/models/constants'; import { AttributeData } from '@shared/models/telemetry/telemetry.models'; @@ -115,21 +113,30 @@ export interface GatewayAttributeData extends AttributeData { skipSync?: boolean; } -export interface GatewayConnector { +export interface GatewayConnectorBase { name: string; type: ConnectorType; configuration?: string; - configurationJson: ConnectorBaseConfig; - basicConfig?: ConnectorBaseConfig; logLevel: string; key?: string; class?: string; mode?: ConfigurationModes; + configVersion?: string; +} + +export interface GatewayConnector<BaseConfig = ConnectorBaseConfig> extends GatewayConnectorBase { + configurationJson: BaseConfig; + basicConfig?: BaseConfig; +} + +export interface GatewayVersionedDefaultConfig { + legacy: GatewayConnector<ConnectorLegacyConfig>; + '3.5.2': GatewayConnector<ConnectorBaseConfig_v3_5_2>; } export interface DataMapping { topicFilter: string; - QoS: string; + QoS: string | number; converter: Converter; } @@ -181,11 +188,20 @@ export interface ConnectorSecurity { mode?: ModeType; } -export type ConnectorMapping = DeviceConnectorMapping | RequestMappingData | ConverterConnectorMapping; +export enum GatewayVersion { + Current = '3.5.2', + Legacy = 'legacy' +} + +export type ConnectorMapping = DeviceConnectorMapping | RequestMappingValue | ConverterConnectorMapping; export type ConnectorMappingFormValue = DeviceConnectorMapping | RequestMappingFormValue | ConverterMappingFormValue; -export type ConnectorBaseConfig = ConnectorBaseInfo | MQTTBasicConfig | OPCBasicConfig | ModbusBasicConfig; +export type ConnectorBaseConfig = ConnectorBaseConfig_v3_5_2 | ConnectorLegacyConfig; + +export type ConnectorLegacyConfig = ConnectorBaseInfo | MQTTLegacyBasicConfig | OPCLegacyBasicConfig | ModbusBasicConfig; + +export type ConnectorBaseConfig_v3_5_2 = ConnectorBaseInfo | MQTTBasicConfig_v3_5_2 | OPCBasicConfig_v3_5_2; export interface ConnectorBaseInfo { name: string; @@ -194,33 +210,64 @@ export interface ConnectorBaseInfo { logLevel: GatewayLogLevel; } -export interface MQTTBasicConfig { - dataMapping: ConverterConnectorMapping[]; - requestsMapping: Record<RequestType, RequestMappingData[]> | RequestMappingData[]; +export type MQTTBasicConfig = MQTTBasicConfig_v3_5_2 | MQTTLegacyBasicConfig; + +export interface MQTTBasicConfig_v3_5_2 { + mapping: ConverterConnectorMapping[]; + requestsMapping: Record<RequestType, RequestMappingData[] | RequestMappingValue[]> | RequestMappingData[] | RequestMappingValue[]; broker: BrokerConfig; workers?: WorkersConfig; } -export interface OPCBasicConfig { +export interface MQTTLegacyBasicConfig { + mapping: LegacyConverterConnectorMapping[]; + broker: BrokerConfig; + workers?: WorkersConfig; + connectRequests: LegacyRequestMappingData[]; + disconnectRequests: LegacyRequestMappingData[]; + attributeRequests: LegacyRequestMappingData[]; + attributeUpdates: LegacyRequestMappingData[]; + serverSideRpc: LegacyRequestMappingData[]; +} + +export type OPCBasicConfig = OPCBasicConfig_v3_5_2 | OPCLegacyBasicConfig; + +export interface OPCBasicConfig_v3_5_2 { mapping: DeviceConnectorMapping[]; server: ServerConfig; } -export interface ModbusBasicConfig { +export interface OPCLegacyBasicConfig { + server: LegacyServerConfig; +} + +export interface LegacyServerConfig extends Omit<ServerConfig, 'enableSubscriptions'> { + mapping: LegacyDeviceConnectorMapping[]; + disableSubscriptions: boolean; +} + +export type ModbusBasicConfig = ModbusBasicConfig_v3_5_2 | ModbusLegacyBasicConfig; + +export interface ModbusBasicConfig_v3_5_2 { master: ModbusMasterConfig; slave: ModbusSlave; } +export interface ModbusLegacyBasicConfig { + master: ModbusMasterConfig; + slave: ModbusLegacySlave; +} + export interface WorkersConfig { maxNumberOfWorkers: number; maxMessageNumberPerWorker: number; } -interface DeviceInfo { +export interface ConnectorDeviceInfo { deviceNameExpression: string; - deviceNameExpressionSource: string; + deviceNameExpressionSource: SourceType | OPCUaSourceType; deviceProfileExpression: string; - deviceProfileExpressionSource: string; + deviceProfileExpressionSource: SourceType | OPCUaSourceType; } export interface Attribute { @@ -229,13 +276,23 @@ export interface Attribute { value: string; } +export interface LegacyAttribute { + key: string; + path: string; +} + export interface Timeseries { key: string; type: string; value: string; } -interface RpcArgument { +export interface LegacyTimeseries { + key: string; + path: string; +} + +export interface RpcArgument { type: string; value: number; } @@ -245,28 +302,59 @@ export interface RpcMethod { arguments: RpcArgument[]; } +export interface LegacyRpcMethod { + method: string; + arguments: unknown[]; +} + export interface AttributesUpdate { key: string; type: string; value: string; } +export interface LegacyDeviceAttributeUpdate { + attributeOnThingsBoard: string; + attributeOnDevice: string; +} + export interface Converter { type: ConvertorType; - deviceNameJsonExpression: string; - deviceTypeJsonExpression: string; + deviceInfo?: ConnectorDeviceInfo; sendDataOnlyOnChange: boolean; timeout: number; - attributes: Attribute[]; - timeseries: Timeseries[]; + attributes?: Attribute[]; + timeseries?: Timeseries[]; + extension?: string; + cached?: boolean; + extensionConfig?: Record<string, number>; +} + +export interface LegacyConverter extends Converter { + deviceNameJsonExpression?: string; + deviceTypeJsonExpression?: string; + deviceNameTopicExpression?: string; + deviceTypeTopicExpression?: string; + deviceNameExpression?: string; + deviceNameExpressionSource?: string; + deviceTypeExpression?: string; + deviceProfileExpression?: string; + deviceProfileExpressionSource?: string; + ['extension-config']?: Record<string, unknown>; } export interface ConverterConnectorMapping { topicFilter: string; - subscriptionQos?: string; + subscriptionQos?: string | number; converter: Converter; } +export interface LegacyConverterConnectorMapping { + topicFilter: string; + subscriptionQos?: string | number; + converter: LegacyConverter; +} + export type ConverterMappingFormValue = Omit<ConverterConnectorMapping, 'converter'> & { converter: { type: ConvertorType; @@ -275,14 +363,24 @@ export type ConverterMappingFormValue = Omit<ConverterConnectorMapping, 'convert export interface DeviceConnectorMapping { deviceNodePattern: string; - deviceNodeSource: string; - deviceInfo: DeviceInfo; + deviceNodeSource: OPCUaSourceType; + deviceInfo: ConnectorDeviceInfo; attributes?: Attribute[]; timeseries?: Timeseries[]; rpc_methods?: RpcMethod[]; attributes_updates?: AttributesUpdate[]; } +export interface LegacyDeviceConnectorMapping { + deviceNamePattern: string; + deviceNodePattern: string; + deviceTypePattern: string; + attributes?: LegacyAttribute[]; + timeseries?: LegacyTimeseries[]; + rpc_methods?: LegacyRpcMethod[]; + attributes_updates?: LegacyDeviceAttributeUpdate[]; +} + export enum ConnectorType { MQTT = 'mqtt', MODBUS = 'modbus', @@ -461,6 +559,7 @@ export interface GatewayLogData { export interface AddConnectorConfigData { dataSourceData: Array<any>; + gatewayVersion: string; } export interface CreatedConnectorConfigData { @@ -591,13 +690,13 @@ export const ConvertorTypeTranslationsMap = new Map<ConvertorType, string>( ] ); -export enum SourceTypes { +export enum SourceType { MSG = 'message', TOPIC = 'topic', CONST = 'constant' } -export enum OPCUaSourceTypes { +export enum OPCUaSourceType { PATH = 'path', IDENTIFIER = 'identifier', CONST = 'constant' @@ -608,33 +707,116 @@ export enum DeviceInfoType { PARTIAL = 'partial' } -export const SourceTypeTranslationsMap = new Map<SourceTypes | OPCUaSourceTypes, string>( +export const SourceTypeTranslationsMap = new Map<SourceType | OPCUaSourceType, string>( [ - [SourceTypes.MSG, 'gateway.source-type.msg'], - [SourceTypes.TOPIC, 'gateway.source-type.topic'], - [SourceTypes.CONST, 'gateway.source-type.const'], - [OPCUaSourceTypes.PATH, 'gateway.source-type.path'], - [OPCUaSourceTypes.IDENTIFIER, 'gateway.source-type.identifier'], - [OPCUaSourceTypes.CONST, 'gateway.source-type.const'] + [SourceType.MSG, 'gateway.source-type.msg'], + [SourceType.TOPIC, 'gateway.source-type.topic'], + [SourceType.CONST, 'gateway.source-type.const'], + [OPCUaSourceType.PATH, 'gateway.source-type.path'], + [OPCUaSourceType.IDENTIFIER, 'gateway.source-type.identifier'], + [OPCUaSourceType.CONST, 'gateway.source-type.const'] ] ); -export interface RequestMappingData { +export interface RequestMappingValue { requestType: RequestType; - requestValue: RequestDataItem; + requestValue: RequestMappingData; } -export type RequestMappingFormValue = Omit<RequestMappingData, 'requestValue'> & { - requestValue: Record<RequestType, RequestDataItem>; -}; - -export interface RequestDataItem { - type: string; - details: string; +export interface RequestMappingFormValue { requestType: RequestType; - methodFilter?: string; - attributeFilter?: string; - topicFilter?: string; + requestValue: Record<RequestType, RequestMappingData>; +} + +export type RequestMappingData = ConnectRequest | DisconnectRequest | AttributeRequest | AttributeUpdate | ServerSideRpc; + +export type LegacyRequestMappingData = + LegacyConnectRequest + | LegacyDisconnectRequest + | LegacyAttributeRequest + | LegacyAttributeUpdate + | LegacyServerSideRpc; + +export interface ConnectRequest { + topicFilter: string; + deviceInfo: ConnectorDeviceInfo; +} + +export interface DisconnectRequest { + topicFilter: string; + deviceInfo: ConnectorDeviceInfo; +} + +export interface AttributeRequest { + retain: boolean; + topicFilter: string; + deviceInfo: ConnectorDeviceInfo; + attributeNameExpressionSource: SourceType; + attributeNameExpression: string; + topicExpression: string; + valueExpression: string; +} + +export interface AttributeUpdate { + retain: boolean; + deviceNameFilter: string; + attributeFilter: string; + topicExpression: string; + valueExpression: string; +} + +export interface ServerSideRpc { + type: ServerSideRpcType; + deviceNameFilter: string; + methodFilter: string; + requestTopicExpression: string; + responseTopicExpression?: string; + responseTopicQoS?: number; + responseTimeout?: number; + valueExpression: string; +} + +export enum ServerSideRpcType { + WithResponse = 'twoWay', + WithoutResponse = 'oneWay' +} + +export interface LegacyConnectRequest { + topicFilter: string; + deviceNameJsonExpression?: string; + deviceNameTopicExpression?: string; +} + +interface LegacyDisconnectRequest { + topicFilter: string; + deviceNameJsonExpression?: string; + deviceNameTopicExpression?: string; +} + +interface LegacyAttributeRequest { + retain: boolean; + topicFilter: string; + deviceNameJsonExpression: string; + attributeNameJsonExpression: string; + topicExpression: string; + valueExpression: string; +} + +interface LegacyAttributeUpdate { + retain: boolean; + deviceNameFilter: string; + attributeFilter: string; + topicExpression: string; + valueExpression: string; +} + +interface LegacyServerSideRpc { + deviceNameFilter: string; + methodFilter: string; + requestTopicExpression: string; + responseTopicExpression?: string; + responseTimeout?: number; + valueExpression: string; } export enum RequestType { @@ -708,9 +890,6 @@ export enum ServerSideRPCType { TWO_WAY = 'twoWay' } -export const getDefaultConfig = (resourcesService: ResourcesService, type: string): Observable<any> => - resourcesService.loadJsonResource(`/assets/metadata/connector-default-configs/${type}.json`); - export enum MappingValueType { STRING = 'string', INTEGER = 'integer', @@ -938,7 +1117,7 @@ export interface SlaveConfig { pollPeriod: number; unitId: number; deviceName: string; - deviceType: string; + deviceType?: string; sendDataOnlyOnChange: boolean; connectAttemptTimeMs: number; connectAttemptCount: number; @@ -990,8 +1169,19 @@ export interface ModbusSlave { security: ModbusSecurity; } +export interface ModbusLegacySlave extends Omit<ModbusSlave, 'values'> { + values: ModbusLegacyRegisterValues; +} + export type ModbusValuesState = ModbusRegisterValues | ModbusValues; +export interface ModbusLegacyRegisterValues { + holding_registers: ModbusValues[]; + coils_initializer: ModbusValues[]; + input_registers: ModbusValues[]; + discrete_inputs: ModbusValues[]; +} + export interface ModbusRegisterValues { holding_registers: ModbusValues; coils_initializer: ModbusValues; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/pipes/gateway-help-link.pipe.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/pipes/gateway-help-link.pipe.ts index 0fec377860..06526ce08e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/pipes/gateway-help-link.pipe.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/pipes/gateway-help-link.pipe.ts @@ -17,8 +17,8 @@ import { Pipe, PipeTransform } from '@angular/core'; import { MappingValueType, - OPCUaSourceTypes, - SourceTypes + OPCUaSourceType, + SourceType } from '@home/components/widget/lib/gateway/gateway-widget.models'; @Pipe({ @@ -26,9 +26,9 @@ import { standalone: true, }) export class GatewayHelpLinkPipe implements PipeTransform { - transform(field: string, sourceType: SourceTypes | OPCUaSourceTypes, sourceTypes?: Array<SourceTypes | OPCUaSourceTypes | MappingValueType> ): string { - if (!sourceTypes || sourceTypes?.includes(OPCUaSourceTypes.PATH)) { - if (sourceType !== OPCUaSourceTypes.CONST) { + transform(field: string, sourceType: SourceType | OPCUaSourceType, sourceTypes?: Array<SourceType | OPCUaSourceType | MappingValueType> ): string { + if (!sourceTypes || sourceTypes?.includes(OPCUaSourceType.PATH)) { + if (sourceType !== OPCUaSourceType.CONST) { return `widget/lib/gateway/${field}-${sourceType}_fn`; } else { return; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts new file mode 100644 index 0000000000..90c89ea316 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/gateway-connector-version-mapping.util.ts @@ -0,0 +1,42 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + ConnectorType, + GatewayConnector, + ModbusBasicConfig, + MQTTBasicConfig, + OPCBasicConfig, +} from '@home/components/widget/lib/gateway/gateway-widget.models'; +import { MqttVersionProcessor } from '@home/components/widget/lib/gateway/abstract/mqtt-version-processor.abstract'; +import { OpcVersionProcessor } from '@home/components/widget/lib/gateway/abstract/opc-version-processor.abstract'; +import { ModbusVersionProcessor } from '@home/components/widget/lib/gateway/abstract/modbus-version-processor.abstract'; + +export abstract class GatewayConnectorVersionMappingUtil { + + static getConfig(connector: GatewayConnector, gatewayVersion: string): GatewayConnector { + switch(connector.type) { + case ConnectorType.MQTT: + return new MqttVersionProcessor(gatewayVersion, connector as GatewayConnector<MQTTBasicConfig>).getProcessedByVersion(); + case ConnectorType.OPCUA: + return new OpcVersionProcessor(gatewayVersion, connector as GatewayConnector<OPCBasicConfig>).getProcessedByVersion(); + case ConnectorType.MODBUS: + return new ModbusVersionProcessor(gatewayVersion, connector as GatewayConnector<ModbusBasicConfig>).getProcessedByVersion(); + default: + return connector; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts new file mode 100644 index 0000000000..fbb78059e1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/modbus-version-mapping.util.ts @@ -0,0 +1,80 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + ModbusDataType, + ModbusLegacyRegisterValues, + ModbusLegacySlave, + ModbusMasterConfig, + ModbusRegisterValues, + ModbusSlave, + ModbusValue, + ModbusValues, + SlaveConfig +} from '@home/components/widget/lib/gateway/gateway-widget.models'; + +export class ModbusVersionMappingUtil { + + static mapMasterToUpgradedVersion(master: ModbusMasterConfig): ModbusMasterConfig { + return { + slaves: master.slaves.map((slave: SlaveConfig) => ({ + ...slave, + deviceType: slave.deviceType ?? 'default', + })) + }; + } + + static mapSlaveToDowngradedVersion(slave: ModbusSlave): ModbusLegacySlave { + const values = Object.keys(slave.values).reduce((acc, valueKey) => { + acc = { + ...acc, + [valueKey]: [ + slave.values[valueKey] + ] + }; + return acc; + }, {} as ModbusLegacyRegisterValues); + return { + ...slave, + values + }; + } + + static mapSlaveToUpgradedVersion(slave: ModbusLegacySlave): ModbusSlave { + const values = Object.keys(slave.values).reduce((acc, valueKey) => { + acc = { + ...acc, + [valueKey]: this.mapValuesToUpgradedVersion(slave.values[valueKey][0]) + }; + return acc; + }, {} as ModbusRegisterValues); + return { + ...slave, + values + }; + } + + private static mapValuesToUpgradedVersion(registerValues: ModbusValues): ModbusValues { + return Object.keys(registerValues).reduce((acc, valueKey) => { + acc = { + ...acc, + [valueKey]: registerValues[valueKey].map((value: ModbusValue) => + ({ ...value, type: (value.type as string) === 'int' ? ModbusDataType.INT16 : value.type })) + }; + return acc; + }, {} as ModbusValues); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts new file mode 100644 index 0000000000..23cc03dc4e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/mqtt-version-mapping.util.ts @@ -0,0 +1,217 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { deleteNullProperties } from '@core/utils'; +import { + AttributeRequest, + ConnectorDeviceInfo, + Converter, + ConverterConnectorMapping, + ConvertorType, + LegacyConverter, + LegacyConverterConnectorMapping, + LegacyRequestMappingData, + RequestMappingData, + RequestType, + ServerSideRpc, + ServerSideRpcType, + SourceType +} from '@home/components/widget/lib/gateway/gateway-widget.models'; + +export class MqttVersionMappingUtil { + + static readonly mqttRequestTypeKeys = Object.values(RequestType); + static readonly mqttRequestMappingOldFields = + ['attributeNameJsonExpression', 'deviceNameJsonExpression', 'deviceNameTopicExpression', 'extension-config']; + static readonly mqttRequestMappingNewFields = + ['attributeNameExpressionSource', 'responseTopicQoS', 'extensionConfig']; + + static mapMappingToUpgradedVersion( + mapping: LegacyConverterConnectorMapping[] + ): ConverterConnectorMapping[] { + return mapping?.map(({ converter, topicFilter, subscriptionQos = 1 }) => { + const deviceInfo = converter.deviceInfo ?? this.extractConverterDeviceInfo(converter); + + const newConverter = { + ...converter, + deviceInfo, + extensionConfig: converter.extensionConfig || converter['extension-config'] || null + }; + + this.cleanUpOldFields(newConverter); + + return { converter: newConverter, topicFilter, subscriptionQos }; + }) as ConverterConnectorMapping[]; + } + + static mapRequestsToUpgradedVersion( + requestMapping: Record<RequestType, + LegacyRequestMappingData[]> + ): Record<RequestType, RequestMappingData[]> { + return this.mqttRequestTypeKeys.reduce((acc, key: RequestType) => { + if (!requestMapping[key]) { + return acc; + } + + acc[key] = requestMapping[key].map(value => { + const newValue = this.mapRequestToUpgradedVersion(value as LegacyRequestMappingData, key); + + this.cleanUpOldFields(newValue as {}); + + return newValue; + }); + + return acc; + }, {}) as Record<RequestType, RequestMappingData[]>; + } + + static mapRequestsToDowngradedVersion( + requestsMapping: Record<RequestType, RequestMappingData[]> + ): Record<RequestType, LegacyRequestMappingData[]> { + return this.mqttRequestTypeKeys.reduce((acc, key) => { + if (!requestsMapping[key]) { + return acc; + } + + acc[key] = requestsMapping[key].map((value: RequestMappingData) => { + if (key === RequestType.SERVER_SIDE_RPC) { + delete (value as ServerSideRpc).type; + } + + const { attributeNameExpression, deviceInfo, ...rest } = value as AttributeRequest; + + const newValue = { + ...rest, + attributeNameJsonExpression: attributeNameExpression || null, + deviceNameJsonExpression: deviceInfo?.deviceNameExpressionSource !== SourceType.TOPIC ? deviceInfo?.deviceNameExpression : null, + deviceNameTopicExpression: deviceInfo?.deviceNameExpressionSource === SourceType.TOPIC ? deviceInfo?.deviceNameExpression : null, + }; + + this.cleanUpNewFields(newValue); + + return newValue; + }); + + return acc; + }, {}) as Record<RequestType, LegacyRequestMappingData[]>; + } + + static mapMappingToDowngradedVersion( + mapping: ConverterConnectorMapping[] + ): LegacyConverterConnectorMapping[] { + return mapping?.map((converterMapping: ConverterConnectorMapping) => { + const converter = this.mapConverterToDowngradedVersion(converterMapping.converter); + + this.cleanUpNewFields(converter as {}); + + return { converter, topicFilter: converterMapping.topicFilter }; + }); + } + + private static mapConverterToDowngradedVersion(converter: Converter): LegacyConverter { + const { deviceInfo, ...restConverter } = converter; + + return converter.type !== ConvertorType.BYTES ? { + ...restConverter, + deviceNameJsonExpression: deviceInfo?.deviceNameExpressionSource === SourceType.MSG ? deviceInfo.deviceNameExpression : null, + deviceTypeJsonExpression: + deviceInfo?.deviceProfileExpressionSource === SourceType.MSG ? deviceInfo.deviceProfileExpression : null, + deviceNameTopicExpression: + deviceInfo?.deviceNameExpressionSource !== SourceType.MSG + ? deviceInfo?.deviceNameExpression + : null, + deviceTypeTopicExpression: deviceInfo?.deviceProfileExpressionSource !== SourceType.MSG + ? deviceInfo?.deviceProfileExpression + : null, + } : { + ...restConverter, + deviceNameExpression: deviceInfo.deviceNameExpression, + deviceTypeExpression: deviceInfo.deviceProfileExpression, + ['extension-config']: converter.extensionConfig, + }; + } + + private static cleanUpOldFields(obj: Record<string, unknown>): void { + this.mqttRequestMappingOldFields.forEach(field => delete obj[field]); + deleteNullProperties(obj); + } + + private static cleanUpNewFields(obj: Record<string, unknown>): void { + this.mqttRequestMappingNewFields.forEach(field => delete obj[field]); + deleteNullProperties(obj); + } + + private static getTypeSourceByValue(value: string): SourceType { + if (value.includes('${')) { + return SourceType.MSG; + } + if (value.includes(`/`)) { + return SourceType.TOPIC; + } + return SourceType.CONST; + } + + private static extractConverterDeviceInfo(converter: LegacyConverter): ConnectorDeviceInfo { + const deviceNameExpression = converter.deviceNameExpression + || converter.deviceNameJsonExpression + || converter.deviceNameTopicExpression + || null; + const deviceNameExpressionSource = converter.deviceNameExpressionSource + ? converter.deviceNameExpressionSource as SourceType + : deviceNameExpression ? this.getTypeSourceByValue(deviceNameExpression) : null; + const deviceProfileExpression = converter.deviceProfileExpression + || converter.deviceTypeTopicExpression + || converter.deviceTypeJsonExpression + || 'default'; + const deviceProfileExpressionSource = converter.deviceProfileExpressionSource + ? converter.deviceProfileExpressionSource as SourceType + : deviceProfileExpression ? this.getTypeSourceByValue(deviceProfileExpression) : null; + + return deviceNameExpression || deviceProfileExpression ? { + deviceNameExpression, + deviceNameExpressionSource, + deviceProfileExpression, + deviceProfileExpressionSource + } : null; + } + + private static mapRequestToUpgradedVersion(value, key: RequestType): RequestMappingData { + const deviceNameExpression = value.deviceNameJsonExpression || value.deviceNameTopicExpression || null; + const deviceProfileExpression = value.deviceTypeTopicExpression || value.deviceTypeJsonExpression || 'default'; + const deviceProfileExpressionSource = deviceProfileExpression ? this.getTypeSourceByValue(deviceProfileExpression) : null; + const attributeNameExpression = value.attributeNameExpressionSource || value.attributeNameJsonExpression || null; + const responseTopicQoS = key === RequestType.SERVER_SIDE_RPC ? 1 : null; + const type = key === RequestType.SERVER_SIDE_RPC + ? (value as ServerSideRpc).responseTopicExpression + ? ServerSideRpcType.WithResponse + : ServerSideRpcType.WithoutResponse + : null; + + return { + ...value, + attributeNameExpression, + attributeNameExpressionSource: attributeNameExpression ? this.getTypeSourceByValue(attributeNameExpression) : null, + deviceInfo: value.deviceInfo ? value.deviceInfo : deviceNameExpression ? { + deviceNameExpression, + deviceNameExpressionSource: this.getTypeSourceByValue(deviceNameExpression), + deviceProfileExpression, + deviceProfileExpressionSource + } : null, + responseTopicQoS, + type + }; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts new file mode 100644 index 0000000000..35807065e9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts @@ -0,0 +1,134 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + Attribute, + AttributesUpdate, + DeviceConnectorMapping, + LegacyAttribute, + LegacyDeviceAttributeUpdate, + LegacyDeviceConnectorMapping, + LegacyRpcMethod, + LegacyServerConfig, + LegacyTimeseries, + OPCBasicConfig_v3_5_2, + OPCUaSourceType, + RpcArgument, + RpcMethod, + ServerConfig, + Timeseries +} from '@home/components/widget/lib/gateway/gateway-widget.models'; + +export class OpcVersionMappingUtil { + + static mapServerToUpgradedVersion(server: LegacyServerConfig): ServerConfig { + const { mapping, disableSubscriptions, ...restServer } = server; + return { + ...restServer, + enableSubscriptions: !disableSubscriptions, + }; + } + + static mapServerToDowngradedVersion(config: OPCBasicConfig_v3_5_2): LegacyServerConfig { + const { mapping, server } = config; + const { enableSubscriptions, ...restServer } = server; + return { + ...restServer, + mapping: mapping ? this.mapMappingToDowngradedVersion(mapping) : [], + disableSubscriptions: !enableSubscriptions, + }; + } + + static mapMappingToUpgradedVersion(mapping: LegacyDeviceConnectorMapping[]): DeviceConnectorMapping[] { + return mapping.map((legacyMapping: LegacyDeviceConnectorMapping) => ({ + ...legacyMapping, + deviceNodeSource: this.getTypeSourceByValue(legacyMapping.deviceNodePattern), + deviceInfo: { + deviceNameExpression: legacyMapping.deviceNamePattern, + deviceNameExpressionSource: this.getTypeSourceByValue(legacyMapping.deviceNamePattern), + deviceProfileExpression: legacyMapping.deviceTypePattern ?? 'default', + deviceProfileExpressionSource: this.getTypeSourceByValue(legacyMapping.deviceTypePattern ?? 'default'), + }, + attributes: legacyMapping.attributes.map((attribute: LegacyAttribute) => ({ + key: attribute.key, + type: this.getTypeSourceByValue(attribute.path), + value: attribute.path, + })), + attributes_updates: legacyMapping.attributes_updates.map((attributeUpdate: LegacyDeviceAttributeUpdate) => ({ + key: attributeUpdate.attributeOnThingsBoard, + type: this.getTypeSourceByValue(attributeUpdate.attributeOnDevice), + value: attributeUpdate.attributeOnDevice, + })), + timeseries: legacyMapping.timeseries.map((timeseries: LegacyTimeseries) => ({ + key: timeseries.key, + type: this.getTypeSourceByValue(timeseries.path), + value: timeseries.path, + })), + rpc_methods: legacyMapping.rpc_methods.map((rpcMethod: LegacyRpcMethod) => ({ + method: rpcMethod.method, + arguments: rpcMethod.arguments.map(arg => ({ + value: arg, + type: this.getArgumentType(arg), + } as RpcArgument)) + })) + })); + } + + static mapMappingToDowngradedVersion(mapping: DeviceConnectorMapping[]): LegacyDeviceConnectorMapping[] { + return mapping.map((upgradedMapping: DeviceConnectorMapping) => ({ + ...upgradedMapping, + deviceNamePattern: upgradedMapping.deviceInfo.deviceNameExpression, + deviceTypePattern: upgradedMapping.deviceInfo.deviceProfileExpression, + attributes: upgradedMapping.attributes.map((attribute: Attribute) => ({ + key: attribute.key, + path: attribute.value, + })), + attributes_updates: upgradedMapping.attributes_updates.map((attributeUpdate: AttributesUpdate) => ({ + attributeOnThingsBoard: attributeUpdate.key, + attributeOnDevice: attributeUpdate.value, + })), + timeseries: upgradedMapping.timeseries.map((timeseries: Timeseries) => ({ + key: timeseries.key, + path: timeseries.value, + })), + rpc_methods: upgradedMapping.rpc_methods.map((rpcMethod: RpcMethod) => ({ + method: rpcMethod.method, + arguments: rpcMethod.arguments.map((arg: RpcArgument) => arg.value) + })) + })); + } + + private static getTypeSourceByValue(value: string): OPCUaSourceType { + if (value.includes('${')) { + return OPCUaSourceType.IDENTIFIER; + } + if (value.includes(`/`) || value.includes('\\')) { + return OPCUaSourceType.PATH; + } + return OPCUaSourceType.CONST; + } + + private static getArgumentType(arg: unknown): string { + switch (typeof arg) { + case 'boolean': + return 'boolean'; + case 'number': + return Number.isInteger(arg) ? 'integer' : 'float'; + default: + return 'string'; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.component.html index 391ade6228..95eb4a0ba1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.component.html @@ -20,7 +20,7 @@ <div class="tb-status-widget-title-panel"> <ng-container *ngTemplateOutlet="widgetTitlePanel"></ng-container> </div> - <div #statusWidgetContent class="tb-status-widget-content" [class]="this.layout"> + <div #statusWidgetContent class="tb-status-widget-content" [class]="this.layout" [style.padding]="padding"> <div class="tb-status-widget-icon-container"> <tb-icon [style]="iconStyle">{{ icon }}</tb-icon> </div> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.component.ts index 5b59b0210f..d8d5b48ff6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.component.ts @@ -21,14 +21,16 @@ import { ElementRef, OnDestroy, OnInit, - Renderer2, ViewChild, + Renderer2, + ViewChild, ViewEncapsulation } from '@angular/core'; import { BasicActionWidgetComponent } from '@home/components/widget/lib/action/action-widget.models'; import { statusWidgetDefaultSettings, StatusWidgetLayout, - StatusWidgetSettings, StatusWidgetStateSettings + StatusWidgetSettings, + StatusWidgetStateSettings } from '@home/components/widget/lib/indicator/status-widget.models'; import { Observable } from 'rxjs'; import { @@ -36,12 +38,12 @@ import { ComponentStyle, iconStyle, overlayStyle, + resolveCssSize, textStyle } from '@shared/models/widget-settings.models'; import { ResizeObserver } from '@juggle/resize-observer'; import { ImagePipe } from '@shared/pipe/image.pipe'; import { DomSanitizer } from '@angular/platform-browser'; -import { UtilsService } from '@core/services/utils.service'; import { ValueType } from '@shared/models/constants'; const initialStatusWidgetSize = 147; @@ -65,6 +67,7 @@ export class StatusWidgetComponent extends backgroundStyle$: Observable<ComponentStyle>; overlayStyle: ComponentStyle = {}; + padding: string; overlayInset = '12px'; borderRadius = ''; @@ -101,9 +104,7 @@ export class StatusWidgetComponent extends constructor(protected imagePipe: ImagePipe, protected sanitizer: DomSanitizer, private renderer: Renderer2, - private utils: UtilsService, - protected cd: ChangeDetectorRef, - private elementRef: ElementRef) { + protected cd: ChangeDetectorRef) { super(cd); } @@ -191,8 +192,13 @@ export class StatusWidgetComponent extends } private onResize() { - const panelWidth = this.statusWidgetPanel.nativeElement.getBoundingClientRect().width; - const panelHeight = this.statusWidgetPanel.nativeElement.getBoundingClientRect().height; + const computedStyle = getComputedStyle(this.statusWidgetPanel.nativeElement); + const [pLeft, pRight, pTop, pBottom] = ['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom'] + .map(side => resolveCssSize(computedStyle[side])[0]); + + const widgetBoundingClientRect = this.statusWidgetPanel.nativeElement.getBoundingClientRect(); + const panelWidth = widgetBoundingClientRect.width - (pLeft + pRight); + const panelHeight = widgetBoundingClientRect.height - (pTop + pBottom); const targetSize = Math.min(panelWidth, panelHeight); const scale = targetSize / initialStatusWidgetSize; const width = initialStatusWidgetSize; @@ -220,6 +226,9 @@ export class StatusWidgetComponent extends this.showLabel = stateSettings.showLabel && this.layout !== StatusWidgetLayout.icon; this.showStatus = stateSettings.showStatus && this.layout !== StatusWidgetLayout.icon; this.icon = stateSettings.icon; + this.padding = stateSettings.backgroundDisabled.overlay.enabled || stateSettings.background.overlay.enabled + ? undefined + : this.settings.padding; const primaryColor = disabled ? stateSettings.primaryColorDisabled : stateSettings.primaryColor; const secondaryColor = disabled ? stateSettings.secondaryColorDisabled : stateSettings.secondaryColor; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.models.ts index 2ef999c6f2..4dbea591f9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/status-widget.models.ts @@ -65,6 +65,7 @@ export interface StatusWidgetSettings { layout: StatusWidgetLayout; onState: StatusWidgetStateSettings; offState: StatusWidgetStateSettings; + padding: string } export const statusWidgetDefaultSettings: StatusWidgetSettings = { @@ -200,5 +201,6 @@ export const statusWidgetDefaultSettings: StatusWidgetSettings = { blur: 3 } } - } + }, + padding: '' }; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.component.html index fd9aaca4a6..a8dde3ed4c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -<div #singleSwitchPanel class="tb-single-switch-panel" [class.auto-scale]="autoScale" [style.pointer-events]="ctx.isEdit ? 'none' : 'all'" [style]="backgroundStyle$ | async"> +<div #singleSwitchPanel class="tb-single-switch-panel" [class.auto-scale]="autoScale" [style.pointer-events]="ctx.isEdit ? 'none' : 'all'" [style.padding]="padding" [style]="backgroundStyle$ | async"> <div class="tb-single-switch-overlay" [style]="overlayStyle" [style.inset]="overlayInset"></div> <div class="tb-single-switch-title-panel"> <ng-container *ngTemplateOutlet="widgetTitlePanel"></ng-container> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.component.ts index 2c15634893..63ed57628b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.component.ts @@ -36,6 +36,7 @@ import { ComponentStyle, iconStyle, overlayStyle, + resolveCssSize, textStyle } from '@shared/models/widget-settings.models'; import { Observable } from 'rxjs'; @@ -74,6 +75,7 @@ export class SingleSwitchWidgetComponent extends backgroundStyle$: Observable<ComponentStyle>; overlayStyle: ComponentStyle = {}; + padding: string; overlayInset = '12px'; value = false; @@ -123,6 +125,7 @@ export class SingleSwitchWidgetComponent extends this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer); this.overlayStyle = overlayStyle(this.settings.background.overlay); + this.padding = this.settings.background.overlay.enabled ? undefined : this.settings.padding; this.layout = this.settings.layout; @@ -231,11 +234,15 @@ export class SingleSwitchWidgetComponent extends } private onResize() { - const height = this.singleSwitchPanel.nativeElement.getBoundingClientRect().height; + const widgetBoundingClientRect = this.singleSwitchPanel.nativeElement.getBoundingClientRect(); + const height = widgetBoundingClientRect.height; const switchScale = height / initialSwitchHeight; const paddingScale = Math.min(switchScale, 1); - const panelWidth = this.singleSwitchPanel.nativeElement.getBoundingClientRect().width - (horizontalLayoutPadding * paddingScale); - const panelHeight = this.singleSwitchPanel.nativeElement.getBoundingClientRect().height - (verticalLayoutPadding * paddingScale); + const computedStyle = getComputedStyle(this.singleSwitchPanel.nativeElement); + const [pLeft, pRight, pTop, pBottom] = ['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom'] + .map(side => resolveCssSize(computedStyle[side])[0]); + const panelWidth = widgetBoundingClientRect.width - ((pLeft + pRight) || horizontalLayoutPadding * paddingScale); + const panelHeight = widgetBoundingClientRect.height - ((pTop + pBottom) || verticalLayoutPadding * paddingScale); this.renderer.setStyle(this.singleSwitchContent.nativeElement, 'transform', `scale(1)`); this.renderer.setStyle(this.singleSwitchContent.nativeElement, 'width', 'auto'); let contentWidth = this.singleSwitchToggleRow.nativeElement.getBoundingClientRect().width; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.models.ts index 94586c31de..62aae25816 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/single-switch-widget.models.ts @@ -80,6 +80,7 @@ export interface SingleSwitchWidgetSettings { offLabelFont: Font; offLabelColor: string; background: BackgroundSettings; + padding: string; } export const singleSwitchDefaultSettings: SingleSwitchWidgetSettings = { @@ -217,5 +218,6 @@ export const singleSwitchDefaultSettings: SingleSwitchWidgetSettings = { color: 'rgba(255,255,255,0.72)', blur: 3 } - } + }, + padding: '' }; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts index 6db0d202c7..010cb9d6bc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol-widget.component.ts @@ -40,6 +40,7 @@ import { WidgetComponent } from '@home/components/widget/widget.component'; import { isDefinedAndNotNull, mergeDeep } from '@core/utils'; import { WidgetContext } from '@home/models/widget-component.models'; import { catchError, share } from 'rxjs/operators'; +import { MatIconRegistry } from '@angular/material/icon'; @Component({ selector: 'tb-scada-symbol-widget', @@ -75,6 +76,7 @@ export class ScadaSymbolWidgetComponent implements OnInit, AfterViewInit, OnDest protected imagePipe: ImagePipe, protected sanitizer: DomSanitizer, private imageService: ImageService, + private iconRegistry: MatIconRegistry, protected cd: ChangeDetectorRef) { } @@ -138,7 +140,8 @@ export class ScadaSymbolWidgetComponent implements OnInit, AfterViewInit, OnDest this.noScadaSymbol = true; this.cd.markForCheck(); } else { - this.scadaSymbolObject = new ScadaSymbolObject(rootElement, this.ctx, content, + this.scadaSymbolObject = new ScadaSymbolObject(rootElement, this.ctx, this.iconRegistry, + content, this.settings.scadaSymbolObjectSettings, this, simulated); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts index ff74bc58ac..8e5993902d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/scada/scada-symbol.models.ts @@ -34,7 +34,7 @@ import { mergeDeep, parseFunction } from '@core/utils'; -import { BehaviorSubject, forkJoin, Observable, Observer, Subject } from 'rxjs'; +import { BehaviorSubject, forkJoin, Observable, Observer, of, Subject } from 'rxjs'; import { ValueAction, ValueGetter, ValueSetter } from '@home/components/widget/lib/action/action-widget.models'; import { WidgetContext } from '@home/models/widget-component.models'; import { ColorProcessor, constantColor, Font } from '@shared/models/widget-settings.models'; @@ -42,13 +42,16 @@ import { AttributeScope } from '@shared/models/telemetry/telemetry.models'; import { UtilsService } from '@core/services/utils.service'; import { WidgetAction, WidgetActionType, widgetActionTypeTranslationMap } from '@shared/models/widget.models'; import { ResizeObserver } from '@juggle/resize-observer'; -import { takeUntil } from 'rxjs/operators'; +import { catchError, map, take, takeUntil } from 'rxjs/operators'; +import { isSvgIcon, splitIconName } from '@shared/models/icon.models'; +import { MatIconRegistry } from '@angular/material/icon'; export interface ScadaSymbolApi { generateElementId: () => string; formatValue: (value: any, dec?: number, units?: string, showZeroDecimals?: boolean) => string | undefined; text: (element: Element | Element[], text: string) => void; font: (element: Element | Element[], font: Font, color: string) => void; + icon: (element: Element | Element[], icon: string, size?: number, color?: string, center?: boolean) => void; animate: (element: Element, duration: number) => Runner; resetAnimation: (element: Element) => void; finishAnimation: (element: Element) => void; @@ -133,7 +136,8 @@ export enum ScadaSymbolPropertyType { color = 'color', color_settings = 'color_settings', font = 'font', - units = 'units' + units = 'units', + icon = 'icon' } export const scadaSymbolPropertyTypes = Object.keys(ScadaSymbolPropertyType) as ScadaSymbolPropertyType[]; @@ -146,7 +150,8 @@ export const scadaSymbolPropertyTypeTranslations = new Map<ScadaSymbolPropertyTy [ScadaSymbolPropertyType.color, 'scada.property.type-color'], [ScadaSymbolPropertyType.color_settings, 'scada.property.type-color-settings'], [ScadaSymbolPropertyType.font, 'scada.property.type-font'], - [ScadaSymbolPropertyType.units, 'scada.property.type-units'] + [ScadaSymbolPropertyType.units, 'scada.property.type-units'], + [ScadaSymbolPropertyType.icon, 'scada.property.type-icon'] ] ); @@ -191,10 +196,10 @@ export interface ScadaSymbolMetadata { properties: ScadaSymbolProperty[]; } -export const emptyMetadata = (): ScadaSymbolMetadata => ({ +export const emptyMetadata = (width?: number, height?: number): ScadaSymbolMetadata => ({ title: '', - widgetSizeX: 3, - widgetSizeY: 3, + widgetSizeX: width ? width/100 : 3, + widgetSizeY: height ? height/100 : 3, tags: [], behavior: [], properties: [] @@ -255,7 +260,17 @@ const parseScadaSymbolMetadataFromDom = (svgDoc: Document): ScadaSymbolMetadata if (elements.length) { return JSON.parse(elements[0].textContent); } else { - return emptyMetadata(); + const svg = svgDoc.getElementsByTagName('svg')[0]; + let width = null; + let height = null; + if (svg.viewBox.baseVal.width && svg.viewBox.baseVal.height) { + width = svg.viewBox.baseVal.width; + height = svg.viewBox.baseVal.height; + } else if (svg.width.baseVal.value && svg.height.baseVal.value) { + width = svg.width.baseVal.value; + height = svg.height.baseVal.value; + } + return emptyMetadata(width, height); } } catch (_e) { console.error(_e); @@ -496,6 +511,7 @@ export class ScadaSymbolObject { constructor(private rootElement: HTMLElement, private ctx: WidgetContext, + private iconRegistry: MatIconRegistry, private svgContent: string, private inputSettings: ScadaSymbolObjectSettings, private callbacks: ScadaSymbolObjectCallbacks, @@ -599,6 +615,7 @@ export class ScadaSymbolObject { formatValue, text: this.setElementText.bind(this), font: this.setElementFont.bind(this), + icon: this.setElementIcon.bind(this), animate: this.animate.bind(this), resetAnimation: this.resetAnimation.bind(this), finishAnimation: this.finishAnimation.bind(this), @@ -859,6 +876,74 @@ export class ScadaSymbolObject { }); } + private setElementIcon(e: Element | Element[], + icon: string, + size = 12, + color = '#0000008A', + center = true) { + this.elements(e).forEach(element => { + if (element.type === 'g') { + let skip = false; + const firstChild = element.first(); + if (firstChild) { + const iconData: {icon: string; size: number; color: string} = firstChild.remember('iconData'); + if (iconData && iconData.icon === icon && iconData.size === size && iconData.color === color) { + skip = true; + } + } + if (!skip) { + element.clear(); + this.createIconElement(icon, size, color).subscribe((iconElement) => { + if (iconElement) { + iconElement.remember('iconData', {icon, size, color}); + element.add(iconElement); + if (center) { + const box = iconElement.bbox(); + iconElement.translate(-box.cx, -box.cy); + } + } + }); + } + } + }); + } + + private createIconElement(icon: string, size: number, color: string): Observable<Element> { + const isSvg = isSvgIcon(icon); + if (isSvg) { + const [namespace, iconName] = splitIconName(icon); + return this.iconRegistry + .getNamedSvgIcon(iconName, namespace) + .pipe( + take(1), + map((svgElement) => { + const element = new Element(svgElement.firstChild); + const box = element.bbox(); + const scale = size / box.height; + element.scale(scale); + element.fill(color); + return element; + }), + catchError(() => of(null) + )); + } else { + const iconName = splitIconName(icon)[1]; + const textElement = this.svgShape.text(iconName); + const fontSetClasses = ( + this.iconRegistry.getDefaultFontSetClass() + ).filter(className => className.length > 0); + fontSetClasses.forEach(className => textElement.addClass(className)); + textElement.font({size: `${size}px`}); + textElement.attr({ + 'text-anchor': 'start', + 'dominant-baseline': 'hanging', + style: `font-size: ${size}px` + }); + textElement.fill(color); + return of(textElement); + } + } + private animate(element: Element, duration: number): Runner { this.finishAnimation(element); return element.animate(duration, 0, 'now'); 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 76f46862a6..5077c93d8e 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 @@ -93,5 +93,11 @@ <tb-background-settings formControlName="background"> </tb-background-settings> </div> + <div class="tb-form-row space-between"> + <div>{{ 'widget-config.card-padding' | translate }}</div> + <mat-form-field appearance="outline" subscriptSizing="dynamic"> + <input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}"> + </mat-form-field> + </div> </div> </ng-container> 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 9693ca22d4..be7794802c 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 @@ -110,7 +110,8 @@ export class ValueCardWidgetSettingsComponent extends WidgetSettingsComponent { dateFont: [settings.dateFont, []], dateColor: [settings.dateColor, []], - background: [settings.background, []] + background: [settings.background, []], + padding: [settings.padding, []] }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/scada/scada-symbol-object-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/scada/scada-symbol-object-settings.component.html index 5b6d50bf1c..1a4d5eb77b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/scada/scada-symbol-object-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/scada/scada-symbol-object-settings.component.html @@ -79,6 +79,10 @@ [class]="property.fieldClass" [required]="property.required" formControlName="{{ property.id }}"></tb-unit-input> + <tb-material-icon-select *ngIf="property.type === ScadaSymbolPropertyType.icon" + asBoxInput + formControlName="{{ property.id }}"> + </tb-material-icon-select> <mat-divider *ngIf="property.divider" vertical></mat-divider> </ng-container> </div> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/single-switch-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/single-switch-widget-settings.component.html index db6d0371f9..2709266f2f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/single-switch-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/single-switch-widget-settings.component.html @@ -123,6 +123,12 @@ <tb-background-settings formControlName="background"> </tb-background-settings> </div> + <div class="tb-form-row space-between"> + <div>{{ 'widget-config.card-padding' | translate }}</div> + <mat-form-field appearance="outline" subscriptSizing="dynamic"> + <input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}"> + </mat-form-field> + </div> </div> <div class="tb-form-panel"> <div class="tb-form-panel-title" translate>widgets.single-switch.switch</div> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/single-switch-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/single-switch-widget-settings.component.ts index a1a3e951f2..a4a76e5294 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/single-switch-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/single-switch-widget-settings.component.ts @@ -102,7 +102,8 @@ export class SingleSwitchWidgetSettingsComponent extends WidgetSettingsComponent offLabelFont: [settings.offLabelFont, []], offLabelColor: [settings.offLabelColor, []], - background: [settings.background, []] + background: [settings.background, []], + padding: [settings.padding, []] }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/status-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/status-widget-settings.component.html index 21b7bc5cf0..892311733c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/status-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/status-widget-settings.component.html @@ -78,5 +78,11 @@ [layout]="statusWidgetSettingsForm.get('layout').value" formControlName="offState"> </tb-status-widget-state-settings> + <div class="tb-form-row space-between"> + <div>{{ 'widget-config.card-padding' | translate }}</div> + <mat-form-field appearance="outline" subscriptSizing="dynamic"> + <input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}"> + </mat-form-field> + </div> </div> </ng-container> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/status-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/status-widget-settings.component.ts index 03da985a0e..1130b58b21 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/status-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/status-widget-settings.component.ts @@ -73,7 +73,8 @@ export class StatusWidgetSettingsComponent extends WidgetSettingsComponent { disabledState: [settings.disabledState, []], layout: [settings.layout, []], onState: [settings.onState, []], - offState: [settings.offState, []] + offState: [settings.offState, []], + padding: [settings.padding, []] }); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.html index 9265164c52..5271825ccf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.html @@ -100,5 +100,11 @@ <tb-background-settings formControlName="background"> </tb-background-settings> </div> + <div class="tb-form-row space-between"> + <div>{{ 'widget-config.card-padding' | translate }}</div> + <mat-form-field appearance="outline" subscriptSizing="dynamic"> + <input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}"> + </mat-form-field> + </div> </div> </ng-container> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.ts index e6b8880758..2d16a030b7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.ts @@ -91,7 +91,8 @@ export class WindSpeedDirectionWidgetSettingsComponent extends WidgetSettingsCom arrowColor: [settings.arrowColor, []], - background: [settings.background, []] + background: [settings.background, []], + padding: [settings.padding, []] }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.html index 80ca1960f9..0ec08c2a05 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -<div class="tb-wind-speed-direction-panel" [style]="backgroundStyle$ | async" [class.tb-wind-speed-direction-pointer]="hasCardClickAction" (click)="cardClick($event)"> +<div class="tb-wind-speed-direction-panel" [style.padding]="padding" [style]="backgroundStyle$ | async" [class.tb-wind-speed-direction-pointer]="hasCardClickAction" (click)="cardClick($event)"> <div class="tb-wind-speed-direction-overlay" [style]="overlayStyle"></div> <ng-container *ngTemplateOutlet="widgetTitlePanel"></ng-container> <div class="tb-wind-speed-direction-content"> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts index 4ce5cf21d7..929f41fe48 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts @@ -42,7 +42,6 @@ import { getSingleTsValueByDataKey, overlayStyle } from '@shared/models/widget-settings.models'; -import { WidgetComponent } from '@home/components/widget/widget.component'; import { formatValue, isDefinedAndNotNull, isNumeric } from '@core/utils'; import { ResizeObserver } from '@juggle/resize-observer'; import { Path, Svg, SVG, Text } from '@svgdotjs/svg.js'; @@ -92,6 +91,7 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft backgroundStyle$: Observable<ComponentStyle>; overlayStyle: ComponentStyle = {}; + padding: string; shapeResize$: ResizeObserver; @@ -111,8 +111,7 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft private windDirection = 0; private centerValueText = 'N/A'; - constructor(private widgetComponent: WidgetComponent, - private imagePipe: ImagePipe, + constructor(private imagePipe: ImagePipe, private sanitizer: DomSanitizer, private renderer: Renderer2, private cd: ChangeDetectorRef) { @@ -142,6 +141,7 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer); this.overlayStyle = overlayStyle(this.settings.background.overlay); + this.padding = this.settings.background.overlay.enabled ? undefined : this.settings.padding; this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts index 7801f80a17..5daa9e3d68 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts @@ -14,7 +14,6 @@ /// limitations under the License. /// -import { BatteryLevelLayout } from '@home/components/widget/lib/indicator/battery-level-widget.models'; import { BackgroundSettings, BackgroundType, @@ -59,6 +58,7 @@ export interface WindSpeedDirectionWidgetSettings { minorTicksColor: string; minorTicksFont: Font; background: BackgroundSettings; + padding: string } export const windSpeedDirectionDefaultSettings: WindSpeedDirectionWidgetSettings = { @@ -101,5 +101,6 @@ export const windSpeedDirectionDefaultSettings: WindSpeedDirectionWidgetSettings color: 'rgba(255,255,255,0.72)', blur: 3 } - } + }, + padding: '' }; 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 508d07ea0d..8e1e6f1b3a 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 @@ -381,9 +381,8 @@ export class WidgetComponentService { widgetInfo.templateHtml, resolvedModules.modules ).pipe( - map((componentData) => { - widgetInfo.componentType = componentData.componentType; - widgetInfo.componentModuleRef = componentData.componentModuleRef; + map((componentType) => { + widgetInfo.componentType = componentType; return null; }), catchError(e => { 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 2acc299586..f241bc91d0 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 @@ -113,22 +113,22 @@ import { GatewayHelpLinkPipe } from '@home/components/widget/lib/gateway/pipes/g import { EllipsisChipListDirective } from '@shared/directives/ellipsis-chip-list.directive'; import { BrokerConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/broker-config-control/broker-config-control.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/broker-config-control/broker-config-control.component'; import { WorkersConfigControlComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/workers-config-control/workers-config-control.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/workers-config-control/workers-config-control.component'; import { OpcServerConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/opc-server-config/opc-server-config.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-server-config/opc-server-config.component'; import { MqttBasicConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt-basic-config/mqtt-basic-config.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-basic-config.component'; import { MappingTableComponent } from '@home/components/widget/lib/gateway/connectors-configuration/mapping-table/mapping-table.component'; import { OpcUaBasicConfigComponent -} from '@home/components/widget/lib/gateway/connectors-configuration/opc-ua-basic-config/opc-ua-basic-config.component'; +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-basic-config.component'; import { ModbusBasicConfigComponent } from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-basic-config.component'; @@ -145,12 +145,21 @@ import { ModbusRpcParametersComponent } from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-rpc-parameters/modbus-rpc-parameters.component'; import { ScadaSymbolWidgetComponent } from '@home/components/widget/lib/scada/scada-symbol-widget.component'; +import { + MqttLegacyBasicConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/mqtt/basic-config/mqtt-legacy-basic-config.component'; import { GatewayBasicConfigurationComponent } from '@home/components/widget/lib/gateway/configuration/basic/gateway-basic-configuration.component'; import { GatewayAdvancedConfigurationComponent } from '@home/components/widget/lib/gateway/configuration/advanced/gateway-advanced-configuration.component'; +import { + OpcUaLegacyBasicConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/opc/opc-ua-basic-config/opc-ua-legacy-basic-config.component'; +import { + ModbusLegacyBasicConfigComponent +} from '@home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-basic-config/modbus-legacy-basic-config.component'; @NgModule({ declarations: [ @@ -239,8 +248,11 @@ import { ModbusBasicConfigComponent, EllipsisChipListDirective, ModbusRpcParametersComponent, + MqttLegacyBasicConfigComponent, GatewayBasicConfigurationComponent, GatewayAdvancedConfigurationComponent, + OpcUaLegacyBasicConfigComponent, + ModbusLegacyBasicConfigComponent, ], exports: [ EntitiesTableWidgetComponent, 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 76845a11ef..5bd4910af7 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 @@ -760,7 +760,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI try { this.dynamicWidgetComponentRef = this.widgetContentContainer.createComponent(this.widgetInfo.componentType, - {index: 0, injector, ngModuleRef: this.widgetInfo.componentModuleRef}); + {index: 0, injector}); this.cd.detectChanges(); } catch (e) { if (this.dynamicWidgetComponentRef) { diff --git a/ui-ngx/src/app/modules/home/models/services.map.ts b/ui-ngx/src/app/modules/home/models/services.map.ts index cca04d8dc9..073bbd5b43 100644 --- a/ui-ngx/src/app/modules/home/models/services.map.ts +++ b/ui-ngx/src/app/modules/home/models/services.map.ts @@ -50,6 +50,8 @@ import { TenantService } from '@core/http/tenant.service'; import { TenantProfileService } from '@core/http/tenant-profile.service'; import { UiSettingsService } from '@core/http/ui-settings.service'; import { UsageInfoService } from '@core/http/usage-info.service'; +import { EventService } from '@core/http/event.service'; +import { AuditLogService } from '@core/http/audit-log.service'; export const ServicesMap = new Map<string, Type<any>>( [ @@ -87,6 +89,8 @@ export const ServicesMap = new Map<string, Type<any>>( ['userSettingsService', UserSettingsService], ['uiSettingsService', UiSettingsService], ['usageInfoService', UsageInfoService], - ['notificationService', NotificationService] + ['notificationService', NotificationService], + ['eventService', EventService], + ['auditLogService', AuditLogService] ] ); 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 5a1a28472e..673bc21edb 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 @@ -47,7 +47,7 @@ import { WidgetActionsApi, WidgetSubscriptionApi } from '@core/api/widget-api.models'; -import { ChangeDetectorRef, Injector, NgModuleRef, NgZone, Type } from '@angular/core'; +import { ChangeDetectorRef, Injector, 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'; @@ -101,7 +101,6 @@ import { AlarmQuery, AlarmSearchStatus, AlarmStatus } from '@app/shared/models/a import { ImagePipe, 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 { DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models'; import { UtilsService } from '@core/services/utils.service'; @@ -549,7 +548,6 @@ export interface WidgetInfo extends WidgetTypeDescriptor, WidgetControllerDescri description?: string; tags?: string[]; componentType?: Type<IDynamicWidgetComponent>; - componentModuleRef?: NgModuleRef<DynamicComponentModule>; } export interface WidgetConfigComponentData { diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts index 1e7eef1c41..66a704996b 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library-table-config.resolve.ts @@ -22,7 +22,7 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { Resolve, Router } from '@angular/router'; -import { Resource, ResourceInfo, ResourceTypeTranslationMap } from '@shared/models/resource.models'; +import { Resource, ResourceInfo, ResourceType, ResourceTypeTranslationMap } from '@shared/models/resource.models'; import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; import { NULL_UUID } from '@shared/models/id/has-uuid'; import { DatePipe } from '@angular/common'; @@ -118,7 +118,7 @@ export class ResourcesLibraryTableConfigResolver implements Resolve<EntityTableC const authUser = getCurrentAuthUser(this.store); this.config.deleteEnabled = (resource) => this.isResourceEditable(resource, authUser.authority); this.config.entitySelectionEnabled = (resource) => this.isResourceEditable(resource, authUser.authority); - this.config.detailsReadonly = (resource) => !this.isResourceEditable(resource, authUser.authority); + this.config.detailsReadonly = (resource) => this.detailsReadonly(resource, authUser.authority); return this.config; } @@ -149,6 +149,13 @@ export class ResourcesLibraryTableConfigResolver implements Resolve<EntityTableC return false; } + private detailsReadonly(resource: ResourceInfo, authority: Authority): boolean { + if (resource?.resourceType === ResourceType.LWM2M_MODEL) { + return true; + } + return !this.isResourceEditable(resource, authority); + } + private isResourceEditable(resource: ResourceInfo, authority: Authority): boolean { if (authority === Authority.TENANT_ADMIN) { return resource && resource.tenantId && resource.tenantId.id !== NULL_UUID; diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.html b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.html index 5c3d9da081..441a311021 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.html @@ -58,7 +58,7 @@ </mat-form-field> <mat-form-field class="mat-block" *ngIf="entityForm.get('resourceType').value !== resourceType.LWM2M_MODEL || !isAdd"> <mat-label translate>resource.title</mat-label> - <input matInput formControlName="title" required [readonly]="entityForm.get('resourceType').value === resourceType.LWM2M_MODEL"> + <input matInput formControlName="title" required> <mat-error *ngIf="entityForm.get('title').hasError('required')"> {{ 'resource.title-required' | translate }} </mat-error> diff --git a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.ts b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.ts index f6a8befe9b..de6a62e15c 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/resource/resources-library.component.ts @@ -43,8 +43,7 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme readonly resourceType = ResourceType; readonly resourceTypes: ResourceType[] = Object.values(this.resourceType); readonly resourceTypesTranslationMap = ResourceTypeTranslationMap; - - maxResourceSize = getCurrentAuthState(this.store).maxResourceSize; + readonly maxResourceSize = getCurrentAuthState(this.store).maxResourceSize; private destroy$ = new Subject<void>(); @@ -57,20 +56,20 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme super(store, fb, entityValue, entitiesTableConfigValue, cd); } - ngOnInit() { + ngOnInit(): void { super.ngOnInit(); if (this.isAdd) { this.observeResourceTypeChange(); } } - ngOnDestroy() { + ngOnDestroy(): void { super.ngOnDestroy(); this.destroy$.next(); this.destroy$.complete(); } - hideDelete() { + hideDelete(): boolean { if (this.entitiesTableConfig) { return !this.entitiesTableConfig.deleteEnabled(this.entity); } else { @@ -87,19 +86,18 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme }); } - updateForm(entity: Resource) { - if (this.isEdit) { - this.entityForm.get('resourceType').disable({emitEvent: false}); - if (entity.resourceType !== ResourceType.JS_MODULE) { - this.entityForm.get('fileName').disable({emitEvent: false}); + updateForm(entity: Resource): void { + this.entityForm.patchValue(entity); + } + + override updateFormState(): void { + super.updateFormState(); + if (this.isEdit && this.entityForm) { + this.entityForm.get('resourceType').disable({ emitEvent: false }); + if (this.entityForm.get('resourceType').value !== ResourceType.JS_MODULE) { + this.entityForm.get('fileName').disable({ emitEvent: false }); } } - this.entityForm.patchValue({ - resourceType: entity.resourceType, - fileName: entity.fileName, - title: entity.title, - data: entity.data - }); } prepareFormValue(formValue: Resource): Resource { @@ -109,7 +107,7 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme return super.prepareFormValue(formValue); } - getAllowedExtensions() { + getAllowedExtensions(): string { try { return ResourceTypeExtension.get(this.entityForm.get('resourceType').value); } catch (e) { @@ -117,7 +115,7 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme } } - getAcceptType() { + getAcceptType(): string { try { return ResourceTypeMIMETypes.get(this.entityForm.get('resourceType').value); } catch (e) { @@ -129,7 +127,7 @@ export class ResourcesLibraryComponent extends EntityComponent<Resource> impleme return window.btoa(data); } - onResourceIdCopied() { + onResourceIdCopied(): void { this.store.dispatch(new ActionNotificationShow( { message: this.translate.instant('resource.idCopiedMessage'), diff --git a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.html index 3d399d01a1..0b9df7c5ae 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.html @@ -46,6 +46,44 @@ <input matInput type="email" formControlName="userLockoutNotificationEmail"/> </mat-form-field> + <mat-form-field class="mat-block"> + <mat-label translate>admin.user-activation-token-ttl</mat-label> + <input matInput type="number" + formControlName="userActivationTokenTtl" + step="1" + min="1" + max="24"/> + <mat-error *ngIf="securitySettingsFormGroup.get('userActivationTokenTtl').hasError('min')"> + {{ 'admin.user-activation-token-ttl-range' | translate }} + </mat-error> + <mat-error *ngIf="securitySettingsFormGroup.get('userActivationTokenTtl').hasError('max')"> + {{ 'admin.user-activation-token-ttl-range' | translate }} + </mat-error> + </mat-form-field> + <mat-form-field class="mat-block"> + <mat-label translate>admin.password-reset-token-ttl</mat-label> + <input matInput type="number" + formControlName="passwordResetTokenTtl" + step="1" + min="1" + max="24"/> + <mat-error *ngIf="securitySettingsFormGroup.get('passwordResetTokenTtl').hasError('min')"> + {{ 'admin.password-reset-token-ttl-range' | translate }} + </mat-error> + <mat-error *ngIf="securitySettingsFormGroup.get('passwordResetTokenTtl').hasError('max')"> + {{ 'admin.password-reset-token-ttl-range' | translate }} + </mat-error> + </mat-form-field> + <mat-form-field class="mat-block"> + <mat-label translate>admin.mobile-secret-key-length</mat-label> + <input matInput type="number" + formControlName="mobileSecretKeyLength" + step="1" + min="1"/> + <mat-error *ngIf="securitySettingsFormGroup.get('mobileSecretKeyLength').hasError('min')"> + {{ 'admin.mobile-secret-key-length-range' | translate }} + </mat-error> + </mat-form-field> </fieldset> <fieldset class="fields-group"> diff --git a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts index c7ac489753..712e2bb358 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts @@ -75,6 +75,9 @@ export class SecuritySettingsComponent extends PageComponent implements HasConfi this.securitySettingsFormGroup = this.fb.group({ maxFailedLoginAttempts: [null, [Validators.min(0)]], userLockoutNotificationEmail: ['', []], + userActivationTokenTtl: [24, [Validators.required, Validators.min(1), Validators.max(24)]], + passwordResetTokenTtl: [24, [Validators.required, Validators.min(1), Validators.max(24)]], + mobileSecretKeyLength: [null, [Validators.min(1)]], passwordPolicy: this.fb.group( { minimumLength: [null, [Validators.required, Validators.min(6), Validators.max(50)]], diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.html b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.html index 27c22df7a8..940be57364 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.html +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.html @@ -30,8 +30,7 @@ <tb-js-func #tagFunctionComponent minHeight="300px" formControlName="tagFunction" - [objectHighlightRules]="objectHighlightRules" - [propertyHighlightRules]="propertyHighlightRules" + [highlightRules]="highlightRules" [editorCompleter]="completer" [functionArgs]="tagFunctionArgs" [helpId]="tagFunctionHelpId"> diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.ts index d46ba364d7..3da729c442 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag-function-panel.component.ts @@ -28,12 +28,10 @@ import { TbPopoverComponent } from '@shared/components/popover.component'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { WidgetService } from '@core/http/widget.service'; import { TbEditorCompleter } from '@shared/models/ace/completion.models'; -import { TbHighlightRule } from '@shared/models/ace/ace.models'; +import { AceHighlightRules } from '@shared/models/ace/ace.models'; import { scadaSymbolClickActionHighlightRules, - scadaSymbolClickActionPropertiesHighlightRules, - scadaSymbolElementStateRenderHighlightRules, - scadaSymbolElementStateRenderPropertiesHighlightRules + scadaSymbolRenderFunctionHighlightRules } from '@home/pages/scada-symbol/scada-symbol-editor.models'; import { JsFuncComponent } from '@shared/components/js-func.component'; @@ -79,9 +77,7 @@ export class ScadaSymbolMetadataTagFunctionPanelComponent implements OnInit, Aft tagFunctionHelpId: string; - objectHighlightRules: TbHighlightRule[]; - - propertyHighlightRules: TbHighlightRule[]; + highlightRules: AceHighlightRules; constructor(private fb: UntypedFormBuilder, private widgetService: WidgetService) { @@ -99,14 +95,12 @@ export class ScadaSymbolMetadataTagFunctionPanelComponent implements OnInit, Aft if (this.tagFunctionType === 'renderFunction') { this.panelTitle = 'scada.state-render-function'; this.tagFunctionArgs = ['ctx', 'element']; - this.objectHighlightRules = scadaSymbolElementStateRenderHighlightRules; - this.propertyHighlightRules = scadaSymbolElementStateRenderPropertiesHighlightRules; + this.highlightRules = scadaSymbolRenderFunctionHighlightRules; this.tagFunctionHelpId = 'scada/tag_state_render_fn'; } else if (this.tagFunctionType === 'clickAction') { this.panelTitle = 'scada.tag.on-click-action'; this.tagFunctionArgs = ['ctx', 'element', 'event']; - this.objectHighlightRules = scadaSymbolClickActionHighlightRules; - this.propertyHighlightRules = scadaSymbolClickActionPropertiesHighlightRules; + this.highlightRules = scadaSymbolClickActionHighlightRules; this.tagFunctionHelpId = 'scada/tag_click_action_fn'; } } diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.html b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.html index 9e5d22fa94..67c77f7f2a 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.html +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.html @@ -80,8 +80,7 @@ <tb-js-func formControlName="stateRenderFunction" minHeight="300px" [editorCompleter]="generalStateRenderFunctionCompleter" - [objectHighlightRules]="scadaSymbolGeneralStateRenderHighlightRules" - [propertyHighlightRules]="scadaSymbolGeneralStateRenderPropertiesHighlightRules" + [highlightRules]="highlightRules" [functionArgs]="['ctx', 'svg']" helpId="scada/symbol_state_render_fn"> </tb-js-func> diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts index f5ecaab3d2..a5d38991b9 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts @@ -49,8 +49,7 @@ import { elementStateRenderFunctionCompletions, generalStateRenderFunctionCompletions, scadaSymbolContextCompletion, - scadaSymbolGeneralStateRenderHighlightRules, - scadaSymbolGeneralStateRenderPropertiesHighlightRules + scadaSymbolGeneralStateHighlightRules } from '@home/pages/scada-symbol/scada-symbol-editor.models'; import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; import { IAliasController } from '@core/api/widget-api.models'; @@ -122,9 +121,7 @@ export class ScadaSymbolMetadataComponent extends PageComponent implements OnIni elementStateRenderFunctionCompleter: TbEditorCompleter; clickActionFunctionCompleter: TbEditorCompleter; - scadaSymbolGeneralStateRenderHighlightRules = scadaSymbolGeneralStateRenderHighlightRules; - - scadaSymbolGeneralStateRenderPropertiesHighlightRules = scadaSymbolGeneralStateRenderPropertiesHighlightRules; + highlightRules = scadaSymbolGeneralStateHighlightRules; constructor(protected store: Store<AppState>, private fb: UntypedFormBuilder, diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component.html b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component.html index 9fd461c229..6090a9504e 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component.html +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-panel.component.html @@ -76,6 +76,10 @@ <tb-value-input *ngIf="propertyFormGroup.get('type').value === ScadaSymbolPropertyType.switch" [valueType]="ValueType.BOOLEAN" formControlName="default"></tb-value-input> + <tb-material-icon-select *ngIf="propertyFormGroup.get('type').value === ScadaSymbolPropertyType.icon" + asBoxInput + formControlName="default"> + </tb-material-icon-select> </div> <div *ngIf="propertyFormGroup.get('type').value === ScadaSymbolPropertyType.number" class="tb-form-row space-between"> <div translate>scada.property.number-settings</div> @@ -136,6 +140,7 @@ <div class="fixed-title-width" translate>scada.property.disable-on-property</div> <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic"> <mat-select formControlName="disableOnProperty" placeholder="{{ 'widget-config.set' | translate }}"> + <mat-option [value]="null"></mat-option> <mat-option *ngFor="let prop of booleanPropertyIds" [value]="prop"> {{ prop }} </mat-option> diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component.ts index 3c5ea6cb07..3da851063f 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-property-row.component.ts @@ -81,6 +81,8 @@ export const defaultPropertyValue = (type: ScadaSymbolPropertyType): any => { } as Font; case ScadaSymbolPropertyType.units: return ''; + case ScadaSymbolPropertyType.icon: + return 'star'; } }; diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts index ddc935d202..9c1ad96894 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.models.ts @@ -34,7 +34,7 @@ import { } from '@home/components/widget/lib/scada/scada-symbol.models'; import { TbEditorCompletion, TbEditorCompletions } from '@shared/models/ace/completion.models'; import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; -import { TbHighlightRule } from '@shared/models/ace/ace.models'; +import { AceHighlightRule, AceHighlightRules } from '@shared/models/ace/ace.models'; import { ValueType } from '@shared/models/constants'; import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance; import TooltipPositioningSide = JQueryTooltipster.TooltipPositioningSide; @@ -491,17 +491,6 @@ export class ScadaSymbolElement { element.show(); } this.box = element.rbox(this.editObject.svgShape); -/* if (element.visible()) { - this.box = element.rbox(this.editObject.svgShape); - if (parentGroup && parentGroup.invisible) { - this.invisible = true; - } - } else { - element.show(); - this.box = element.rbox(this.editObject.svgShape); - element.hide(); - this.invisible = true; - }*/ } public init() { @@ -916,91 +905,184 @@ export class ScadaSymbolElement { } -const scadaSymbolCtxObjectHighlightRules: TbHighlightRule[] = [ - { - class: 'scada-symbol-ctx', - regex: /(?<=\W|^)(ctx)(?=\W|$)\b/ - } -]; +const identifierRe = /[a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*/; -export const scadaSymbolGeneralStateRenderHighlightRules: TbHighlightRule[] = - scadaSymbolCtxObjectHighlightRules.concat({ - class: 'scada-symbol-svg', - regex: /(?<=\W|^)(svg)(?=\W|$)\b/ - }); +const dotOperatorHighlightRule: AceHighlightRule = { + token: 'punctuation.operator', + regex: /[.](?![.])/, +}; -export const scadaSymbolElementStateRenderHighlightRules: TbHighlightRule[] = - scadaSymbolCtxObjectHighlightRules.concat({ - class: 'scada-symbol-element', - regex: /(?<=\W|^)(element)(?=\W|$)\b/ - }); +const endGroupHighlightRule: AceHighlightRule = { + regex: '', + token: 'empty', + next: 'no_regex' +}; -export const scadaSymbolClickActionHighlightRules: TbHighlightRule[] = - scadaSymbolElementStateRenderHighlightRules.concat({ - class: 'scada-symbol-event', - regex: /(?<=\W|^)(event)(?=\W|$)\b/ - }); +const scadaSymbolCtxObjectHighlightRule: AceHighlightRule = { + token: 'tb.scada-symbol-ctx', + regex: /\bctx\b/, + next: 'scadaSymbolCtxApi' +}; -const scadaSymbolCtxPropertyHighlightRules: TbHighlightRule[] = [ - { - class: 'scada-symbol-ctx-properties', - regex: /(?<=ctx\.)(properties)\b/ - }, - { - class: 'scada-symbol-ctx-tags', - regex: /(?<=ctx\.)(tags)\b/ - }, - { - class: 'scada-symbol-ctx-values', - regex: /(?<=ctx\.)(values)\b/ - }, - { - class: 'scada-symbol-ctx-api', - regex: /(?<=ctx\.)(api)\b/ - }, - { - class: 'scada-symbol-ctx-svg', - regex: /(?<=ctx\.)(svg)\b/ - }, - { - class: 'scada-symbol-ctx-property', - regex: /(?<=ctx\.properties\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ - }, - { - class: 'scada-symbol-ctx-tag', - regex: /(?<=ctx\.tags\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ - }, - { - class: 'scada-symbol-ctx-value', - regex: /(?<=ctx\.values\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ - }, - { - class: 'scada-symbol-ctx-api-method', - regex: /(?<=ctx\.api\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ - }, - { - class: 'scada-symbol-ctx-svg-method', - regex: /(?<=ctx\.svg\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ - } -]; - -export const scadaSymbolGeneralStateRenderPropertiesHighlightRules: TbHighlightRule[] = - scadaSymbolCtxPropertyHighlightRules.concat({ - class: 'scada-symbol-svg-properties', - regex: /(?<=svg\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ - }); +const scadaSymbolSVGHighlightRule: AceHighlightRule = { + token: 'tb.scada-symbol-svg', + regex: /\bsvg\b/, + next: 'scadaSymbolSVGApi' +}; -export const scadaSymbolElementStateRenderPropertiesHighlightRules: TbHighlightRule[] = - scadaSymbolCtxPropertyHighlightRules.concat({ - class: 'scada-symbol-element-properties', - regex: /(?<=element\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ - }); +const scadaSymbolElementHighlightRule: AceHighlightRule = { + token: 'tb.scada-symbol-element', + regex: /\belement\b/, + next: 'scadaSymbolElementApi' +}; -export const scadaSymbolClickActionPropertiesHighlightRules: TbHighlightRule[] = - scadaSymbolElementStateRenderPropertiesHighlightRules.concat({ - class: 'scada-symbol-event-properties', - regex: /(?<=event\.)([a-zA-Z$_\u00a1-\uffff][a-zA-Z\d$_\u00a1-\uffff]*)\b/ - }); +const scadaSymbolEventHighlightRule: AceHighlightRule = { + token: 'tb.scada-symbol-event', + regex: /\bevent\b/, + next: 'scadaSymbolEventApi' +}; + +const scadaSymbolCtxApiHighlightRules: AceHighlightRules = { + scadaSymbolCtxApi: [ + dotOperatorHighlightRule, + { + token: 'tb.scada-symbol-ctx-properties', + regex: /properties/, + next: 'scadaSymbolCtxPropertiesApi' + }, + { + token: 'tb.scada-symbol-ctx-tags', + regex: /tags/, + next: 'scadaSymbolCtxTagsApi' + }, + { + token: 'tb.scada-symbol-ctx-values', + regex: /values/, + next: 'scadaSymbolCtxValuesApi' + }, + { + token: 'tb.scada-symbol-ctx-api', + regex: /api/, + next: 'scadaSymbolCtxApiMethodApi' + }, + { + token: 'tb.scada-symbol-ctx-svg', + regex: /svg/, + next: 'scadaSymbolCtxSVGMethodApi' + }, + endGroupHighlightRule + ], + scadaSymbolCtxPropertiesApi: [ + dotOperatorHighlightRule, + { + token: 'tb.scada-symbol-ctx-property', + regex: identifierRe, + next: 'no_regex' + }, + endGroupHighlightRule + ], + scadaSymbolCtxTagsApi: [ + dotOperatorHighlightRule, + { + token: 'tb.scada-symbol-ctx-tag', + regex: identifierRe, + next: 'no_regex' + }, + endGroupHighlightRule + ], + scadaSymbolCtxValuesApi: [ + dotOperatorHighlightRule, + { + token: 'tb.scada-symbol-ctx-value', + regex: identifierRe, + next: 'no_regex' + }, + endGroupHighlightRule + ], + scadaSymbolCtxApiMethodApi: [ + dotOperatorHighlightRule, + { + token: 'tb.scada-symbol-ctx-api-method', + regex: identifierRe, + next: 'no_regex' + }, + endGroupHighlightRule + ], + scadaSymbolCtxSVGMethodApi: [ + dotOperatorHighlightRule, + { + token: 'tb.scada-symbol-ctx-svg-method', + regex: identifierRe, + next: 'no_regex' + }, + endGroupHighlightRule + ] +}; + +const scadaSymbolSVGPropertyHighlightRules: AceHighlightRules = { + scadaSymbolSVGApi: [ + dotOperatorHighlightRule, + { + token: 'tb.scada-symbol-svg-properties', + regex: identifierRe, + next: 'no_regex' + }, + endGroupHighlightRule + ] +}; + +const scadaSymbolElementPropertyHighlightRules: AceHighlightRules = { + scadaSymbolElementApi: [ + dotOperatorHighlightRule, + { + token: 'tb.scada-symbol-element-properties', + regex: identifierRe, + next: 'no_regex' + }, + endGroupHighlightRule + ] +}; + +const scadaSymbolEventPropertyHighlightRules: AceHighlightRules = { + scadaSymbolEventApi: [ + dotOperatorHighlightRule, + { + token: 'tb.scada-symbol-event-properties', + regex: identifierRe, + next: 'no_regex' + }, + endGroupHighlightRule + ] +}; + +export const scadaSymbolGeneralStateHighlightRules: AceHighlightRules = { + start: [ + scadaSymbolCtxObjectHighlightRule, + scadaSymbolSVGHighlightRule + ], + ...scadaSymbolCtxApiHighlightRules, + ...scadaSymbolSVGPropertyHighlightRules +}; + +export const scadaSymbolRenderFunctionHighlightRules: AceHighlightRules = { + no_regex: [ + scadaSymbolCtxObjectHighlightRule, + scadaSymbolElementHighlightRule + ], + ...scadaSymbolCtxApiHighlightRules, + ...scadaSymbolElementPropertyHighlightRules +}; + +export const scadaSymbolClickActionHighlightRules: AceHighlightRules = { + start: [ + scadaSymbolCtxObjectHighlightRule, + scadaSymbolElementHighlightRule, + scadaSymbolEventHighlightRule + ], + ...scadaSymbolCtxApiHighlightRules, + ...scadaSymbolElementPropertyHighlightRules, + ...scadaSymbolEventPropertyHighlightRules +}; export const generalStateRenderFunctionCompletions = (ctxCompletion: TbEditorCompletion): TbEditorCompletions => ({ ctx: ctxCompletion, @@ -1204,6 +1286,41 @@ export const scadaSymbolContextCompletion = (metadata: ScadaSymbolMetadata, tags } ] }, + icon: { + meta: 'function', + description: 'Draws icon inside element(s). Only applicable for elements of type ' + + '<a href="https://svgjs.dev/docs/3.2/container-elements/#svg-g">SVG.G</a>.', + args: [ + { + name: 'element', + description: 'SVG element or an array of SVG elements', + type: 'Element | Array&lt;Element&gt;' + }, + { + name: 'icon', + description: 'Icon to draw', + type: 'string' + }, + { + name: 'size', + description: 'Optional icon size in pixels. Default 12 pixels.', + type: 'number', + optional: true + }, + { + name: 'color', + description: 'Optional icon color. Default #0000008A.', + type: 'string', + optional: true + }, + { + name: 'center', + description: 'Whether to center icon inside group element. Default true.', + type: 'boolean', + optional: true + } + ] + }, disable: { meta: 'function', description: 'Disables element(s). Disabled element doesn\'t accept any user interaction. ' + @@ -1324,6 +1441,8 @@ const scadaSymbolPropertyCompletionType = (type: ScadaSymbolPropertyType): strin return 'Font'; case ScadaSymbolPropertyType.units: return 'units string'; + case ScadaSymbolPropertyType.icon: + return 'icon string'; } }; diff --git a/ui-ngx/src/app/modules/home/pages/user/activation-link-dialog.component.html b/ui-ngx/src/app/modules/home/pages/user/activation-link-dialog.component.html index cabb688525..d03b50418d 100644 --- a/ui-ngx/src/app/modules/home/pages/user/activation-link-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/user/activation-link-dialog.component.html @@ -30,7 +30,7 @@ <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div> <div mat-dialog-content tb-toast toastTarget="activationLinkDialogContent"> <div class="mat-content" fxLayout="column"> - <span [innerHTML]="'user.activation-link-text' | translate: {activationLink: activationLink}"></span> + <span [innerHTML]="'user.activation-link-text' | translate: {activationLink: activationLink, activationLinkTtl: activationLinkTtl}"></span> <div fxLayout="row" fxLayoutAlign="start center"> <pre class="tb-highlight" fxFlex><code>{{ activationLink }}</code></pre> <button mat-icon-button diff --git a/ui-ngx/src/app/modules/home/pages/user/activation-link-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/user/activation-link-dialog.component.ts index d2c2037d6b..598cda29ef 100644 --- a/ui-ngx/src/app/modules/home/pages/user/activation-link-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/user/activation-link-dialog.component.ts @@ -14,7 +14,7 @@ /// 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'; @@ -22,29 +22,31 @@ import { TranslateService } from '@ngx-translate/core'; import { ActionNotificationShow } from '@core/notification/notification.actions'; import { DialogComponent } from '@shared/components/dialog.component'; import { Router } from '@angular/router'; +import { ActivationLinkInfo } from '@shared/models/user.model'; +import { MillisecondsToTimeStringPipe } from '@shared/pipe/milliseconds-to-time-string.pipe'; export interface ActivationLinkDialogData { - activationLink: string; + activationLinkInfo: ActivationLinkInfo; } @Component({ selector: 'tb-activation-link-dialog', templateUrl: './activation-link-dialog.component.html' }) -export class ActivationLinkDialogComponent extends DialogComponent<ActivationLinkDialogComponent, void> implements OnInit { +export class ActivationLinkDialogComponent extends DialogComponent<ActivationLinkDialogComponent, void> { activationLink: string; + activationLinkTtl: string; constructor(protected store: Store<AppState>, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: ActivationLinkDialogData, public dialogRef: MatDialogRef<ActivationLinkDialogComponent, void>, - private translate: TranslateService) { + private translate: TranslateService, + private millisecondsToTimeStringPipe: MillisecondsToTimeStringPipe) { super(store, router, dialogRef); - this.activationLink = this.data.activationLink; - } - - ngOnInit(): void { + this.activationLink = this.data.activationLinkInfo.value; + this.activationLinkTtl = this.millisecondsToTimeStringPipe.transform(this.data.activationLinkInfo.ttlMs); } close(): void { diff --git a/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.ts index 73bacc4c17..37c55c40c2 100644 --- a/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.ts @@ -21,7 +21,7 @@ import { AppState } from '@core/core.state'; import { UntypedFormGroup } from '@angular/forms'; import { UserComponent } from '@modules/home/pages/user/user.component'; import { Authority } from '@shared/models/authority.enum'; -import { ActivationMethod, activationMethodTranslations, User } from '@shared/models/user.model'; +import { ActivationLinkInfo, ActivationMethod, activationMethodTranslations, User } from '@shared/models/user.model'; import { CustomerId } from '@shared/models/id/customer-id'; import { UserService } from '@core/http/user.service'; import { Observable } from 'rxjs'; @@ -88,7 +88,7 @@ export class AddUserDialogComponent extends DialogComponent<AddUserDialogCompone this.userService.saveUser(this.user, sendActivationEmail).subscribe( (user) => { if (this.activationMethod === ActivationMethod.DISPLAY_ACTIVATION_LINK) { - this.userService.getActivationLink(user.id.id).subscribe( + this.userService.getActivationLinkInfo(user.id.id).subscribe( (activationLink) => { this.displayActivationLink(activationLink).subscribe( () => { @@ -105,13 +105,13 @@ export class AddUserDialogComponent extends DialogComponent<AddUserDialogCompone } } - displayActivationLink(activationLink: string): Observable<void> { + displayActivationLink(activationLinkInfo: ActivationLinkInfo): Observable<void> { return this.dialog.open<ActivationLinkDialogComponent, ActivationLinkDialogData, void>(ActivationLinkDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { - activationLink + activationLinkInfo } }).afterClosed(); } diff --git a/ui-ngx/src/app/modules/home/pages/user/users-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/user/users-table-config.resolver.ts index 6e762064cc..a8f7df963f 100644 --- a/ui-ngx/src/app/modules/home/pages/user/users-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/user/users-table-config.resolver.ts @@ -193,14 +193,14 @@ export class UsersTableConfigResolver implements Resolve<EntityTableConfig<User> if ($event) { $event.stopPropagation(); } - this.userService.getActivationLink(user.id.id).subscribe( - (activationLink) => { + this.userService.getActivationLinkInfo(user.id.id).subscribe( + (activationLinkInfo) => { this.dialog.open<ActivationLinkDialogComponent, ActivationLinkDialogData, void>(ActivationLinkDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { - activationLink + activationLinkInfo } }); } diff --git a/ui-ngx/src/app/modules/home/pages/widget/save-widget-type-as-dialog.component.html b/ui-ngx/src/app/modules/home/pages/widget/save-widget-type-as-dialog.component.html index 8d0f6bd6f5..804730dbfe 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/save-widget-type-as-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/save-widget-type-as-dialog.component.html @@ -39,6 +39,7 @@ </mat-form-field> <tb-widgets-bundle-select formControlName="widgetsBundle" + createNew bundlesScope="{{bundlesScope}}"> </tb-widgets-bundle-select> </div> diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-library.module.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-library.module.ts index 1ee25529b0..80438b4f4d 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-library.module.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-library.module.ts @@ -28,6 +28,7 @@ import { WidgetTypeComponent } from '@home/pages/widget/widget-type.component'; import { WidgetTypeTabsComponent } from '@home/pages/widget/widget-type-tabs.component'; import { WidgetsBundleWidgetsComponent } from '@home/pages/widget/widgets-bundle-widgets.component'; import { WidgetTypeAutocompleteComponent } from '@home/pages/widget/widget-type-autocomplete.component'; +import { WidgetsBundleDialogComponent } from '@home/pages/widget/widgets-bundle-dialog.component'; @NgModule({ declarations: [ @@ -39,7 +40,8 @@ import { WidgetTypeAutocompleteComponent } from '@home/pages/widget/widget-type- SelectWidgetTypeDialogComponent, SaveWidgetTypeAsDialogComponent, WidgetTypeTabsComponent, - WidgetsBundleTabsComponent + WidgetsBundleTabsComponent, + WidgetsBundleDialogComponent ], imports: [ CommonModule, diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-dialog.component.html b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-dialog.component.html new file mode 100644 index 0000000000..592be51486 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-dialog.component.html @@ -0,0 +1,53 @@ +<!-- + + Copyright © 2016-2024 The Thingsboard Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<form (ngSubmit)="save()" style="width: 650px;"> + <mat-toolbar color="primary"> + <h2 translate>widgets-bundle.add</h2> + <span fxFlex></span> + <button mat-icon-button + (click)="cancel()" + type="button"> + <mat-icon class="material-icons">close</mat-icon> + </button> + </mat-toolbar> + <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> + </mat-progress-bar> + <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div> + <div mat-dialog-content> + <tb-widgets-bundle + #widgetsBundleComponent + [isEdit]="true" + [entity]="widgetsBundle" + [standalone]="true"> + </tb-widgets-bundle> + </div> + <div mat-dialog-actions fxLayoutAlign="end center"> + <button mat-button color="primary" + type="button" + cdkFocusInitial + [disabled]="(isLoading$ | async)" + (click)="cancel()"> + {{ 'action.cancel' | translate }} + </button> + <button mat-raised-button color="primary" + type="submit" + [disabled]="(isLoading$ | async) || widgetsBundleComponent.entityForm?.invalid || !widgetsBundleComponent.entityForm?.dirty"> + {{ 'action.add' | translate }} + </button> + </div> +</form> diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-dialog.component.scss new file mode 100644 index 0000000000..0556c6bd25 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-dialog.component.scss @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host ::ng-deep { + tb-widgets-bundle { + .mat-padding { + padding: 0; + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-dialog.component.ts new file mode 100644 index 0000000000..bb5f93cb66 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-dialog.component.ts @@ -0,0 +1,78 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Inject, SkipSelf, ViewChild } from '@angular/core'; +import { ErrorStateMatcher } from '@angular/material/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { FormGroupDirective, NgForm, UntypedFormControl } from '@angular/forms'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Router } from '@angular/router'; +import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; +import { WidgetsBundleComponent } from '@home/pages/widget/widgets-bundle.component'; +import { WidgetService } from '@core/http/widget.service'; + +export interface WidgetsBundleDialogData { + widgetsBundle: WidgetsBundle; +} + +@Component({ + selector: 'tb-widgets-bundle-dialog', + templateUrl: './widgets-bundle-dialog.component.html', + providers: [{provide: ErrorStateMatcher, useExisting: WidgetsBundleDialogComponent}], + styleUrls: ['widgets-bundle-dialog.component.scss'] +}) +export class WidgetsBundleDialogComponent extends + DialogComponent<WidgetsBundleDialogComponent, WidgetsBundle> implements ErrorStateMatcher { + + widgetsBundle: WidgetsBundle; + + submitted = false; + + @ViewChild('widgetsBundleComponent', {static: true}) widgetsBundleComponent: WidgetsBundleComponent; + + constructor(protected store: Store<AppState>, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: WidgetsBundleDialogData, + public dialogRef: MatDialogRef<WidgetsBundleDialogComponent, WidgetsBundle>, + @SkipSelf() private errorStateMatcher: ErrorStateMatcher, + private widgetsService: WidgetService) { + super(store, router, dialogRef); + this.widgetsBundle = this.data.widgetsBundle; + } + + isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const originalErrorState = this.errorStateMatcher.isErrorState(control, form); + const customErrorState = !!(control && control.invalid && this.submitted); + return originalErrorState || customErrorState; + } + + cancel(): void { + this.dialogRef.close(null); + } + + save(): void { + this.submitted = true; + if (this.widgetsBundleComponent.entityForm.valid) { + this.widgetsBundle = {...this.widgetsBundle, ...this.widgetsBundleComponent.entityFormValue()}; + this.widgetsService.saveWidgetsBundle(this.widgetsBundle).subscribe((widgetBundle) => { + this.dialogRef.close(widgetBundle); + }); + } + } + +} diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html index f95d085688..df66eee579 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -<div class="tb-details-buttons" fxLayout.xs="column"> +<div class="tb-details-buttons" fxLayout.xs="column" *ngIf="!standalone"> <button mat-raised-button color="primary" [disabled]="(isLoading$ | async)" (click)="onEntityAction($event, 'open')" diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts index ca0912ea11..5b0d118313 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, Inject } from '@angular/core'; +import { ChangeDetectorRef, Component, Inject, Input, Optional } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { EntityComponent } from '../../components/entity/entity.component'; @@ -29,9 +29,12 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.mod }) export class WidgetsBundleComponent extends EntityComponent<WidgetsBundle> { + @Input() + standalone = false; + constructor(protected store: Store<AppState>, - @Inject('entity') protected entityValue: WidgetsBundle, - @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<WidgetsBundle>, + @Optional() @Inject('entity') protected entityValue: WidgetsBundle, + @Optional() @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<WidgetsBundle>, public fb: UntypedFormBuilder, protected cd: ChangeDetectorRef) { super(store, fb, entityValue, entitiesTableConfigValue, cd); diff --git a/ui-ngx/src/app/modules/login/login-routing.module.ts b/ui-ngx/src/app/modules/login/login-routing.module.ts index bfebce37a1..4b569f2e9f 100644 --- a/ui-ngx/src/app/modules/login/login-routing.module.ts +++ b/ui-ngx/src/app/modules/login/login-routing.module.ts @@ -24,6 +24,7 @@ import { ResetPasswordComponent } from '@modules/login/pages/login/reset-passwor import { CreatePasswordComponent } from '@modules/login/pages/login/create-password.component'; import { TwoFactorAuthLoginComponent } from '@modules/login/pages/login/two-factor-auth-login.component'; import { Authority } from '@shared/models/authority.enum'; +import { LinkExpiredComponent } from '@modules/login/pages/login/link-expired.component'; const routes: Routes = [ { @@ -81,6 +82,25 @@ const routes: Routes = [ module: 'public' }, canActivate: [AuthGuard] + }, + { + path: 'activationLinkExpired', + component: LinkExpiredComponent, + data: { + title: 'login.activation-link-expired', + module: 'public' + }, + canActivate: [AuthGuard] + }, + { + path: 'passwordResetLinkExpired', + component: LinkExpiredComponent, + data: { + title: 'login.reset-password-link-expired', + module: 'public', + passwordLinkExpired: true + }, + canActivate: [AuthGuard] } ]; diff --git a/ui-ngx/src/app/modules/login/login.module.ts b/ui-ngx/src/app/modules/login/login.module.ts index 0a664133e4..d995d9b2a6 100644 --- a/ui-ngx/src/app/modules/login/login.module.ts +++ b/ui-ngx/src/app/modules/login/login.module.ts @@ -24,6 +24,7 @@ import { ResetPasswordRequestComponent } from '@modules/login/pages/login/reset- import { ResetPasswordComponent } from '@modules/login/pages/login/reset-password.component'; import { CreatePasswordComponent } from '@modules/login/pages/login/create-password.component'; import { TwoFactorAuthLoginComponent } from '@modules/login/pages/login/two-factor-auth-login.component'; +import { LinkExpiredComponent } from '@modules/login/pages/login/link-expired.component'; @NgModule({ declarations: [ @@ -31,7 +32,8 @@ import { TwoFactorAuthLoginComponent } from '@modules/login/pages/login/two-fact ResetPasswordRequestComponent, ResetPasswordComponent, CreatePasswordComponent, - TwoFactorAuthLoginComponent + TwoFactorAuthLoginComponent, + LinkExpiredComponent ], imports: [ CommonModule, diff --git a/ui-ngx/src/app/modules/login/pages/login/link-expired.component.html b/ui-ngx/src/app/modules/login/pages/login/link-expired.component.html new file mode 100644 index 0000000000..a1d52f0735 --- /dev/null +++ b/ui-ngx/src/app/modules/login/pages/login/link-expired.component.html @@ -0,0 +1,40 @@ +<!-- + + Copyright © 2016-2024 The Thingsboard Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<div class="tb-expired-link-content mat-app-background tb-dark tb-flex row center align-center" + style="width: 100%;"> + <mat-card appearance="raised" class="tb-expired-link-card"> + <mat-card-header style="justify-content: center"> + <mat-card-title> + <span class="mat-headline-5">{{ title | translate }}</span> + </mat-card-title> + </mat-card-header> + <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> + </mat-progress-bar> + <span style="height: 4px;" *ngIf="!(isLoading$ | async)"></span> + <mat-card-content style="padding: 24px 16px"> + <div>{{ message | translate }}</div> + </mat-card-content> + <mat-card-actions class="tb-flex row center"> + <button mat-raised-button color="accent" + [disabled]="(isLoading$ | async)" + (click)="navigateToLoginPage()"> + {{ 'login.login' | translate }} + </button> + </mat-card-actions> + </mat-card> +</div> diff --git a/ui-ngx/src/app/modules/login/pages/login/link-expired.component.scss b/ui-ngx/src/app/modules/login/pages/login/link-expired.component.scss new file mode 100644 index 0000000000..323437e66b --- /dev/null +++ b/ui-ngx/src/app/modules/login/pages/login/link-expired.component.scss @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import '../../../../../scss/constants'; + +:host { + display: flex; + flex: 1 1 0; + .tb-expired-link-content { + background-color: #eee; + .tb-expired-link-card { + letter-spacing: 0.15px; + line-height: 24px; + padding: 24px; + @media #{$mat-gt-xs} { + width: 486px !important; + } + } + } +} diff --git a/ui-ngx/src/app/modules/login/pages/login/link-expired.component.ts b/ui-ngx/src/app/modules/login/pages/login/link-expired.component.ts new file mode 100644 index 0000000000..d394e426dd --- /dev/null +++ b/ui-ngx/src/app/modules/login/pages/login/link-expired.component.ts @@ -0,0 +1,47 @@ +/// +/// Copyright © 2016-2024 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { PageComponent } from '@shared/components/page.component'; +import { ActivatedRoute, Router } from '@angular/router'; + +@Component({ + selector: 'tb-link-expired', + templateUrl: './link-expired.component.html', + styleUrls: ['./link-expired.component.scss'] +}) +export class LinkExpiredComponent extends PageComponent { + + isPasswordLinkExpired: boolean; + title: string; + message: string; + + constructor(protected store: Store<AppState>, + private route: ActivatedRoute, + private router: Router) { + super(store); + this.isPasswordLinkExpired = this.route.snapshot.data.passwordLinkExpired; + this.title = this.isPasswordLinkExpired ? 'login.reset-password-link-expired' : 'login.activation-link-expired'; + this.message = this.isPasswordLinkExpired ? 'login.reset-password-link-expired-message' : + 'login.activation-link-expired-message'; + } + + navigateToLoginPage() { + this.router.navigateByUrl('login'); + } +} diff --git a/ui-ngx/src/app/shared/components/image/image-gallery.component.ts b/ui-ngx/src/app/shared/components/image/image-gallery.component.ts index 23f489d78c..24a4c3dde7 100644 --- a/ui-ngx/src/app/shared/components/image/image-gallery.component.ts +++ b/ui-ngx/src/app/shared/components/image/image-gallery.component.ts @@ -639,11 +639,15 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe } rowClick($event, image: ImageResourceInfo) { - if (this.selectionMode) { - this.selectImage($event, image); + if (this.isScada) { + this.editImage($event, image); } else { - if (this.deleteEnabled(image)) { - this.dataSource.selection.toggle(image); + if (this.selectionMode) { + this.selectImage($event, image); + } else { + if (this.deleteEnabled(image)) { + this.dataSource.selection.toggle(image); + } } } } diff --git a/ui-ngx/src/app/shared/components/js-func.component.ts b/ui-ngx/src/app/shared/components/js-func.component.ts index 8c3fa0a423..e15535391f 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.ts +++ b/ui-ngx/src/app/shared/components/js-func.component.ts @@ -25,15 +25,15 @@ import { ViewChild, ViewEncapsulation } from '@angular/core'; -import { ControlValueAccessor, UntypedFormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; +import { ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, UntypedFormControl, Validator } from '@angular/forms'; import { Ace } from 'ace-builds'; -import { getAce, Range, TbHighlightRule } from '@shared/models/ace/ace.models'; +import { AceHighlightRules, getAce, Range } from '@shared/models/ace/ace.models'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { ActionNotificationHide, ActionNotificationShow } from '@core/notification/notification.actions'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { UtilsService } from '@core/services/utils.service'; -import { deepClone, guid, isUndefined } from '@app/core/utils'; +import { guid, isUndefined } from '@app/core/utils'; import { TranslateService } from '@ngx-translate/core'; import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; import { ResizeObserver } from '@juggle/resize-observer'; @@ -90,9 +90,7 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, @Input() editorCompleter: TbEditorCompleter; - @Input() propertyHighlightRules: TbHighlightRule[]; - - @Input() objectHighlightRules: TbHighlightRule[]; + @Input() highlightRules: AceHighlightRules; @Input() globalVariables: Array<string>; @@ -220,27 +218,16 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor, }); } // @ts-ignore - if ((this.propertyHighlightRules?.length || this.objectHighlightRules?.length) && !!this.jsEditor.session.$mode) { + if (!!this.highlightRules && !!this.jsEditor.session.$mode) { // @ts-ignore const newMode = new this.jsEditor.session.$mode.constructor(); newMode.$highlightRules = new newMode.HighlightRules(); - if (this.propertyHighlightRules?.length) { - const propertiesRules: { token: string; regex: RegExp }[] = newMode.$highlightRules.$rules.property; - const index = propertiesRules.findIndex(p => p.token === 'support.constant'); - const additionalPropertyRules: { token: string; regex: RegExp }[] = this.propertyHighlightRules.map(r => ({ - token: `tb.${r.class}`, - regex: r.regex - })); - propertiesRules.splice(index, 0, ...additionalPropertyRules); - } - if (this.objectHighlightRules?.length) { - const noRegexRules: { token: string; regex: RegExp }[] = newMode.$highlightRules.$rules.no_regex; - const index = noRegexRules.findIndex(p => Array.isArray(p.token) && p.token[0] === 'support.constant'); - const additionalNoRegexRules: { token: string; regex: RegExp }[] = this.objectHighlightRules.map(r => ({ - token: `tb.${r.class}`, - regex: r.regex - })); - noRegexRules.splice(index, 0, ...additionalNoRegexRules); + for(const group in this.highlightRules) { + if(!!newMode.$highlightRules.$rules[group]) { + newMode.$highlightRules.$rules[group].unshift(...this.highlightRules[group]); + } else { + newMode.$highlightRules.$rules[group] = this.highlightRules[group]; + } } // @ts-ignore this.jsEditor.session.$onChangeMode(newMode); diff --git a/ui-ngx/src/app/shared/components/markdown.component.ts b/ui-ngx/src/app/shared/components/markdown.component.ts index fc7c2d0d8d..d890817d04 100644 --- a/ui-ngx/src/app/shared/components/markdown.component.ts +++ b/ui-ngx/src/app/shared/components/markdown.component.ts @@ -22,7 +22,8 @@ import { EventEmitter, Inject, Injector, - Input, NgZone, + Input, + NgZone, OnChanges, Output, Renderer2, @@ -132,7 +133,8 @@ export class TbMarkdownComponent implements OnChanges { let readyObservable: Observable<void>; if (this.applyDefaultMarkdownStyle) { if (!defaultMarkdownStyle) { - defaultMarkdownStyle = deepClone(TbMarkdownComponent['ɵcmp'].styles)[0].replace(/\[_nghost\-%COMP%\]/g, '') + const compDef = this.dynamicComponentFactoryService.getComponentDef(TbMarkdownComponent); + defaultMarkdownStyle = deepClone(compDef.styles[0]).replace(/\[_nghost\-%COMP%\]/g, '') .replace(/\[_ngcontent\-%COMP%\]/g, ''); } styles.push(defaultMarkdownStyle); @@ -160,14 +162,14 @@ export class TbMarkdownComponent implements OnChanges { }, template, compileModules, - true, 1, styles - ).subscribe((componentData) => { - this.tbMarkdownInstanceComponentType = componentData.componentType; + true, styles + ).subscribe((componentType) => { + this.tbMarkdownInstanceComponentType = componentType; const injector: Injector = Injector.create({providers: [], parent: this.markdownContainer.injector}); try { this.tbMarkdownInstanceComponentRef = this.markdownContainer.createComponent(this.tbMarkdownInstanceComponentType, - {index: 0, injector, ngModuleRef: componentData.componentModuleRef}); + {index: 0, injector}); if (this.context) { for (const propName of Object.keys(this.context)) { this.tbMarkdownInstanceComponentRef.instance[propName] = this.context[propName]; diff --git a/ui-ngx/src/app/shared/components/widgets-bundle-select.component.html b/ui-ngx/src/app/shared/components/widgets-bundle-select.component.html index 2f3f0199e4..2826d06d42 100644 --- a/ui-ngx/src/app/shared/components/widgets-bundle-select.component.html +++ b/ui-ngx/src/app/shared/components/widgets-bundle-select.component.html @@ -22,6 +22,7 @@ panelClass="tb-widgets-bundle-select" placeholder="{{ 'widget.select-widgets-bundle' | translate }}" (blur)="onTouched()" + [compareWith]="compareById" (ngModelChange)="widgetsBundleChanged()"> <mat-select-trigger> <div class="tb-bundle-item"> @@ -29,8 +30,12 @@ <span translate class="tb-bundle-system" *ngIf="isSystem(widgetsBundle)">widgets-bundle.system</span> </div> </mat-select-trigger> - <mat-option [value]="null" *ngIf="!required"> + <mat-option *ngIf="createNew; else empty" [value]="null" (click)="openWidgetsBundleDialog($event)"> + <a translate>widgets-bundle.create-new</a> </mat-option> + <ng-template #empty> + <mat-option [value]="null" *ngIf="!required"></mat-option> + </ng-template> <mat-option *ngFor="let widgetsBundle of widgetsBundles$ | async" [value]="widgetsBundle"> <div class="tb-bundle-item"> <span>{{widgetsBundle.title}}</span> diff --git a/ui-ngx/src/app/shared/components/widgets-bundle-select.component.ts b/ui-ngx/src/app/shared/components/widgets-bundle-select.component.ts index d81fcbe88e..b5baccc893 100644 --- a/ui-ngx/src/app/shared/components/widgets-bundle-select.component.ts +++ b/ui-ngx/src/app/shared/components/widgets-bundle-select.component.ts @@ -14,9 +14,18 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnChanges, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + forwardRef, + Input, + OnChanges, + OnInit, + SimpleChanges, + ViewEncapsulation +} from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { map, share, tap } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; @@ -26,6 +35,11 @@ import { isDefined } from '@core/utils'; import { NULL_UUID } from '@shared/models/id/has-uuid'; import { getCurrentAuthState } from '@core/auth/auth.selectors'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { MatDialog } from '@angular/material/dialog'; +import { + WidgetsBundleDialogComponent, + WidgetsBundleDialogData +} from '@home/pages/widget/widgets-bundle-dialog.component'; @Component({ selector: 'tb-widgets-bundle-select', @@ -60,6 +74,10 @@ export class WidgetsBundleSelectComponent implements ControlValueAccessor, OnIni @Input() excludeBundleIds: Array<string>; + @Input() + @coerceBoolean() + createNew: boolean; + widgetsBundles$: Observable<Array<WidgetsBundle>>; widgetsBundles: Array<WidgetsBundle>; @@ -70,7 +88,9 @@ export class WidgetsBundleSelectComponent implements ControlValueAccessor, OnIni private propagateChange: (value: any) => void = () => {}; constructor(private store: Store<AppState>, - private widgetService: WidgetService) { + private widgetService: WidgetService, + private dialog: MatDialog, + private cd: ChangeDetectorRef) { } registerOnChange(fn: any): void { @@ -171,4 +191,35 @@ export class WidgetsBundleSelectComponent implements ControlValueAccessor, OnIni return widgetsBundlesObservable; } + compareById(f1: WidgetsBundle, f2: WidgetsBundle): boolean { + return f1 && f2 && f1.id.id === f2.id.id; + } + + openWidgetsBundleDialog($event) { + $event.preventDefault(); + const widgetsBundle: WidgetsBundle = { + title: '', + image: '', + description: '', + scada: true, + order: null + }; + this.dialog.open<WidgetsBundleDialogComponent, WidgetsBundleDialogData, + WidgetsBundle>(WidgetsBundleDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + widgetsBundle + } + }).afterClosed().subscribe( + (savedWidgetBundle) => { + if (savedWidgetBundle) { + this.widgetsBundles$ = of([...this.widgetsBundles, savedWidgetBundle]); + this.widgetsBundle = savedWidgetBundle; + this.widgetsBundleChanged(); + } + } + ); + } + } diff --git a/ui-ngx/src/app/shared/models/ace/ace.models.ts b/ui-ngx/src/app/shared/models/ace/ace.models.ts index 221e68564b..381d897066 100644 --- a/ui-ngx/src/app/shared/models/ace/ace.models.ts +++ b/ui-ngx/src/app/shared/models/ace/ace.models.ts @@ -352,8 +352,15 @@ export class Range implements Ace.Range { } -export interface TbHighlightRule { - class: string; - regex: RegExp; +export interface AceHighlightRules { + [group: string]: Array<AceHighlightRule>; } +export interface AceHighlightRule { + regex: RegExp | string; + token: string; + next?: string; +} + + + diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 829e49257f..b43081c6e8 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -161,7 +161,7 @@ export const HelpLinks = { assetProfiles: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/asset-profiles`, edges: `${helpBaseUrl}/docs/edge/getting-started-guides/what-is-edge`, assets: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/assets`, - entityViews: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/entity-views`, + entityViews: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/entity-views`, entitiesImport: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/bulk-provisioning`, rulechains: `${helpBaseUrl}/docs${docPlatformPrefix}/user-guide/ui/rule-chains`, lwm2mResourceLibrary: `${helpBaseUrl}/docs${docPlatformPrefix}/reference/lwm2m-api`, diff --git a/ui-ngx/src/app/shared/models/dashboard.models.ts b/ui-ngx/src/app/shared/models/dashboard.models.ts index c4e767b314..45f4eb8cf2 100644 --- a/ui-ngx/src/app/shared/models/dashboard.models.ts +++ b/ui-ngx/src/app/shared/models/dashboard.models.ts @@ -97,7 +97,6 @@ export interface GridSettings { mobileRowHeight?: number; mobileDisplayLayoutFirst?: boolean; layoutDimension?: LayoutDimension; - [key: string]: any; } export interface DashboardLayout { diff --git a/ui-ngx/src/app/shared/models/settings.models.ts b/ui-ngx/src/app/shared/models/settings.models.ts index 113bc1a789..e0a31e4eea 100644 --- a/ui-ngx/src/app/shared/models/settings.models.ts +++ b/ui-ngx/src/app/shared/models/settings.models.ts @@ -111,6 +111,11 @@ export interface UserPasswordPolicy { export interface SecuritySettings { passwordPolicy: UserPasswordPolicy; + maxFailedLoginAttempts: number; + userLockoutNotificationEmail: string; + mobileSecretKeyLength: number; + userActivationTokenTtl: number; + passwordResetTokenTtl: number; } export interface JwtSettings { diff --git a/ui-ngx/src/app/shared/models/user.model.ts b/ui-ngx/src/app/shared/models/user.model.ts index 5b2cdec08b..a17cf040a8 100644 --- a/ui-ngx/src/app/shared/models/user.model.ts +++ b/ui-ngx/src/app/shared/models/user.model.ts @@ -44,6 +44,11 @@ export const activationMethodTranslations = new Map<ActivationMethod, string>( ] ); +export interface ActivationLinkInfo { + value: string; + ttlMs: number; +} + export interface AuthUser { sub: string; scopes: string[]; diff --git a/ui-ngx/src/app/shared/models/widgets-bundle.model.ts b/ui-ngx/src/app/shared/models/widgets-bundle.model.ts index 7066defdf7..d0d2731ac2 100644 --- a/ui-ngx/src/app/shared/models/widgets-bundle.model.ts +++ b/ui-ngx/src/app/shared/models/widgets-bundle.model.ts @@ -20,8 +20,7 @@ import { WidgetsBundleId } from '@shared/models/id/widgets-bundle-id'; import { HasTenantId, HasVersion } from '@shared/models/entity.models'; export interface WidgetsBundle extends BaseData<WidgetsBundleId>, HasTenantId, HasVersion, ExportableEntity<WidgetsBundleId> { - tenantId: TenantId; - alias: string; + alias?: string; title: string; image: string; scada: boolean; 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 369985740d..37ea4a1a87 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -205,6 +205,12 @@ "max-failed-login-attempts": "Maximum number of failed login attempts, before account is locked", "minimum-max-failed-login-attempts-range": "Maximum number of failed login attempts can't be negative", "user-lockout-notification-email": "In case user account lockout, send notification to email", + "user-activation-token-ttl": "User activation link TTL in hours", + "user-activation-token-ttl-range": "User activation link TTL must be in range from 1 to 24 hours", + "password-reset-token-ttl": "Password reset link TTL in hours", + "password-reset-token-ttl-range": "Password reset link TTL must be in range from 1 to 24 hours", + "mobile-secret-key-length": "Mobile secret key length", + "mobile-secret-key-length-range": "Mobile secret key length must be positive", "domain-name": "Domain name", "domain-name-unique": "Domain name and protocol need to unique.", "domain-name-max-length": "Domain name should be less than 256", @@ -3740,6 +3746,7 @@ "type-color-settings": "Color settings", "type-font": "Font", "type-units": "Units", + "type-icon": "Icon", "no-properties": "No properties configured", "add-property": "Add property", "property-settings": "Property settings", @@ -4014,7 +4021,11 @@ "email-auth-description": "A security code has been sent to your email address at {{contact}}.", "email-auth-placeholder": "Email code", "backup-code-auth-description": "Please enter one of your backup codes.", - "backup-code-auth-placeholder": "Backup code" + "backup-code-auth-placeholder": "Backup code", + "activation-link-expired": "Activation link has expired", + "activation-link-expired-message": "The link to activate your profile has expired. You can return to the login page to receive a new email.", + "reset-password-link-expired": "Password reset link has expired", + "reset-password-link-expired-message": "The link to reset your password has expired. You can return to the login page to receive a new email." }, "markdown": { "edit": "Edit", @@ -5634,7 +5645,7 @@ "display-activation-link": "Display activation link", "send-activation-mail": "Send activation mail", "activation-link": "User activation link", - "activation-link-text": "In order to activate user use the following <a href='{{activationLink}}' target='_blank'>activation link</a> :", + "activation-link-text": "In order to activate user use the following <a href='{{activationLink}}' target='_blank'>activation link</a> (expires in {{activationLinkTtl}}) :", "copy-activation-link": "Copy activation link", "activation-link-copied-message": "User activation link has been copied to clipboard", "details": "Details", @@ -5951,7 +5962,8 @@ "search": "Search widget bundles", "selected-widgets-bundles": "{ count, plural, =1 {1 widgets bundle} other {# widgets bundles} } selected", "open-widgets-bundle": "Open widgets bundle", - "loading-widgets-bundles": "Loading widgets bundles..." + "loading-widgets-bundles": "Loading widgets bundles...", + "create-new": "Create new widget bundle" }, "widget-config": { "data": "Data", diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json b/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json index 441f63ab5f..38bb44e036 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json @@ -1,246 +1,474 @@ { - "master": { - "slaves": [ - { - "name": "Slave 1", - "host": "127.0.0.1", - "port": 5021, - "type": "tcp", - "method": "socket", - "timeout": 35, - "byteOrder": "LITTLE", - "wordOrder": "LITTLE", - "retries": true, - "retryOnEmpty": true, - "retryOnInvalid": true, - "pollPeriod": 5000, - "unitId": 1, - "deviceName": "Temp Sensor", - "deviceType": "default", - "sendDataOnlyOnChange": true, - "connectAttemptTimeMs": 5000, - "connectAttemptCount": 5, - "waitAfterFailedAttemptsMs": 300000, - "attributes": [ - { - "tag": "string_read", - "type": "string", - "functionCode": 4, - "objectsCount": 4, - "address": 1 - }, - { - "tag": "bits_read", - "type": "bits", - "functionCode": 4, - "objectsCount": 1, - "address": 5 - }, - { - "tag": "8int_read", - "type": "8int", - "functionCode": 4, - "objectsCount": 1, - "address": 6 - }, - { - "tag": "16int_read", - "type": "16int", - "functionCode": 4, - "objectsCount": 1, - "address": 7 - }, - { - "tag": "32int_read_divider", - "type": "32int", - "functionCode": 4, - "objectsCount": 2, - "address": 8, - "divider": 10 - }, - { - "tag": "8int_read_multiplier", - "type": "8int", - "functionCode": 4, - "objectsCount": 1, - "address": 10, - "multiplier": 10 - }, - { - "tag": "32int_read", - "type": "32int", - "functionCode": 4, - "objectsCount": 2, - "address": 11 - }, - { - "tag": "64int_read", - "type": "64int", - "functionCode": 4, - "objectsCount": 4, - "address": 13 - } - ], - "timeseries": [ - { - "tag": "8uint_read", - "type": "8uint", - "functionCode": 4, - "objectsCount": 1, - "address": 17 - }, - { - "tag": "16uint_read", - "type": "16uint", - "functionCode": 4, - "objectsCount": 2, - "address": 18 - }, - { - "tag": "32uint_read", - "type": "32uint", - "functionCode": 4, - "objectsCount": 4, - "address": 20 - }, - { - "tag": "64uint_read", - "type": "64uint", - "functionCode": 4, - "objectsCount": 1, - "address": 24 - }, - { - "tag": "16float_read", - "type": "16float", - "functionCode": 4, - "objectsCount": 1, - "address": 25 - }, - { - "tag": "32float_read", - "type": "32float", - "functionCode": 4, - "objectsCount": 2, - "address": 26 - }, - { - "tag": "64float_read", - "type": "64float", - "functionCode": 4, - "objectsCount": 4, - "address": 28 - } - ], - "attributeUpdates": [ - { - "tag": "shared_attribute_write", - "type": "32int", - "functionCode": 6, - "objectsCount": 2, - "address": 29 - } - ], - "rpc": [ - { - "tag": "setValue", - "type": "bits", - "functionCode": 5, - "objectsCount": 1, - "address": 31 - }, - { - "tag": "getValue", - "type": "bits", - "functionCode": 1, - "objectsCount": 1, - "address": 31 - }, - { - "tag": "setCPUFanSpeed", - "type": "32int", - "functionCode": 16, - "objectsCount": 2, - "address": 33 - }, - { - "tag": "getCPULoad", - "type": "32int", - "functionCode": 4, - "objectsCount": 2, - "address": 35 - } - ] - } - ] - }, - "slave": { - "type": "tcp", - "host": "127.0.0.1", - "port": 5026, - "method": "socket", - "deviceName": "Modbus Slave Example", - "deviceType": "default", - "pollPeriod": 5000, - "sendDataToThingsBoard": false, - "byteOrder": "LITTLE", - "wordOrder": "LITTLE", - "unitId": 0, - "values": { - "holding_registers": { - "attributes": [ + "3.5.2": { + "master": { + "slaves": [ { - "address": 1, - "type": "string", - "tag": "sm", - "objectsCount": 1, - "value": "ON" + "name": "Slave 1", + "host": "127.0.0.1", + "port": 5021, + "type": "tcp", + "method": "socket", + "timeout": 35, + "byteOrder": "LITTLE", + "wordOrder": "LITTLE", + "retries": true, + "retryOnEmpty": true, + "retryOnInvalid": true, + "pollPeriod": 5000, + "unitId": 1, + "deviceName": "Temp Sensor", + "deviceType": "default", + "sendDataOnlyOnChange": true, + "connectAttemptTimeMs": 5000, + "connectAttemptCount": 5, + "waitAfterFailedAttemptsMs": 300000, + "attributes": [ + { + "tag": "string_read", + "type": "string", + "functionCode": 4, + "objectsCount": 4, + "address": 1 + }, + { + "tag": "bits_read", + "type": "bits", + "functionCode": 4, + "objectsCount": 1, + "address": 5 + }, + { + "tag": "8int_read", + "type": "8int", + "functionCode": 4, + "objectsCount": 1, + "address": 6 + }, + { + "tag": "16int_read", + "type": "16int", + "functionCode": 4, + "objectsCount": 1, + "address": 7 + }, + { + "tag": "32int_read_divider", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 8, + "divider": 10 + }, + { + "tag": "8int_read_multiplier", + "type": "8int", + "functionCode": 4, + "objectsCount": 1, + "address": 10, + "multiplier": 10 + }, + { + "tag": "32int_read", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 11 + }, + { + "tag": "64int_read", + "type": "64int", + "functionCode": 4, + "objectsCount": 4, + "address": 13 + } + ], + "timeseries": [ + { + "tag": "8uint_read", + "type": "8uint", + "functionCode": 4, + "objectsCount": 1, + "address": 17 + }, + { + "tag": "16uint_read", + "type": "16uint", + "functionCode": 4, + "objectsCount": 2, + "address": 18 + }, + { + "tag": "32uint_read", + "type": "32uint", + "functionCode": 4, + "objectsCount": 4, + "address": 20 + }, + { + "tag": "64uint_read", + "type": "64uint", + "functionCode": 4, + "objectsCount": 1, + "address": 24 + }, + { + "tag": "16float_read", + "type": "16float", + "functionCode": 4, + "objectsCount": 1, + "address": 25 + }, + { + "tag": "32float_read", + "type": "32float", + "functionCode": 4, + "objectsCount": 2, + "address": 26 + }, + { + "tag": "64float_read", + "type": "64float", + "functionCode": 4, + "objectsCount": 4, + "address": 28 + } + ], + "attributeUpdates": [ + { + "tag": "shared_attribute_write", + "type": "32int", + "functionCode": 6, + "objectsCount": 2, + "address": 29 + } + ], + "rpc": [ + { + "tag": "setValue", + "type": "bits", + "functionCode": 5, + "objectsCount": 1, + "address": 31 + }, + { + "tag": "getValue", + "type": "bits", + "functionCode": 1, + "objectsCount": 1, + "address": 31 + }, + { + "tag": "setCPUFanSpeed", + "type": "32int", + "functionCode": 16, + "objectsCount": 2, + "address": 33 + }, + { + "tag": "getCPULoad", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 35 + } + ] } - ], - "timeseries": [ - { - "address": 2, - "type": "8int", - "tag": "smm", - "objectsCount": 1, - "value": "12334" - } - ], - "attributeUpdates": [ - { - "tag": "shared_attribute_write", - "type": "32int", - "functionCode": 6, - "objectsCount": 2, - "address": 29, - "value": 1243 + ] + }, + "slave": { + "type": "tcp", + "host": "127.0.0.1", + "port": 5026, + "method": "socket", + "deviceName": "Modbus Slave Example", + "deviceType": "default", + "pollPeriod": 5000, + "sendDataToThingsBoard": false, + "byteOrder": "LITTLE", + "wordOrder": "LITTLE", + "unitId": 0, + "values": { + "holding_registers": { + "attributes": [ + { + "address": 1, + "type": "string", + "tag": "sm", + "objectsCount": 1, + "value": "ON" + } + ], + "timeseries": [ + { + "address": 2, + "type": "8int", + "tag": "smm", + "objectsCount": 1, + "value": "12334" + } + ], + "attributeUpdates": [ + { + "tag": "shared_attribute_write", + "type": "32int", + "functionCode": 6, + "objectsCount": 2, + "address": 29, + "value": 1243 + } + ], + "rpc": [ + { + "tag": "setValue", + "type": "bits", + "functionCode": 5, + "objectsCount": 1, + "address": 31, + "value": 22 + } + ] + }, + "coils_initializer": { + "attributes": [ + { + "address": 5, + "type": "string", + "tag": "sm", + "objectsCount": 1, + "value": "12" + } + ], + "timeseries": [], + "attributeUpdates": [], + "rpc": [] } - ], - "rpc": [ + } + } + }, + "legacy": { + "master": { + "slaves": [ { - "tag": "setValue", - "type": "bits", - "functionCode": 5, - "objectsCount": 1, - "address": 31, - "value": 22 + "host": "127.0.0.1", + "port": 5021, + "type": "tcp", + "method": "socket", + "timeout": 35, + "byteOrder": "LITTLE", + "wordOrder": "LITTLE", + "retries": true, + "retryOnEmpty": true, + "retryOnInvalid": true, + "pollPeriod": 5000, + "unitId": 1, + "deviceName": "Temp Sensor", + "sendDataOnlyOnChange": true, + "connectAttemptTimeMs": 5000, + "connectAttemptCount": 5, + "waitAfterFailedAttemptsMs": 300000, + "attributes": [ + { + "tag": "string_read", + "type": "string", + "functionCode": 4, + "objectsCount": 4, + "address": 1 + }, + { + "tag": "bits_read", + "type": "bits", + "functionCode": 4, + "objectsCount": 1, + "address": 5 + }, + { + "tag": "16int_read", + "type": "16int", + "functionCode": 4, + "objectsCount": 1, + "address": 7 + }, + { + "tag": "32int_read_divider", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 8, + "divider": 10 + }, + { + "tag": "32int_read", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 11 + }, + { + "tag": "64int_read", + "type": "64int", + "functionCode": 4, + "objectsCount": 4, + "address": 13 + } + ], + "timeseries": [ + { + "tag": "16uint_read", + "type": "16uint", + "functionCode": 4, + "objectsCount": 2, + "address": 18 + }, + { + "tag": "32uint_read", + "type": "32uint", + "functionCode": 4, + "objectsCount": 4, + "address": 20 + }, + { + "tag": "64uint_read", + "type": "64uint", + "functionCode": 4, + "objectsCount": 1, + "address": 24 + }, + { + "tag": "16float_read", + "type": "16float", + "functionCode": 4, + "objectsCount": 1, + "address": 25 + }, + { + "tag": "32float_read", + "type": "32float", + "functionCode": 4, + "objectsCount": 2, + "address": 26 + }, + { + "tag": "64float_read", + "type": "64float", + "functionCode": 4, + "objectsCount": 4, + "address": 28 + } + ], + "attributeUpdates": [ + { + "tag": "shared_attribute_write", + "type": "32int", + "functionCode": 6, + "objectsCount": 2, + "address": 29 + } + ], + "rpc": [ + { + "tag": "setValue", + "type": "bits", + "functionCode": 5, + "objectsCount": 1, + "address": 31 + }, + { + "tag": "getValue", + "type": "bits", + "functionCode": 1, + "objectsCount": 1, + "address": 31 + }, + { + "tag": "setCPUFanSpeed", + "type": "32int", + "functionCode": 16, + "objectsCount": 2, + "address": 33 + }, + { + "tag": "getCPULoad", + "type": "32int", + "functionCode": 4, + "objectsCount": 2, + "address": 35 + } + ] } ] }, - "coils_initializer": { - "attributes": [ - { - "address": 5, - "type": "string", - "tag": "sm", - "objectsCount": 1, - "value": "12" - } - ], - "timeseries": [], - "attributeUpdates": [], - "rpc": [] + "slave": { + "type": "tcp", + "host": "127.0.0.1", + "port": 5026, + "method": "socket", + "deviceName": "Modbus Slave Example", + "deviceType": "default", + "pollPeriod": 5000, + "sendDataToThingsBoard": false, + "byteOrder": "LITTLE", + "wordOrder": "LITTLE", + "unitId": 0, + "values": { + "holding_registers": [ + { + "attributes": [ + { + "address": 1, + "type": "string", + "tag": "sm", + "objectsCount": 1, + "value": "ON" + } + ], + "timeseries": [ + { + "address": 2, + "type": "int", + "tag": "smm", + "objectsCount": 1, + "value": "12334" + } + ], + "attributeUpdates": [ + { + "tag": "shared_attribute_write", + "type": "32int", + "functionCode": 6, + "objectsCount": 2, + "address": 29, + "value": 1243 + } + ], + "rpc": [ + { + "tag": "setValue", + "type": "bits", + "functionCode": 5, + "objectsCount": 1, + "address": 31, + "value": 22 + } + ] + } + ], + "coils_initializer": [ + { + "attributes": [ + { + "address": 5, + "type": "string", + "tag": "sm", + "objectsCount": 1, + "value": "12" + } + ], + "timeseries": [], + "attributeUpdates": [], + "rpc": [] + } + ] + } } } - } } diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json b/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json index 3e0800c5d6..5b8b8dbd44 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/mqtt.json @@ -1,217 +1,398 @@ { - "broker": { - "host": "127.0.0.1", - "port": 1883, - "clientId": "ThingsBoard_gateway", - "version": 5, - "maxMessageNumberPerWorker": 10, - "maxNumberOfWorkers": 100, - "sendDataOnlyOnChange": false, - "security": { - "type": "anonymous" - } - }, - "dataMapping": [ - { - "topicFilter": "sensor/data", - "subscriptionQos": 1, - "converter": { - "type": "json", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "${serialNumber}", - "deviceProfileExpressionSource": "message", - "deviceProfileExpression": "${sensorType}" + "3.5.2": { + "broker": { + "host": "127.0.0.1", + "port": 1883, + "clientId": "ThingsBoard_gateway", + "version": 5, + "maxMessageNumberPerWorker": 10, + "maxNumberOfWorkers": 100, + "sendDataOnlyOnChange": false, + "security": { + "type": "anonymous" + } }, - "sendDataOnlyOnChange": false, - "timeout": 60000, - "attributes": [ - { - "type": "string", - "key": "model", - "value": "${sensorModel}" - }, - { - "type": "string", - "key": "${sensorModel}", - "value": "on" - } + "mapping": [ + { + "topicFilter": "sensor/data", + "subscriptionQos": 1, + "converter": { + "type": "json", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "${serialNumber}", + "deviceProfileExpressionSource": "message", + "deviceProfileExpression": "${sensorType}" + }, + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "string", + "key": "model", + "value": "${sensorModel}" + }, + { + "type": "string", + "key": "${sensorModel}", + "value": "on" + } + ], + "timeseries": [ + { + "type": "string", + "key": "temperature", + "value": "${temp}" + }, + { + "type": "double", + "key": "humidity", + "value": "${hum}" + }, + { + "type": "string", + "key": "combine", + "value": "${hum}:${temp}" + } + ] + } + }, + { + "topicFilter": "sensor/+/data", + "subscriptionQos": 1, + "converter": { + "type": "json", + "deviceInfo": { + "deviceNameExpressionSource": "topic", + "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/data)", + "deviceProfileExpressionSource": "constant", + "deviceProfileExpression": "Thermometer" + }, + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "string", + "key": "model", + "value": "${sensorModel}" + } + ], + "timeseries": [ + { + "type": "double", + "key": "temperature", + "value": "${temp}" + }, + { + "type": "string", + "key": "humidity", + "value": "${hum}" + } + ] + } + }, + { + "topicFilter": "sensor/raw_data", + "subscriptionQos": 1, + "converter": { + "type": "bytes", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "[0:4]", + "deviceProfileExpressionSource": "constant", + "deviceProfileExpression": "default" + }, + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "raw", + "key": "rawData", + "value": "[:]" + } + ], + "timeseries": [ + { + "type": "raw", + "key": "temp", + "value": "[4:]" + } + ] + } + }, + { + "topicFilter": "custom/sensors/+", + "subscriptionQos": 1, + "converter": { + "type": "custom", + "extension": "CustomMqttUplinkConverter", + "cached": true, + "extensionConfig": { + "temperature": 2, + "humidity": 2, + "batteryLevel": 1 + } + } + } ], - "timeseries": [ - { - "type": "string", - "key": "temperature", - "value": "${temp}" - }, - { - "type": "double", - "key": "humidity", - "value": "${hum}" - }, - { - "type": "string", - "key": "combine", - "value": "${hum}:${temp}" - } - ] - } + "requestsMapping": { + "connectRequests": [ + { + "topicFilter": "sensor/connect", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "${serialNumber}", + "deviceProfileExpressionSource": "constant", + "deviceProfileExpression": "Thermometer" + } + }, + { + "topicFilter": "sensor/+/connect", + "deviceInfo": { + "deviceNameExpressionSource": "topic", + "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/connect)", + "deviceProfileExpressionSource": "constant", + "deviceProfileExpression": "Thermometer" + } + } + ], + "disconnectRequests": [ + { + "topicFilter": "sensor/disconnect", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "${serialNumber}" + } + }, + { + "topicFilter": "sensor/+/disconnect", + "deviceInfo": { + "deviceNameExpressionSource": "topic", + "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/connect)" + } + } + ], + "attributeRequests": [ + { + "retain": false, + "topicFilter": "v1/devices/me/attributes/request", + "deviceInfo": { + "deviceNameExpressionSource": "message", + "deviceNameExpression": "${serialNumber}" + }, + "attributeNameExpressionSource": "message", + "attributeNameExpression": "${versionAttribute}, ${pduAttribute}", + "topicExpression": "devices/${deviceName}/attrs", + "valueExpression": "${attributeKey}: ${attributeValue}" + } + ], + "attributeUpdates": [ + { + "retain": true, + "deviceNameFilter": ".*", + "attributeFilter": "firmwareVersion", + "topicExpression": "sensor/${deviceName}/${attributeKey}", + "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}" + } + ], + "serverSideRpc": [ + { + "type": "twoWay", + "deviceNameFilter": ".*", + "methodFilter": "echo", + "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", + "responseTopicExpression": "sensor/${deviceName}/response/${methodName}/${requestId}", + "responseTopicQoS": 1, + "responseTimeout": 10000, + "valueExpression": "${params}" + }, + { + "type": "oneWay", + "deviceNameFilter": ".*", + "methodFilter": "no-reply", + "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", + "valueExpression": "${params}" + } + ] + } }, - { - "topicFilter": "sensor/+/data", - "subscriptionQos": 1, - "converter": { - "type": "json", - "deviceInfo": { - "deviceNameExpressionSource": "topic", - "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/data)", - "deviceProfileExpressionSource": "constant", - "deviceProfileExpression": "Thermometer" + "legacy": { + "broker": { + "name": "Default Local Broker", + "host": "127.0.0.1", + "port": 1883, + "clientId": "ThingsBoard_gateway", + "version": 5, + "maxMessageNumberPerWorker": 10, + "maxNumberOfWorkers": 100, + "sendDataOnlyOnChange": false, + "security": { + "type": "basic", + "username": "user", + "password": "password" + } }, - "sendDataOnlyOnChange": false, - "timeout": 60000, - "attributes": [ - { - "type": "string", - "key": "model", - "value": "${sensorModel}" - } + "mapping": [ + { + "topicFilter": "sensor/data", + "converter": { + "type": "json", + "deviceNameJsonExpression": "${serialNumber}", + "deviceTypeJsonExpression": "${sensorType}", + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "string", + "key": "model", + "value": "${sensorModel}" + }, + { + "type": "string", + "key": "${sensorModel}", + "value": "on" + } + ], + "timeseries": [ + { + "type": "double", + "key": "temperature", + "value": "${temp}" + }, + { + "type": "double", + "key": "humidity", + "value": "${hum}" + }, + { + "type": "string", + "key": "combine", + "value": "${hum}:${temp}" + } + ] + } + }, + { + "topicFilter": "sensor/+/data", + "converter": { + "type": "json", + "deviceNameTopicExpression": "(?<=sensor\/)(.*?)(?=\/data)", + "deviceTypeTopicExpression": "Thermometer", + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "string", + "key": "model", + "value": "${sensorModel}" + } + ], + "timeseries": [ + { + "type": "double", + "key": "temperature", + "value": "${temp}" + }, + { + "type": "double", + "key": "humidity", + "value": "${hum}" + } + ] + } + }, + { + "topicFilter": "sensor/raw_data", + "converter": { + "type": "bytes", + "deviceNameExpression": "[0:4]", + "deviceTypeExpression": "default", + "sendDataOnlyOnChange": false, + "timeout": 60000, + "attributes": [ + { + "type": "raw", + "key": "rawData", + "value": "[:]" + } + ], + "timeseries": [ + { + "type": "raw", + "key": "temp", + "value": "[4:]" + } + ] + } + }, + { + "topicFilter": "custom/sensors/+", + "converter": { + "type": "custom", + "extension": "CustomMqttUplinkConverter", + "cached": true, + "extension-config": { + "temperatureBytes": 2, + "humidityBytes": 2, + "batteryLevelBytes": 1 + } + } + } ], - "timeseries": [ - { - "type": "double", - "key": "temperature", - "value": "${temp}" - }, - { - "type": "string", - "key": "humidity", - "value": "${hum}" - } - ] - } - }, - { - "topicFilter": "sensor/raw_data", - "subscriptionQos": 1, - "converter": { - "type": "bytes", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "[0:4]", - "deviceProfileExpressionSource": "constant", - "deviceProfileExpression": "default" - }, - "sendDataOnlyOnChange": false, - "timeout": 60000, - "attributes": [ - { - "type": "raw", - "key": "rawData", - "value": "[:]" - } + "connectRequests": [ + { + "topicFilter": "sensor/connect", + "deviceNameJsonExpression": "${serialNumber}" + }, + { + "topicFilter": "sensor/+/connect", + "deviceNameTopicExpression": "(?<=sensor\/)(.*?)(?=\/connect)" + } + ], + "disconnectRequests": [ + { + "topicFilter": "sensor/disconnect", + "deviceNameJsonExpression": "${serialNumber}" + }, + { + "topicFilter": "sensor/+/disconnect", + "deviceNameTopicExpression": "(?<=sensor\/)(.*?)(?=\/disconnect)" + } + ], + "attributeRequests": [ + { + "retain": false, + "topicFilter": "v1/devices/me/attributes/request", + "deviceNameJsonExpression": "${serialNumber}", + "attributeNameJsonExpression": "${versionAttribute}, ${pduAttribute}", + "topicExpression": "devices/${deviceName}/attrs", + "valueExpression": "${attributeKey}: ${attributeValue}" + } ], - "timeseries": [ - { - "type": "raw", - "key": "temp", - "value": "[4:]" - } + "attributeUpdates": [ + { + "retain": true, + "deviceNameFilter": ".*", + "attributeFilter": "firmwareVersion", + "topicExpression": "sensor/${deviceName}/${attributeKey}", + "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}" + } + ], + "serverSideRpc": [ + { + "deviceNameFilter": ".*", + "methodFilter": "echo", + "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", + "responseTopicExpression": "sensor/${deviceName}/response/${methodName}/${requestId}", + "responseTimeout": 10000, + "valueExpression": "${params}" + }, + { + "deviceNameFilter": ".*", + "methodFilter": "no-reply", + "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", + "valueExpression": "${params}" + } ] - } - }, - { - "topicFilter": "custom/sensors/+", - "subscriptionQos": 1, - "converter": { - "type": "custom", - "extension": "CustomMqttUplinkConverter", - "cached": true, - "extensionConfig": { - "temperature": 2, - "humidity": 2, - "batteryLevel": 1 - } - } - } - ], - "requestsMapping": { - "connectRequests": [ - { - "topicFilter": "sensor/connect", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "${serialNumber}", - "deviceProfileExpressionSource": "constant", - "deviceProfileExpression": "Thermometer" - } - }, - { - "topicFilter": "sensor/+/connect", - "deviceInfo": { - "deviceNameExpressionSource": "topic", - "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/connect)", - "deviceProfileExpressionSource": "constant", - "deviceProfileExpression": "Thermometer" - } - } - ], - "disconnectRequests": [ - { - "topicFilter": "sensor/disconnect", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "${serialNumber}" - } - }, - { - "topicFilter": "sensor/+/disconnect", - "deviceInfo": { - "deviceNameExpressionSource": "topic", - "deviceNameExpression": "(?<=sensor\/)(.*?)(?=\/connect)" - } - } - ], - "attributeRequests": [ - { - "retain": false, - "topicFilter": "v1/devices/me/attributes/request", - "deviceInfo": { - "deviceNameExpressionSource": "message", - "deviceNameExpression": "${serialNumber}" - }, - "attributeNameExpressionSource": "message", - "attributeNameExpression": "${versionAttribute}, ${pduAttribute}", - "topicExpression": "devices/${deviceName}/attrs", - "valueExpression": "${attributeKey}: ${attributeValue}" - } - ], - "attributeUpdates": [ - { - "retain": true, - "deviceNameFilter": ".*", - "attributeFilter": "firmwareVersion", - "topicExpression": "sensor/${deviceName}/${attributeKey}", - "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}" - } - ], - "serverSideRpc": [ - { - "type": "twoWay", - "deviceNameFilter": ".*", - "methodFilter": "echo", - "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", - "responseTopicExpression": "sensor/${deviceName}/response/${methodName}/${requestId}", - "responseTopicQoS": 1, - "responseTimeout": 10000, - "valueExpression": "${params}" - }, - { - "type": "oneWay", - "deviceNameFilter": ".*", - "methodFilter": "no-reply", - "requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}", - "valueExpression": "${params}" } - ] - } } diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json b/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json index 7ff5b78433..c0ef993dd1 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/opcua.json @@ -1,66 +1,120 @@ { - "server": { - "url": "localhost:4840/freeopcua/server/", - "timeoutInMillis": 5000, - "scanPeriodInMillis": 3600000, - "pollPeriodInMillis": 5000, - "enableSubscriptions": true, - "subCheckPeriodInMillis": 100, - "showMap": false, - "security": "Basic128Rsa15", - "identity": { - "type": "anonymous" - } - }, - "mapping": [{ - "deviceNodePattern": "Root\\.Objects\\.Device1", - "deviceNodeSource": "path", - "deviceInfo": { - "deviceNameExpression": "Device ${Root\\.Objects\\.Device1\\.serialNumber}", - "deviceNameExpressionSource": "path", - "deviceProfileExpression": "Device", - "deviceProfileExpressionSource": "constant" + "3.5.2": { + "server": { + "url": "localhost:4840/freeopcua/server/", + "timeoutInMillis": 5000, + "scanPeriodInMillis": 3600000, + "pollPeriodInMillis": 5000, + "enableSubscriptions": true, + "subCheckPeriodInMillis": 100, + "showMap": false, + "security": "Basic128Rsa15", + "identity": { + "type": "anonymous" + } + }, + "mapping": [{ + "deviceNodePattern": "Root\\.Objects\\.Device1", + "deviceNodeSource": "path", + "deviceInfo": { + "deviceNameExpression": "Device ${Root\\.Objects\\.Device1\\.serialNumber}", + "deviceNameExpressionSource": "path", + "deviceProfileExpression": "Device", + "deviceProfileExpressionSource": "constant" + }, + "attributes": [ + { + "key": "temperature °C", + "type": "path", + "value": "${ns=2;i=5}" + } + ], + "timeseries": [ + { + "key": "humidity", + "type": "path", + "value": "${Root\\.Objects\\.Device1\\.TemperatureAndHumiditySensor\\.Humidity}" + }, + { + "key": "batteryLevel", + "type": "path", + "value": "${Battery\\.batteryLevel}" + } + ], + "rpc_methods": [ + { + "method": "multiply", + "arguments": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 4 + } + ] + } + ], + "attributes_updates": [ + { + "key": "deviceName", + "type": "path", + "value": "Root\\.Objects\\.Device1\\.serialNumber" + } + ] + }] }, - "attributes": [ - { - "key": "temperature °C", - "type": "path", - "value": "${ns=2;i=5}" - } - ], - "timeseries": [ - { - "key": "humidity", - "type": "path", - "value": "${Root\\.Objects\\.Device1\\.TemperatureAndHumiditySensor\\.Humidity}" - }, - { - "key": "batteryLevel", - "type": "path", - "value": "${Battery\\.batteryLevel}" - } - ], - "rpc_methods": [ - { - "method": "multiply", - "arguments": [ - { - "type": "integer", - "value": 2 - }, - { - "type": "integer", - "value": 4 - } - ] - } - ], - "attributes_updates": [ - { - "key": "deviceName", - "type": "path", - "value": "Root\\.Objects\\.Device1\\.serialNumber" - } - ] - }] + "legacy": { + "server": { + "name": "OPC-UA Default Server", + "url": "localhost:4840/freeopcua/server/", + "timeoutInMillis": 5000, + "scanPeriodInMillis": 5000, + "disableSubscriptions": false, + "subCheckPeriodInMillis": 100, + "showMap": false, + "security": "Basic128Rsa15", + "identity": { + "type": "anonymous" + }, + "mapping": [ + { + "deviceNodePattern": "Root\\.Objects\\.Device1", + "deviceNamePattern": "Device ${Root\\.Objects\\.Device1\\.serialNumber}", + "attributes": [ + { + "key": "temperature °C", + "path": "${ns=2;i=5}" + } + ], + "timeseries": [ + { + "key": "humidity", + "path": "${Root\\.Objects\\.Device1\\.TemperatureAndHumiditySensor\\.Humidity}" + }, + { + "key": "batteryLevel", + "path": "${Battery\\.batteryLevel}" + } + ], + "rpc_methods": [ + { + "method": "multiply", + "arguments": [ + 2, + 4 + ] + } + ], + "attributes_updates": [ + { + "attributeOnThingsBoard": "deviceName", + "attributeOnDevice": "Root\\.Objects\\.Device1\\.serialNumber" + } + ] + } + ] + } + } }