diff --git a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json index 16a155cebb..04f4042fae 100644 --- a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json @@ -3,7 +3,9 @@ "alias": "alarm_widgets", "title": "Alarm widgets", "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAIAAADGnbT+AAAABmJLR0QA/wD/AP+gvaeTAAAOPElEQVR42u2deVsTVx+G/Xb9ALVeffuHtmql2kVrVWytWltr64KoqIgbolRFRMQNtCwioiLIqii7grIoShARwnbee3Js3pgibzYQzPNcXLmGyUwmc+ae35kE7jOzjDHDw8MvFCVCGRoaAqpZlqqxsTGjKGEHkMAJqGaJKmUy2HLAUlsokY0DVk9PjxpCiWyASmApAksRWIrAEliKwFI+DLD4pst3gbKyss7OTjWcEi5Yubm5X3zxxejoqP01ISGhtLRUDaeEC9ZPP/30xx9/UKj8wBoYGLh9+3Z5ebllrrW1taOj49atW263u6mpqaWl5ebNm/39/c+ePbt+/bq3yD1//vzatWsNDQ1q+qgG6/Hjx+vWrauvr9+8ebMvWPyVccWKFZmZmXv37k1MTGT+rl27li1bduLECfD67LPPjh07lpyc/N133+3YsSMrK2vhwoUvX77s7u5mzvnz59evX3/lyhW1fvSCBR95eXlMAERvb68XLMoSzLW3t9+9e3fx4sUWrJKSEiYAKzY21q4+b948ChsT27Ztq6mpoZKtXLmSFYHs0aNHav0oBYs+jquruLi4PXv2fPPNN1QaL1ivX7/++eefjx49mpaWFhMTY8G6c+eOBWv16tX2FebPn287SupWZWUlE3SdW7duXbVqFVVQrR+lYAEQPWCnJw8ePKCn84IFJfBh+8pFixYFCFZtbS0XXvxaUVFBDVPrRylYf/75p/ea3V7FNzY2WrC4Kl++fDld3u+///7pp59CTyBg0ZlydbVp0yYY9X1lJRo/FU4Qe/0UbAYHB71fXigCS1EEliKwFIGlKAJLEViKwFIUgaUILEVgKYrAUgSWIrAURWApAksRWIoisBSBpXz4YO3evXvleEHameJ3WVBQoEP14YAFQ0HNn7xM/RZHRkaCWp4RLt7j1qMOLLyd77///qOPPlq6dOmpU6dmBFjV1dWYkrzt1NTUwNc6c+YMCi7jXIQv4m7YsIH9xRB++vQptrDfC+JjFhUVqWI5WbBgAboYLYLyigN98ODBnJwchDCU1ydPnvT19WEvopG5XC6/FfGt/bZoBxCf1Ozfv/+vv/7CI2JkAEb/PXLkCO8TrRIpnIYCHexIhp9g5qVLl3DdEHoZZODcuXNYcXPnzv31119Pnz798OHDGzduWDU8qKAwffzxx69evUIc5xVQyeGMRkPDZAKLk+3SnnV1dbxJe7lCecO941lWiUawkKcZwYEDk5KSQnNw2VRYWMhR2bdvH3MOHTrEkfNdC4eR1gQ77xZpbpZn/qS2CEeRQVC+/vpryi2jnvz444/FxcWIkOCSnZ3NBOOaoFJyFBmi4t69exRj9o63SqnjbGEt9vHw4cPIlZw2IbyBq1evfvXVV7wUkO3cuZMXbGtr4zWTkpIOHDgA0zxCGJqn8QxiANw4w7wf63VGHVhM/Pbbb19++SWNAliczRwJ5lCrOOE44/99wgEfvjWaK1u0VE3BUCKXL19mKGnomTNnDiQx9gnvLT8/n5n0j2vXrmX8nNmzZzOTksZ7pkQZz+AUXrA4hehM6ctC2DrbZR+plCDFJixYbJ2CRO2kNFqwQJZhCsw/o2Pgl9OMdAVRChb7D1i2gHOQOC/Bi2PDYaDCc2D+vS6tDE9scWqoMp6BBRiogi1u374dpildHFR7gYj8zTFmgpJGwaAHZzwmX7BYzDYOJ0xo15T0a7/88gutQXVvbm5OT0/nBRkcyl72bdmyhSsKOlwuvBhWg01/8sknjOFD1WQV2zlG3adCPjfR2XGRa8ECKe8nKS5oJvgcRN1ii1M87JHvxdy4n/je9TGQFbno5g1T2CKydTvtuzk7x6/RpuDqM2Jg8X3VuN9jMSZWCFuiaFHbbVtQpWj9wNdl/KMZ9EmboZ0Y9UTfY+mbd0VgKQJLEVgCSxFYisBSBJaiCCxlRoDFXzF143UlsgEqVSxFXaEisBSBJbAUgaUILEVgKYrAUgSWIrD8M30Ue+WDAmv6KPbTKSNmbNLviee1JDAD8N6CXZ07vX/gYCFB4KOiK/GI/BmpN42CPIlN0pRsbi14M125xtRufuvZzlzTM7nCMboi5hl3IcXIOHv2bAh+M45hVFQsa95ZICAM/47GQn1GRqXhsFXxQnkP9LDcvhUP2C6JnFnjCQtwO9aMjAy6Zqxz5EScO3xo5hiPeIi7zKuxOiIQE2zCaoyhg1U027xsMO4eU/wfB6zhl6Z2m6neYPrbTFehcVWb/sfm3iZzP84M95vWDHNvc6RoQ1XFSbRF6+LFixYs7EUkVSsqImTTSjQCFj86K24c06iqqNKsgi3NNI5hFIGFvLtx40YGQUD1ZKwLWoQ/gNtGRNFk2lpl69atwyjn9r4suWbNmlxPcOiQNquqqhDevWekfQQjjE2W5JDQprwswOGZhQVWfaKpTzCt6c4EYIERhaphv2lIMi1HTcffpiLWmfnkvGlJNTUbTddVp4uM0PFAp/b+asFir2kNWg+J3LYDbcgjd3oHph9++IGhHDC2UTVh0SqvUQQWDUR5t2cYYFF7qDSccxYRwKLYGI9DTJMhGbMkjQhVLE8FYj53leaW0l6kLJQWLDuHtRhuhBU5m8MC60mOKVvm/DwvdcDqLDA1Gxyk6ve+Aaskxgy5nPnQBli9dRG8ukK89qtYGNgFnrS3t9t2AB1aiUFWaBkMafssbcUwE1HXFdJSmOmMlnHhwoVxwUJsT/IE69cuSctasBgNgTOSzpFlWJ5SzzlKj0CRYzwML1gM0QG7LBbWWEKA1Z5jWk+ZugTzvNwBq7vEIenOcqfLs2B15pmKFQ55/a2RBctWKXYNm55RGyxY6OPsFDuL8m/b4dtvv7VgsTy/UqqxzBlAhaEl6DSp31H3qfBdZrqtWL7P+i3pa5SPeGLG88ontvXDuPbxvJnhAefSqqvozcfDSQv77nc/9omHI/A+y/XANBm0beoU+4lDSecyYrp/1eB+YVrPvIFMCRksRRFYisBSBJaiCCxFYCkCS1EEljKdwJJir0ixV9QVKgJLDaEILEVgKQJLUQSWIrAUgeUXmdDKpIAV1Sb02/9y7vzq+7/kE9zDDQs5HKvRE5nQ/ycz0oTu7jbcHHX1ahTH/8HETTrz8kxdncGvev3aJCW9c3V8obqwpB2Z0IFmhpnQKSkmJ8eZ4IalbW0mPt6sXeuAVVho0GUXLjS4ZYcPO8whleAc44Bw7+dNm5wf7mAdHlgyoYMGa8aY0Bs3Gt8iMWcOHZLJzXWAKyhwkHrxwixdyj3BTUKC89TZs6a21sGO3fz77zDBkgkdNFgzxoQGHTAimZlOKZo715n+N1gXL5rUVKduUdWYmZhotmyh0oYJlkzooMGaMSY0RWjJEqeP4wdufMGi15s3z+EGsFwu51KMprhwgf7JmV60yNBbhX2NJRM6lMwYE3pwcPz5brff/vhPRCIyoSOWmWFCKxEBS1EEliKwFIGlKAJLEViKwFIUgaVMJ7BkQisyoRV1hYrAUkMoAksRWIrAUhSBpQgsRWD5RSa0MilgTXMTmv/v9k5b99d3zlRmZHTkvex1VIMVlONmzacA17KOio21dOycMD3pQ3eTXwz0lHXeyWzI4tftZfFjZmxiqi42Z0f2qKAhlZeX+81EbRoYGEAe7OrqElhvIYJKiquE1YTShMrMI9OoWjyOC5Z1ne0jRhRd8PHjx9GbUDpxUex8BClec/HixXbJoqIiPGnMuxyPzWzt4aCS+zCv+llNen3G/qoDPYM9KfdSe929p+szTj5I63W/LOkoOV13pvb5/cyGc8fvnyxoLRweGb788Epnf+e5pgssXNlVNWrGeDajPjO7JSeEQ8If2rgIsdoqAzewv7jg9fX1S5YswZxDm6PF7CnE/iLG4cnRArhfUQpWbW0terilh7EuUlJSsOFoEY496rNdBj72eTJ//nzztvGMIc0j6qbb7T5y5Ah9H/NdLldcXBzz8en8lme7HIBUnNIg0+hqutScDSKZjVnFT24WtBV29HdUP7sLK9cfF4NLRVely+3aVbFn1IxuLY0bHB3cU7mvsacp7cGpvqE+pmu677Lu4Mjg9rIdIRySkydPMuYFxiXmUnJyMpIqEjnnHnhhYmI/AxnWIY4hDcUOcgrBWXp6epSCxamWn5/PBDIqFwrx8fGHPKG93tUVWtfZFxc0c1uHaFzmdHZ2ckL7LWMfaXE8fY5KsC3iHnFvK4271JINTFtKtz3qbb3RfutMQxb9XeHja4D1sPdRn7vvQNVBFo6/s9MLVlbjebrFXeV76EZzH+XbZ0M4JCjzEMObZ6AA6hZ4UZ4pSL5gARMNiLXLApQxNOjm5uboAouOyRYhKjxIQRJnJPMxnlGcORHp494FFhix4ueff/4usJhGfabysRXvMrGxsdQzLkToO0JrFKpR3Yv6V0Ov1havh5XKp5V7q/YlViXR5QUCFs/urkg8cT8thIqFzG3bh3OPRgCdzZ6wv3R8aZ4wTQ8YExPDYkzTqrQSlxZR/akwWE93OADD2O81WYU5IBvW0CBvZ3RsNPCF6QRvdty63VF6rPZ4BD5y/qN9O9XUz8O2722SboM9eWBNpQkd2cAWVL3H5qbglbTfHhgZ0PdYiiKwFIGlCCxFEViKwFIElqIILGWagyUTWpEJragrVASWGkIRWIrAUgSWoggsRWApAssvMqGVSQFLJnSAkQn9HsCSCR1CZEIHB5ZM6EAiEzo4sGRCBxiZ0MGBJRM6wMiEDigyoYOKTOhQP0DJhA6+xWRCT5fIhJ7WYCmKwFIEliKwFEVgKdMMLL5hUkMokQ1QOWDNlL+ZKzMi4OSANTQ0JLaUyFLFl4izjOcbxe7ubv709lRRwggIAZL9avq/0p2LbK71A+cAAAAASUVORK5CYII=", - "description": "Visualization of alarms for devices, assets and other entities." + "description": "Visualization of alarms for devices, assets and other entities.", + "externalId": null, + "name": "Alarm widgets" }, "widgetTypes": [ { @@ -23,7 +25,9 @@ "dataKeySettingsSchema": "", "settingsDirective": "tb-alarms-table-widget-settings", "dataKeySettingsDirective": "tb-alarms-table-key-settings", - "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayActivity\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false}" + "hasBasicMode": true, + "basicModeDirective": "tb-alarms-table-basic-config", + "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayActivity\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true,\"entitiesTitle\":null,\"alarmsTitle\":\"Alarms\"},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"warning\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false,\"configMode\":\"basic\",\"alarmFilterConfig\":null}" } } ] diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 9ab33665e6..1289923667 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -64,7 +64,9 @@ "settingsDirective": "tb-timeseries-table-widget-settings", "dataKeySettingsDirective": "tb-timeseries-table-key-settings", "latestDataKeySettingsDirective": "tb-timeseries-table-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true}" + "hasBasicMode": true, + "basicModeDirective": "tb-timeseries-table-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true,\"configMode\":\"basic\"}" } }, { @@ -223,6 +225,48 @@ "settingsDirective": "tb-dashboard-state-widget-settings", "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"syncParentStateParams\":true,\"defaultAutofillLayout\":true,\"defaultMargin\":0,\"defaultBackgroundColor\":\"#fff\"},\"title\":\"Dashboard state widget\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"widgetCss\":\"\",\"noDataDisplayMessage\":\"\",\"showLegend\":false}" } + }, + { + "alias": "value_card", + "name": "Value card", + "image": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyNyIgZmlsbD0ibm9uZSIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgMTI4IDEyNyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2RfMTE0Ml8yMDM5NTQpIj4KICA8cmVjdCB4PSI1LjUiIHk9IjIuNSIgd2lkdGg9IjExNyIgaGVpZ2h0PSIxMTciIHJ4PSIyLjI5NDEiIGZpbGw9IiNmZmYiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPgogIDxwYXRoIGQ9Im0zMy42MDMgMjkuMjIxdi03LjY0NzFjMC0xLjU4NjgtMS4yODA4LTIuODY3Ni0yLjg2NzYtMi44Njc2cy0yLjg2NzcgMS4yODA4LTIuODY3NyAyLjg2NzZ2Ny42NDcxYy0xLjE1NjYgMC44Njk4LTEuOTExNyAyLjI2NTQtMS45MTE3IDMuODIzNSAwIDIuNjM4MiAyLjE0MTIgNC43Nzk0IDQuNzc5NCA0Ljc3OTRzNC43Nzk0LTIuMTQxMiA0Ljc3OTQtNC43Nzk0YzAtMS41NTgxLTAuNzU1MS0yLjk1MzctMS45MTE4LTMuODIzNXptLTMuODIzNS03LjY0NzFjMC0wLjUyNTcgMC40MzAyLTAuOTU1OSAwLjk1NTktMC45NTU5czAuOTU1OSAwLjQzMDIgMC45NTU5IDAuOTU1OWgtMC45NTU5djAuOTU1OWgwLjk1NTl2MS45MTE3aC0wLjk1NTl2MC45NTU5aDAuOTU1OXYxLjkxMThoLTEuOTExOHYtNS43MzUzeiIgZmlsbD0iIzU0NjlGRiIvPgogIDxnIGZpbGw9IiMwMDAiPgogICA8cGF0aCBkPSJtNTAuMTQxIDE5Ljc0MXY2LjUyMzhoLTEuMTE1N3YtNi41MjM4aDEuMTE1N3ptMi4wNDc3IDB2MC44OTYxaC01LjE5MzJ2LTAuODk2MWg1LjE5MzJ6bTIuNjAzMyA2LjYxMzVjLTAuMzU4NSAwLTAuNjgyNi0wLjA1ODMtMC45NzIzLTAuMTc0OC0wLjI4NjgtMC4xMTk1LTAuNTMxOC0wLjI4NTMtMC43MzQ5LTAuNDk3My0wLjIwMDEtMC4yMTIxLTAuMzU0LTAuNDYxNi0wLjQ2MTUtMC43NDgzLTAuMTA3NS0wLjI4NjgtMC4xNjEzLTAuNTk2LTAuMTYxMy0wLjkyNzV2LTAuMTc5M2MwLTAuMzc5MyAwLjA1NTMtMC43MjI4IDAuMTY1OC0xLjAzMDVzMC4yNjQzLTAuNTcwNiAwLjQ2MTUtMC43ODg2YzAuMTk3MS0wLjIyMTEgMC40MzAxLTAuMzg5OCAwLjY5OS0wLjUwNjMgMC4yNjg4LTAuMTE2NSAwLjU2MDEtMC4xNzQ4IDAuODczNy0wLjE3NDggMC4zNDY1IDAgMC42NDk3IDAuMDU4MyAwLjkwOTYgMC4xNzQ4czAuNDc1IDAuMjgwOCAwLjY0NTIgMC40OTI4YzAuMTczMyAwLjIwOTEgMC4zMDE3IDAuNDU4NiAwLjM4NTQgMC43NDgzIDAuMDg2NiAwLjI4OTggMC4xMjk5IDAuNjA5NCAwLjEyOTkgMC45NTg5djAuNDYxNWgtMy43NDU5di0wLjc3NTJoMi42Nzk1di0wLjA4NTFjLTZlLTMgLTAuMTk0Mi0wLjA0NDgtMC4zNzY0LTAuMTE2NS0wLjU0NjYtMC4wNjg3LTAuMTcwMy0wLjE3NDctMC4zMDc3LTAuMzE4MS0wLjQxMjMtMC4xNDM0LTAuMTA0NS0wLjMzNDYtMC4xNTY4LTAuNTczNi0wLjE1NjgtMC4xNzkyIDAtMC4zMzkgMC4wMzg4LTAuNDc5NCAwLjExNjUtMC4xMzc0IDAuMDc0Ny0wLjI1MjQgMC4xODM3LTAuMzQ1IDAuMzI3MXMtMC4xNjQzIDAuMzE2Ni0wLjIxNTEgMC41MTk4Yy0wLjA0NzggMC4yMDAxLTAuMDcxNyAwLjQyNTYtMC4wNzE3IDAuNjc2NXYwLjE3OTNjMCAwLjIxMjEgMC4wMjg0IDAuNDA5MiAwLjA4NTIgMC41OTE0IDAuMDU5NyAwLjE3OTMgMC4xNDYzIDAuMzM2MSAwLjI1OTggMC40NzA1IDAuMTEzNiAwLjEzNDQgMC4yNTEgMC4yNDA1IDAuNDEyMyAwLjMxODEgMC4xNjEzIDAuMDc0NyAwLjM0NSAwLjExMiAwLjU1MTEgMC4xMTIgMC4yNTk5IDAgMC40OTE0LTAuMDUyMiAwLjY5NDUtMC4xNTY4IDAuMjAzMS0wLjEwNDUgMC4zNzk0LTAuMjUyNCAwLjUyODctMC40NDM2bDAuNTY5MSAwLjU1MTJjLTAuMTA0NiAwLjE1MjMtMC4yNDA1IDAuMjk4Ny0wLjQwNzggMC40MzkxLTAuMTY3MyAwLjEzNzQtMC4zNzE5IDAuMjQ5NC0wLjYxMzggMC4zMzYtMC4yMzkgMC4wODY2LTAuNTE2OCAwLjEzLTAuODMzNCAwLjEzem00LjAwNTctMy45NTJ2My44NjIzaC0xLjA3OTh2LTQuODQ4MWgxLjAxNzFsMC4wNjI3IDAuOTg1OHptLTAuMTc0NyAxLjI1OTEtMC4zNjc1LTAuMDA0NWMwLTAuMzM0NiAwLjA0MTktMC42NDM3IDAuMTI1NS0wLjkyNzVzMC4yMDYxLTAuNTMwMiAwLjM2NzQtMC43MzkzYzAuMTYxMy0wLjIxMjEgMC4zNjE1LTAuMzc0OSAwLjYwMDQtMC40ODg0IDAuMjQyLTAuMTE2NSAwLjUyMTMtMC4xNzQ4IDAuODM3OS0wLjE3NDggMC4yMjExIDAgMC40MjI3IDAuMDMyOSAwLjYwNDkgMC4wOTg2IDAuMTg1MiAwLjA2MjcgMC4zNDUgMC4xNjI4IDAuNDc5NSAwLjMwMDIgMC4xMzc0IDAuMTM3NCAwLjI0MTkgMC4zMTM2IDAuMzEzNiAwLjUyODcgMC4wNzQ3IDAuMjE1MSAwLjExMiAwLjQ3NSAwLjExMiAwLjc3OTd2My4yMzA1aC0xLjA3OTh2LTMuMTM2NGMwLTAuMjM2LTAuMDM1OS0wLjQyMTItMC4xMDc2LTAuNTU1Ni0wLjA2ODctMC4xMzQ1LTAuMTY4Ny0wLjIzMDEtMC4zMDAyLTAuMjg2OC0wLjEyODQtMC4wNTk4LTAuMjgyMy0wLjA4OTYtMC40NjE1LTAuMDg5Ni0wLjIwMzEgMC0wLjM3NjQgMC4wMzg4LTAuNTE5NyAwLjExNjUtMC4xNDA0IDAuMDc3Ni0wLjI1NTQgMC4xODM3LTAuMzQ1MSAwLjMxODEtMC4wODk2IDAuMTM0NC0wLjE1NTMgMC4yODk4LTAuMTk3MSAwLjQ2NnMtMC4wNjI3IDAuMzY0NC0wLjA2MjcgMC41NjQ2em0zLjAwNjUtMC4yODY4LTAuNTA2MyAwLjExMmMwLTAuMjkyNyAwLjA0MDMtMC41NjkgMC4xMjEtMC44Mjg5IDAuMDgzNi0wLjI2MjkgMC4yMDQ2LTAuNDkyOSAwLjM2MjktMC42OSAwLjE2MTMtMC4yMDAyIDAuMzYtMC4zNTcgMC41OTU5LTAuNDcwNSAwLjIzNi0wLjExMzUgMC41MDY0LTAuMTcwMyAwLjgxMS0wLjE3MDMgMC4yNDggMCAwLjQ2OSAwLjAzNDQgMC42NjMyIDAuMTAzMSAwLjE5NzEgMC4wNjU3IDAuMzY0NCAwLjE3MDIgMC41MDE4IDAuMzEzNnMwLjI0MiAwLjMzMDEgMC4zMTM3IDAuNTYwMWMwLjA3MTcgMC4yMjcgMC4xMDc1IDAuNTAxOCAwLjEwNzUgMC44MjQ1djMuMTM2NGgtMS4wODQzdi0zLjE0MDljMC0wLjI0NS0wLjAzNTktMC40MzQ2LTAuMTA3Ni0wLjU2OTEtMC4wNjg3LTAuMTM0NC0wLjE2NzItMC4yMjctMC4yOTU3LTAuMjc3OC0wLjEyODQtMC4wNTM3LTAuMjgyMy0wLjA4MDYtMC40NjE1LTAuMDgwNi0wLjE2NzMgMC0wLjMxNTEgMC4wMzEzLTAuNDQzNiAwLjA5NDEtMC4xMjU0IDAuMDU5Ny0wLjIzMTUgMC4xNDQ4LTAuMzE4MSAwLjI1NTQtMC4wODY2IDAuMTA3NS0wLjE1MjQgMC4yMzE1LTAuMTk3MiAwLjM3MTktMC4wNDE4IDAuMTQwNC0wLjA2MjcgMC4yOTI3LTAuMDYyNyAwLjQ1N3ptNS4zMDk2LTEuMDI2MXY1Ljc4MDFoLTEuMDc5OHYtNi43MTIxaDAuOTk0N2wwLjA4NTEgMC45MzJ6bTMuMTU4OSAxLjQ0NzN2MC4wOTQxYzAgMC4zNTI1LTAuMDQxOCAwLjY3OTYtMC4xMjU0IDAuOTgxMy0wLjA4MDcgMC4yOTg3LTAuMjAxNyAwLjU2LTAuMzYzIDAuNzg0MS0wLjE1ODMgMC4yMjEtMC4zNTM5IDAuMzkyOC0wLjU4NjkgMC41MTUzLTAuMjMzIDAuMTIyNC0wLjUwMTkgMC4xODM3LTAuODA2NiAwLjE4MzctMC4zMDE3IDAtMC41NjYtMC4wNTUzLTAuNzkzLTAuMTY1OC0wLjIyNDEtMC4xMTM1LTAuNDEzOC0wLjI3MzMtMC41NjkxLTAuNDc5NS0wLjE1NTMtMC4yMDYxLTAuMjgwOC0wLjQ0OC0wLjM3NjQtMC43MjU4LTAuMDkyNi0wLjI4MDgtMC4xNTgzLTAuNTg4NS0wLjE5NzEtMC45MjMxdi0wLjM2MjljMC4wMzg4LTAuMzU1NSAwLjEwNDUtMC42NzgxIDAuMTk3MS0wLjk2NzggMC4wOTU2LTAuMjg5OCAwLjIyMTEtMC41MzkyIDAuMzc2NC0wLjc0ODNzMC4zNDUtMC4zNzA0IDAuNTY5MS0wLjQ4MzljMC4yMjQtMC4xMTM1IDAuNDg1NC0wLjE3MDMgMC43ODQxLTAuMTcwMyAwLjMwNDcgMCAwLjU3NSAwLjA1OTggMC44MTEgMC4xNzkyIDAuMjM2IDAuMTE2NSAwLjQzNDYgMC4yODM4IDAuNTk1OSAwLjUwMTkgMC4xNjEzIDAuMjE1MSAwLjI4MjMgMC40NzQ5IDAuMzYyOSAwLjc3OTYgMC4wODA3IDAuMzAxNyAwLjEyMSAwLjYzNzggMC4xMjEgMS4wMDgyem0tMS4wNzk4IDAuMDk0MXYtMC4wOTQxYzAtMC4yMjQxLTAuMDIwOS0wLjQzMTctMC4wNjI3LTAuNjIyOC0wLjA0MTktMC4xOTQyLTAuMTA3Ni0wLjM2NDUtMC4xOTcyLTAuNTEwOC0wLjA4OTYtMC4xNDY0LTAuMjA0Ni0wLjI1OTktMC4zNDUtMC4zNDA2LTAuMTM3NC0wLjA4MzYtMC4zMDMyLTAuMTI1NC0wLjQ5NzQtMC4xMjU0LTAuMTkxMSAwLTAuMzU1NCAwLjAzMjgtMC40OTI4IDAuMDk4NS0wLjEzNzUgMC4wNjI4LTAuMjUyNSAwLjE1MDktMC4zNDUxIDAuMjY0NHMtMC4xNjQzIDAuMjQ2NC0wLjIxNSAwLjM5ODhjLTAuMDUwOCAwLjE0OTMtMC4wODY3IDAuMzEyMS0wLjEwNzYgMC40ODg0djAuODY5MmMwLjAzNTkgMC4yMTUxIDAuMDk3MSAwLjQxMjMgMC4xODM3IDAuNTkxNSAwLjA4NjcgMC4xNzkyIDAuMjA5MSAwLjMyMjYgMC4zNjc1IDAuNDMwMSAwLjE2MTMgMC4xMDQ2IDAuMzY3NCAwLjE1NjkgMC42MTgzIDAuMTU2OSAwLjE5NDIgMCAwLjM1OTktMC4wNDE5IDAuNDk3My0wLjEyNTUgMC4xMzc1LTAuMDgzNiAwLjI0OTUtMC4xOTg2IDAuMzM2MS0wLjM0NSAwLjA4OTYtMC4xNDk0IDAuMTU1My0wLjMyMTEgMC4xOTcyLTAuNTE1MyAwLjA0MTgtMC4xOTQxIDAuMDYyNy0wLjQwMDMgMC4wNjI3LTAuNjE4M3ptNC4yNzkgMi40NjQ0Yy0wLjM1ODQgMC0wLjY4MjUtMC4wNTgzLTAuOTcyMy0wLjE3NDgtMC4yODY3LTAuMTE5NS0wLjUzMTctMC4yODUzLTAuNzM0OC0wLjQ5NzMtMC4yMDAxLTAuMjEyMS0wLjM1NC0wLjQ2MTYtMC40NjE1LTAuNzQ4My0wLjEwNzUtMC4yODY4LTAuMTYxMy0wLjU5Ni0wLjE2MTMtMC45Mjc1di0wLjE3OTNjMC0wLjM3OTMgMC4wNTUyLTAuNzIyOCAwLjE2NTgtMS4wMzA1IDAuMTEwNS0wLjMwNzcgMC4yNjQzLTAuNTcwNiAwLjQ2MTUtMC43ODg2IDAuMTk3MS0wLjIyMTEgMC40MzAxLTAuMzg5OCAwLjY5OS0wLjUwNjMgMC4yNjg4LTAuMTE2NSAwLjU2MDEtMC4xNzQ4IDAuODczNy0wLjE3NDggMC4zNDY1IDAgMC42NDk3IDAuMDU4MyAwLjkwOTYgMC4xNzQ4czAuNDc0OSAwLjI4MDggMC42NDUyIDAuNDkyOGMwLjE3MzMgMC4yMDkxIDAuMzAxNyAwLjQ1ODYgMC4zODUzIDAuNzQ4MyAwLjA4NjcgMC4yODk4IDAuMTMgMC42MDk0IDAuMTMgMC45NTg5djAuNDYxNWgtMy43NDU5di0wLjc3NTJoMi42Nzk1di0wLjA4NTFjLTZlLTMgLTAuMTk0Mi0wLjA0NDgtMC4zNzY0LTAuMTE2NS0wLjU0NjYtMC4wNjg3LTAuMTcwMy0wLjE3NDgtMC4zMDc3LTAuMzE4MS0wLjQxMjMtMC4xNDM0LTAuMTA0NS0wLjMzNDYtMC4xNTY4LTAuNTczNi0wLjE1NjgtMC4xNzkyIDAtMC4zMzkgMC4wMzg4LTAuNDc5NCAwLjExNjUtMC4xMzc0IDAuMDc0Ny0wLjI1MjQgMC4xODM3LTAuMzQ1IDAuMzI3MXMtMC4xNjQzIDAuMzE2Ni0wLjIxNTEgMC41MTk4Yy0wLjA0NzggMC4yMDAxLTAuMDcxNyAwLjQyNTYtMC4wNzE3IDAuNjc2NXYwLjE3OTNjMCAwLjIxMjEgMC4wMjg0IDAuNDA5MiAwLjA4NTEgMC41OTE0IDAuMDU5OCAwLjE3OTMgMC4xNDY0IDAuMzM2MSAwLjI1OTkgMC40NzA1czAuMjUwOSAwLjI0MDUgMC40MTIzIDAuMzE4MWMwLjE2MTMgMC4wNzQ3IDAuMzQ1IDAuMTEyIDAuNTUxMSAwLjExMiAwLjI1OTkgMCAwLjQ5MTQtMC4wNTIyIDAuNjk0NS0wLjE1NjggMC4yMDMxLTAuMTA0NSAwLjM3OTQtMC4yNTI0IDAuNTI4Ny0wLjQ0MzZsMC41NjkxIDAuNTUxMmMtMC4xMDQ2IDAuMTUyMy0wLjI0MDUgMC4yOTg3LTAuNDA3OCAwLjQzOTEtMC4xNjczIDAuMTM3NC0wLjM3MTkgMC4yNDk0LTAuNjEzOCAwLjMzNi0wLjIzOSAwLjA4NjYtMC41MTY4IDAuMTMtMC44MzM1IDAuMTN6bTQuMDEwMy00LjAxNDd2My45MjVoLTEuMDc5OXYtNC44NDgxaDEuMDMwNmwwLjA0OTMgMC45MjMxem0xLjQ4MzEtMC45NTQ0LTllLTMgMS4wMDM2Yy0wLjA2NTctMC4wMTE5LTAuMTM3NC0wLjAyMDktMC4yMTUxLTAuMDI2OC0wLjA3NDYtNmUtMyAtMC4xNDkzLTllLTMgLTAuMjI0LTllLTMgLTAuMTg1MiAwLTAuMzQ4IDAuMDI2OS0wLjQ4ODQgMC4wODA3LTAuMTQwNCAwLjA1MDctMC4yNTg0IDAuMTI1NC0wLjM1NCAwLjIyNC0wLjA5MjYgMC4wOTU2LTAuMTY0MyAwLjIxMjEtMC4yMTUgMC4zNDk1LTAuMDUwOCAwLjEzNzQtMC4wODA3IDAuMjkxMi0wLjA4OTYgMC40NjE1bC0wLjI0NjUgMC4wMTc5YzAtMC4zMDQ3IDAuMDI5OS0wLjU4NyAwLjA4OTYtMC44NDY4IDAuMDU5OC0wLjI1OTkgMC4xNDk0LTAuNDg4NCAwLjI2ODktMC42ODU2IDAuMTIyNC0wLjE5NzEgMC4yNzQ4LTAuMzUxIDAuNDU3LTAuNDYxNSAwLjE4NTItMC4xMTA1IDAuMzk4OC0wLjE2NTggMC42NDA3LTAuMTY1OCAwLjA2NTggMCAwLjEzNiA2ZS0zIDAuMjEwNiAwLjAxNzkgMC4wNzc3IDAuMDEyIDAuMTM2IDAuMDI1NCAwLjE3NDggMC4wNDA0em0zLjM5MTkgMy45MDcxdi0yLjMxMmMwLTAuMTczMy0wLjAzMTQtMC4zMjI2LTAuMDk0MS0wLjQ0ODEtMC4wNjI4LTAuMTI1NC0wLjE1ODMtMC4yMjI1LTAuMjg2OC0wLjI5MTItMC4xMjU0LTAuMDY4Ny0wLjI4MzgtMC4xMDMxLTAuNDc0OS0wLjEwMzEtMC4xNzYzIDAtMC4zMjg2IDAuMDI5OS0wLjQ1NzEgMC4wODk2LTAuMTI4NCAwLjA1OTgtMC4yMjg1IDAuMTQwNC0wLjMwMDIgMC4yNDJzLTAuMTA3NSAwLjIxNjYtMC4xMDc1IDAuMzQ1aC0xLjA3NTRjMC0wLjE5MTIgMC4wNDYzLTAuMzc2NCAwLjEzODktMC41NTU2czAuMjI3LTAuMzM5IDAuNDAzMy0wLjQ3OTRjMC4xNzYyLTAuMTQwNCAwLjM4NjgtMC4yNTA5IDAuNjMxOC0wLjMzMTYgMC4yNDQ5LTAuMDgwNyAwLjUxOTctMC4xMjEgMC44MjQ0LTAuMTIxIDAuMzY0NCAwIDAuNjg3IDAuMDYxMyAwLjk2NzggMC4xODM3IDAuMjgzOCAwLjEyMjUgMC41MDY0IDAuMzA3NyAwLjY2NzcgMC41NTU2IDAuMTY0MyAwLjI0NSAwLjI0NjQgMC41NTI3IDAuMjQ2NCAwLjkyMzF2Mi4xNTUyYzAgMC4yMjEgMC4wMTQ5IDAuNDE5NyAwLjA0NDggMC41OTU5IDAuMDMyOSAwLjE3MzMgMC4wNzkyIDAuMzI0MSAwLjEzODkgMC40NTI2djAuMDcxNmgtMS4xMDY3Yy0wLjA1MDgtMC4xMTY0LTAuMDkxMS0wLjI2NDMtMC4xMjEtMC40NDM1LTAuMDI2OS0wLjE4MjMtMC4wNDAzLTAuMzU4NS0wLjA0MDMtMC41Mjg4em0wLjE1NjgtMS45NzYgOWUtMyAwLjY2NzdoLTAuNzc1MmMtMC4yMDAxIDAtMC4zNzY0IDAuMDE5NC0wLjUyODcgMC4wNTgyLTAuMTUyNCAwLjAzNTktMC4yNzkzIDAuMDg5Ni0wLjM4MDkgMC4xNjEzLTAuMTAxNSAwLjA3MTctMC4xNzc3IDAuMTU4My0wLjIyODUgMC4yNTk5cy0wLjA3NjIgMC4yMTY2LTAuMDc2MiAwLjM0NWMwIDAuMTI4NSAwLjAyOTkgMC4yNDY1IDAuMDg5NiAwLjM1NCAwLjA1OTggMC4xMDQ1IDAuMTQ2NCAwLjE4NjcgMC4yNTk5IDAuMjQ2NCAwLjExNjUgMC4wNTk4IDAuMjU2OSAwLjA4OTYgMC40MjEyIDAuMDg5NiAwLjIyMTEgMCAwLjQxMzctMC4wNDQ4IDAuNTc4LTAuMTM0NCAwLjE2NzMtMC4wOTI2IDAuMjk4Ny0wLjIwNDYgMC4zOTQzLTAuMzM2IDAuMDk1Ni0wLjEzNDQgMC4xNDY0LTAuMjYxNCAwLjE1MjQtMC4zODA5bDAuMzQ5NSAwLjQ3OTVjLTAuMDM1OSAwLjEyMjQtMC4wOTcxIDAuMjUzOS0wLjE4MzggMC4zOTQzLTAuMDg2NiAwLjE0MDMtMC4yMDAxIDAuMjc0OC0wLjM0MDUgMC40MDMyLTAuMTM3NCAwLjEyNTUtMC4zMDMyIDAuMjI4NS0wLjQ5NzMgMC4zMDkyLTAuMTkxMiAwLjA4MDYtMC40MTIzIDAuMTIxLTAuNjYzMiAwLjEyMS0wLjMxNjYgMC0wLjU5ODktMC4wNjI4LTAuODQ2OC0wLjE4ODItMC4yNDgtMC4xMjg1LTAuNDQyMS0wLjMwMDItMC41ODI1LTAuNTE1My0wLjE0MDQtMC4yMTgxLTAuMjEwNi0wLjQ2NDUtMC4yMTA2LTAuNzM5MyAwLTAuMjU2OSAwLjA0NzgtMC40ODM5IDAuMTQzNC0wLjY4MTEgMC4wOTg1LTAuMjAwMSAwLjI0MTktMC4zNjc0IDAuNDMwMS0wLjUwMTggMC4xOTEyLTAuMTM0NCAwLjQyNDItMC4yMzYgMC42OTktMC4zMDQ3IDAuMjc0OC0wLjA3MTcgMC41ODg1LTAuMTA3NiAwLjk0MDktMC4xMDc2aDAuODQ2OXptNC40MjI0LTEuODk5OHYwLjc4ODZoLTIuNzMzMnYtMC43ODg2aDIuNzMzMnptLTEuOTQ0Ni0xLjE4NzRoMS4wNzk5djQuNjk1OGMwIDAuMTQ5NCAwLjAyMDkgMC4yNjQ0IDAuMDYyNyAwLjM0NSAwLjA0NDggMC4wNzc3IDAuMTA2IDAuMTMgMC4xODM3IDAuMTU2OSAwLjA3NzcgMC4wMjY4IDAuMTY4OCAwLjA0MDMgMC4yNzMzIDAuMDQwMyAwLjA3NDcgMCAwLjE0NjQtMC4wMDQ1IDAuMjE1MS0wLjAxMzUgMC4wNjg3LTAuMDA4OSAwLjEyNC0wLjAxNzkgMC4xNjU4LTAuMDI2OGwwLjAwNDUgMC44MjQ0Yy0wLjA4OTYgMC4wMjY5LTAuMTk0MiAwLjA1MDgtMC4zMTM3IDAuMDcxNy0wLjExNjUgMC4wMjA5LTAuMjUwOSAwLjAzMTQtMC40MDMyIDAuMDMxNC0wLjI0OCAwLTAuNDY3NS0wLjA0MzQtMC42NTg3LTAuMTMtMC4xOTEyLTAuMDg5Ni0wLjM0MDUtMC4yMzQ1LTAuNDQ4MS0wLjQzNDYtMC4xMDc1LTAuMjAwMS0wLjE2MTMtMC40NjYtMC4xNjEzLTAuNzk3NnYtNC43NjN6bTUuODM4NCA0Ljg5M3YtMy43MDU2aDEuMDg0M3Y0Ljg0ODFoLTEuMDIxNmwtMC4wNjI3LTEuMTQyNXptMC4xNTIzLTEuMDA4MiAwLjM2My0wLjAwODljMCAwLjMyNTUtMC4wMzU5IDAuNjI1OC0wLjEwNzYgMC45MDA2LTAuMDcxNyAwLjI3MTgtMC4xODIyIDAuNTA5My0wLjMzMTYgMC43MTI0LTAuMTQ5MyAwLjIwMDEtMC4zNDA1IDAuMzU3LTAuNTczNSAwLjQ3MDUtMC4yMzMgMC4xMTA1LTAuNTEyMyAwLjE2NTgtMC44Mzc5IDAuMTY1OC0wLjIzNiAwLTAuNDUyNS0wLjAzNDQtMC42NDk3LTAuMTAzMS0wLjE5NzEtMC4wNjg3LTAuMzY3NC0wLjE3NDctMC41MTA4LTAuMzE4MS0wLjE0MDQtMC4xNDM0LTAuMjQ5NC0wLjMzMDEtMC4zMjcxLTAuNTYwMS0wLjA3NzYtMC4yMy0wLjExNjUtMC41MDQ4LTAuMTE2NS0wLjgyNDV2LTMuMTMyaDEuMDc5OXYzLjE0MWMwIDAuMTc2MiAwLjAyMDkgMC4zMjQxIDAuMDYyNyAwLjQ0MzYgMC4wNDE4IDAuMTE2NSAwLjA5ODYgMC4yMTA2IDAuMTcwMyAwLjI4MjNzMC4xNTUzIDAuMTIyNCAwLjI1MDkgMC4xNTIzIDAuMTk3MSAwLjA0NDggMC4zMDQ3IDAuMDQ0OGMwLjMwNzcgMCAwLjU0OTYtMC4wNTk3IDAuNzI1OS0wLjE3OTIgMC4xNzkyLTAuMTIyNSAwLjMwNjEtMC4yODY4IDAuMzgwOC0wLjQ5MjkgMC4wNzc3LTAuMjA2MSAwLjExNjUtMC40Mzc2IDAuMTE2NS0wLjY5NDV6bTMuMjY2NC0xLjc3NDN2My45MjVoLTEuMDc5OHYtNC44NDgxaDEuMDMwNmwwLjA0OTIgMC45MjMxem0xLjQ4MzItMC45NTQ0LTllLTMgMS4wMDM2Yy0wLjA2NTctMC4wMTE5LTAuMTM3NC0wLjAyMDktMC4yMTUxLTAuMDI2OC0wLjA3NDctNmUtMyAtMC4xNDkzLTllLTMgLTAuMjI0LTllLTMgLTAuMTg1MiAwLTAuMzQ4IDAuMDI2OS0wLjQ4ODQgMC4wODA3LTAuMTQwNCAwLjA1MDctMC4yNTg0IDAuMTI1NC0wLjM1NCAwLjIyNC0wLjA5MjYgMC4wOTU2LTAuMTY0MyAwLjIxMjEtMC4yMTUxIDAuMzQ5NS0wLjA1MDcgMC4xMzc0LTAuMDgwNiAwLjI5MTItMC4wODk2IDAuNDYxNWwtMC4yNDY0IDAuMDE3OWMwLTAuMzA0NyAwLjAyOTktMC41ODcgMC4wODk2LTAuODQ2OCAwLjA1OTctMC4yNTk5IDAuMTQ5NC0wLjQ4ODQgMC4yNjg4LTAuNjg1NiAwLjEyMjUtMC4xOTcxIDAuMjc0OS0wLjM1MSAwLjQ1NzEtMC40NjE1IDAuMTg1Mi0wLjExMDUgMC4zOTg4LTAuMTY1OCAwLjY0MDctMC4xNjU4IDAuMDY1NyAwIDAuMTM1OSA2ZS0zIDAuMjEwNiAwLjAxNzkgMC4wNzc3IDAuMDEyIDAuMTM1OSAwLjAyNTQgMC4xNzQ4IDAuMDQwNHptMi44Njc2IDQuOTY5MWMtMC4zNTg1IDAtMC42ODI2LTAuMDU4My0wLjk3MjMtMC4xNzQ4LTAuMjg2OC0wLjExOTUtMC41MzE3LTAuMjg1My0wLjczNDgtMC40OTczLTAuMjAwMi0wLjIxMjEtMC4zNTQtMC40NjE2LTAuNDYxNi0wLjc0ODMtMC4xMDc1LTAuMjg2OC0wLjE2MTMtMC41OTYtMC4xNjEzLTAuOTI3NXYtMC4xNzkzYzAtMC4zNzkzIDAuMDU1My0wLjcyMjggMC4xNjU4LTEuMDMwNSAwLjExMDYtMC4zMDc3IDAuMjY0NC0wLjU3MDYgMC40NjE1LTAuNzg4NiAwLjE5NzItMC4yMjExIDAuNDMwMi0wLjM4OTggMC42OTktMC41MDYzIDAuMjY4OS0wLjExNjUgMC41NjAxLTAuMTc0OCAwLjg3MzgtMC4xNzQ4IDAuMzQ2NSAwIDAuNjQ5NyAwLjA1ODMgMC45MDk1IDAuMTc0OCAwLjI1OTkgMC4xMTY1IDAuNDc1IDAuMjgwOCAwLjY0NTMgMC40OTI4IDAuMTcyOSAwLjIwOTEgMC4zMDE5IDAuNDU4NiAwLjM4NDkgMC43NDgzIDAuMDg3IDAuMjg5OCAwLjEzIDAuNjA5NCAwLjEzIDAuOTU4OXYwLjQ2MTVoLTMuNzQ1NXYtMC43NzUyaDIuNjc5NHYtMC4wODUxYy0wLjAwNTktMC4xOTQyLTAuMDQ0OC0wLjM3NjQtMC4xMTY1LTAuNTQ2Ni0wLjA2ODctMC4xNzAzLTAuMTc0Ny0wLjMwNzctMC4zMTgxLTAuNDEyMy0wLjE0MzQtMC4xMDQ1LTAuMzM0NS0wLjE1NjgtMC41NzM1LTAuMTU2OC0wLjE3OTIgMC0wLjMzOTEgMC4wMzg4LTAuNDc5NSAwLjExNjUtMC4xMzc0IDAuMDc0Ny0wLjI1MjQgMC4xODM3LTAuMzQ1IDAuMzI3MXMtMC4xNjQzIDAuMzE2Ni0wLjIxNSAwLjUxOThjLTAuMDQ3OCAwLjIwMDEtMC4wNzE3IDAuNDI1Ni0wLjA3MTcgMC42NzY1djAuMTc5M2MwIDAuMjEyMSAwLjAyODMgMC40MDkyIDAuMDg1MSAwLjU5MTQgMC4wNTk3IDAuMTc5MyAwLjE0NjQgMC4zMzYxIDAuMjU5OSAwLjQ3MDVzMC4yNTA5IDAuMjQwNSAwLjQxMjIgMC4zMTgxYzAuMTYxMyAwLjA3NDcgMC4zNDUgMC4xMTIgMC41NTExIDAuMTEyIDAuMjU5OSAwIDAuNDkxNC0wLjA1MjIgMC42OTQ1LTAuMTU2OCAwLjIwMzItMC4xMDQ1IDAuMzc5NC0wLjI1MjQgMC41Mjg4LTAuNDQzNmwwLjU2ODggMC41NTEyYy0wLjEwNCAwLjE1MjMtMC4yNCAwLjI5ODctMC40MDc1IDAuNDM5MS0wLjE2NzMgMC4xMzc0LTAuMzcxOSAwLjI0OTQtMC42MTM5IDAuMzM2LTAuMjM5IDAuMDg2Ni0wLjUxNjggMC4xMy0wLjgzMzQgMC4xM3oiIGZpbGwtb3BhY2l0eT0iLjg3Ii8+CiAgIDxwYXRoIGQ9Im01MC4zNTYgMzYuNTk2djAuNjY4N2gtMi40NTY2di0wLjY2ODdoMi40NTY2em0tMi4yMjEzLTQuMjI0MnY0Ljg5MjloLTAuODQzNXYtNC44OTI5aDAuODQzNXptNC45ODU5IDQuMTYzN3YtMS43MzRjMC0wLjEzLTAuMDIzNi0wLjI0Mi0wLjA3MDYtMC4zMzYxLTAuMDQ3MS0wLjA5NDEtMC4xMTg3LTAuMTY2OS0wLjIxNTEtMC4yMTg0LTAuMDk0MS0wLjA1MTUtMC4yMTI4LTAuMDc3My0wLjM1NjItMC4wNzczLTAuMTMyMiAwLTAuMjQ2NCAwLjAyMjQtMC4zNDI4IDAuMDY3Mi0wLjA5NjMgMC4wNDQ4LTAuMTcxNCAwLjEwNTMtMC4yMjUxIDAuMTgxNS0wLjA1MzggMC4wNzYyLTAuMDgwNyAwLjE2MjQtMC4wODA3IDAuMjU4N2gtMC44MDY1YzAtMC4xNDMzIDAuMDM0Ny0wLjI4MjIgMC4xMDQyLTAuNDE2NyAwLjA2OTQtMC4xMzQ0IDAuMTcwMi0wLjI1NDIgMC4zMDI0LTAuMzU5NXMwLjI5MDEtMC4xODgyIDAuNDczOS0wLjI0ODdjMC4xODM3LTAuMDYwNSAwLjM4OTgtMC4wOTA3IDAuNjE4My0wLjA5MDcgMC4yNzMzIDAgMC41MTUzIDAuMDQ1OSAwLjcyNTkgMC4xMzc3IDAuMjEyOCAwLjA5MTkgMC4zNzk3IDAuMjMwOCAwLjUwMDcgMC40MTY3IDAuMTIzMiAwLjE4MzcgMC4xODQ4IDAuNDE0NSAwLjE4NDggMC42OTIzdjEuNjE2NGMwIDAuMTY1OCAwLjAxMTIgMC4zMTQ4IDAuMDMzNiAwLjQ0NyAwLjAyNDcgMC4xMjk5IDAuMDU5NCAwLjI0MyAwLjEwNDIgMC4zMzk0djAuMDUzN2gtMC44MzAxYy0wLjAzOC0wLjA4NzMtMC4wNjgzLTAuMTk4Mi0wLjA5MDctMC4zMzI2LTAuMDIwMi0wLjEzNjctMC4wMzAyLTAuMjY4OS0wLjAzMDItMC4zOTY2em0wLjExNzYtMS40ODIgMC4wMDY3IDAuNTAwN2gtMC41ODE0Yy0wLjE1MDEgMC0wLjI4MjMgMC4wMTQ2LTAuMzk2NSAwLjA0MzctMC4xMTQzIDAuMDI2OS0wLjIwOTUgMC4wNjcyLTAuMjg1NyAwLjEyMS0wLjA3NjEgMC4wNTM4LTAuMTMzMyAwLjExODctMC4xNzEzIDAuMTk0OS0wLjAzODEgMC4wNzYyLTAuMDU3MiAwLjE2MjQtMC4wNTcyIDAuMjU4OCAwIDAuMDk2MyAwLjAyMjQgMC4xODQ4IDAuMDY3MiAwLjI2NTUgMC4wNDQ4IDAuMDc4NCAwLjEwOTggMC4xNCAwLjE5NDkgMC4xODQ4IDAuMDg3NCAwLjA0NDggMC4xOTI3IDAuMDY3MiAwLjMxNTkgMC4wNjcyIDAuMTY1OCAwIDAuMzEwMy0wLjAzMzYgMC40MzM1LTAuMTAwOCAwLjEyNTUtMC4wNjk1IDAuMjI0MS0wLjE1MzUgMC4yOTU4LTAuMjUyMSAwLjA3MTctMC4xMDA4IDAuMTA5Ny0wLjE5NiAwLjExNDItMC4yODU2bDAuMjYyMiAwLjM1OTZjLTAuMDI2OSAwLjA5MTgtMC4wNzI5IDAuMTkwNC0wLjEzNzggMC4yOTU3LTAuMDY1IDAuMTA1My0wLjE1MDEgMC4yMDYxLTAuMjU1NCAwLjMwMjQtMC4xMDMxIDAuMDk0MS0wLjIyNzQgMC4xNzE0LTAuMzczIDAuMjMxOS0wLjE0MzQgMC4wNjA1LTAuMzA5MiAwLjA5MDgtMC40OTc0IDAuMDkwOC0wLjIzNzUgMC0wLjQ0OTItMC4wNDcxLTAuNjM1MS0wLjE0MTItMC4xODYtMC4wOTYzLTAuMzMxNi0wLjIyNTEtMC40MzY5LTAuMzg2NC0wLjEwNTMtMC4xNjM2LTAuMTU4LTAuMzQ4NC0wLjE1OC0wLjU1NDUgMC0wLjE5MjcgMC4wMzU5LTAuMzYzIDAuMTA3Ni0wLjUxMDggMC4wNzM5LTAuMTUwMSAwLjE4MTQtMC4yNzU2IDAuMzIyNi0wLjM3NjQgMC4xNDM0LTAuMTAwOCAwLjMxODEtMC4xNzcgMC41MjQyLTAuMjI4NSAwLjIwNjEtMC4wNTM4IDAuNDQxNC0wLjA4MDcgMC43MDU3LTAuMDgwN2gwLjYzNTJ6bTMuNzI1NyAxLjIyNjZjMC0wLjA4MDYtMC4wMjAyLTAuMTUzNC0wLjA2MDUtMC4yMTg0LTAuMDQwMy0wLjA2NzItMC4xMTc2LTAuMTI3Ny0wLjIzMTktMC4xODE1LTAuMTEyLTAuMDUzOC0wLjI3NzgtMC4xMDMtMC40OTczLTAuMTQ3OS0wLjE5MjctMC4wNDI1LTAuMzY5Ny0wLjA5MjktMC41MzEtMC4xNTEyLTAuMTU5MS0wLjA2MDUtMC4yOTU3LTAuMTMzMy0wLjQxLTAuMjE4NC0wLjExNDItMC4wODUxLTAuMjAyNy0wLjE4Ni0wLjI2NTUtMC4zMDI1LTAuMDYyNy0wLjExNjUtMC4wOTQxLTAuMjUwOS0wLjA5NDEtMC40MDMyIDAtMC4xNDc5IDAuMDMyNS0wLjI4NzkgMC4wOTc1LTAuNDIwMXMwLjE1NzktMC4yNDg3IDAuMjc4OS0wLjM0OTUgMC4yNjc3LTAuMTgwMyAwLjQ0MDItMC4yMzg2YzAuMTc0OC0wLjA1ODIgMC4zNjk3LTAuMDg3MyAwLjU4NDgtMC4wODczIDAuMzA0NyAwIDAuNTY1NyAwLjA1MTUgMC43ODMgMC4xNTQ1IDAuMjE5NSAwLjEwMDkgMC4zODc2IDAuMjM4NiAwLjUwNDEgMC40MTM0IDAuMTE2NSAwLjE3MjUgMC4xNzQ3IDAuMzY3NCAwLjE3NDcgMC41ODQ3aC0wLjgwOTljMC0wLjA5NjMtMC4wMjQ2LTAuMTg1OS0wLjA3MzktMC4yNjg4LTAuMDQ3MS0wLjA4NTItMC4xMTg4LTAuMTUzNS0wLjIxNTEtMC4yMDUtMC4wOTYzLTAuMDUzOC0wLjIxNzMtMC4wODA3LTAuMzYyOS0wLjA4MDctMC4xMzg5IDAtMC4yNTQzIDAuMDIyNC0wLjM0NjIgMC4wNjcyLTAuMDg5NiAwLjA0MjYtMC4xNTY4IDAuMDk4Ni0wLjIwMTYgMC4xNjgxLTAuMDQyNiAwLjA2OTQtMC4wNjM4IDAuMTQ1Ni0wLjA2MzggMC4yMjg1IDAgMC4wNjA1IDAuMDExMiAwLjExNTQgMC4wMzM2IDAuMTY0NiAwLjAyNDYgMC4wNDcxIDAuMDY0OSAwLjA5MDggMC4xMjA5IDAuMTMxMSAwLjA1NjEgMC4wMzgxIDAuMTMyMiAwLjA3MzkgMC4yMjg2IDAuMTA3NSAwLjA5ODUgMC4wMzM2IDAuMjIxOCAwLjA2NjEgMC4zNjk2IDAuMDk3NSAwLjI3NzggMC4wNTgyIDAuNTE2NCAwLjEzMzMgMC43MTU4IDAuMjI1MSAwLjIwMTYgMC4wODk3IDAuMzU2MiAwLjIwNjIgMC40NjM4IDAuMzQ5NSAwLjEwNzUgMC4xNDEyIDAuMTYxMyAwLjMyMDQgMC4xNjEzIDAuNTM3NyAwIDAuMTYxMy0wLjAzNDggMC4zMDkyLTAuMTA0MiAwLjQ0MzYtMC4wNjcyIDAuMTMyMi0wLjE2NTggMC4yNDc2LTAuMjk1NyAwLjM0NjItMC4xMyAwLjA5NjMtMC4yODU3IDAuMTcxMy0wLjQ2NzIgMC4yMjUxLTAuMTc5MiAwLjA1MzgtMC4zODA4IDAuMDgwNy0wLjYwNDggMC4wODA3LTAuMzI5NCAwLTAuNjA4My0wLjA1ODMtMC44MzY4LTAuMTc0OC0wLjIyODUtMC4xMTg3LTAuNDAyMi0wLjI3LTAuNTIwOS0wLjQ1MzctMC4xMTY1LTAuMTg1OS0wLjE3NDctMC4zNzg2LTAuMTc0Ny0wLjU3OGgwLjc4M2MwLjAwODkgMC4xNTAxIDAuMDUwNCAwLjI3IDAuMTI0MyAwLjM1OTYgMC4wNzYyIDAuMDg3NCAwLjE3MDMgMC4xNTEyIDAuMjgyMyAwLjE5MTYgMC4xMTQyIDAuMDM4IDAuMjMxOSAwLjA1NzEgMC4zNTI4IDAuMDU3MSAwLjE0NTcgMCAwLjI2NzgtMC4wMTkxIDAuMzY2My0wLjA1NzEgMC4wOTg2LTAuMDQwNCAwLjE3MzctMC4wOTQxIDAuMjI1Mi0wLjE2MTMgMC4wNTE1LTAuMDY5NSAwLjA3NzMtMC4xNDc5IDAuMDc3My0wLjIzNTN6bTMuMzEyMy0yLjY1MTR2MC41OTE0aC0yLjA0OTl2LTAuNTkxNGgyLjA0OTl6bS0xLjQ1ODQtMC44OTA2aDAuODA5OXYzLjUyMTljMCAwLjExMiAwLjAxNTYgMC4xOTgyIDAuMDQ3IDAuMjU4NyAwLjAzMzYgMC4wNTgzIDAuMDc5NSAwLjA5NzUgMC4xMzc4IDAuMTE3NiAwLjA1ODIgMC4wMjAyIDAuMTI2NiAwLjAzMDMgMC4yMDUgMC4wMzAzIDAuMDU2IDAgMC4xMDk4LTAuMDAzNCAwLjE2MTMtMC4wMTAxczAuMDkzLTAuMDEzNCAwLjEyNDMtMC4wMjAybDAuMDAzNCAwLjYxODRjLTAuMDY3MiAwLjAyMDEtMC4xNDU2IDAuMDM4MS0wLjIzNTMgMC4wNTM3LTAuMDg3MyAwLjAxNTctMC4xODgxIDAuMDIzNi0wLjMwMjQgMC4wMjM2LTAuMTg2IDAtMC4zNTA2LTAuMDMyNS0wLjQ5NC0wLjA5NzUtMC4xNDM0LTAuMDY3Mi0wLjI1NTQtMC4xNzU5LTAuMzM2MS0wLjMyNi0wLjA4MDYtMC4xNTAxLTAuMTIwOS0wLjM0OTUtMC4xMjA5LTAuNTk4MXYtMy41NzIzem02LjI3MTggMy42Njk3di0yLjc3OTFoMC44MTMzdjMuNjM2aC0wLjc2NjJsLTAuMDQ3MS0wLjg1Njl6bTAuMTE0My0wLjc1NjEgMC4yNzIyLTAuMDA2N2MwIDAuMjQ0Mi0wLjAyNjkgMC40NjkzLTAuMDgwNyAwLjY3NTQtMC4wNTM3IDAuMjAzOS0wLjEzNjYgMC4zODItMC4yNDg2IDAuNTM0NC0wLjExMjEgMC4xNTAxLTAuMjU1NCAwLjI2NzctMC40MzAyIDAuMzUyOC0wLjE3NDcgMC4wODI5LTAuMzg0MiAwLjEyNDQtMC42Mjg0IDAuMTI0NC0wLjE3NyAwLTAuMzM5NC0wLjAyNTgtMC40ODczLTAuMDc3My0wLjE0NzgtMC4wNTE2LTAuMjc1NS0wLjEzMTEtMC4zODMxLTAuMjM4Ni0wLjEwNTMtMC4xMDc2LTAuMTg3MS0wLjI0NzYtMC4yNDUzLTAuNDIwMS0wLjA1ODMtMC4xNzI1LTAuMDg3NC0wLjM3ODYtMC4wODc0LTAuNjE4M3YtMi4zNDloMC44MDk5djIuMzU1N2MwIDAuMTMyMiAwLjAxNTcgMC4yNDMxIDAuMDQ3MSAwLjMzMjcgMC4wMzEzIDAuMDg3NCAwLjA3MzkgMC4xNTc5IDAuMTI3NyAwLjIxMTcgMC4wNTM3IDAuMDUzOCAwLjExNjUgMC4wOTE4IDAuMTg4MSAwLjExNDMgMC4wNzE3IDAuMDIyNCAwLjE0NzkgMC4wMzM2IDAuMjI4NiAwLjAzMzYgMC4yMzA3IDAgMC40MTIyLTAuMDQ0OSAwLjU0NDQtMC4xMzQ1IDAuMTM0NC0wLjA5MTggMC4yMjk2LTAuMjE1IDAuMjg1Ni0wLjM2OTYgMC4wNTgzLTAuMTU0NiAwLjA4NzQtMC4zMjgyIDAuMDg3NC0wLjUyMDl6bTIuNDg1Ny0xLjMyNHY0LjMzNWgtMC44MDk5di01LjAzNGgwLjc0NmwwLjA2MzkgMC42OTl6bTIuMzY5MSAxLjA4NTR2MC4wNzA2YzAgMC4yNjQzLTAuMDMxMyAwLjUwOTctMC4wOTQxIDAuNzM1OS0wLjA2MDUgMC4yMjQxLTAuMTUxMiAwLjQyMDEtMC4yNzIyIDAuNTg4MS0wLjExODcgMC4xNjU4LTAuMjY1NSAwLjI5NDYtMC40NDAyIDAuMzg2NS0wLjE3NDggMC4wOTE4LTAuMzc2NCAwLjEzNzgtMC42MDQ5IDAuMTM3OC0wLjIyNjMgMC0wLjQyNDUtMC4wNDE1LTAuNTk0OC0wLjEyNDQtMC4xNjgtMC4wODUxLTAuMzEwMy0wLjIwNS0wLjQyNjgtMC4zNTk2LTAuMTE2NS0wLjE1NDUtMC4yMTA2LTAuMzM2LTAuMjgyMy0wLjU0NDQtMC4wNjk0LTAuMjEwNi0wLjExODctMC40NDEzLTAuMTQ3OC0wLjY5MjJ2LTAuMjcyMmMwLjAyOTEtMC4yNjY2IDAuMDc4NC0wLjUwODYgMC4xNDc4LTAuNzI1OSAwLjA3MTctMC4yMTczIDAuMTY1OC0wLjQwNDQgMC4yODIzLTAuNTYxMnMwLjI1ODgtMC4yNzc4IDAuNDI2OC0wLjM2MjljMC4xNjgtMC4wODUyIDAuMzY0LTAuMTI3NyAwLjU4ODEtMC4xMjc3IDAuMjI4NSAwIDAuNDMxMiAwLjA0NDggMC42MDgyIDAuMTM0NCAwLjE3NyAwLjA4NzMgMC4zMjYgMC4yMTI4IDAuNDQ3IDAuMzc2NCAwLjEyMSAwLjE2MTMgMC4yMTE3IDAuMzU2MiAwLjI3MjIgMC41ODQ3IDAuMDYwNSAwLjIyNjMgMC4wOTA3IDAuNDc4MyAwLjA5MDcgMC43NTYxem0tMC44MDk5IDAuMDcwNnYtMC4wNzA2YzAtMC4xNjgtMC4wMTU2LTAuMzIzNy0wLjA0Ny0wLjQ2NzEtMC4wMzE0LTAuMTQ1Ni0wLjA4MDctMC4yNzMzLTAuMTQ3OS0wLjM4MzFzLTAuMTUzNC0wLjE5NDktMC4yNTg3LTAuMjU1NGMtMC4xMDMxLTAuMDYyNy0wLjIyNzQtMC4wOTQxLTAuMzczMS0wLjA5NDEtMC4xNDMzIDAtMC4yNjY2IDAuMDI0Ni0wLjM2OTYgMC4wNzM5LTAuMTAzMSAwLjA0NzEtMC4xODkzIDAuMTEzMi0wLjI1ODggMC4xOTgzLTAuMDY5NCAwLjA4NTEtMC4xMjMyIDAuMTg0OC0wLjE2MTMgMC4yOTkxLTAuMDM4MSAwLjExMi0wLjA2NDkgMC4yMzQxLTAuMDgwNiAwLjM2NjN2MC42NTE5YzAuMDI2OSAwLjE2MTMgMC4wNzI4IDAuMzA5MiAwLjEzNzggMC40NDM2IDAuMDY0OSAwLjEzNDQgMC4xNTY4IDAuMjQyIDAuMjc1NSAwLjMyMjYgMC4xMjEgMC4wNzg0IDAuMjc1NiAwLjExNzYgMC40NjM4IDAuMTE3NiAwLjE0NTYgMCAwLjI2OTktMC4wMzEzIDAuMzczLTAuMDk0MSAwLjEwMy0wLjA2MjcgMC4xODcxLTAuMTQ4OSAwLjI1Mi0wLjI1ODcgMC4wNjcyLTAuMTEyIDAuMTE2NS0wLjI0MDkgMC4xNDc5LTAuMzg2NXMwLjA0Ny0wLjMwMDIgMC4wNDctMC40NjM3em0zLjg2MDIgMS4wMjgzdi00LjQwOWgwLjgxMzJ2NS4xNjE3aC0wLjczNTlsLTAuMDc3My0wLjc1Mjd6bS0yLjM2NTktMS4wMjV2LTAuMDcwNWMwLTAuMjc1NiAwLjAzMjUtMC41MjY1IDAuMDk3NS0wLjc1MjggMC4wNjUtMC4yMjg1IDAuMTU5MS0wLjQyNDUgMC4yODIzLTAuNTg4MSAwLjEyMzItMC4xNjU4IDAuMjczMy0wLjI5MjQgMC40NTAzLTAuMzc5NyAwLjE3Ny0wLjA4OTYgMC4zNzY0LTAuMTM0NCAwLjU5ODItMC4xMzQ0IDAuMjE5NSAwIDAuNDEyMiAwLjA0MjUgMC41NzggMC4xMjc3IDAuMTY1OCAwLjA4NTEgMC4zMDY5IDAuMjA3MiAwLjQyMzQgMC4zNjYyIDAuMTE2NSAwLjE1NjkgMC4yMDk1IDAuMzQ1MSAwLjI3ODkgMC41NjQ2IDAuMDY5NSAwLjIxNzMgMC4xMTg4IDAuNDU5MyAwLjE0NzkgMC43MjU5djAuMjI1MWMtMC4wMjkxIDAuMjU5OS0wLjA3ODQgMC40OTc0LTAuMTQ3OSAwLjcxMjUtMC4wNjk0IDAuMjE1LTAuMTYyNCAwLjQwMS0wLjI3ODkgMC41NTc4cy0wLjI1ODggMC4yNzc4LTAuNDI2OCAwLjM2M2MtMC4xNjU4IDAuMDg1MS0wLjM1OTYgMC4xMjc3LTAuNTgxMyAwLjEyNzctMC4yMTk2IDAtMC40MTc5LTAuMDQ2LTAuNTk0OS0wLjEzNzgtMC4xNzQ3LTAuMDkxOS0wLjMyMzctMC4yMjA3LTAuNDQ2OS0wLjM4NjVzLTAuMjE3My0wLjM2MDctMC4yODIzLTAuNTg0N2MtMC4wNjUtMC4yMjYzLTAuMDk3NS0wLjQ3MTYtMC4wOTc1LTAuNzM2em0wLjgwOTktMC4wNzA1djAuMDcwNWMwIDAuMTY1OCAwLjAxNDYgMC4zMjA0IDAuMDQzNyAwLjQ2MzggMC4wMzE0IDAuMTQzNCAwLjA3OTYgMC4yNjk5IDAuMTQ0NSAwLjM3OTcgMC4wNjUgMC4xMDc2IDAuMTQ5IDAuMTkyNyAwLjI1MjEgMC4yNTU0IDAuMTA1MyAwLjA2MDUgMC4yMzA3IDAuMDkwOCAwLjM3NjMgMC4wOTA4IDAuMTgzOCAwIDAuMzM1LTAuMDQwNCAwLjQ1MzctMC4xMjEgMC4xMTg4LTAuMDgwNyAwLjIxMTctMC4xODkzIDAuMjc4OS0wLjMyNiAwLjA2OTUtMC4xMzg5IDAuMTE2NS0wLjI5MzUgMC4xNDEyLTAuNDYzN3YtMC42MDgzYy0wLjAxMzUtMC4xMzIyLTAuMDQxNS0wLjI1NTQtMC4wODQtMC4zNjk3LTAuMDQwNC0wLjExNDItMC4wOTUyLTAuMjEzOS0wLjE2NDctMC4yOTktMC4wNjk1LTAuMDg3NC0wLjE1NTctMC4xNTQ2LTAuMjU4OC0wLjIwMTctMC4xMDA4LTAuMDQ5My0wLjIyMDYtMC4wNzM5LTAuMzU5NS0wLjA3MzktMC4xNDc5IDAtMC4yNzM0IDAuMDMxNC0wLjM3NjQgMC4wOTQxLTAuMTAzMSAwLjA2MjctMC4xODgyIDAuMTQ5LTAuMjU1NCAwLjI1ODctMC4wNjUgMC4xMDk4LTAuMTEzMiAwLjIzNzUtMC4xNDQ1IDAuMzgzMS0wLjAzMTQgMC4xNDU3LTAuMDQ3MSAwLjMwMTQtMC4wNDcxIDAuNDY3MnptNS40MDk0IDEuMTE5di0xLjczNGMwLTAuMTMtMC4wMjM2LTAuMjQyLTAuMDcwNi0wLjMzNjEtMC4wNDcxLTAuMDk0MS0wLjExODgtMC4xNjY5LTAuMjE1MS0wLjIxODQtMC4wOTQxLTAuMDUxNS0wLjIxMjgtMC4wNzczLTAuMzU2Mi0wLjA3NzMtMC4xMzIyIDAtMC4yNDY0IDAuMDIyNC0wLjM0MjggMC4wNjcyLTAuMDk2MyAwLjA0NDgtMC4xNzE0IDAuMTA1My0wLjIyNTEgMC4xODE1LTAuMDUzOCAwLjA3NjItMC4wODA3IDAuMTYyNC0wLjA4MDcgMC4yNTg3aC0wLjgwNjVjMC0wLjE0MzMgMC4wMzQ3LTAuMjgyMiAwLjEwNDItMC40MTY3IDAuMDY5NC0wLjEzNDQgMC4xNzAyLTAuMjU0MiAwLjMwMjQtMC4zNTk1czAuMjkwMS0wLjE4ODIgMC40NzM4LTAuMjQ4N2MwLjE4MzgtMC4wNjA1IDAuMzg5OS0wLjA5MDcgMC42MTg0LTAuMDkwNyAwLjI3MzMgMCAwLjUxNTMgMC4wNDU5IDAuNzI1OSAwLjEzNzcgMC4yMTI4IDAuMDkxOSAwLjM3OTcgMC4yMzA4IDAuNTAwNyAwLjQxNjcgMC4xMjMyIDAuMTgzNyAwLjE4NDggMC40MTQ1IDAuMTg0OCAwLjY5MjN2MS42MTY0YzAgMC4xNjU4IDAuMDExMiAwLjMxNDggMC4wMzM2IDAuNDQ3IDAuMDI0NyAwLjEyOTkgMC4wNTk0IDAuMjQzIDAuMTA0MiAwLjMzOTR2MC4wNTM3aC0wLjgzMDFjLTAuMDM4LTAuMDg3My0wLjA2ODMtMC4xOTgyLTAuMDkwNy0wLjMzMjYtMC4wMjAyLTAuMTM2Ny0wLjAzMDItMC4yNjg5LTAuMDMwMi0wLjM5NjZ6bTAuMTE3Ni0xLjQ4MiAwLjAwNjcgMC41MDA3aC0wLjU4MTRjLTAuMTUwMSAwLTAuMjgyMyAwLjAxNDYtMC4zOTY1IDAuMDQzNy0wLjExNDMgMC4wMjY5LTAuMjA5NSAwLjA2NzItMC4yODU3IDAuMTIxLTAuMDc2MSAwLjA1MzgtMC4xMzMzIDAuMTE4Ny0wLjE3MTMgMC4xOTQ5LTAuMDM4MSAwLjA3NjItMC4wNTcyIDAuMTYyNC0wLjA1NzIgMC4yNTg4IDAgMC4wOTYzIDAuMDIyNCAwLjE4NDggMC4wNjcyIDAuMjY1NSAwLjA0NDggMC4wNzg0IDAuMTA5OCAwLjE0IDAuMTk0OSAwLjE4NDggMC4wODc0IDAuMDQ0OCAwLjE5MjcgMC4wNjcyIDAuMzE1OSAwLjA2NzIgMC4xNjU4IDAgMC4zMTAzLTAuMDMzNiAwLjQzMzUtMC4xMDA4IDAuMTI1NS0wLjA2OTUgMC4yMjQxLTAuMTUzNSAwLjI5NTgtMC4yNTIxIDAuMDcxNy0wLjEwMDggMC4xMDk3LTAuMTk2IDAuMTE0Mi0wLjI4NTZsMC4yNjIxIDAuMzU5NmMtMC4wMjY4IDAuMDkxOC0wLjA3MjggMC4xOTA0LTAuMTM3NyAwLjI5NTctMC4wNjUgMC4xMDUzLTAuMTUwMSAwLjIwNjEtMC4yNTU0IDAuMzAyNC0wLjEwMzEgMC4wOTQxLTAuMjI3NCAwLjE3MTQtMC4zNzMxIDAuMjMxOS0wLjE0MzMgMC4wNjA1LTAuMzA5MSAwLjA5MDgtMC40OTczIDAuMDkwOC0wLjIzNzUgMC0wLjQ0OTItMC4wNDcxLTAuNjM1MS0wLjE0MTItMC4xODYtMC4wOTYzLTAuMzMxNi0wLjIyNTEtMC40MzY5LTAuMzg2NC0wLjEwNTMtMC4xNjM2LTAuMTU4LTAuMzQ4NC0wLjE1OC0wLjU1NDUgMC0wLjE5MjcgMC4wMzU5LTAuMzYzIDAuMTA3Ni0wLjUxMDggMC4wNzM5LTAuMTUwMSAwLjE4MTQtMC4yNzU2IDAuMzIyNi0wLjM3NjQgMC4xNDM0LTAuMTAwOCAwLjMxODEtMC4xNzcgMC41MjQyLTAuMjI4NSAwLjIwNjEtMC4wNTM4IDAuNDQxNC0wLjA4MDcgMC43MDU3LTAuMDgwN2gwLjYzNTJ6bTMuMzUyNy0xLjQyNDh2MC41OTE0aC0yLjA1di0wLjU5MTRoMi4wNXptLTEuNDU4NS0wLjg5MDZoMC44MDk5djMuNTIxOWMwIDAuMTEyIDAuMDE1NyAwLjE5ODIgMC4wNDcgMC4yNTg3IDAuMDMzNiAwLjA1ODMgMC4wNzk2IDAuMDk3NSAwLjEzNzggMC4xMTc2IDAuMDU4MyAwLjAyMDIgMC4xMjY2IDAuMDMwMyAwLjIwNSAwLjAzMDMgMC4wNTYgMCAwLjEwOTgtMC4wMDM0IDAuMTYxMy0wLjAxMDFzMC4wOTMtMC4wMTM0IDAuMTI0My0wLjAyMDJsMC4wMDM0IDAuNjE4NGMtMC4wNjcyIDAuMDIwMS0wLjE0NTYgMC4wMzgxLTAuMjM1MiAwLjA1MzctMC4wODc0IDAuMDE1Ny0wLjE4ODIgMC4wMjM2LTAuMzAyNSAwLjAyMzYtMC4xODU5IDAtMC4zNTA2LTAuMDMyNS0wLjQ5NC0wLjA5NzUtMC4xNDM0LTAuMDY3Mi0wLjI1NTQtMC4xNzU5LTAuMzM2LTAuMzI2LTAuMDgwNy0wLjE1MDEtMC4xMjEtMC4zNDk1LTAuMTIxLTAuNTk4MXYtMy41NzIzem0zLjgyOTkgNC41OTM5Yy0wLjI2ODkgMC0wLjUxMi0wLjA0MzctMC43MjkzLTAuMTMxMS0wLjIxNS0wLjA4OTYtMC4zOTg3LTAuMjE0LTAuNTUxMS0wLjM3My0wLjE1MDEtMC4xNTkxLTAuMjY1NS0wLjM0NjItMC4zNDYxLTAuNTYxMi0wLjA4MDctMC4yMTUxLTAuMTIxLTAuNDQ3LTAuMTIxLTAuNjk1N3YtMC4xMzQ0YzAtMC4yODQ1IDAuMDQxNC0wLjU0MjEgMC4xMjQzLTAuNzcyOXMwLjE5ODMtMC40Mjc5IDAuMzQ2Mi0wLjU5MTRjMC4xNDc4LTAuMTY1OCAwLjMyMjYtMC4yOTI0IDAuNTI0Mi0wLjM3OThzMC40MjAxLTAuMTMxIDAuNjU1My0wLjEzMWMwLjI1OTkgMCAwLjQ4NzMgMC4wNDM2IDAuNjgyMiAwLjEzMXMwLjM1NjIgMC4yMTA2IDAuNDgzOSAwLjM2OTdjMC4xMyAwLjE1NjggMC4yMjYzIDAuMzQzOSAwLjI4OSAwLjU2MTIgMC4wNjUgMC4yMTczIDAuMDk3NSAwLjQ1NyAwLjA5NzUgMC43MTkxdjAuMzQ2MmgtMi44MDk0di0wLjU4MTRoMi4wMDk2di0wLjA2MzljLTAuMDA0NS0wLjE0NTYtMC4wMzM2LTAuMjgyMi0wLjA4NzQtMC40MDk5LTAuMDUxNS0wLjEyNzctMC4xMzExLTAuMjMwOC0wLjIzODYtMC4zMDkycy0wLjI1MDktMC4xMTc2LTAuNDMwMS0wLjExNzZjLTAuMTM0NSAwLTAuMjU0MyAwLjAyOTEtMC4zNTk2IDAuMDg3My0wLjEwMzEgMC4wNTYxLTAuMTg5MyAwLjEzNzgtMC4yNTg4IDAuMjQ1NC0wLjA2OTQgMC4xMDc1LTAuMTIzMiAwLjIzNzQtMC4xNjEzIDAuMzg5OC0wLjAzNTggMC4xNTAxLTAuMDUzOCAwLjMxOTItMC4wNTM4IDAuNTA3NHYwLjEzNDRjMCAwLjE1OTEgMC4wMjEzIDAuMzA3IDAuMDYzOSAwLjQ0MzYgMC4wNDQ4IDAuMTM0NSAwLjEwOTggMC4yNTIxIDAuMTk0OSAwLjM1MjlzMC4xODgyIDAuMTgwMyAwLjMwOTIgMC4yMzg2YzAuMTIwOSAwLjA1NiAwLjI1ODcgMC4wODQgMC40MTMzIDAuMDg0IDAuMTk0OSAwIDAuMzY4Ni0wLjAzOTIgMC41MjA5LTAuMTE3NnMwLjI4NDUtMC4xODkzIDAuMzk2NS0wLjMzMjdsMC40MjY4IDAuNDEzM2MtMC4wNzg0IDAuMTE0My0wLjE4MDMgMC4yMjQxLTAuMzA1OCAwLjMyOTQtMC4xMjU0IDAuMTAzLTAuMjc4OSAwLjE4Ny0wLjQ2MDQgMC4yNTItMC4xNzkyIDAuMDY1LTAuMzg3NiAwLjA5NzUtMC42MjUgMC4wOTc1em02LjI1MTctNC45Nzd2NC45MDk3aC0wLjgwOTl2LTMuOTQ4NmwtMS4xOTk3IDAuNDA2N3YtMC42Njg4bDEuOTEyMS0wLjY5OWgwLjA5NzV6bTQuMTA4OCA0LjE1N3YtNC40MDloMC44MTMydjUuMTYxN2gtMC43MzU5bC0wLjA3NzMtMC43NTI3em0tMi4zNjU4LTEuMDI1di0wLjA3MDVjMC0wLjI3NTYgMC4wMzI0LTAuNTI2NSAwLjA5NzQtMC43NTI4IDAuMDY1LTAuMjI4NSAwLjE1OTEtMC40MjQ1IDAuMjgyMy0wLjU4ODEgMC4xMjMyLTAuMTY1OCAwLjI3MzMtMC4yOTI0IDAuNDUwMy0wLjM3OTcgMC4xNzctMC4wODk2IDAuMzc2NC0wLjEzNDQgMC41OTgyLTAuMTM0NCAwLjIxOTUgMCAwLjQxMjIgMC4wNDI1IDAuNTc4IDAuMTI3NyAwLjE2NTggMC4wODUxIDAuMzA2OSAwLjIwNzIgMC40MjM0IDAuMzY2MiAwLjExNjUgMC4xNTY5IDAuMjA5NSAwLjM0NTEgMC4yNzg5IDAuNTY0NiAwLjA2OTUgMC4yMTczIDAuMTE4OCAwLjQ1OTMgMC4xNDc5IDAuNzI1OXYwLjIyNTFjLTAuMDI5MSAwLjI1OTktMC4wNzg0IDAuNDk3NC0wLjE0NzkgMC43MTI1LTAuMDY5NCAwLjIxNS0wLjE2MjQgMC40MDEtMC4yNzg5IDAuNTU3OHMtMC4yNTg3IDAuMjc3OC0wLjQyNjggMC4zNjNjLTAuMTY1OCAwLjA4NTEtMC4zNTk1IDAuMTI3Ny0wLjU4MTMgMC4xMjc3LTAuMjE5NiAwLTAuNDE3OS0wLjA0Ni0wLjU5NDktMC4xMzc4LTAuMTc0Ny0wLjA5MTktMC4zMjM3LTAuMjIwNy0wLjQ0NjktMC4zODY1cy0wLjIxNzMtMC4zNjA3LTAuMjgyMy0wLjU4NDdjLTAuMDY1LTAuMjI2My0wLjA5NzQtMC40NzE2LTAuMDk3NC0wLjczNnptMC44MDk4LTAuMDcwNXYwLjA3MDVjMCAwLjE2NTggMC4wMTQ2IDAuMzIwNCAwLjA0MzcgMC40NjM4IDAuMDMxNCAwLjE0MzQgMC4wNzk2IDAuMjY5OSAwLjE0NDUgMC4zNzk3IDAuMDY1IDAuMTA3NiAwLjE0OSAwLjE5MjcgMC4yNTIxIDAuMjU1NCAwLjEwNTMgMC4wNjA1IDAuMjMwNyAwLjA5MDggMC4zNzYzIDAuMDkwOCAwLjE4MzggMCAwLjMzNS0wLjA0MDQgMC40NTM3LTAuMTIxIDAuMTE4OC0wLjA4MDcgMC4yMTE3LTAuMTg5MyAwLjI3ODktMC4zMjYgMC4wNjk1LTAuMTM4OSAwLjExNjUtMC4yOTM1IDAuMTQxMi0wLjQ2Mzd2LTAuNjA4M2MtMC4wMTM1LTAuMTMyMi0wLjA0MTUtMC4yNTU0LTAuMDg0LTAuMzY5Ny0wLjA0MDQtMC4xMTQyLTAuMDk1Mi0wLjIxMzktMC4xNjQ3LTAuMjk5LTAuMDY5NC0wLjA4NzQtMC4xNTU3LTAuMTU0Ni0wLjI1ODgtMC4yMDE3LTAuMTAwOC0wLjA0OTMtMC4yMjA2LTAuMDczOS0wLjM1OTUtMC4wNzM5LTAuMTQ3OSAwLTAuMjczNCAwLjAzMTQtMC4zNzY0IDAuMDk0MS0wLjEwMzEgMC4wNjI3LTAuMTg4MiAwLjE0OS0wLjI1NTQgMC4yNTg3LTAuMDY1IDAuMTA5OC0wLjExMzEgMC4yMzc1LTAuMTQ0NSAwLjM4MzEtMC4wMzE0IDAuMTQ1Ny0wLjA0NzEgMC4zMDE0LTAuMDQ3MSAwLjQ2NzJ6bTcuMjY2NiAxLjExOXYtMS43MzRjMC0wLjEzLTAuMDIzNS0wLjI0Mi0wLjA3MDYtMC4zMzYxLTAuMDQ3LTAuMDk0MS0wLjExODctMC4xNjY5LTAuMjE1LTAuMjE4NC0wLjA5NDEtMC4wNTE1LTAuMjEyOS0wLjA3NzMtMC4zNTYyLTAuMDc3My0wLjEzMjIgMC0wLjI0NjUgMC4wMjI0LTAuMzQyOCAwLjA2NzItMC4wOTY0IDAuMDQ0OC0wLjE3MTQgMC4xMDUzLTAuMjI1MiAwLjE4MTUtMC4wNTM3IDAuMDc2Mi0wLjA4MDYgMC4xNjI0LTAuMDgwNiAwLjI1ODdoLTAuODA2NmMwLTAuMTQzMyAwLjAzNDgtMC4yODIyIDAuMTA0Mi0wLjQxNjcgMC4wNjk1LTAuMTM0NCAwLjE3MDMtMC4yNTQyIDAuMzAyNS0wLjM1OTUgMC4xMzIxLTAuMTA1MyAwLjI5MDEtMC4xODgyIDAuNDczOC0wLjI0ODdzMC4zODk4LTAuMDkwNyAwLjYxODMtMC4wOTA3YzAuMjczNCAwIDAuNTE1MyAwLjA0NTkgMC43MjU5IDAuMTM3NyAwLjIxMjggMC4wOTE5IDAuMzc5OCAwLjIzMDggMC41MDA3IDAuNDE2NyAwLjEyMzIgMC4xODM3IDAuMTg0OSAwLjQxNDUgMC4xODQ5IDAuNjkyM3YxLjYxNjRjMCAwLjE2NTggMC4wMTEyIDAuMzE0OCAwLjAzMzYgMC40NDcgMC4wMjQ2IDAuMTI5OSAwLjA1OTMgMC4yNDMgMC4xMDQxIDAuMzM5NHYwLjA1MzdoLTAuODNjLTAuMDM4MS0wLjA4NzMtMC4wNjgzLTAuMTk4Mi0wLjA5MDctMC4zMzI2LTAuMDIwMi0wLjEzNjctMC4wMzAzLTAuMjY4OS0wLjAzMDMtMC4zOTY2em0wLjExNzYtMS40ODIgMC4wMDY4IDAuNTAwN2gtMC41ODE0Yy0wLjE1MDEgMC0wLjI4MjMgMC4wMTQ2LTAuMzk2NiAwLjA0MzctMC4xMTQyIDAuMDI2OS0wLjIwOTQgMC4wNjcyLTAuMjg1NiAwLjEyMXMtMC4xMzMzIDAuMTE4Ny0wLjE3MTQgMC4xOTQ5LTAuMDU3MSAwLjE2MjQtMC4wNTcxIDAuMjU4OGMwIDAuMDk2MyAwLjAyMjQgMC4xODQ4IDAuMDY3MiAwLjI2NTUgMC4wNDQ4IDAuMDc4NCAwLjEwOTggMC4xNCAwLjE5NDkgMC4xODQ4IDAuMDg3NCAwLjA0NDggMC4xOTI3IDAuMDY3MiAwLjMxNTkgMC4wNjcyIDAuMTY1OCAwIDAuMzEwMy0wLjAzMzYgMC40MzM1LTAuMTAwOCAwLjEyNTUtMC4wNjk1IDAuMjI0LTAuMTUzNSAwLjI5NTctMC4yNTIxIDAuMDcxNy0wLjEwMDggMC4xMDk4LTAuMTk2IDAuMTE0My0wLjI4NTZsMC4yNjIxIDAuMzU5NmMtMC4wMjY5IDAuMDkxOC0wLjA3MjggMC4xOTA0LTAuMTM3OCAwLjI5NTdzLTAuMTUwMSAwLjIwNjEtMC4yNTU0IDAuMzAyNGMtMC4xMDMgMC4wOTQxLTAuMjI3NCAwLjE3MTQtMC4zNzMgMC4yMzE5LTAuMTQzNCAwLjA2MDUtMC4zMDkyIDAuMDkwOC0wLjQ5NzQgMC4wOTA4LTAuMjM3NCAwLTAuNDQ5MS0wLjA0NzEtMC42MzUxLTAuMTQxMi0wLjE4NTktMC4wOTYzLTAuMzMxNi0wLjIyNTEtMC40MzY5LTAuMzg2NC0wLjEwNTMtMC4xNjM2LTAuMTU3OS0wLjM0ODQtMC4xNTc5LTAuNTU0NSAwLTAuMTkyNyAwLjAzNTgtMC4zNjMgMC4xMDc1LTAuNTEwOCAwLjA3NC0wLjE1MDEgMC4xODE1LTAuMjc1NiAwLjMyMjYtMC4zNzY0IDAuMTQzNC0wLjEwMDggMC4zMTgyLTAuMTc3IDAuNTI0My0wLjIyODUgMC4yMDYxLTAuMDUzOCAwLjQ0MTMtMC4wODA3IDAuNzA1Ny0wLjA4MDdoMC42MzUxem00LjAxNDktMS40MjQ4aDAuNzM2djMuNTM1MmMwIDAuMzI3MS0wLjA3IDAuNjA0OS0wLjIwOSAwLjgzMzQtMC4xMzggMC4yMjg2LTAuMzMyIDAuNDAyMi0wLjU4MSAwLjUyMDktMC4yNDkgMC4xMjEtMC41MzYgMC4xODE1LTAuODY0IDAuMTgxNS0wLjEzOCAwLTAuMjkzLTAuMDIwMi0wLjQ2My0wLjA2MDUtMC4xNjgtMC4wNDAzLTAuMzMyLTAuMTA1My0wLjQ5MS0wLjE5NDktMC4xNTctMC4wODc0LTAuMjg4LTAuMjAyOC0wLjM5My0wLjM0NjFsMC4zOC0wLjQ3NzJjMC4xMyAwLjE1NDUgMC4yNzMgMC4yNjc3IDAuNDMgMC4zMzk0czAuMzIxIDAuMTA3NSAwLjQ5NCAwLjEwNzVjMC4xODYgMCAwLjM0NC0wLjAzNDcgMC40NzQtMC4xMDQyIDAuMTMyLTAuMDY3MiAwLjIzNC0wLjE2NjkgMC4zMDUtMC4yOTkgMC4wNzItMC4xMzIyIDAuMTA4LTAuMjkzNSAwLjEwOC0wLjQ4NHYtMi43Mjg3bDAuMDc0LTAuODIzM3ptLTIuNDcgMS44NTgzdi0wLjA3MDVjMC0wLjI3NTYgMC4wMzMtMC41MjY1IDAuMTAxLTAuNzUyOCAwLjA2Ny0wLjIyODUgMC4xNjMtMC40MjQ1IDAuMjg5LTAuNTg4MSAwLjEyNS0wLjE2NTggMC4yNzctMC4yOTI0IDAuNDU3LTAuMzc5NyAwLjE3OS0wLjA4OTYgMC4zODItMC4xMzQ0IDAuNjA4LTAuMTM0NCAwLjIzNSAwIDAuNDM2IDAuMDQyNSAwLjYwMSAwLjEyNzcgMC4xNjkgMC4wODUxIDAuMzA5IDAuMjA3MiAwLjQyMSAwLjM2NjIgMC4xMTIgMC4xNTY5IDAuMTk5IDAuMzQ1MSAwLjI2MiAwLjU2NDYgMC4wNjUgMC4yMTczIDAuMTEzIDAuNDU5MyAwLjE0NCAwLjcyNTl2MC4yMjUxYy0wLjAyOSAwLjI1OTktMC4wNzggMC40OTc0LTAuMTQ4IDAuNzEyNS0wLjA2OSAwLjIxNS0wLjE2MSAwLjQwMS0wLjI3NSAwLjU1NzgtMC4xMTUgMC4xNTY4LTAuMjU2IDAuMjc3OC0wLjQyNCAwLjM2My0wLjE2NSAwLjA4NTEtMC4zNjEgMC4xMjc3LTAuNTg4IDAuMTI3Ny0wLjIyMiAwLTAuNDIyLTAuMDQ2LTAuNjAxLTAuMTM3OC0wLjE3Ny0wLjA5MTktMC4zMy0wLjIyMDctMC40NTctMC4zODY1LTAuMTI2LTAuMTY1OC0wLjIyMi0wLjM2MDctMC4yODktMC41ODQ3LTAuMDY4LTAuMjI2My0wLjEwMS0wLjQ3MTYtMC4xMDEtMC43MzZ6bTAuODEtMC4wNzA1djAuMDcwNWMwIDAuMTY1OCAwLjAxNSAwLjMyMDQgMC4wNDcgMC40NjM4IDAuMDMzIDAuMTQzNCAwLjA4NCAwLjI2OTkgMC4xNTEgMC4zNzk3IDAuMDY5IDAuMTA3NiAwLjE1NyAwLjE5MjcgMC4yNjIgMC4yNTU0IDAuMTA4IDAuMDYwNSAwLjIzNCAwLjA5MDggMC4zOCAwLjA5MDggMC4xOSAwIDAuMzQ2LTAuMDQwNCAwLjQ2Ny0wLjEyMSAwLjEyMy0wLjA4MDcgMC4yMTctMC4xODkzIDAuMjgyLTAuMzI2IDAuMDY3LTAuMTM4OSAwLjExNS0wLjI5MzUgMC4xNDEtMC40NjM3di0wLjYwODNjLTAuMDEzLTAuMTMyMi0wLjA0MS0wLjI1NTQtMC4wODQtMC4zNjk3LTAuMDQtMC4xMTQyLTAuMDk1LTAuMjEzOS0wLjE2NC0wLjI5OS0wLjA3LTAuMDg3NC0wLjE1Ny0wLjE1NDYtMC4yNjItMC4yMDE3LTAuMTA2LTAuMDQ5My0wLjIzLTAuMDczOS0wLjM3My0wLjA3MzktMC4xNDYgMC0wLjI3MyAwLjAzMTQtMC4zOCAwLjA5NDEtMC4xMDggMC4wNjI3LTAuMTk2IDAuMTQ5LTAuMjY2IDAuMjU4Ny0wLjA2NyAwLjEwOTgtMC4xMTcgMC4yMzc1LTAuMTUxIDAuMzgzMS0wLjAzMyAwLjE0NTctMC4wNSAwLjMwMTQtMC4wNSAwLjQ2NzJ6bTMuMjI1IDAuMDcwNXYtMC4wNzczYzAtMC4yNjIxIDAuMDM4LTAuNTA1MiAwLjExNC0wLjcyOTIgMC4wNzYtMC4yMjYzIDAuMTg2LTAuNDIyMyAwLjMyOS0wLjU4ODEgMC4xNDYtMC4xNjggMC4zMjMtMC4yOTggMC41MzEtMC4zODk4IDAuMjExLTAuMDk0MSAwLjQ0OC0wLjE0MTEgMC43MTMtMC4xNDExIDAuMjY2IDAgMC41MDQgMC4wNDcgMC43MTIgMC4xNDExIDAuMjExIDAuMDkxOCAwLjM4OSAwLjIyMTggMC41MzQgMC4zODk4IDAuMTQ2IDAuMTY1OCAwLjI1NyAwLjM2MTggMC4zMzMgMC41ODgxIDAuMDc2IDAuMjI0IDAuMTE0IDAuNDY3MSAwLjExNCAwLjcyOTJ2MC4wNzczYzAgMC4yNjIyLTAuMDM4IDAuNTA1Mi0wLjExNCAwLjcyOTMtMC4wNzYgMC4yMjQtMC4xODcgMC40Mi0wLjMzMyAwLjU4ODEtMC4xNDUgMC4xNjU3LTAuMzIyIDAuMjk1Ny0wLjUzMSAwLjM4OTgtMC4yMDggMC4wOTE4LTAuNDQ0IDAuMTM3OC0wLjcwOSAwLjEzNzgtMC4yNjYgMC0wLjUwNS0wLjA0Ni0wLjcxNS0wLjEzNzgtMC4yMDktMC4wOTQxLTAuMzg2LTAuMjI0MS0wLjUzMS0wLjM4OTgtMC4xNDYtMC4xNjgxLTAuMjU3LTAuMzY0MS0wLjMzMy0wLjU4ODEtMC4wNzYtMC4yMjQxLTAuMTE0LTAuNDY3MS0wLjExNC0wLjcyOTN6bTAuODEtMC4wNzczdjAuMDc3M2MwIDAuMTYzNiAwLjAxNiAwLjMxODIgMC4wNSAwLjQ2MzhzMC4wODYgMC4yNzMzIDAuMTU4IDAuMzgzMSAwLjE2NCAwLjE5NiAwLjI3NiAwLjI1ODdjMC4xMTIgMC4wNjI4IDAuMjQ1IDAuMDk0MSAwLjM5OSAwLjA5NDEgMC4xNTEgMCAwLjI4LTAuMDMxMyAwLjM5LTAuMDk0MSAwLjExMi0wLjA2MjcgMC4yMDQtMC4xNDg5IDAuMjc2LTAuMjU4N3MwLjEyNC0wLjIzNzUgMC4xNTgtMC4zODMxYzAuMDM2LTAuMTQ1NiAwLjA1NC0wLjMwMDIgMC4wNTQtMC40NjM4di0wLjA3NzNjMC0wLjE2MTMtMC4wMTgtMC4zMTM2LTAuMDU0LTAuNDU3LTAuMDM0LTAuMTQ1Ni0wLjA4OC0wLjI3NDQtMC4xNjItMC4zODY1LTAuMDcxLTAuMTEyLTAuMTYzLTAuMTk5My0wLjI3NS0wLjI2MjEtMC4xMS0wLjA2NDktMC4yNDEtMC4wOTc0LTAuMzkzLTAuMDk3NC0wLjE1MyAwLTAuMjg1IDAuMDMyNS0wLjM5NyAwLjA5NzQtMC4xMSAwLjA2MjgtMC4yIDAuMTUwMS0wLjI3MiAwLjI2MjEtMC4wNzIgMC4xMTIxLTAuMTI0IDAuMjQwOS0wLjE1OCAwLjM4NjUtMC4wMzQgMC4xNDM0LTAuMDUgMC4yOTU3LTAuMDUgMC40NTd6IiBmaWxsLW9wYWNpdHk9Ii4zOCIvPgogICA8cGF0aCBkPSJtNDguMTk2IDgwLjQ2OXYyLjc5NTloLTE0LjIxM3YtMi40MDI3bDYuOTAyNS03LjUyODdjMC43NTcyLTAuODU0MyAxLjM1NDMtMS41OTIyIDEuNzkxMS0yLjIxMzUgMC40MzY5LTAuNjIxMyAwLjc0MjctMS4xNzk1IDAuOTE3NS0xLjY3NDYgMC4xODQ0LTAuNTA0OSAwLjI3NjYtMC45OTUxIDAuMjc2Ni0xLjQ3MDggMC0wLjY2OTktMC4xMjYyLTEuMjU3Mi0wLjM3ODYtMS43NjIxLTAuMjQyNy0wLjUxNDUtMC42MDE5LTAuOTE3NC0xLjA3NzYtMS4yMDg2LTAuNDc1Ny0wLjMwMS0xLjA1MzMtMC40NTE1LTEuNzMyOS0wLjQ1MTUtMC43ODY0IDAtMS40NDY1IDAuMTY5OS0xLjk4MDUgMC41MDk3LTAuNTMzOSAwLjMzOTgtMC45MzY4IDAuODEwNi0xLjIwODYgMS40MTI2LTAuMjcxOSAwLjU5MjEtMC40MDc4IDEuMjcxNy0wLjQwNzggMi4wMzg3aC0zLjUwOTVjMC0xLjIzMyAwLjI4MTYtMi4zNTkxIDAuODQ0Ni0zLjM3ODUgMC41NjMxLTEuMDI5IDEuMzc4Ni0xLjg0NDUgMi40NDY1LTIuNDQ2NCAxLjA2NzktMC42MTE3IDIuMzU0Mi0wLjkxNzUgMy44NTktMC45MTc1IDEuNDE3NCAwIDIuNjIxMiAwLjIzNzkgMy42MTE0IDAuNzEzNiAwLjk5MDMgMC40NzU3IDEuNzQyNyAxLjE1MDQgMi4yNTcyIDIuMDI0MSAwLjUyNDIgMC44NzM4IDAuNzg2NCAxLjkwNzcgMC43ODY0IDMuMTAxOCAwIDAuNjYwMi0wLjEwNjggMS4zMTU1LTAuMzIwNCAxLjk2NTktMC4yMTM2IDAuNjUwNS0wLjUxOTQgMS4zMDA5LTAuOTE3NCAxLjk1MTQtMC4zODg0IDAuNjQwNy0wLjg0OTUgMS4yODYzLTEuMzgzNSAxLjkzNjctMC41MzM5IDAuNjQwOC0xLjEyMTIgMS4yOTEyLTEuNzYyIDEuOTUxNGwtNC41ODcxIDUuMDUzMWg5Ljc4NTh6bTE2LjQyOSAwdjIuNzk1OWgtMTQuMjEzdi0yLjQwMjdsNi45MDI2LTcuNTI4N2MwLjc1NzItMC44NTQzIDEuMzU0Mi0xLjU5MjIgMS43OTExLTIuMjEzNXMwLjc0MjctMS4xNzk1IDAuOTE3NC0xLjY3NDZjMC4xODQ1LTAuNTA0OSAwLjI3NjctMC45OTUxIDAuMjc2Ny0xLjQ3MDggMC0wLjY2OTktMC4xMjYyLTEuMjU3Mi0wLjM3ODYtMS43NjIxLTAuMjQyNy0wLjUxNDUtMC42MDE5LTAuOTE3NC0xLjA3NzYtMS4yMDg2LTAuNDc1Ny0wLjMwMS0xLjA1MzMtMC40NTE1LTEuNzMyOS0wLjQ1MTUtMC43ODY0IDAtMS40NDY1IDAuMTY5OS0xLjk4MDUgMC41MDk3LTAuNTMzOSAwLjMzOTgtMC45MzY4IDAuODEwNi0xLjIwODcgMS40MTI2LTAuMjcxOCAwLjU5MjEtMC40MDc3IDEuMjcxNy0wLjQwNzcgMi4wMzg3aC0zLjUwOTVjMC0xLjIzMyAwLjI4MTUtMi4zNTkxIDAuODQ0Ni0zLjM3ODUgMC41NjMxLTEuMDI5IDEuMzc4Ni0xLjg0NDUgMi40NDY1LTIuNDQ2NCAxLjA2NzktMC42MTE3IDIuMzU0Mi0wLjkxNzUgMy44NTktMC45MTc1IDEuNDE3NCAwIDIuNjIxMiAwLjIzNzkgMy42MTE0IDAuNzEzNnMxLjc0MjYgMS4xNTA0IDIuMjU3MiAyLjAyNDFjMC41MjQyIDAuODczOCAwLjc4NjMgMS45MDc3IDAuNzg2MyAzLjEwMTggMCAwLjY2MDItMC4xMDY4IDEuMzE1NS0wLjMyMDMgMS45NjU5LTAuMjEzNiAwLjY1MDUtMC41MTk0IDEuMzAwOS0wLjkxNzUgMS45NTE0LTAuMzg4MyAwLjY0MDctMC44NDk0IDEuMjg2My0xLjM4MzQgMS45MzY3LTAuNTMzOSAwLjY0MDgtMS4xMjEzIDEuMjkxMi0xLjc2MiAxLjk1MTRsLTQuNTg3MSA1LjA1MzFoOS43ODU4em0yLjQ5MjUtMTQuODFjMC0wLjcwODcgMC4xNzQ3LTEuMzU5MiAwLjUyNDItMS45NTE0czAuODE1NS0xLjA2MyAxLjM5OC0xLjQxMjVjMC41OTIyLTAuMzU5MiAxLjIzMjktMC41Mzg4IDEuOTIyMi0wLjUzODggMC42OTkgMCAxLjMzNDkgMC4xNzk2IDEuOTA3NyAwLjUzODggMC41NzI4IDAuMzQ5NSAxLjAyOTEgMC44MjAzIDEuMzY4OCAxLjQxMjUgMC4zNDk1IDAuNTkyMiAwLjUyNDMgMS4yNDI3IDAuNTI0MyAxLjk1MTRzLTAuMTc0OCAxLjM1OTEtMC41MjQzIDEuOTUxM2MtMC4zMzk3IDAuNTgyNS0wLjc5NiAxLjA0MzYtMS4zNjg4IDEuMzgzNHMtMS4yMDg3IDAuNTA5Ny0xLjkwNzcgMC41MDk3Yy0wLjY4OTMgMC0xLjMzLTAuMTY5OS0xLjkyMjItMC41MDk3LTAuNTgyNS0wLjMzOTgtMS4wNDg1LTAuODAwOS0xLjM5OC0xLjM4MzQtMC4zNDk1LTAuNTkyMi0wLjUyNDItMS4yNDI2LTAuNTI0Mi0xLjk1MTN6bTEuOTY1OSAwYzAgMC41MjQyIDAuMTg0NSAwLjk2NTkgMC41NTM0IDEuMzI1MSAwLjM2ODkgMC4zNDk1IDAuODEwNiAwLjUyNDMgMS4zMjUxIDAuNTI0MyAwLjUxNDYgMCAwLjk0NjYtMC4xNzQ4IDEuMjk2MS0wLjUyNDNzMC41MjQyLTAuNzkxMiAwLjUyNDItMS4zMjUxYzAtMC41NDM3LTAuMTc0Ny0wLjk5NTEtMC41MjQyLTEuMzU0M3MtMC43ODE1LTAuNTM4OC0xLjI5NjEtMC41Mzg4Yy0wLjUxNDUgMC0wLjk1NjIgMC4xNzk2LTEuMzI1MSAwLjUzODhzLTAuNTUzNCAwLjgxMDYtMC41NTM0IDEuMzU0M3ptMjEuNzI5IDEwLjcwM2gzLjY0MDZjLTAuMTE2NSAxLjM4ODMtMC41MDQ4IDIuNjI2MS0xLjE2NSAzLjcxMzQtMC42NjAxIDEuMDc3Ni0xLjU4NzMgMS45MjcxLTIuNzgxNCAyLjU0ODRzLTIuNjQ1NCAwLjkzMi00LjM1NDEgMC45MzJjLTEuMzEwNiAwLTIuNDkwMS0wLjIzMy0zLjUzODYtMC42OTktMS4wNDg1LTAuNDc1Ny0xLjk0NjUtMS4xNDU2LTIuNjk0LTIuMDA5Ni0wLjc0NzYtMC44NzM3LTEuMzIwNC0xLjkyNzEtMS43MTg0LTMuMTYtMC4zODgzLTEuMjMyOS0wLjU4MjUtMi42MTE1LTAuNTgyNS00LjEzNTd2LTEuNzYyYzAtMS41MjQyIDAuMTk5LTIuOTAyOCAwLjU5NzEtNC4xMzU3IDAuNDA3Ny0xLjIzMjkgMC45OTAyLTIuMjg2MyAxLjc0NzQtMy4xNiAwLjc1NzMtMC44ODM1IDEuNjY1LTEuNTU4MiAyLjcyMzItMi4wMjQyIDEuMDY3OS0wLjQ2NiAyLjI2NjktMC42OTkgMy41OTY5LTAuNjk5IDEuNjg5MiAwIDMuMTE2MyAwLjMxMDcgNC4yODEzIDAuOTMyczIuMDY3OCAxLjQ4MDUgMi43MDg2IDIuNTc3NWMwLjY1MDQgMS4wOTcxIDEuMDQ4NCAyLjM1NDMgMS4xOTQxIDMuNzcxN2gtMy42NDA2Yy0wLjA5NzEtMC45MTI2LTAuMzEwNy0xLjY5NDEtMC42NDA3LTIuMzQ0Ni0wLjMyMDQtMC42NTA0LTAuNzk2MS0xLjE0NTUtMS40MjcxLTEuNDg1My0wLjYzMTEtMC4zNDk1LTEuNDU2My0wLjUyNDItMi40NzU2LTAuNTI0Mi0wLjgzNDkgMC0xLjU2MyAwLjE1NTMtMi4xODQ0IDAuNDY1OS0wLjYyMTMgMC4zMTA3LTEuMTQwNyAwLjc2Ny0xLjU1ODEgMS4zNjg5LTAuNDE3NSAwLjYwMTktMC43MzMgMS4zNDQ2LTAuOTQ2NiAyLjIyOC0wLjIwMzkgMC44NzM4LTAuMzA1OCAxLjg3MzctMC4zMDU4IDIuOTk5OXYxLjc5MTFjMCAxLjA2NzkgMC4wOTIyIDIuMDM4NyAwLjI3NjcgMi45MTI1IDAuMTk0MiAwLjg2NCAwLjQ4NTQgMS42MDY3IDAuODczNyAyLjIyOCAwLjM5ODEgMC42MjEzIDAuOTAyOSAxLjEwMTkgMS41MTQ1IDEuNDQxNyAwLjYxMTYgMC4zMzk3IDEuMzQ0NiAwLjUwOTYgMi4xOTg5IDAuNTA5NiAxLjAzODggMCAxLjg3ODUtMC4xNjUgMi41MTkzLTAuNDk1MSAwLjY1MDQtMC4zMzAxIDEuMTQwNy0wLjgxMDYgMS40NzA4LTEuNDQxNiAwLjMzOTgtMC42NDA4IDAuNTYzLTEuNDIyMyAwLjY2OTgtMi4zNDQ2eiIgZmlsbC1vcGFjaXR5PSIuODciLz4KICA8L2c+CiA8L2c+CiA8ZGVmcz4KICA8ZmlsdGVyIGlkPSJmaWx0ZXIwX2RfMTE0Ml8yMDM5NTQiIHg9Ii45MTE3NiIgeT0iLjIwNTg4IiB3aWR0aD0iMTI2LjE4IiBoZWlnaHQ9IjEyNi4xOCIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiPgogICA8ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPgogICA8ZmVDb2xvck1hdHJpeCBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0iaGFyZEFscGhhIiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDEyNyAwIi8+CiAgIDxmZU9mZnNldCBkeT0iMi4yOTQxMiIvPgogICA8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIyLjI5NDEyIi8+CiAgIDxmZUNvbXBvc2l0ZSBpbjI9ImhhcmRBbHBoYSIgb3BlcmF0b3I9Im91dCIvPgogICA8ZmVDb2xvck1hdHJpeCB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAuMDQgMCIvPgogICA8ZmVCbGVuZCBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3dfMTE0Ml8yMDM5NTQiLz4KICAgPGZlQmxlbmQgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iZWZmZWN0MV9kcm9wU2hhZG93XzExNDJfMjAzOTU0IiByZXN1bHQ9InNoYXBlIi8+CiAgPC9maWx0ZXI+CiA8L2RlZnM+Cjwvc3ZnPgo=", + "description": "Designed to display single value of the selected attribute or timeseries data. Widget styles are customizable.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n absoluteHeader: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\"}" + } + }, + { + "alias": "horizontal_value_card", + "name": "Horizontal value card", + "image": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzk5IiBoZWlnaHQ9IjEwOCIgdmlld0JveD0iMCAwIDM5OSAxMDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2RfMTI0Nl80NDQ0NykiPgo8cmVjdCB4PSI4IiB5PSI0IiB3aWR0aD0iMzgzIiBoZWlnaHQ9IjkyIiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTU3LjAwMDEgNTEuNjY2N1YzOC4zMzM0QzU3LjAwMDEgMzUuNTY2NyA1NC43NjY3IDMzLjMzMzQgNTIuMDAwMSAzMy4zMzM0QzQ5LjIzMzQgMzMuMzMzNCA0Ny4wMDAxIDM1LjU2NjcgNDcuMDAwMSAzOC4zMzM0VjUxLjY2NjdDNDQuOTgzNCA1My4xODM0IDQzLjY2NjcgNTUuNjE2NyA0My42NjY3IDU4LjMzMzRDNDMuNjY2NyA2Mi45MzM0IDQ3LjQwMDEgNjYuNjY2NyA1Mi4wMDAxIDY2LjY2NjdDNTYuNjAwMSA2Ni42NjY3IDYwLjMzMzQgNjIuOTMzNCA2MC4zMzM0IDU4LjMzMzRDNjAuMzMzNCA1NS42MTY3IDU5LjAxNjcgNTMuMTgzNCA1Ny4wMDAxIDUxLjY2NjdaTTUwLjMzMzQgMzguMzMzNEM1MC4zMzM0IDM3LjQxNjcgNTEuMDgzNCAzNi42NjY3IDUyLjAwMDEgMzYuNjY2N0M1Mi45MTY3IDM2LjY2NjcgNTMuNjY2NyAzNy40MTY3IDUzLjY2NjcgMzguMzMzNEg1Mi4wMDAxVjQwSDUzLjY2NjdWNDMuMzMzNEg1Mi4wMDAxVjQ1SDUzLjY2NjdWNDguMzMzNEg1MC4zMzM0VjM4LjMzMzRaIiBmaWxsPSIjNTQ2OUZGIi8+CjxwYXRoIGQ9Ik04NS44MzU5IDM1LjYyNVY0N0g4My44OTA2VjM1LjYyNUg4NS44MzU5Wk04OS40MDYyIDM1LjYyNVYzNy4xODc1SDgwLjM1MTZWMzUuNjI1SDg5LjQwNjJaTTkzLjk0NTMgNDcuMTU2MkM5My4zMjAzIDQ3LjE1NjIgOTIuNzU1MiA0Ny4wNTQ3IDkyLjI1IDQ2Ljg1MTZDOTEuNzUgNDYuNjQzMiA5MS4zMjI5IDQ2LjM1NDIgOTAuOTY4OCA0NS45ODQ0QzkwLjYxOTggNDUuNjE0NiA5MC4zNTE2IDQ1LjE3OTcgOTAuMTY0MSA0NC42Nzk3Qzg5Ljk3NjYgNDQuMTc5NyA4OS44ODI4IDQzLjY0MDYgODkuODgyOCA0My4wNjI1VjQyLjc1Qzg5Ljg4MjggNDIuMDg4NSA4OS45NzkyIDQxLjQ4OTYgOTAuMTcxOSA0MC45NTMxQzkwLjM2NDYgNDAuNDE2NyA5MC42MzI4IDM5Ljk1ODMgOTAuOTc2NiAzOS41NzgxQzkxLjMyMDMgMzkuMTkyNyA5MS43MjY2IDM4Ljg5ODQgOTIuMTk1MyAzOC42OTUzQzkyLjY2NDEgMzguNDkyMiA5My4xNzE5IDM4LjM5MDYgOTMuNzE4OCAzOC4zOTA2Qzk0LjMyMjkgMzguMzkwNiA5NC44NTE2IDM4LjQ5MjIgOTUuMzA0NyAzOC42OTUzQzk1Ljc1NzggMzguODk4NCA5Ni4xMzI4IDM5LjE4NDkgOTYuNDI5NyAzOS41NTQ3Qzk2LjczMTggMzkuOTE5MyA5Ni45NTU3IDQwLjM1NDIgOTcuMTAxNiA0MC44NTk0Qzk3LjI1MjYgNDEuMzY0NiA5Ny4zMjgxIDQxLjkyMTkgOTcuMzI4MSA0Mi41MzEyVjQzLjMzNTlIOTAuNzk2OVY0MS45ODQ0SDk1LjQ2ODhWNDEuODM1OUM5NS40NTgzIDQxLjQ5NzQgOTUuMzkwNiA0MS4xNzk3IDk1LjI2NTYgNDAuODgyOEM5NS4xNDU4IDQwLjU4NTkgOTQuOTYwOSA0MC4zNDY0IDk0LjcxMDkgNDAuMTY0MUM5NC40NjA5IDM5Ljk4MTggOTQuMTI3NiAzOS44OTA2IDkzLjcxMDkgMzkuODkwNkM5My4zOTg0IDM5Ljg5MDYgOTMuMTE5OCAzOS45NTgzIDkyLjg3NSA0MC4wOTM4QzkyLjYzNTQgNDAuMjI0IDkyLjQzNDkgNDAuNDE0MSA5Mi4yNzM0IDQwLjY2NDFDOTIuMTEyIDQwLjkxNDEgOTEuOTg3IDQxLjIxNjEgOTEuODk4NCA0MS41NzAzQzkxLjgxNTEgNDEuOTE5MyA5MS43NzM0IDQyLjMxMjUgOTEuNzczNCA0Mi43NVY0My4wNjI1QzkxLjc3MzQgNDMuNDMyMyA5MS44MjI5IDQzLjc3NiA5MS45MjE5IDQ0LjA5MzhDOTIuMDI2IDQ0LjQwNjIgOTIuMTc3MSA0NC42Nzk3IDkyLjM3NSA0NC45MTQxQzkyLjU3MjkgNDUuMTQ4NCA5Mi44MTI1IDQ1LjMzMzMgOTMuMDkzOCA0NS40Njg4QzkzLjM3NSA0NS41OTkgOTMuNjk1MyA0NS42NjQxIDk0LjA1NDcgNDUuNjY0MUM5NC41MDc4IDQ1LjY2NDEgOTQuOTExNSA0NS41NzI5IDk1LjI2NTYgNDUuMzkwNkM5NS42MTk4IDQ1LjIwODMgOTUuOTI3MSA0NC45NTA1IDk2LjE4NzUgNDQuNjE3Mkw5Ny4xNzk3IDQ1LjU3ODFDOTYuOTk3NCA0NS44NDM4IDk2Ljc2MDQgNDYuMDk5IDk2LjQ2ODggNDYuMzQzOEM5Ni4xNzcxIDQ2LjU4MzMgOTUuODIwMyA0Ni43Nzg2IDk1LjM5ODQgNDYuOTI5N0M5NC45ODE4IDQ3LjA4MDcgOTQuNDk3NCA0Ny4xNTYyIDkzLjk0NTMgNDcuMTU2MlpNMTAwLjkzIDQwLjI2NTZWNDdIOTkuMDQ2OVYzOC41NDY5SDEwMC44MkwxMDAuOTMgNDAuMjY1NlpNMTAwLjYyNSA0Mi40NjA5TDk5Ljk4NDQgNDIuNDUzMUM5OS45ODQ0IDQxLjg2OTggMTAwLjA1NyA0MS4zMzA3IDEwMC4yMDMgNDAuODM1OUMxMDAuMzQ5IDQwLjM0MTEgMTAwLjU2MiAzOS45MTE1IDEwMC44NDQgMzkuNTQ2OUMxMDEuMTI1IDM5LjE3NzEgMTAxLjQ3NCAzOC44OTMyIDEwMS44OTEgMzguNjk1M0MxMDIuMzEyIDM4LjQ5MjIgMTAyLjc5OSAzOC4zOTA2IDEwMy4zNTIgMzguMzkwNkMxMDMuNzM3IDM4LjM5MDYgMTA0LjA4OSAzOC40NDc5IDEwNC40MDYgMzguNTYyNUMxMDQuNzI5IDM4LjY3MTkgMTA1LjAwOCAzOC44NDY0IDEwNS4yNDIgMzkuMDg1OUMxMDUuNDgyIDM5LjMyNTUgMTA1LjY2NCAzOS42MzI4IDEwNS43ODkgNDAuMDA3OEMxMDUuOTE5IDQwLjM4MjggMTA1Ljk4NCA0MC44MzU5IDEwNS45ODQgNDEuMzY3MlY0N0gxMDQuMTAyVjQxLjUzMTJDMTA0LjEwMiA0MS4xMTk4IDEwNC4wMzkgNDAuNzk2OSAxMDMuOTE0IDQwLjU2MjVDMTAzLjc5NCA0MC4zMjgxIDEwMy42MiA0MC4xNjE1IDEwMy4zOTEgNDAuMDYyNUMxMDMuMTY3IDM5Ljk1ODMgMTAyLjg5OCAzOS45MDYyIDEwMi41ODYgMzkuOTA2MkMxMDIuMjMyIDM5LjkwNjIgMTAxLjkzIDM5Ljk3NCAxMDEuNjggNDAuMTA5NEMxMDEuNDM1IDQwLjI0NDggMTAxLjIzNCA0MC40Mjk3IDEwMS4wNzggNDAuNjY0MUMxMDAuOTIyIDQwLjg5ODQgMTAwLjgwNyA0MS4xNjkzIDEwMC43MzQgNDEuNDc2NkMxMDAuNjYxIDQxLjc4MzkgMTAwLjYyNSA0Mi4xMTIgMTAwLjYyNSA0Mi40NjA5Wk0xMDUuODY3IDQxLjk2MDlMMTA0Ljk4NCA0Mi4xNTYyQzEwNC45ODQgNDEuNjQ1OCAxMDUuMDU1IDQxLjE2NDEgMTA1LjE5NSA0MC43MTA5QzEwNS4zNDEgNDAuMjUyNiAxMDUuNTUyIDM5Ljg1MTYgMTA1LjgyOCAzOS41MDc4QzEwNi4xMDkgMzkuMTU4OSAxMDYuNDU2IDM4Ljg4NTQgMTA2Ljg2NyAzOC42ODc1QzEwNy4yNzkgMzguNDg5NiAxMDcuNzUgMzguMzkwNiAxMDguMjgxIDM4LjM5MDZDMTA4LjcxNCAzOC4zOTA2IDEwOS4wOTkgMzguNDUwNSAxMDkuNDM4IDM4LjU3MDNDMTA5Ljc4MSAzOC42ODQ5IDExMC4wNzMgMzguODY3MiAxMTAuMzEyIDM5LjExNzJDMTEwLjU1MiAzOS4zNjcyIDExMC43MzQgMzkuNjkyNyAxMTAuODU5IDQwLjA5MzhDMTEwLjk4NCA0MC40ODk2IDExMS4wNDcgNDAuOTY4OCAxMTEuMDQ3IDQxLjUzMTJWNDdIMTA5LjE1NlY0MS41MjM0QzEwOS4xNTYgNDEuMDk2NCAxMDkuMDk0IDQwLjc2NTYgMTA4Ljk2OSA0MC41MzEyQzEwOC44NDkgNDAuMjk2OSAxMDguNjc3IDQwLjEzNTQgMTA4LjQ1MyA0MC4wNDY5QzEwOC4yMjkgMzkuOTUzMSAxMDcuOTYxIDM5LjkwNjIgMTA3LjY0OCAzOS45MDYyQzEwNy4zNTcgMzkuOTA2MiAxMDcuMDk5IDM5Ljk2MDkgMTA2Ljg3NSA0MC4wNzAzQzEwNi42NTYgNDAuMTc0NSAxMDYuNDcxIDQwLjMyMjkgMTA2LjMyIDQwLjUxNTZDMTA2LjE2OSA0MC43MDMxIDEwNi4wNTUgNDAuOTE5MyAxMDUuOTc3IDQxLjE2NDFDMTA1LjkwNCA0MS40MDg5IDEwNS44NjcgNDEuNjc0NSAxMDUuODY3IDQxLjk2MDlaTTExNS4xMjUgNDAuMTcxOVY1MC4yNUgxMTMuMjQyVjM4LjU0NjlIMTE0Ljk3N0wxMTUuMTI1IDQwLjE3MTlaTTEyMC42MzMgNDIuNjk1M1Y0Mi44NTk0QzEyMC42MzMgNDMuNDc0IDEyMC41NiA0NC4wNDQzIDEyMC40MTQgNDQuNTcwM0MxMjAuMjczIDQ1LjA5MTEgMTIwLjA2MiA0NS41NDY5IDExOS43ODEgNDUuOTM3NUMxMTkuNTA1IDQ2LjMyMjkgMTE5LjE2NCA0Ni42MjI0IDExOC43NTggNDYuODM1OUMxMTguMzUyIDQ3LjA0OTUgMTE3Ljg4MyA0Ny4xNTYyIDExNy4zNTIgNDcuMTU2MkMxMTYuODI2IDQ3LjE1NjIgMTE2LjM2NSA0Ny4wNTk5IDExNS45NjkgNDYuODY3MkMxMTUuNTc4IDQ2LjY2OTMgMTE1LjI0NyA0Ni4zOTA2IDExNC45NzcgNDYuMDMxMkMxMTQuNzA2IDQ1LjY3MTkgMTE0LjQ4NyA0NS4yNSAxMTQuMzIgNDQuNzY1NkMxMTQuMTU5IDQ0LjI3NiAxMTQuMDQ0IDQzLjczOTYgMTEzLjk3NyA0My4xNTYyVjQyLjUyMzRDMTE0LjA0NCA0MS45MDM2IDExNC4xNTkgNDEuMzQxMSAxMTQuMzIgNDAuODM1OUMxMTQuNDg3IDQwLjMzMDcgMTE0LjcwNiAzOS44OTU4IDExNC45NzcgMzkuNTMxMkMxMTUuMjQ3IDM5LjE2NjcgMTE1LjU3OCAzOC44ODU0IDExNS45NjkgMzguNjg3NUMxMTYuMzU5IDM4LjQ4OTYgMTE2LjgxNSAzOC4zOTA2IDExNy4zMzYgMzguMzkwNkMxMTcuODY3IDM4LjM5MDYgMTE4LjMzOSAzOC40OTQ4IDExOC43NSAzOC43MDMxQzExOS4xNjEgMzguOTA2MiAxMTkuNTA4IDM5LjE5NzkgMTE5Ljc4OSAzOS41NzgxQzEyMC4wNyAzOS45NTMxIDEyMC4yODEgNDAuNDA2MiAxMjAuNDIyIDQwLjkzNzVDMTIwLjU2MiA0MS40NjM1IDEyMC42MzMgNDIuMDQ5NSAxMjAuNjMzIDQyLjY5NTNaTTExOC43NSA0Mi44NTk0VjQyLjY5NTNDMTE4Ljc1IDQyLjMwNDcgMTE4LjcxNCA0MS45NDI3IDExOC42NDEgNDEuNjA5NEMxMTguNTY4IDQxLjI3MDggMTE4LjQ1MyA0MC45NzQgMTE4LjI5NyA0MC43MTg4QzExOC4xNDEgNDAuNDYzNSAxMTcuOTQgNDAuMjY1NiAxMTcuNjk1IDQwLjEyNUMxMTcuNDU2IDM5Ljk3OTIgMTE3LjE2NyAzOS45MDYyIDExNi44MjggMzkuOTA2MkMxMTYuNDk1IDM5LjkwNjIgMTE2LjIwOCAzOS45NjM1IDExNS45NjkgNDAuMDc4MUMxMTUuNzI5IDQwLjE4NzUgMTE1LjUyOSA0MC4zNDExIDExNS4zNjcgNDAuNTM5MUMxMTUuMjA2IDQwLjczNyAxMTUuMDgxIDQwLjk2ODggMTE0Ljk5MiA0MS4yMzQ0QzExNC45MDQgNDEuNDk0OCAxMTQuODQxIDQxLjc3ODYgMTE0LjgwNSA0Mi4wODU5VjQzLjYwMTZDMTE0Ljg2NyA0My45NzY2IDExNC45NzQgNDQuMzIwMyAxMTUuMTI1IDQ0LjYzMjhDMTE1LjI3NiA0NC45NDUzIDExNS40OSA0NS4xOTUzIDExNS43NjYgNDUuMzgyOEMxMTYuMDQ3IDQ1LjU2NTEgMTE2LjQwNiA0NS42NTYyIDExNi44NDQgNDUuNjU2MkMxMTcuMTgyIDQ1LjY1NjIgMTE3LjQ3MSA0NS41ODMzIDExNy43MTEgNDUuNDM3NUMxMTcuOTUxIDQ1LjI5MTcgMTE4LjE0NiA0NS4wOTExIDExOC4yOTcgNDQuODM1OUMxMTguNDUzIDQ0LjU3NTUgMTE4LjU2OCA0NC4yNzYgMTE4LjY0MSA0My45Mzc1QzExOC43MTQgNDMuNTk5IDExOC43NSA0My4yMzk2IDExOC43NSA0Mi44NTk0Wk0xMjYuMjExIDQ3LjE1NjJDMTI1LjU4NiA0Ny4xNTYyIDEyNS4wMjEgNDcuMDU0NyAxMjQuNTE2IDQ2Ljg1MTZDMTI0LjAxNiA0Ni42NDMyIDEyMy41ODkgNDYuMzU0MiAxMjMuMjM0IDQ1Ljk4NDRDMTIyLjg4NSA0NS42MTQ2IDEyMi42MTcgNDUuMTc5NyAxMjIuNDMgNDQuNjc5N0MxMjIuMjQyIDQ0LjE3OTcgMTIyLjE0OCA0My42NDA2IDEyMi4xNDggNDMuMDYyNVY0Mi43NUMxMjIuMTQ4IDQyLjA4ODUgMTIyLjI0NSA0MS40ODk2IDEyMi40MzggNDAuOTUzMUMxMjIuNjMgNDAuNDE2NyAxMjIuODk4IDM5Ljk1ODMgMTIzLjI0MiAzOS41NzgxQzEyMy41ODYgMzkuMTkyNyAxMjMuOTkyIDM4Ljg5ODQgMTI0LjQ2MSAzOC42OTUzQzEyNC45MyAzOC40OTIyIDEyNS40MzggMzguMzkwNiAxMjUuOTg0IDM4LjM5MDZDMTI2LjU4OSAzOC4zOTA2IDEyNy4xMTcgMzguNDkyMiAxMjcuNTcgMzguNjk1M0MxMjguMDIzIDM4Ljg5ODQgMTI4LjM5OCAzOS4xODQ5IDEyOC42OTUgMzkuNTU0N0MxMjguOTk3IDM5LjkxOTMgMTI5LjIyMSA0MC4zNTQyIDEyOS4zNjcgNDAuODU5NEMxMjkuNTE4IDQxLjM2NDYgMTI5LjU5NCA0MS45MjE5IDEyOS41OTQgNDIuNTMxMlY0My4zMzU5SDEyMy4wNjJWNDEuOTg0NEgxMjcuNzM0VjQxLjgzNTlDMTI3LjcyNCA0MS40OTc0IDEyNy42NTYgNDEuMTc5NyAxMjcuNTMxIDQwLjg4MjhDMTI3LjQxMSA0MC41ODU5IDEyNy4yMjcgNDAuMzQ2NCAxMjYuOTc3IDQwLjE2NDFDMTI2LjcyNyAzOS45ODE4IDEyNi4zOTMgMzkuODkwNiAxMjUuOTc3IDM5Ljg5MDZDMTI1LjY2NCAzOS44OTA2IDEyNS4zODUgMzkuOTU4MyAxMjUuMTQxIDQwLjA5MzhDMTI0LjkwMSA0MC4yMjQgMTI0LjcwMSA0MC40MTQxIDEyNC41MzkgNDAuNjY0MUMxMjQuMzc4IDQwLjkxNDEgMTI0LjI1MyA0MS4yMTYxIDEyNC4xNjQgNDEuNTcwM0MxMjQuMDgxIDQxLjkxOTMgMTI0LjAzOSA0Mi4zMTI1IDEyNC4wMzkgNDIuNzVWNDMuMDYyNUMxMjQuMDM5IDQzLjQzMjMgMTI0LjA4OSA0My43NzYgMTI0LjE4OCA0NC4wOTM4QzEyNC4yOTIgNDQuNDA2MiAxMjQuNDQzIDQ0LjY3OTcgMTI0LjY0MSA0NC45MTQxQzEyNC44MzkgNDUuMTQ4NCAxMjUuMDc4IDQ1LjMzMzMgMTI1LjM1OSA0NS40Njg4QzEyNS42NDEgNDUuNTk5IDEyNS45NjEgNDUuNjY0MSAxMjYuMzIgNDUuNjY0MUMxMjYuNzczIDQ1LjY2NDEgMTI3LjE3NyA0NS41NzI5IDEyNy41MzEgNDUuMzkwNkMxMjcuODg1IDQ1LjIwODMgMTI4LjE5MyA0NC45NTA1IDEyOC40NTMgNDQuNjE3MkwxMjkuNDQ1IDQ1LjU3ODFDMTI5LjI2MyA0NS44NDM4IDEyOS4wMjYgNDYuMDk5IDEyOC43MzQgNDYuMzQzOEMxMjguNDQzIDQ2LjU4MzMgMTI4LjA4NiA0Ni43Nzg2IDEyNy42NjQgNDYuOTI5N0MxMjcuMjQ3IDQ3LjA4MDcgMTI2Ljc2MyA0Ny4xNTYyIDEyNi4yMTEgNDcuMTU2MlpNMTMzLjIwMyA0MC4xNTYyVjQ3SDEzMS4zMlYzOC41NDY5SDEzMy4xMTdMMTMzLjIwMyA0MC4xNTYyWk0xMzUuNzg5IDM4LjQ5MjJMMTM1Ljc3MyA0MC4yNDIyQzEzNS42NTkgNDAuMjIxNCAxMzUuNTM0IDQwLjIwNTcgMTM1LjM5OCA0MC4xOTUzQzEzNS4yNjggNDAuMTg0OSAxMzUuMTM4IDQwLjE3OTcgMTM1LjAwOCA0MC4xNzk3QzEzNC42ODUgNDAuMTc5NyAxMzQuNDAxIDQwLjIyNjYgMTM0LjE1NiA0MC4zMjAzQzEzMy45MTEgNDAuNDA4OSAxMzMuNzA2IDQwLjUzOTEgMTMzLjUzOSA0MC43MTA5QzEzMy4zNzggNDAuODc3NiAxMzMuMjUzIDQxLjA4MDcgMTMzLjE2NCA0MS4zMjAzQzEzMy4wNzYgNDEuNTU5OSAxMzMuMDIzIDQxLjgyODEgMTMzLjAwOCA0Mi4xMjVMMTMyLjU3OCA0Mi4xNTYyQzEzMi41NzggNDEuNjI1IDEzMi42MyA0MS4xMzI4IDEzMi43MzQgNDAuNjc5N0MxMzIuODM5IDQwLjIyNjYgMTMyLjk5NSAzOS44MjgxIDEzMy4yMDMgMzkuNDg0NEMxMzMuNDE3IDM5LjE0MDYgMTMzLjY4MiAzOC44NzI0IDEzNCAzOC42Nzk3QzEzNC4zMjMgMzguNDg3IDEzNC42OTUgMzguMzkwNiAxMzUuMTE3IDM4LjM5MDZDMTM1LjIzMiAzOC4zOTA2IDEzNS4zNTQgMzguNDAxIDEzNS40ODQgMzguNDIxOUMxMzUuNjIgMzguNDQyNyAxMzUuNzIxIDM4LjQ2NjEgMTM1Ljc4OSAzOC40OTIyWk0xNDEuNzAzIDQ1LjMwNDdWNDEuMjczNEMxNDEuNzAzIDQwLjk3MTQgMTQxLjY0OCA0MC43MTA5IDE0MS41MzkgNDAuNDkyMkMxNDEuNDMgNDAuMjczNCAxNDEuMjYzIDQwLjEwNDIgMTQxLjAzOSAzOS45ODQ0QzE0MC44MiAzOS44NjQ2IDE0MC41NDQgMzkuODA0NyAxNDAuMjExIDM5LjgwNDdDMTM5LjkwNCAzOS44MDQ3IDEzOS42MzggMzkuODU2OCAxMzkuNDE0IDM5Ljk2MDlDMTM5LjE5IDQwLjA2NTEgMTM5LjAxNiA0MC4yMDU3IDEzOC44OTEgNDAuMzgyOEMxMzguNzY2IDQwLjU1OTkgMTM4LjcwMyA0MC43NjA0IDEzOC43MDMgNDAuOTg0NEgxMzYuODI4QzEzNi44MjggNDAuNjUxIDEzNi45MDkgNDAuMzI4MSAxMzcuMDcgNDAuMDE1NkMxMzcuMjMyIDM5LjcwMzEgMTM3LjQ2NiAzOS40MjQ1IDEzNy43NzMgMzkuMTc5N0MxMzguMDgxIDM4LjkzNDkgMTM4LjQ0OCAzOC43NDIyIDEzOC44NzUgMzguNjAxNkMxMzkuMzAyIDM4LjQ2MDkgMTM5Ljc4MSAzOC4zOTA2IDE0MC4zMTIgMzguMzkwNkMxNDAuOTQ4IDM4LjM5MDYgMTQxLjUxIDM4LjQ5NzQgMTQyIDM4LjcxMDlDMTQyLjQ5NSAzOC45MjQ1IDE0Mi44ODMgMzkuMjQ3NCAxNDMuMTY0IDM5LjY3OTdDMTQzLjQ1MSA0MC4xMDY4IDE0My41OTQgNDAuNjQzMiAxNDMuNTk0IDQxLjI4OTFWNDUuMDQ2OUMxNDMuNTk0IDQ1LjQzMjMgMTQzLjYyIDQ1Ljc3ODYgMTQzLjY3MiA0Ni4wODU5QzE0My43MjkgNDYuMzg4IDE0My44MSA0Ni42NTEgMTQzLjkxNCA0Ni44NzVWNDdIMTQxLjk4NEMxNDEuODk2IDQ2Ljc5NjkgMTQxLjgyNiA0Ni41MzkxIDE0MS43NzMgNDYuMjI2NkMxNDEuNzI3IDQ1LjkwODkgMTQxLjcwMyA0NS42MDE2IDE0MS43MDMgNDUuMzA0N1pNMTQxLjk3NyA0MS44NTk0TDE0MS45OTIgNDMuMDIzNEgxNDAuNjQxQzE0MC4yOTIgNDMuMDIzNCAxMzkuOTg0IDQzLjA1NzMgMTM5LjcxOSA0My4xMjVDMTM5LjQ1MyA0My4xODc1IDEzOS4yMzIgNDMuMjgxMiAxMzkuMDU1IDQzLjQwNjJDMTM4Ljg3OCA0My41MzEyIDEzOC43NDUgNDMuNjgyMyAxMzguNjU2IDQzLjg1OTRDMTM4LjU2OCA0NC4wMzY1IDEzOC41MjMgNDQuMjM3IDEzOC41MjMgNDQuNDYwOUMxMzguNTIzIDQ0LjY4NDkgMTM4LjU3NiA0NC44OTA2IDEzOC42OCA0NS4wNzgxQzEzOC43ODQgNDUuMjYwNCAxMzguOTM1IDQ1LjQwMzYgMTM5LjEzMyA0NS41MDc4QzEzOS4zMzYgNDUuNjEyIDEzOS41ODEgNDUuNjY0MSAxMzkuODY3IDQ1LjY2NDFDMTQwLjI1MyA0NS42NjQxIDE0MC41ODkgNDUuNTg1OSAxNDAuODc1IDQ1LjQyOTdDMTQxLjE2NyA0NS4yNjgyIDE0MS4zOTYgNDUuMDcyOSAxNDEuNTYyIDQ0Ljg0MzhDMTQxLjcyOSA0NC42MDk0IDE0MS44MTggNDQuMzg4IDE0MS44MjggNDQuMTc5N0wxNDIuNDM4IDQ1LjAxNTZDMTQyLjM3NSA0NS4yMjkyIDE0Mi4yNjggNDUuNDU4MyAxNDIuMTE3IDQ1LjcwMzFDMTQxLjk2NiA0NS45NDc5IDE0MS43NjggNDYuMTgyMyAxNDEuNTIzIDQ2LjQwNjJDMTQxLjI4NCA0Ni42MjUgMTQwLjk5NSA0Ni44MDQ3IDE0MC42NTYgNDYuOTQ1M0MxNDAuMzIzIDQ3LjA4NTkgMTM5LjkzOCA0Ny4xNTYyIDEzOS41IDQ3LjE1NjJDMTM4Ljk0OCA0Ny4xNTYyIDEzOC40NTYgNDcuMDQ2OSAxMzguMDIzIDQ2LjgyODFDMTM3LjU5MSA0Ni42MDQyIDEzNy4yNTMgNDYuMzA0NyAxMzcuMDA4IDQ1LjkyOTdDMTM2Ljc2MyA0NS41NDk1IDEzNi42NDEgNDUuMTE5OCAxMzYuNjQxIDQ0LjY0MDZDMTM2LjY0MSA0NC4xOTI3IDEzNi43MjQgNDMuNzk2OSAxMzYuODkxIDQzLjQ1MzFDMTM3LjA2MiA0My4xMDQyIDEzNy4zMTIgNDIuODEyNSAxMzcuNjQxIDQyLjU3ODFDMTM3Ljk3NCA0Mi4zNDM4IDEzOC4zOCA0Mi4xNjY3IDEzOC44NTkgNDIuMDQ2OUMxMzkuMzM5IDQxLjkyMTkgMTM5Ljg4NSA0MS44NTk0IDE0MC41IDQxLjg1OTRIMTQxLjk3N1pNMTQ5LjY4OCAzOC41NDY5VjM5LjkyMTlIMTQ0LjkyMlYzOC41NDY5SDE0OS42ODhaTTE0Ni4yOTcgMzYuNDc2NkgxNDguMThWNDQuNjY0MUMxNDguMTggNDQuOTI0NSAxNDguMjE2IDQ1LjEyNSAxNDguMjg5IDQ1LjI2NTZDMTQ4LjM2NyA0NS40MDEgMTQ4LjQ3NCA0NS40OTIyIDE0OC42MDkgNDUuNTM5MUMxNDguNzQ1IDQ1LjU4NTkgMTQ4LjkwNCA0NS42MDk0IDE0OS4wODYgNDUuNjA5NEMxNDkuMjE2IDQ1LjYwOTQgMTQ5LjM0MSA0NS42MDE2IDE0OS40NjEgNDUuNTg1OUMxNDkuNTgxIDQ1LjU3MDMgMTQ5LjY3NyA0NS41NTQ3IDE0OS43NSA0NS41MzkxTDE0OS43NTggNDYuOTc2NkMxNDkuNjAyIDQ3LjAyMzQgMTQ5LjQxOSA0Ny4wNjUxIDE0OS4yMTEgNDcuMTAxNkMxNDkuMDA4IDQ3LjEzOCAxNDguNzczIDQ3LjE1NjIgMTQ4LjUwOCA0Ny4xNTYyQzE0OC4wNzYgNDcuMTU2MiAxNDcuNjkzIDQ3LjA4MDcgMTQ3LjM1OSA0Ni45Mjk3QzE0Ny4wMjYgNDYuNzczNCAxNDYuNzY2IDQ2LjUyMDggMTQ2LjU3OCA0Ni4xNzE5QzE0Ni4zOTEgNDUuODIyOSAxNDYuMjk3IDQ1LjM1OTQgMTQ2LjI5NyA0NC43ODEyVjM2LjQ3NjZaTTE1Ni40NzcgNDUuMDA3OFYzOC41NDY5SDE1OC4zNjdWNDdIMTU2LjU4NkwxNTYuNDc3IDQ1LjAwNzhaTTE1Ni43NDIgNDMuMjVMMTU3LjM3NSA0My4yMzQ0QzE1Ny4zNzUgNDMuODAyMSAxNTcuMzEyIDQ0LjMyNTUgMTU3LjE4OCA0NC44MDQ3QzE1Ny4wNjIgNDUuMjc4NiAxNTYuODcgNDUuNjkyNyAxNTYuNjA5IDQ2LjA0NjlDMTU2LjM0OSA0Ni4zOTU4IDE1Ni4wMTYgNDYuNjY5MyAxNTUuNjA5IDQ2Ljg2NzJDMTU1LjIwMyA0Ny4wNTk5IDE1NC43MTYgNDcuMTU2MiAxNTQuMTQ4IDQ3LjE1NjJDMTUzLjczNyA0Ny4xNTYyIDE1My4zNTkgNDcuMDk2NCAxNTMuMDE2IDQ2Ljk3NjZDMTUyLjY3MiA0Ni44NTY4IDE1Mi4zNzUgNDYuNjcxOSAxNTIuMTI1IDQ2LjQyMTlDMTUxLjg4IDQ2LjE3MTkgMTUxLjY5IDQ1Ljg0NjQgMTUxLjU1NSA0NS40NDUzQzE1MS40MTkgNDUuMDQ0MyAxNTEuMzUyIDQ0LjU2NTEgMTUxLjM1MiA0NC4wMDc4VjM4LjU0NjlIMTUzLjIzNFY0NC4wMjM0QzE1My4yMzQgNDQuMzMwNyAxNTMuMjcxIDQ0LjU4ODUgMTUzLjM0NCA0NC43OTY5QzE1My40MTcgNDUgMTUzLjUxNiA0NS4xNjQxIDE1My42NDEgNDUuMjg5MUMxNTMuNzY2IDQ1LjQxNDEgMTUzLjkxMSA0NS41MDI2IDE1NC4wNzggNDUuNTU0N0MxNTQuMjQ1IDQ1LjYwNjggMTU0LjQyMiA0NS42MzI4IDE1NC42MDkgNDUuNjMyOEMxNTUuMTQ2IDQ1LjYzMjggMTU1LjU2OCA0NS41Mjg2IDE1NS44NzUgNDUuMzIwM0MxNTYuMTg4IDQ1LjEwNjggMTU2LjQwOSA0NC44MjAzIDE1Ni41MzkgNDQuNDYwOUMxNTYuNjc0IDQ0LjEwMTYgMTU2Ljc0MiA0My42OTc5IDE1Ni43NDIgNDMuMjVaTTE2Mi40MzggNDAuMTU2MlY0N0gxNjAuNTU1VjM4LjU0NjlIMTYyLjM1MkwxNjIuNDM4IDQwLjE1NjJaTTE2NS4wMjMgMzguNDkyMkwxNjUuMDA4IDQwLjI0MjJDMTY0Ljg5MyA0MC4yMjE0IDE2NC43NjggNDAuMjA1NyAxNjQuNjMzIDQwLjE5NTNDMTY0LjUwMyA0MC4xODQ5IDE2NC4zNzIgNDAuMTc5NyAxNjQuMjQyIDQwLjE3OTdDMTYzLjkxOSA0MC4xNzk3IDE2My42MzUgNDAuMjI2NiAxNjMuMzkxIDQwLjMyMDNDMTYzLjE0NiA0MC40MDg5IDE2Mi45NCA0MC41MzkxIDE2Mi43NzMgNDAuNzEwOUMxNjIuNjEyIDQwLjg3NzYgMTYyLjQ4NyA0MS4wODA3IDE2Mi4zOTggNDEuMzIwM0MxNjIuMzEgNDEuNTU5OSAxNjIuMjU4IDQxLjgyODEgMTYyLjI0MiA0Mi4xMjVMMTYxLjgxMiA0Mi4xNTYyQzE2MS44MTIgNDEuNjI1IDE2MS44NjUgNDEuMTMyOCAxNjEuOTY5IDQwLjY3OTdDMTYyLjA3MyA0MC4yMjY2IDE2Mi4yMjkgMzkuODI4MSAxNjIuNDM4IDM5LjQ4NDRDMTYyLjY1MSAzOS4xNDA2IDE2Mi45MTcgMzguODcyNCAxNjMuMjM0IDM4LjY3OTdDMTYzLjU1NyAzOC40ODcgMTYzLjkzIDM4LjM5MDYgMTY0LjM1MiAzOC4zOTA2QzE2NC40NjYgMzguMzkwNiAxNjQuNTg5IDM4LjQwMSAxNjQuNzE5IDM4LjQyMTlDMTY0Ljg1NCAzOC40NDI3IDE2NC45NTYgMzguNDY2MSAxNjUuMDIzIDM4LjQ5MjJaTTE3MC4wMjMgNDcuMTU2MkMxNjkuMzk4IDQ3LjE1NjIgMTY4LjgzMyA0Ny4wNTQ3IDE2OC4zMjggNDYuODUxNkMxNjcuODI4IDQ2LjY0MzIgMTY3LjQwMSA0Ni4zNTQyIDE2Ny4wNDcgNDUuOTg0NEMxNjYuNjk4IDQ1LjYxNDYgMTY2LjQzIDQ1LjE3OTcgMTY2LjI0MiA0NC42Nzk3QzE2Ni4wNTUgNDQuMTc5NyAxNjUuOTYxIDQzLjY0MDYgMTY1Ljk2MSA0My4wNjI1VjQyLjc1QzE2NS45NjEgNDIuMDg4NSAxNjYuMDU3IDQxLjQ4OTYgMTY2LjI1IDQwLjk1MzFDMTY2LjQ0MyA0MC40MTY3IDE2Ni43MTEgMzkuOTU4MyAxNjcuMDU1IDM5LjU3ODFDMTY3LjM5OCAzOS4xOTI3IDE2Ny44MDUgMzguODk4NCAxNjguMjczIDM4LjY5NTNDMTY4Ljc0MiAzOC40OTIyIDE2OS4yNSAzOC4zOTA2IDE2OS43OTcgMzguMzkwNkMxNzAuNDAxIDM4LjM5MDYgMTcwLjkzIDM4LjQ5MjIgMTcxLjM4MyAzOC42OTUzQzE3MS44MzYgMzguODk4NCAxNzIuMjExIDM5LjE4NDkgMTcyLjUwOCAzOS41NTQ3QzE3Mi44MSAzOS45MTkzIDE3My4wMzQgNDAuMzU0MiAxNzMuMTggNDAuODU5NEMxNzMuMzMxIDQxLjM2NDYgMTczLjQwNiA0MS45MjE5IDE3My40MDYgNDIuNTMxMlY0My4zMzU5SDE2Ni44NzVWNDEuOTg0NEgxNzEuNTQ3VjQxLjgzNTlDMTcxLjUzNiA0MS40OTc0IDE3MS40NjkgNDEuMTc5NyAxNzEuMzQ0IDQwLjg4MjhDMTcxLjIyNCA0MC41ODU5IDE3MS4wMzkgNDAuMzQ2NCAxNzAuNzg5IDQwLjE2NDFDMTcwLjUzOSAzOS45ODE4IDE3MC4yMDYgMzkuODkwNiAxNjkuNzg5IDM5Ljg5MDZDMTY5LjQ3NyAzOS44OTA2IDE2OS4xOTggMzkuOTU4MyAxNjguOTUzIDQwLjA5MzhDMTY4LjcxNCA0MC4yMjQgMTY4LjUxMyA0MC40MTQxIDE2OC4zNTIgNDAuNjY0MUMxNjguMTkgNDAuOTE0MSAxNjguMDY1IDQxLjIxNjEgMTY3Ljk3NyA0MS41NzAzQzE2Ny44OTMgNDEuOTE5MyAxNjcuODUyIDQyLjMxMjUgMTY3Ljg1MiA0Mi43NVY0My4wNjI1QzE2Ny44NTIgNDMuNDMyMyAxNjcuOTAxIDQzLjc3NiAxNjggNDQuMDkzOEMxNjguMTA0IDQ0LjQwNjIgMTY4LjI1NSA0NC42Nzk3IDE2OC40NTMgNDQuOTE0MUMxNjguNjUxIDQ1LjE0ODQgMTY4Ljg5MSA0NS4zMzMzIDE2OS4xNzIgNDUuNDY4OEMxNjkuNDUzIDQ1LjU5OSAxNjkuNzczIDQ1LjY2NDEgMTcwLjEzMyA0NS42NjQxQzE3MC41ODYgNDUuNjY0MSAxNzAuOTkgNDUuNTcyOSAxNzEuMzQ0IDQ1LjM5MDZDMTcxLjY5OCA0NS4yMDgzIDE3Mi4wMDUgNDQuOTUwNSAxNzIuMjY2IDQ0LjYxNzJMMTczLjI1OCA0NS41NzgxQzE3My4wNzYgNDUuODQzOCAxNzIuODM5IDQ2LjA5OSAxNzIuNTQ3IDQ2LjM0MzhDMTcyLjI1NSA0Ni41ODMzIDE3MS44OTggNDYuNzc4NiAxNzEuNDc3IDQ2LjkyOTdDMTcxLjA2IDQ3LjA4MDcgMTcwLjU3NiA0Ny4xNTYyIDE3MC4wMjMgNDcuMTU2MloiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTg2LjIxMDkgNjQuODM0VjY2SDgxLjkyNzdWNjQuODM0SDg2LjIxMDlaTTgyLjMzNzkgNTcuNDY4OFY2Nkg4MC44NjcyVjU3LjQ2ODhIODIuMzM3OVpNOTEuMDMxMiA2NC43Mjg1VjYxLjcwNTFDOTEuMDMxMiA2MS40Nzg1IDkwLjk5MDIgNjEuMjgzMiA5MC45MDgyIDYxLjExOTFDOTAuODI2MiA2MC45NTUxIDkwLjcwMTIgNjAuODI4MSA5MC41MzMyIDYwLjczODNDOTAuMzY5MSA2MC42NDg0IDkwLjE2MjEgNjAuNjAzNSA4OS45MTIxIDYwLjYwMzVDODkuNjgxNiA2MC42MDM1IDg5LjQ4MjQgNjAuNjQyNiA4OS4zMTQ1IDYwLjcyMDdDODkuMTQ2NSA2MC43OTg4IDg5LjAxNTYgNjAuOTA0MyA4OC45MjE5IDYxLjAzNzFDODguODI4MSA2MS4xNjk5IDg4Ljc4MTIgNjEuMzIwMyA4OC43ODEyIDYxLjQ4ODNIODcuMzc1Qzg3LjM3NSA2MS4yMzgzIDg3LjQzNTUgNjAuOTk2MSA4Ny41NTY2IDYwLjc2MTdDODcuNjc3NyA2MC41MjczIDg3Ljg1MzUgNjAuMzE4NCA4OC4wODQgNjAuMTM0OEM4OC4zMTQ1IDU5Ljk1MTIgODguNTg5OCA1OS44MDY2IDg4LjkxMDIgNTkuNzAxMkM4OS4yMzA1IDU5LjU5NTcgODkuNTg5OCA1OS41NDMgODkuOTg4MyA1OS41NDNDOTAuNDY0OCA1OS41NDMgOTAuODg2NyA1OS42MjMgOTEuMjUzOSA1OS43ODMyQzkxLjYyNSA1OS45NDM0IDkxLjkxNiA2MC4xODU1IDkyLjEyNyA2MC41MDk4QzkyLjM0MTggNjAuODMwMSA5Mi40NDkyIDYxLjIzMjQgOTIuNDQ5MiA2MS43MTY4VjY0LjUzNTJDOTIuNDQ5MiA2NC44MjQyIDkyLjQ2ODggNjUuMDg0IDkyLjUwNzggNjUuMzE0NUM5Mi41NTA4IDY1LjU0MSA5Mi42MTEzIDY1LjczODMgOTIuNjg5NSA2NS45MDYyVjY2SDkxLjI0MjJDOTEuMTc1OCA2NS44NDc3IDkxLjEyMyA2NS42NTQzIDkxLjA4NCA2NS40MTk5QzkxLjA0ODggNjUuMTgxNiA5MS4wMzEyIDY0Ljk1MTIgOTEuMDMxMiA2NC43Mjg1Wk05MS4yMzYzIDYyLjE0NDVMOTEuMjQ4IDYzLjAxNzZIOTAuMjM0NEM4OS45NzI3IDYzLjAxNzYgODkuNzQyMiA2My4wNDMgODkuNTQzIDYzLjA5MzhDODkuMzQzOCA2My4xNDA2IDg5LjE3NzcgNjMuMjEwOSA4OS4wNDQ5IDYzLjMwNDdDODguOTEyMSA2My4zOTg0IDg4LjgxMjUgNjMuNTExNyA4OC43NDYxIDYzLjY0NDVDODguNjc5NyA2My43NzczIDg4LjY0NjUgNjMuOTI3NyA4OC42NDY1IDY0LjA5NTdDODguNjQ2NSA2NC4yNjM3IDg4LjY4NTUgNjQuNDE4IDg4Ljc2MzcgNjQuNTU4NkM4OC44NDE4IDY0LjY5NTMgODguOTU1MSA2NC44MDI3IDg5LjEwMzUgNjQuODgwOUM4OS4yNTU5IDY0Ljk1OSA4OS40Mzk1IDY0Ljk5OCA4OS42NTQzIDY0Ljk5OEM4OS45NDM0IDY0Ljk5OCA5MC4xOTUzIDY0LjkzOTUgOTAuNDEwMiA2NC44MjIzQzkwLjYyODkgNjQuNzAxMiA5MC44MDA4IDY0LjU1NDcgOTAuOTI1OCA2NC4zODI4QzkxLjA1MDggNjQuMjA3IDkxLjExNzIgNjQuMDQxIDkxLjEyNSA2My44ODQ4TDkxLjU4MiA2NC41MTE3QzkxLjUzNTIgNjQuNjcxOSA5MS40NTUxIDY0Ljg0MzggOTEuMzQxOCA2NS4wMjczQzkxLjIyODUgNjUuMjEwOSA5MS4wODAxIDY1LjM4NjcgOTAuODk2NSA2NS41NTQ3QzkwLjcxNjggNjUuNzE4OCA5MC41IDY1Ljg1MzUgOTAuMjQ2MSA2NS45NTlDODkuOTk2MSA2Ni4wNjQ1IDg5LjcwNyA2Ni4xMTcyIDg5LjM3ODkgNjYuMTE3MkM4OC45NjQ4IDY2LjExNzIgODguNTk1NyA2Ni4wMzUyIDg4LjI3MTUgNjUuODcxMUM4Ny45NDczIDY1LjcwMzEgODcuNjkzNCA2NS40Nzg1IDg3LjUwOTggNjUuMTk3M0M4Ny4zMjYyIDY0LjkxMjEgODcuMjM0NCA2NC41ODk4IDg3LjIzNDQgNjQuMjMwNUM4Ny4yMzQ0IDYzLjg5NDUgODcuMjk2OSA2My41OTc3IDg3LjQyMTkgNjMuMzM5OEM4Ny41NTA4IDYzLjA3ODEgODcuNzM4MyA2Mi44NTk0IDg3Ljk4NDQgNjIuNjgzNkM4OC4yMzQ0IDYyLjUwNzggODguNTM5MSA2Mi4zNzUgODguODk4NCA2Mi4yODUyQzg5LjI1NzggNjIuMTkxNCA4OS42NjggNjIuMTQ0NSA5MC4xMjg5IDYyLjE0NDVIOTEuMjM2M1pNOTcuNzMyNCA2NC4yODMyQzk3LjczMjQgNjQuMTQyNiA5Ny42OTczIDY0LjAxNTYgOTcuNjI3IDYzLjkwMjNDOTcuNTU2NiA2My43ODUyIDk3LjQyMTkgNjMuNjc5NyA5Ny4yMjI3IDYzLjU4NTlDOTcuMDI3MyA2My40OTIyIDk2LjczODMgNjMuNDA2MiA5Ni4zNTU1IDYzLjMyODFDOTYuMDE5NSA2My4yNTM5IDk1LjcxMDkgNjMuMTY2IDk1LjQyOTcgNjMuMDY0NUM5NS4xNTIzIDYyLjk1OSA5NC45MTQxIDYyLjgzMiA5NC43MTQ4IDYyLjY4MzZDOTQuNTE1NiA2Mi41MzUyIDk0LjM2MTMgNjIuMzU5NCA5NC4yNTIgNjIuMTU2MkM5NC4xNDI2IDYxLjk1MzEgOTQuMDg3OSA2MS43MTg4IDk0LjA4NzkgNjEuNDUzMUM5NC4wODc5IDYxLjE5NTMgOTQuMTQ0NSA2MC45NTEyIDk0LjI1NzggNjAuNzIwN0M5NC4zNzExIDYwLjQ5MDIgOTQuNTMzMiA2MC4yODcxIDk0Ljc0NDEgNjAuMTExM0M5NC45NTUxIDU5LjkzNTUgOTUuMjEwOSA1OS43OTY5IDk1LjUxMTcgNTkuNjk1M0M5NS44MTY0IDU5LjU5MzggOTYuMTU2MiA1OS41NDMgOTYuNTMxMiA1OS41NDNDOTcuMDYyNSA1OS41NDMgOTcuNTE3NiA1OS42MzI4IDk3Ljg5NjUgNTkuODEyNUM5OC4yNzkzIDU5Ljk4ODMgOTguNTcyMyA2MC4yMjg1IDk4Ljc3NTQgNjAuNTMzMkM5OC45Nzg1IDYwLjgzNCA5OS4wODAxIDYxLjE3MzggOTkuMDgwMSA2MS41NTI3SDk3LjY2OEM5Ny42NjggNjEuMzg0OCA5Ny42MjUgNjEuMjI4NSA5Ny41MzkxIDYxLjA4NEM5Ny40NTcgNjAuOTM1NSA5Ny4zMzIgNjAuODE2NCA5Ny4xNjQxIDYwLjcyNjZDOTYuOTk2MSA2MC42MzI4IDk2Ljc4NTIgNjAuNTg1OSA5Ni41MzEyIDYwLjU4NTlDOTYuMjg5MSA2MC41ODU5IDk2LjA4NzkgNjAuNjI1IDk1LjkyNzcgNjAuNzAzMUM5NS43NzE1IDYwLjc3NzMgOTUuNjU0MyA2MC44NzUgOTUuNTc2MiA2MC45OTYxQzk1LjUwMiA2MS4xMTcyIDk1LjQ2NDggNjEuMjUgOTUuNDY0OCA2MS4zOTQ1Qzk1LjQ2NDggNjEuNSA5NS40ODQ0IDYxLjU5NTcgOTUuNTIzNCA2MS42ODE2Qzk1LjU2NjQgNjEuNzYzNyA5NS42MzY3IDYxLjgzOTggOTUuNzM0NCA2MS45MTAyQzk1LjgzMiA2MS45NzY2IDk1Ljk2NDggNjIuMDM5MSA5Ni4xMzI4IDYyLjA5NzdDOTYuMzA0NyA2Mi4xNTYyIDk2LjUxOTUgNjIuMjEyOSA5Ni43NzczIDYyLjI2NzZDOTcuMjYxNyA2Mi4zNjkxIDk3LjY3NzcgNjIuNSA5OC4wMjU0IDYyLjY2MDJDOTguMzc3IDYyLjgxNjQgOTguNjQ2NSA2My4wMTk1IDk4LjgzNCA2My4yNjk1Qzk5LjAyMTUgNjMuNTE1NiA5OS4xMTUyIDYzLjgyODEgOTkuMTE1MiA2NC4yMDdDOTkuMTE1MiA2NC40ODgzIDk5LjA1NDcgNjQuNzQ2MSA5OC45MzM2IDY0Ljk4MDVDOTguODE2NCA2NS4yMTA5IDk4LjY0NDUgNjUuNDEyMSA5OC40MTggNjUuNTg0Qzk4LjE5MTQgNjUuNzUyIDk3LjkxOTkgNjUuODgyOCA5Ny42MDM1IDY1Ljk3NjZDOTcuMjkxIDY2LjA3MDMgOTYuOTM5NSA2Ni4xMTcyIDk2LjU0ODggNjYuMTE3MkM5NS45NzQ2IDY2LjExNzIgOTUuNDg4MyA2Ni4wMTU2IDk1LjA4OTggNjUuODEyNUM5NC42OTE0IDY1LjYwNTUgOTQuMzg4NyA2NS4zNDE4IDk0LjE4MTYgNjUuMDIxNUM5My45Nzg1IDY0LjY5NzMgOTMuODc3IDY0LjM2MTMgOTMuODc3IDY0LjAxMzdIOTUuMjQyMkM5NS4yNTc4IDY0LjI3NTQgOTUuMzMwMSA2NC40ODQ0IDk1LjQ1OSA2NC42NDA2Qzk1LjU5MTggNjQuNzkzIDk1Ljc1NTkgNjQuOTA0MyA5NS45NTEyIDY0Ljk3NDZDOTYuMTUwNCA2NS4wNDEgOTYuMzU1NSA2NS4wNzQyIDk2LjU2NjQgNjUuMDc0MkM5Ni44MjAzIDY1LjA3NDIgOTcuMDMzMiA2NS4wNDEgOTcuMjA1MSA2NC45NzQ2Qzk3LjM3NyA2NC45MDQzIDk3LjUwNzggNjQuODEwNSA5Ny41OTc3IDY0LjY5MzRDOTcuNjg3NSA2NC41NzIzIDk3LjczMjQgNjQuNDM1NSA5Ny43MzI0IDY0LjI4MzJaTTEwMy41MDggNTkuNjYwMlY2MC42OTE0SDk5LjkzMzZWNTkuNjYwMkgxMDMuNTA4Wk0xMDAuOTY1IDU4LjEwNzRIMTAyLjM3N1Y2NC4yNDhDMTAyLjM3NyA2NC40NDM0IDEwMi40MDQgNjQuNTkzOCAxMDIuNDU5IDY0LjY5OTJDMTAyLjUxOCA2NC44MDA4IDEwMi41OTggNjQuODY5MSAxMDIuNjk5IDY0LjkwNDNDMTAyLjgwMSA2NC45Mzk1IDEwMi45MiA2NC45NTcgMTAzLjA1NyA2NC45NTdDMTAzLjE1NCA2NC45NTcgMTAzLjI0OCA2NC45NTEyIDEwMy4zMzggNjQuOTM5NUMxMDMuNDI4IDY0LjkyNzcgMTAzLjUgNjQuOTE2IDEwMy41NTUgNjQuOTA0M0wxMDMuNTYxIDY1Ljk4MjRDMTAzLjQ0MyA2Ni4wMTc2IDEwMy4zMDcgNjYuMDQ4OCAxMDMuMTUgNjYuMDc2MkMxMDIuOTk4IDY2LjEwMzUgMTAyLjgyMiA2Ni4xMTcyIDEwMi42MjMgNjYuMTE3MkMxMDIuMjk5IDY2LjExNzIgMTAyLjAxMiA2Ni4wNjA1IDEwMS43NjIgNjUuOTQ3M0MxMDEuNTEyIDY1LjgzMDEgMTAxLjMxNiA2NS42NDA2IDEwMS4xNzYgNjUuMzc4OUMxMDEuMDM1IDY1LjExNzIgMTAwLjk2NSA2NC43Njk1IDEwMC45NjUgNjQuMzM1OVY1OC4xMDc0Wk0xMTEuOSA2NC41MDU5VjU5LjY2MDJIMTEzLjMxOFY2NkgxMTEuOTgyTDExMS45IDY0LjUwNTlaTTExMi4xIDYzLjE4NzVMMTEyLjU3NCA2My4xNzU4QzExMi41NzQgNjMuNjAxNiAxMTIuNTI3IDYzLjk5NDEgMTEyLjQzNCA2NC4zNTM1QzExMi4zNCA2NC43MDkgMTEyLjE5NSA2NS4wMTk1IDExMiA2NS4yODUyQzExMS44MDUgNjUuNTQ2OSAxMTEuNTU1IDY1Ljc1MiAxMTEuMjUgNjUuOTAwNEMxMTAuOTQ1IDY2LjA0NDkgMTEwLjU4IDY2LjExNzIgMTEwLjE1NCA2Ni4xMTcyQzEwOS44NDYgNjYuMTE3MiAxMDkuNTYyIDY2LjA3MjMgMTA5LjMwNSA2NS45ODI0QzEwOS4wNDcgNjUuODkyNiAxMDguODI0IDY1Ljc1MzkgMTA4LjYzNyA2NS41NjY0QzEwOC40NTMgNjUuMzc4OSAxMDguMzExIDY1LjEzNDggMTA4LjIwOSA2NC44MzRDMTA4LjEwNyA2NC41MzMyIDEwOC4wNTcgNjQuMTczOCAxMDguMDU3IDYzLjc1NTlWNTkuNjYwMkgxMDkuNDY5VjYzLjc2NzZDMTA5LjQ2OSA2My45OTggMTA5LjQ5NiA2NC4xOTE0IDEwOS41NTEgNjQuMzQ3N0MxMDkuNjA1IDY0LjUgMTA5LjY4IDY0LjYyMyAxMDkuNzczIDY0LjcxNjhDMTA5Ljg2NyA2NC44MTA1IDEwOS45NzcgNjQuODc3IDExMC4xMDIgNjQuOTE2QzExMC4yMjcgNjQuOTU1MSAxMTAuMzU5IDY0Ljk3NDYgMTEwLjUgNjQuOTc0NkMxMTAuOTAyIDY0Ljk3NDYgMTExLjIxOSA2NC44OTY1IDExMS40NDkgNjQuNzQwMkMxMTEuNjg0IDY0LjU4MDEgMTExLjg1IDY0LjM2NTIgMTExLjk0NyA2NC4wOTU3QzExMi4wNDkgNjMuODI2MiAxMTIuMSA2My41MjM0IDExMi4xIDYzLjE4NzVaTTExNi40MzQgNjAuODc4OVY2OC40Mzc1SDExNS4wMjFWNTkuNjYwMkgxMTYuMzIyTDExNi40MzQgNjAuODc4OVpNMTIwLjU2NCA2Mi43NzE1VjYyLjg5NDVDMTIwLjU2NCA2My4zNTU1IDEyMC41MSA2My43ODMyIDEyMC40IDY0LjE3NzdDMTIwLjI5NSA2NC41Njg0IDEyMC4xMzcgNjQuOTEwMiAxMTkuOTI2IDY1LjIwMzFDMTE5LjcxOSA2NS40OTIyIDExOS40NjMgNjUuNzE2OCAxMTkuMTU4IDY1Ljg3N0MxMTguODU0IDY2LjAzNzEgMTE4LjUwMiA2Ni4xMTcyIDExOC4xMDQgNjYuMTE3MkMxMTcuNzA5IDY2LjExNzIgMTE3LjM2MyA2Ni4wNDQ5IDExNy4wNjYgNjUuOTAwNEMxMTYuNzczIDY1Ljc1MiAxMTYuNTI1IDY1LjU0MyAxMTYuMzIyIDY1LjI3MzRDMTE2LjExOSA2NS4wMDM5IDExNS45NTUgNjQuNjg3NSAxMTUuODMgNjQuMzI0MkMxMTUuNzA5IDYzLjk1NyAxMTUuNjIzIDYzLjU1NDcgMTE1LjU3MiA2My4xMTcyVjYyLjY0MjZDMTE1LjYyMyA2Mi4xNzc3IDExNS43MDkgNjEuNzU1OSAxMTUuODMgNjEuMzc3QzExNS45NTUgNjAuOTk4IDExNi4xMTkgNjAuNjcxOSAxMTYuMzIyIDYwLjM5ODRDMTE2LjUyNSA2MC4xMjUgMTE2Ljc3MyA1OS45MTQxIDExNy4wNjYgNTkuNzY1NkMxMTcuMzU5IDU5LjYxNzIgMTE3LjcwMSA1OS41NDMgMTE4LjA5MiA1OS41NDNDMTE4LjQ5IDU5LjU0MyAxMTguODQ0IDU5LjYyMTEgMTE5LjE1MiA1OS43NzczQzExOS40NjEgNTkuOTI5NyAxMTkuNzIxIDYwLjE0ODQgMTE5LjkzMiA2MC40MzM2QzEyMC4xNDMgNjAuNzE0OCAxMjAuMzAxIDYxLjA1NDcgMTIwLjQwNiA2MS40NTMxQzEyMC41MTIgNjEuODQ3NyAxMjAuNTY0IDYyLjI4NzEgMTIwLjU2NCA2Mi43NzE1Wk0xMTkuMTUyIDYyLjg5NDVWNjIuNzcxNUMxMTkuMTUyIDYyLjQ3ODUgMTE5LjEyNSA2Mi4yMDcgMTE5LjA3IDYxLjk1N0MxMTkuMDE2IDYxLjcwMzEgMTE4LjkzIDYxLjQ4MDUgMTE4LjgxMiA2MS4yODkxQzExOC42OTUgNjEuMDk3NyAxMTguNTQ1IDYwLjk0OTIgMTE4LjM2MSA2MC44NDM4QzExOC4xODIgNjAuNzM0NCAxMTcuOTY1IDYwLjY3OTcgMTE3LjcxMSA2MC42Nzk3QzExNy40NjEgNjAuNjc5NyAxMTcuMjQ2IDYwLjcyMjcgMTE3LjA2NiA2MC44MDg2QzExNi44ODcgNjAuODkwNiAxMTYuNzM2IDYxLjAwNTkgMTE2LjYxNSA2MS4xNTQzQzExNi40OTQgNjEuMzAyNyAxMTYuNCA2MS40NzY2IDExNi4zMzQgNjEuNjc1OEMxMTYuMjY4IDYxLjg3MTEgMTE2LjIyMSA2Mi4wODQgMTE2LjE5MyA2Mi4zMTQ1VjYzLjQ1MTJDMTE2LjI0IDYzLjczMjQgMTE2LjMyIDYzLjk5MDIgMTE2LjQzNCA2NC4yMjQ2QzExNi41NDcgNjQuNDU5IDExNi43MDcgNjQuNjQ2NSAxMTYuOTE0IDY0Ljc4NzFDMTE3LjEyNSA2NC45MjM4IDExNy4zOTUgNjQuOTkyMiAxMTcuNzIzIDY0Ljk5MjJDMTE3Ljk3NyA2NC45OTIyIDExOC4xOTMgNjQuOTM3NSAxMTguMzczIDY0LjgyODFDMTE4LjU1MyA2NC43MTg4IDExOC42OTkgNjQuNTY4NCAxMTguODEyIDY0LjM3N0MxMTguOTMgNjQuMTgxNiAxMTkuMDE2IDYzLjk1NyAxMTkuMDcgNjMuNzAzMUMxMTkuMTI1IDYzLjQ0OTIgMTE5LjE1MiA2My4xNzk3IDExOS4xNTIgNjIuODk0NVpNMTI1Ljg4MyA2NC42ODc1VjU3SDEyNy4zMDFWNjZIMTI2LjAxOEwxMjUuODgzIDY0LjY4NzVaTTEyMS43NTggNjIuOTAwNFY2Mi43NzczQzEyMS43NTggNjIuMjk2OSAxMjEuODE0IDYxLjg1OTQgMTIxLjkyOCA2MS40NjQ4QzEyMi4wNDEgNjEuMDY2NCAxMjIuMjA1IDYwLjcyNDYgMTIyLjQyIDYwLjQzOTVDMTIyLjYzNSA2MC4xNTA0IDEyMi44OTYgNTkuOTI5NyAxMjMuMjA1IDU5Ljc3NzNDMTIzLjUxNCA1OS42MjExIDEyMy44NjEgNTkuNTQzIDEyNC4yNDggNTkuNTQzQzEyNC42MzEgNTkuNTQzIDEyNC45NjcgNTkuNjE3MiAxMjUuMjU2IDU5Ljc2NTZDMTI1LjU0NSA1OS45MTQxIDEyNS43OTEgNjAuMTI3IDEyNS45OTQgNjAuNDA0M0MxMjYuMTk3IDYwLjY3NzcgMTI2LjM1OSA2MS4wMDU5IDEyNi40OCA2MS4zODg3QzEyNi42MDIgNjEuNzY3NiAxMjYuNjg4IDYyLjE4OTUgMTI2LjczOCA2Mi42NTQzVjYzLjA0NjlDMTI2LjY4OCA2My41IDEyNi42MDIgNjMuOTE0MSAxMjYuNDggNjQuMjg5MUMxMjYuMzU5IDY0LjY2NDEgMTI2LjE5NyA2NC45ODgzIDEyNS45OTQgNjUuMjYxN0MxMjUuNzkxIDY1LjUzNTIgMTI1LjU0MyA2NS43NDYxIDEyNS4yNSA2NS44OTQ1QzEyNC45NjEgNjYuMDQzIDEyNC42MjMgNjYuMTE3MiAxMjQuMjM2IDY2LjExNzJDMTIzLjg1NCA2Ni4xMTcyIDEyMy41MDggNjYuMDM3MSAxMjMuMTk5IDY1Ljg3N0MxMjIuODk1IDY1LjcxNjggMTIyLjYzNSA2NS40OTIyIDEyMi40MiA2NS4yMDMxQzEyMi4yMDUgNjQuOTE0MSAxMjIuMDQxIDY0LjU3NDIgMTIxLjkyOCA2NC4xODM2QzEyMS44MTQgNjMuNzg5MSAxMjEuNzU4IDYzLjM2MTMgMTIxLjc1OCA2Mi45MDA0Wk0xMjMuMTcgNjIuNzc3M1Y2Mi45MDA0QzEyMy4xNyA2My4xODk1IDEyMy4xOTUgNjMuNDU5IDEyMy4yNDYgNjMuNzA5QzEyMy4zMDEgNjMuOTU5IDEyMy4zODUgNjQuMTc5NyAxMjMuNDk4IDY0LjM3MTFDMTIzLjYxMSA2NC41NTg2IDEyMy43NTggNjQuNzA3IDEyMy45MzggNjQuODE2NEMxMjQuMTIxIDY0LjkyMTkgMTI0LjM0IDY0Ljk3NDYgMTI0LjU5NCA2NC45NzQ2QzEyNC45MTQgNjQuOTc0NiAxMjUuMTc4IDY0LjkwNDMgMTI1LjM4NSA2NC43NjM3QzEyNS41OTIgNjQuNjIzIDEyNS43NTQgNjQuNDMzNiAxMjUuODcxIDY0LjE5NTNDMTI1Ljk5MiA2My45NTMxIDEyNi4wNzQgNjMuNjgzNiAxMjYuMTE3IDYzLjM4NjdWNjIuMzI2MkMxMjYuMDk0IDYyLjA5NTcgMTI2LjA0NSA2MS44ODA5IDEyNS45NzEgNjEuNjgxNkMxMjUuOSA2MS40ODI0IDEyNS44MDUgNjEuMzA4NiAxMjUuNjg0IDYxLjE2MDJDMTI1LjU2MiA2MS4wMDc4IDEyNS40MTIgNjAuODkwNiAxMjUuMjMyIDYwLjgwODZDMTI1LjA1NyA2MC43MjI3IDEyNC44NDggNjAuNjc5NyAxMjQuNjA1IDYwLjY3OTdDMTI0LjM0OCA2MC42Nzk3IDEyNC4xMjkgNjAuNzM0NCAxMjMuOTQ5IDYwLjg0MzhDMTIzLjc3IDYwLjk1MzEgMTIzLjYyMSA2MS4xMDM1IDEyMy41MDQgNjEuMjk0OUMxMjMuMzkxIDYxLjQ4NjMgMTIzLjMwNyA2MS43MDkgMTIzLjI1MiA2MS45NjI5QzEyMy4xOTcgNjIuMjE2OCAxMjMuMTcgNjIuNDg4MyAxMjMuMTcgNjIuNzc3M1pNMTMyLjYwMiA2NC43Mjg1VjYxLjcwNTFDMTMyLjYwMiA2MS40Nzg1IDEzMi41NjEgNjEuMjgzMiAxMzIuNDc5IDYxLjExOTFDMTMyLjM5NiA2MC45NTUxIDEzMi4yNzEgNjAuODI4MSAxMzIuMTA0IDYwLjczODNDMTMxLjkzOSA2MC42NDg0IDEzMS43MzIgNjAuNjAzNSAxMzEuNDgyIDYwLjYwMzVDMTMxLjI1MiA2MC42MDM1IDEzMS4wNTMgNjAuNjQyNiAxMzAuODg1IDYwLjcyMDdDMTMwLjcxNyA2MC43OTg4IDEzMC41ODYgNjAuOTA0MyAxMzAuNDkyIDYxLjAzNzFDMTMwLjM5OCA2MS4xNjk5IDEzMC4zNTIgNjEuMzIwMyAxMzAuMzUyIDYxLjQ4ODNIMTI4Ljk0NUMxMjguOTQ1IDYxLjIzODMgMTI5LjAwNiA2MC45OTYxIDEyOS4xMjcgNjAuNzYxN0MxMjkuMjQ4IDYwLjUyNzMgMTI5LjQyNCA2MC4zMTg0IDEyOS42NTQgNjAuMTM0OEMxMjkuODg1IDU5Ljk1MTIgMTMwLjE2IDU5LjgwNjYgMTMwLjQ4IDU5LjcwMTJDMTMwLjgwMSA1OS41OTU3IDEzMS4xNiA1OS41NDMgMTMxLjU1OSA1OS41NDNDMTMyLjAzNSA1OS41NDMgMTMyLjQ1NyA1OS42MjMgMTMyLjgyNCA1OS43ODMyQzEzMy4xOTUgNTkuOTQzNCAxMzMuNDg2IDYwLjE4NTUgMTMzLjY5NyA2MC41MDk4QzEzMy45MTIgNjAuODMwMSAxMzQuMDIgNjEuMjMyNCAxMzQuMDIgNjEuNzE2OFY2NC41MzUyQzEzNC4wMiA2NC44MjQyIDEzNC4wMzkgNjUuMDg0IDEzNC4wNzggNjUuMzE0NUMxMzQuMTIxIDY1LjU0MSAxMzQuMTgyIDY1LjczODMgMTM0LjI2IDY1LjkwNjJWNjZIMTMyLjgxMkMxMzIuNzQ2IDY1Ljg0NzcgMTMyLjY5MyA2NS42NTQzIDEzMi42NTQgNjUuNDE5OUMxMzIuNjE5IDY1LjE4MTYgMTMyLjYwMiA2NC45NTEyIDEzMi42MDIgNjQuNzI4NVpNMTMyLjgwNyA2Mi4xNDQ1TDEzMi44MTggNjMuMDE3NkgxMzEuODA1QzEzMS41NDMgNjMuMDE3NiAxMzEuMzEyIDYzLjA0MyAxMzEuMTEzIDYzLjA5MzhDMTMwLjkxNCA2My4xNDA2IDEzMC43NDggNjMuMjEwOSAxMzAuNjE1IDYzLjMwNDdDMTMwLjQ4MiA2My4zOTg0IDEzMC4zODMgNjMuNTExNyAxMzAuMzE2IDYzLjY0NDVDMTMwLjI1IDYzLjc3NzMgMTMwLjIxNyA2My45Mjc3IDEzMC4yMTcgNjQuMDk1N0MxMzAuMjE3IDY0LjI2MzcgMTMwLjI1NiA2NC40MTggMTMwLjMzNCA2NC41NTg2QzEzMC40MTIgNjQuNjk1MyAxMzAuNTI1IDY0LjgwMjcgMTMwLjY3NCA2NC44ODA5QzEzMC44MjYgNjQuOTU5IDEzMS4wMSA2NC45OTggMTMxLjIyNSA2NC45OThDMTMxLjUxNCA2NC45OTggMTMxLjc2NiA2NC45Mzk1IDEzMS45OCA2NC44MjIzQzEzMi4xOTkgNjQuNzAxMiAxMzIuMzcxIDY0LjU1NDcgMTMyLjQ5NiA2NC4zODI4QzEzMi42MjEgNjQuMjA3IDEzMi42ODggNjQuMDQxIDEzMi42OTUgNjMuODg0OEwxMzMuMTUyIDY0LjUxMTdDMTMzLjEwNSA2NC42NzE5IDEzMy4wMjUgNjQuODQzOCAxMzIuOTEyIDY1LjAyNzNDMTMyLjc5OSA2NS4yMTA5IDEzMi42NSA2NS4zODY3IDEzMi40NjcgNjUuNTU0N0MxMzIuMjg3IDY1LjcxODggMTMyLjA3IDY1Ljg1MzUgMTMxLjgxNiA2NS45NTlDMTMxLjU2NiA2Ni4wNjQ1IDEzMS4yNzcgNjYuMTE3MiAxMzAuOTQ5IDY2LjExNzJDMTMwLjUzNSA2Ni4xMTcyIDEzMC4xNjYgNjYuMDM1MiAxMjkuODQyIDY1Ljg3MTFDMTI5LjUxOCA2NS43MDMxIDEyOS4yNjQgNjUuNDc4NSAxMjkuMDggNjUuMTk3M0MxMjguODk2IDY0LjkxMjEgMTI4LjgwNSA2NC41ODk4IDEyOC44MDUgNjQuMjMwNUMxMjguODA1IDYzLjg5NDUgMTI4Ljg2NyA2My41OTc3IDEyOC45OTIgNjMuMzM5OEMxMjkuMTIxIDYzLjA3ODEgMTI5LjMwOSA2Mi44NTk0IDEyOS41NTUgNjIuNjgzNkMxMjkuODA1IDYyLjUwNzggMTMwLjEwOSA2Mi4zNzUgMTMwLjQ2OSA2Mi4yODUyQzEzMC44MjggNjIuMTkxNCAxMzEuMjM4IDYyLjE0NDUgMTMxLjY5OSA2Mi4xNDQ1SDEzMi44MDdaTTEzOC42NTIgNTkuNjYwMlY2MC42OTE0SDEzNS4wNzhWNTkuNjYwMkgxMzguNjUyWk0xMzYuMTA5IDU4LjEwNzRIMTM3LjUyMVY2NC4yNDhDMTM3LjUyMSA2NC40NDM0IDEzNy41NDkgNjQuNTkzOCAxMzcuNjA0IDY0LjY5OTJDMTM3LjY2MiA2NC44MDA4IDEzNy43NDIgNjQuODY5MSAxMzcuODQ0IDY0LjkwNDNDMTM3Ljk0NSA2NC45Mzk1IDEzOC4wNjQgNjQuOTU3IDEzOC4yMDEgNjQuOTU3QzEzOC4yOTkgNjQuOTU3IDEzOC4zOTMgNjQuOTUxMiAxMzguNDgyIDY0LjkzOTVDMTM4LjU3MiA2NC45Mjc3IDEzOC42NDUgNjQuOTE2IDEzOC42OTkgNjQuOTA0M0wxMzguNzA1IDY1Ljk4MjRDMTM4LjU4OCA2Ni4wMTc2IDEzOC40NTEgNjYuMDQ4OCAxMzguMjk1IDY2LjA3NjJDMTM4LjE0MyA2Ni4xMDM1IDEzNy45NjcgNjYuMTE3MiAxMzcuNzY4IDY2LjExNzJDMTM3LjQ0MyA2Ni4xMTcyIDEzNy4xNTYgNjYuMDYwNSAxMzYuOTA2IDY1Ljk0NzNDMTM2LjY1NiA2NS44MzAxIDEzNi40NjEgNjUuNjQwNiAxMzYuMzIgNjUuMzc4OUMxMzYuMTggNjUuMTE3MiAxMzYuMTA5IDY0Ljc2OTUgMTM2LjEwOSA2NC4zMzU5VjU4LjEwNzRaTTE0Mi43ODcgNjYuMTE3MkMxNDIuMzE4IDY2LjExNzIgMTQxLjg5NSA2Ni4wNDEgMTQxLjUxNiA2NS44ODg3QzE0MS4xNDEgNjUuNzMyNCAxNDAuODIgNjUuNTE1NiAxNDAuNTU1IDY1LjIzODNDMTQwLjI5MyA2NC45NjA5IDE0MC4wOTIgNjQuNjM0OCAxMzkuOTUxIDY0LjI1OThDMTM5LjgxMSA2My44ODQ4IDEzOS43NCA2My40ODA1IDEzOS43NCA2My4wNDY5VjYyLjgxMjVDMTM5Ljc0IDYyLjMxNjQgMTM5LjgxMiA2MS44NjcyIDEzOS45NTcgNjEuNDY0OEMxNDAuMTAyIDYxLjA2MjUgMTQwLjMwMyA2MC43MTg4IDE0MC41NjEgNjAuNDMzNkMxNDAuODE4IDYwLjE0NDUgMTQxLjEyMyA1OS45MjM4IDE0MS40NzUgNTkuNzcxNUMxNDEuODI2IDU5LjYxOTEgMTQyLjIwNyA1OS41NDMgMTQyLjYxNyA1OS41NDNDMTQzLjA3IDU5LjU0MyAxNDMuNDY3IDU5LjYxOTEgMTQzLjgwNyA1OS43NzE1QzE0NC4xNDYgNTkuOTIzOCAxNDQuNDI4IDYwLjEzODcgMTQ0LjY1IDYwLjQxNkMxNDQuODc3IDYwLjY4OTUgMTQ1LjA0NSA2MS4wMTU2IDE0NS4xNTQgNjEuMzk0NUMxNDUuMjY4IDYxLjc3MzQgMTQ1LjMyNCA2Mi4xOTE0IDE0NS4zMjQgNjIuNjQ4NFY2My4yNTJIMTQwLjQyNlY2Mi4yMzgzSDE0My45M1Y2Mi4xMjdDMTQzLjkyMiA2MS44NzMgMTQzLjg3MSA2MS42MzQ4IDE0My43NzcgNjEuNDEyMUMxNDMuNjg4IDYxLjE4OTUgMTQzLjU0OSA2MS4wMDk4IDE0My4zNjEgNjAuODczQzE0My4xNzQgNjAuNzM2MyAxNDIuOTI0IDYwLjY2OCAxNDIuNjExIDYwLjY2OEMxNDIuMzc3IDYwLjY2OCAxNDIuMTY4IDYwLjcxODggMTQxLjk4NCA2MC44MjAzQzE0MS44MDUgNjAuOTE4IDE0MS42NTQgNjEuMDYwNSAxNDEuNTMzIDYxLjI0OEMxNDEuNDEyIDYxLjQzNTUgMTQxLjMxOCA2MS42NjIxIDE0MS4yNTIgNjEuOTI3N0MxNDEuMTg5IDYyLjE4OTUgMTQxLjE1OCA2Mi40ODQ0IDE0MS4xNTggNjIuODEyNVY2My4wNDY5QzE0MS4xNTggNjMuMzI0MiAxNDEuMTk1IDYzLjU4MiAxNDEuMjcgNjMuODIwM0MxNDEuMzQ4IDY0LjA1NDcgMTQxLjQ2MSA2NC4yNTk4IDE0MS42MDkgNjQuNDM1NUMxNDEuNzU4IDY0LjYxMTMgMTQxLjkzOCA2NC43NSAxNDIuMTQ4IDY0Ljg1MTZDMTQyLjM1OSA2NC45NDkyIDE0Mi42IDY0Ljk5OCAxNDIuODY5IDY0Ljk5OEMxNDMuMjA5IDY0Ljk5OCAxNDMuNTEyIDY0LjkyOTcgMTQzLjc3NyA2NC43OTNDMTQ0LjA0MyA2NC42NTYyIDE0NC4yNzMgNjQuNDYyOSAxNDQuNDY5IDY0LjIxMjlMMTQ1LjIxMyA2NC45MzM2QzE0NS4wNzYgNjUuMTMyOCAxNDQuODk4IDY1LjMyNDIgMTQ0LjY4IDY1LjUwNzhDMTQ0LjQ2MSA2NS42ODc1IDE0NC4xOTMgNjUuODM0IDE0My44NzcgNjUuOTQ3M0MxNDMuNTY0IDY2LjA2MDUgMTQzLjIwMSA2Ni4xMTcyIDE0Mi43ODcgNjYuMTE3MlpNMTUzLjY4OCA1Ny40Mzk1VjY2SDE1Mi4yNzVWNTkuMTE1MkwxNTAuMTg0IDU5LjgyNDJWNTguNjU4MkwxNTMuNTE4IDU3LjQzOTVIMTUzLjY4OFpNMTYwLjg1MiA2NC42ODc1VjU3SDE2Mi4yN1Y2NkgxNjAuOTg2TDE2MC44NTIgNjQuNjg3NVpNMTU2LjcyNyA2Mi45MDA0VjYyLjc3NzNDMTU2LjcyNyA2Mi4yOTY5IDE1Ni43ODMgNjEuODU5NCAxNTYuODk2IDYxLjQ2NDhDMTU3LjAxIDYxLjA2NjQgMTU3LjE3NCA2MC43MjQ2IDE1Ny4zODkgNjAuNDM5NUMxNTcuNjA0IDYwLjE1MDQgMTU3Ljg2NSA1OS45Mjk3IDE1OC4xNzQgNTkuNzc3M0MxNTguNDgyIDU5LjYyMTEgMTU4LjgzIDU5LjU0MyAxNTkuMjE3IDU5LjU0M0MxNTkuNiA1OS41NDMgMTU5LjkzNiA1OS42MTcyIDE2MC4yMjUgNTkuNzY1NkMxNjAuNTE0IDU5LjkxNDEgMTYwLjc2IDYwLjEyNyAxNjAuOTYzIDYwLjQwNDNDMTYxLjE2NiA2MC42Nzc3IDE2MS4zMjggNjEuMDA1OSAxNjEuNDQ5IDYxLjM4ODdDMTYxLjU3IDYxLjc2NzYgMTYxLjY1NiA2Mi4xODk1IDE2MS43MDcgNjIuNjU0M1Y2My4wNDY5QzE2MS42NTYgNjMuNSAxNjEuNTcgNjMuOTE0MSAxNjEuNDQ5IDY0LjI4OTFDMTYxLjMyOCA2NC42NjQxIDE2MS4xNjYgNjQuOTg4MyAxNjAuOTYzIDY1LjI2MTdDMTYwLjc2IDY1LjUzNTIgMTYwLjUxMiA2NS43NDYxIDE2MC4yMTkgNjUuODk0NUMxNTkuOTMgNjYuMDQzIDE1OS41OTIgNjYuMTE3MiAxNTkuMjA1IDY2LjExNzJDMTU4LjgyMiA2Ni4xMTcyIDE1OC40NzcgNjYuMDM3MSAxNTguMTY4IDY1Ljg3N0MxNTcuODYzIDY1LjcxNjggMTU3LjYwNCA2NS40OTIyIDE1Ny4zODkgNjUuMjAzMUMxNTcuMTc0IDY0LjkxNDEgMTU3LjAxIDY0LjU3NDIgMTU2Ljg5NiA2NC4xODM2QzE1Ni43ODMgNjMuNzg5MSAxNTYuNzI3IDYzLjM2MTMgMTU2LjcyNyA2Mi45MDA0Wk0xNTguMTM5IDYyLjc3NzNWNjIuOTAwNEMxNTguMTM5IDYzLjE4OTUgMTU4LjE2NCA2My40NTkgMTU4LjIxNSA2My43MDlDMTU4LjI3IDYzLjk1OSAxNTguMzU0IDY0LjE3OTcgMTU4LjQ2NyA2NC4zNzExQzE1OC41OCA2NC41NTg2IDE1OC43MjcgNjQuNzA3IDE1OC45MDYgNjQuODE2NEMxNTkuMDkgNjQuOTIxOSAxNTkuMzA5IDY0Ljk3NDYgMTU5LjU2MiA2NC45NzQ2QzE1OS44ODMgNjQuOTc0NiAxNjAuMTQ2IDY0LjkwNDMgMTYwLjM1NCA2NC43NjM3QzE2MC41NjEgNjQuNjIzIDE2MC43MjMgNjQuNDMzNiAxNjAuODQgNjQuMTk1M0MxNjAuOTYxIDYzLjk1MzEgMTYxLjA0MyA2My42ODM2IDE2MS4wODYgNjMuMzg2N1Y2Mi4zMjYyQzE2MS4wNjIgNjIuMDk1NyAxNjEuMDE0IDYxLjg4MDkgMTYwLjkzOSA2MS42ODE2QzE2MC44NjkgNjEuNDgyNCAxNjAuNzczIDYxLjMwODYgMTYwLjY1MiA2MS4xNjAyQzE2MC41MzEgNjEuMDA3OCAxNjAuMzgxIDYwLjg5MDYgMTYwLjIwMSA2MC44MDg2QzE2MC4wMjUgNjAuNzIyNyAxNTkuODE2IDYwLjY3OTcgMTU5LjU3NCA2MC42Nzk3QzE1OS4zMTYgNjAuNjc5NyAxNTkuMDk4IDYwLjczNDQgMTU4LjkxOCA2MC44NDM4QzE1OC43MzggNjAuOTUzMSAxNTguNTkgNjEuMTAzNSAxNTguNDczIDYxLjI5NDlDMTU4LjM1OSA2MS40ODYzIDE1OC4yNzUgNjEuNzA5IDE1OC4yMjEgNjEuOTYyOUMxNTguMTY2IDYyLjIxNjggMTU4LjEzOSA2Mi40ODgzIDE1OC4xMzkgNjIuNzc3M1pNMTcwLjgwOSA2NC43Mjg1VjYxLjcwNTFDMTcwLjgwOSA2MS40Nzg1IDE3MC43NjggNjEuMjgzMiAxNzAuNjg2IDYxLjExOTFDMTcwLjYwNCA2MC45NTUxIDE3MC40NzkgNjAuODI4MSAxNzAuMzExIDYwLjczODNDMTcwLjE0NiA2MC42NDg0IDE2OS45MzkgNjAuNjAzNSAxNjkuNjg5IDYwLjYwMzVDMTY5LjQ1OSA2MC42MDM1IDE2OS4yNiA2MC42NDI2IDE2OS4wOTIgNjAuNzIwN0MxNjguOTI0IDYwLjc5ODggMTY4Ljc5MyA2MC45MDQzIDE2OC42OTkgNjEuMDM3MUMxNjguNjA1IDYxLjE2OTkgMTY4LjU1OSA2MS4zMjAzIDE2OC41NTkgNjEuNDg4M0gxNjcuMTUyQzE2Ny4xNTIgNjEuMjM4MyAxNjcuMjEzIDYwLjk5NjEgMTY3LjMzNCA2MC43NjE3QzE2Ny40NTUgNjAuNTI3MyAxNjcuNjMxIDYwLjMxODQgMTY3Ljg2MSA2MC4xMzQ4QzE2OC4wOTIgNTkuOTUxMiAxNjguMzY3IDU5LjgwNjYgMTY4LjY4OCA1OS43MDEyQzE2OS4wMDggNTkuNTk1NyAxNjkuMzY3IDU5LjU0MyAxNjkuNzY2IDU5LjU0M0MxNzAuMjQyIDU5LjU0MyAxNzAuNjY0IDU5LjYyMyAxNzEuMDMxIDU5Ljc4MzJDMTcxLjQwMiA1OS45NDM0IDE3MS42OTMgNjAuMTg1NSAxNzEuOTA0IDYwLjUwOThDMTcyLjExOSA2MC44MzAxIDE3Mi4yMjcgNjEuMjMyNCAxNzIuMjI3IDYxLjcxNjhWNjQuNTM1MkMxNzIuMjI3IDY0LjgyNDIgMTcyLjI0NiA2NS4wODQgMTcyLjI4NSA2NS4zMTQ1QzE3Mi4zMjggNjUuNTQxIDE3Mi4zODkgNjUuNzM4MyAxNzIuNDY3IDY1LjkwNjJWNjZIMTcxLjAyQzE3MC45NTMgNjUuODQ3NyAxNzAuOSA2NS42NTQzIDE3MC44NjEgNjUuNDE5OUMxNzAuODI2IDY1LjE4MTYgMTcwLjgwOSA2NC45NTEyIDE3MC44MDkgNjQuNzI4NVpNMTcxLjAxNCA2Mi4xNDQ1TDE3MS4wMjUgNjMuMDE3NkgxNzAuMDEyQzE2OS43NSA2My4wMTc2IDE2OS41MiA2My4wNDMgMTY5LjMyIDYzLjA5MzhDMTY5LjEyMSA2My4xNDA2IDE2OC45NTUgNjMuMjEwOSAxNjguODIyIDYzLjMwNDdDMTY4LjY4OSA2My4zOTg0IDE2OC41OSA2My41MTE3IDE2OC41MjMgNjMuNjQ0NUMxNjguNDU3IDYzLjc3NzMgMTY4LjQyNCA2My45Mjc3IDE2OC40MjQgNjQuMDk1N0MxNjguNDI0IDY0LjI2MzcgMTY4LjQ2MyA2NC40MTggMTY4LjU0MSA2NC41NTg2QzE2OC42MTkgNjQuNjk1MyAxNjguNzMyIDY0LjgwMjcgMTY4Ljg4MSA2NC44ODA5QzE2OS4wMzMgNjQuOTU5IDE2OS4yMTcgNjQuOTk4IDE2OS40MzIgNjQuOTk4QzE2OS43MjEgNjQuOTk4IDE2OS45NzMgNjQuOTM5NSAxNzAuMTg4IDY0LjgyMjNDMTcwLjQwNiA2NC43MDEyIDE3MC41NzggNjQuNTU0NyAxNzAuNzAzIDY0LjM4MjhDMTcwLjgyOCA2NC4yMDcgMTcwLjg5NSA2NC4wNDEgMTcwLjkwMiA2My44ODQ4TDE3MS4zNTkgNjQuNTExN0MxNzEuMzEyIDY0LjY3MTkgMTcxLjIzMiA2NC44NDM4IDE3MS4xMTkgNjUuMDI3M0MxNzEuMDA2IDY1LjIxMDkgMTcwLjg1NyA2NS4zODY3IDE3MC42NzQgNjUuNTU0N0MxNzAuNDk0IDY1LjcxODggMTcwLjI3NyA2NS44NTM1IDE3MC4wMjMgNjUuOTU5QzE2OS43NzMgNjYuMDY0NSAxNjkuNDg0IDY2LjExNzIgMTY5LjE1NiA2Ni4xMTcyQzE2OC43NDIgNjYuMTE3MiAxNjguMzczIDY2LjAzNTIgMTY4LjA0OSA2NS44NzExQzE2Ny43MjUgNjUuNzAzMSAxNjcuNDcxIDY1LjQ3ODUgMTY3LjI4NyA2NS4xOTczQzE2Ny4xMDQgNjQuOTEyMSAxNjcuMDEyIDY0LjU4OTggMTY3LjAxMiA2NC4yMzA1QzE2Ny4wMTIgNjMuODk0NSAxNjcuMDc0IDYzLjU5NzcgMTY3LjE5OSA2My4zMzk4QzE2Ny4zMjggNjMuMDc4MSAxNjcuNTE2IDYyLjg1OTQgMTY3Ljc2MiA2Mi42ODM2QzE2OC4wMTIgNjIuNTA3OCAxNjguMzE2IDYyLjM3NSAxNjguNjc2IDYyLjI4NTJDMTY5LjAzNSA2Mi4xOTE0IDE2OS40NDUgNjIuMTQ0NSAxNjkuOTA2IDYyLjE0NDVIMTcxLjAxNFpNMTc4LjAxNCA1OS42NjAySDE3OS4yOTdWNjUuODI0MkMxNzkuMjk3IDY2LjM5NDUgMTc5LjE3NiA2Ni44Nzg5IDE3OC45MzQgNjcuMjc3M0MxNzguNjkxIDY3LjY3NTggMTc4LjM1NCA2Ny45Nzg1IDE3Ny45MiA2OC4xODU1QzE3Ny40ODYgNjguMzk2NSAxNzYuOTg0IDY4LjUwMiAxNzYuNDE0IDY4LjUwMkMxNzYuMTcyIDY4LjUwMiAxNzUuOTAyIDY4LjQ2NjggMTc1LjYwNSA2OC4zOTY1QzE3NS4zMTIgNjguMzI2MiAxNzUuMDI3IDY4LjIxMjkgMTc0Ljc1IDY4LjA1NjZDMTc0LjQ3NyA2Ny45MDQzIDE3NC4yNDggNjcuNzAzMSAxNzQuMDY0IDY3LjQ1MzFMMTc0LjcyNyA2Ni42MjExQzE3NC45NTMgNjYuODkwNiAxNzUuMjAzIDY3LjA4NzkgMTc1LjQ3NyA2Ny4yMTI5QzE3NS43NSA2Ny4zMzc5IDE3Ni4wMzcgNjcuNDAwNCAxNzYuMzM4IDY3LjQwMDRDMTc2LjY2MiA2Ny40MDA0IDE3Ni45MzggNjcuMzM5OCAxNzcuMTY0IDY3LjIxODhDMTc3LjM5NSA2Ny4xMDE2IDE3Ny41NzIgNjYuOTI3NyAxNzcuNjk3IDY2LjY5NzNDMTc3LjgyMiA2Ni40NjY4IDE3Ny44ODUgNjYuMTg1NSAxNzcuODg1IDY1Ljg1MzVWNjEuMDk1N0wxNzguMDE0IDU5LjY2MDJaTTE3My43MDcgNjIuOTAwNFY2Mi43NzczQzE3My43MDcgNjIuMjk2OSAxNzMuNzY2IDYxLjg1OTQgMTczLjg4MyA2MS40NjQ4QzE3NCA2MS4wNjY0IDE3NC4xNjggNjAuNzI0NiAxNzQuMzg3IDYwLjQzOTVDMTc0LjYwNSA2MC4xNTA0IDE3NC44NzEgNTkuOTI5NyAxNzUuMTg0IDU5Ljc3NzNDMTc1LjQ5NiA1OS42MjExIDE3NS44NSA1OS41NDMgMTc2LjI0NCA1OS41NDNDMTc2LjY1NCA1OS41NDMgMTc3LjAwNCA1OS42MTcyIDE3Ny4yOTMgNTkuNzY1NkMxNzcuNTg2IDU5LjkxNDEgMTc3LjgzIDYwLjEyNyAxNzguMDI1IDYwLjQwNDNDMTc4LjIyMSA2MC42Nzc3IDE3OC4zNzMgNjEuMDA1OSAxNzguNDgyIDYxLjM4ODdDMTc4LjU5NiA2MS43Njc2IDE3OC42OCA2Mi4xODk1IDE3OC43MzQgNjIuNjU0M1Y2My4wNDY5QzE3OC42ODQgNjMuNSAxNzguNTk4IDYzLjkxNDEgMTc4LjQ3NyA2NC4yODkxQzE3OC4zNTUgNjQuNjY0MSAxNzguMTk1IDY0Ljk4ODMgMTc3Ljk5NiA2NS4yNjE3QzE3Ny43OTcgNjUuNTM1MiAxNzcuNTUxIDY1Ljc0NjEgMTc3LjI1OCA2NS44OTQ1QzE3Ni45NjkgNjYuMDQzIDE3Ni42MjcgNjYuMTE3MiAxNzYuMjMyIDY2LjExNzJDMTc1Ljg0NiA2Ni4xMTcyIDE3NS40OTYgNjYuMDM3MSAxNzUuMTg0IDY1Ljg3N0MxNzQuODc1IDY1LjcxNjggMTc0LjYwOSA2NS40OTIyIDE3NC4zODcgNjUuMjAzMUMxNzQuMTY4IDY0LjkxNDEgMTc0IDY0LjU3NDIgMTczLjg4MyA2NC4xODM2QzE3My43NjYgNjMuNzg5MSAxNzMuNzA3IDYzLjM2MTMgMTczLjcwNyA2Mi45MDA0Wk0xNzUuMTE5IDYyLjc3NzNWNjIuOTAwNEMxNzUuMTE5IDYzLjE4OTUgMTc1LjE0NiA2My40NTkgMTc1LjIwMSA2My43MDlDMTc1LjI2IDYzLjk1OSAxNzUuMzQ4IDY0LjE3OTcgMTc1LjQ2NSA2NC4zNzExQzE3NS41ODYgNjQuNTU4NiAxNzUuNzM4IDY0LjcwNyAxNzUuOTIyIDY0LjgxNjRDMTc2LjEwOSA2NC45MjE5IDE3Ni4zMyA2NC45NzQ2IDE3Ni41ODQgNjQuOTc0NkMxNzYuOTE2IDY0Ljk3NDYgMTc3LjE4OCA2NC45MDQzIDE3Ny4zOTggNjQuNzYzN0MxNzcuNjEzIDY0LjYyMyAxNzcuNzc3IDY0LjQzMzYgMTc3Ljg5MSA2NC4xOTUzQzE3OC4wMDggNjMuOTUzMSAxNzguMDkgNjMuNjgzNiAxNzguMTM3IDYzLjM4NjdWNjIuMzI2MkMxNzguMTEzIDYyLjA5NTcgMTc4LjA2NCA2MS44ODA5IDE3Ny45OSA2MS42ODE2QzE3Ny45MiA2MS40ODI0IDE3Ny44MjQgNjEuMzA4NiAxNzcuNzAzIDYxLjE2MDJDMTc3LjU4MiA2MS4wMDc4IDE3Ny40MyA2MC44OTA2IDE3Ny4yNDYgNjAuODA4NkMxNzcuMDYyIDYwLjcyMjcgMTc2Ljg0NiA2MC42Nzk3IDE3Ni41OTYgNjAuNjc5N0MxNzYuMzQyIDYwLjY3OTcgMTc2LjEyMSA2MC43MzQ0IDE3NS45MzQgNjAuODQzOEMxNzUuNzQ2IDYwLjk1MzEgMTc1LjU5MiA2MS4xMDM1IDE3NS40NzEgNjEuMjk0OUMxNzUuMzU0IDYxLjQ4NjMgMTc1LjI2NiA2MS43MDkgMTc1LjIwNyA2MS45NjI5QzE3NS4xNDggNjIuMjE2OCAxNzUuMTE5IDYyLjQ4ODMgMTc1LjExOSA2Mi43NzczWk0xODAuNzQyIDYyLjkwMDRWNjIuNzY1NkMxODAuNzQyIDYyLjMwODYgMTgwLjgwOSA2MS44ODQ4IDE4MC45NDEgNjEuNDk0MUMxODEuMDc0IDYxLjA5OTYgMTgxLjI2NiA2MC43NTc4IDE4MS41MTYgNjAuNDY4OEMxODEuNzcgNjAuMTc1OCAxODIuMDc4IDU5Ljk0OTIgMTgyLjQ0MSA1OS43ODkxQzE4Mi44MDkgNTkuNjI1IDE4My4yMjMgNTkuNTQzIDE4My42ODQgNTkuNTQzQzE4NC4xNDggNTkuNTQzIDE4NC41NjIgNTkuNjI1IDE4NC45MjYgNTkuNzg5MUMxODUuMjkzIDU5Ljk0OTIgMTg1LjYwNCA2MC4xNzU4IDE4NS44NTcgNjAuNDY4OEMxODYuMTExIDYwLjc1NzggMTg2LjMwNSA2MS4wOTk2IDE4Ni40MzggNjEuNDk0MUMxODYuNTcgNjEuODg0OCAxODYuNjM3IDYyLjMwODYgMTg2LjYzNyA2Mi43NjU2VjYyLjkwMDRDMTg2LjYzNyA2My4zNTc0IDE4Ni41NyA2My43ODEyIDE4Ni40MzggNjQuMTcxOUMxODYuMzA1IDY0LjU2MjUgMTg2LjExMSA2NC45MDQzIDE4NS44NTcgNjUuMTk3M0MxODUuNjA0IDY1LjQ4NjMgMTg1LjI5NSA2NS43MTI5IDE4NC45MzIgNjUuODc3QzE4NC41NjggNjYuMDM3MSAxODQuMTU2IDY2LjExNzIgMTgzLjY5NSA2Ni4xMTcyQzE4My4yMyA2Ni4xMTcyIDE4Mi44MTQgNjYuMDM3MSAxODIuNDQ3IDY1Ljg3N0MxODIuMDg0IDY1LjcxMjkgMTgxLjc3NSA2NS40ODYzIDE4MS41MjEgNjUuMTk3M0MxODEuMjY4IDY0LjkwNDMgMTgxLjA3NCA2NC41NjI1IDE4MC45NDEgNjQuMTcxOUMxODAuODA5IDYzLjc4MTIgMTgwLjc0MiA2My4zNTc0IDE4MC43NDIgNjIuOTAwNFpNMTgyLjE1NCA2Mi43NjU2VjYyLjkwMDRDMTgyLjE1NCA2My4xODU1IDE4Mi4xODQgNjMuNDU1MSAxODIuMjQyIDYzLjcwOUMxODIuMzAxIDYzLjk2MjkgMTgyLjM5MyA2NC4xODU1IDE4Mi41MTggNjQuMzc3QzE4Mi42NDMgNjQuNTY4NCAxODIuODAzIDY0LjcxODggMTgyLjk5OCA2NC44MjgxQzE4My4xOTMgNjQuOTM3NSAxODMuNDI2IDY0Ljk5MjIgMTgzLjY5NSA2NC45OTIyQzE4My45NTcgNjQuOTkyMiAxODQuMTg0IDY0LjkzNzUgMTg0LjM3NSA2NC44MjgxQzE4NC41NyA2NC43MTg4IDE4NC43MyA2NC41Njg0IDE4NC44NTUgNjQuMzc3QzE4NC45OCA2NC4xODU1IDE4NS4wNzIgNjMuOTYyOSAxODUuMTMxIDYzLjcwOUMxODUuMTkzIDYzLjQ1NTEgMTg1LjIyNSA2My4xODU1IDE4NS4yMjUgNjIuOTAwNFY2Mi43NjU2QzE4NS4yMjUgNjIuNDg0NCAxODUuMTkzIDYyLjIxODggMTg1LjEzMSA2MS45Njg4QzE4NS4wNzIgNjEuNzE0OCAxODQuOTc5IDYxLjQ5MDIgMTg0Ljg1IDYxLjI5NDlDMTg0LjcyNSA2MS4wOTk2IDE4NC41NjQgNjAuOTQ3MyAxODQuMzY5IDYwLjgzNzlDMTg0LjE3OCA2MC43MjQ2IDE4My45NDkgNjAuNjY4IDE4My42ODQgNjAuNjY4QzE4My40MTggNjAuNjY4IDE4My4xODggNjAuNzI0NiAxODIuOTkyIDYwLjgzNzlDMTgyLjgwMSA2MC45NDczIDE4Mi42NDMgNjEuMDk5NiAxODIuNTE4IDYxLjI5NDlDMTgyLjM5MyA2MS40OTAyIDE4Mi4zMDEgNjEuNzE0OCAxODIuMjQyIDYxLjk2ODhDMTgyLjE4NCA2Mi4yMTg4IDE4Mi4xNTQgNjIuNDg0NCAxODIuMTU0IDYyLjc2NTZaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjM4Ii8+CjxwYXRoIGQ9Ik0yODMuNTc0IDYzLjEyNVY2OEgyNTguNzkzVjYzLjgxMDVMMjcwLjgyOCA1MC42ODM2QzI3Mi4xNDggNDkuMTk0IDI3My4xODkgNDcuOTA3NiAyNzMuOTUxIDQ2LjgyNDJDMjc0LjcxMyA0NS43NDA5IDI3NS4yNDYgNDQuNzY3NiAyNzUuNTUxIDQzLjkwNDNDMjc1Ljg3MiA0My4wMjQxIDI3Ni4wMzMgNDIuMTY5MyAyNzYuMDMzIDQxLjMzOThDMjc2LjAzMyA0MC4xNzE5IDI3NS44MTMgMzkuMTQ3OCAyNzUuMzczIDM4LjI2NzZDMjc0Ljk1IDM3LjM3MDQgMjc0LjMyNCAzNi42NjggMjczLjQ5NCAzNi4xNjAyQzI3Mi42NjUgMzUuNjM1NCAyNzEuNjU4IDM1LjM3MyAyNzAuNDczIDM1LjM3M0MyNjkuMTAyIDM1LjM3MyAyNjcuOTUxIDM1LjY2OTMgMjY3LjAyIDM2LjI2MTdDMjY2LjA4OSAzNi44NTQyIDI2NS4zODYgMzcuNjc1MSAyNjQuOTEyIDM4LjcyNDZDMjY0LjQzOCAzOS43NTcyIDI2NC4yMDEgNDAuOTQyMSAyNjQuMjAxIDQyLjI3OTNIMjU4LjA4MkMyNTguMDgyIDQwLjEyOTYgMjU4LjU3MyAzOC4xNjYgMjU5LjU1NSAzNi4zODg3QzI2MC41MzYgMzQuNTk0NCAyNjEuOTU4IDMzLjE3MjUgMjYzLjgyIDMyLjEyM0MyNjUuNjgyIDMxLjA1NjYgMjY3LjkyNSAzMC41MjM0IDI3MC41NDkgMzAuNTIzNEMyNzMuMDIgMzAuNTIzNCAyNzUuMTE5IDMwLjkzODIgMjc2Ljg0NiAzMS43Njc2QzI3OC41NzIgMzIuNTk3IDI3OS44ODQgMzMuNzczNCAyODAuNzgxIDM1LjI5NjlDMjgxLjY5NSAzNi44MjAzIDI4Mi4xNTIgMzguNjIzIDI4Mi4xNTIgNDAuNzA1MUMyODIuMTUyIDQxLjg1NjEgMjgxLjk2NiA0Mi45OTg3IDI4MS41OTQgNDQuMTMyOEMyODEuMjIxIDQ1LjI2NjkgMjgwLjY4OCA0Ni40MDEgMjc5Ljk5NCA0Ny41MzUyQzI3OS4zMTcgNDguNjUyMyAyNzguNTEzIDQ5Ljc3OCAyNzcuNTgyIDUwLjkxMjFDMjc2LjY1MSA1Mi4wMjkzIDI3NS42MjcgNTMuMTYzNCAyNzQuNTEgNTQuMzE0NUwyNjYuNTEyIDYzLjEyNUgyODMuNTc0Wk0zMTIuMjE5IDYzLjEyNVY2OEgyODcuNDM4VjYzLjgxMDVMMjk5LjQ3MyA1MC42ODM2QzMwMC43OTMgNDkuMTk0IDMwMS44MzQgNDcuOTA3NiAzMDIuNTk2IDQ2LjgyNDJDMzAzLjM1OCA0NS43NDA5IDMwMy44OTEgNDQuNzY3NiAzMDQuMTk1IDQzLjkwNDNDMzA0LjUxNyA0My4wMjQxIDMwNC42NzggNDIuMTY5MyAzMDQuNjc4IDQxLjMzOThDMzA0LjY3OCA0MC4xNzE5IDMwNC40NTggMzkuMTQ3OCAzMDQuMDE4IDM4LjI2NzZDMzAzLjU5NSAzNy4zNzA0IDMwMi45NjggMzYuNjY4IDMwMi4xMzkgMzYuMTYwMkMzMDEuMzA5IDM1LjYzNTQgMzAwLjMwMiAzNS4zNzMgMjk5LjExNyAzNS4zNzNDMjk3Ljc0NiAzNS4zNzMgMjk2LjU5NSAzNS42NjkzIDI5NS42NjQgMzYuMjYxN0MyOTQuNzMzIDM2Ljg1NDIgMjk0LjAzMSAzNy42NzUxIDI5My41NTcgMzguNzI0NkMyOTMuMDgzIDM5Ljc1NzIgMjkyLjg0NiA0MC45NDIxIDI5Mi44NDYgNDIuMjc5M0gyODYuNzI3QzI4Ni43MjcgNDAuMTI5NiAyODcuMjE4IDM4LjE2NiAyODguMTk5IDM2LjM4ODdDMjg5LjE4MSAzNC41OTQ0IDI5MC42MDMgMzMuMTcyNSAyOTIuNDY1IDMyLjEyM0MyOTQuMzI3IDMxLjA1NjYgMjk2LjU3IDMwLjUyMzQgMjk5LjE5NCAzMC41MjM0QzMwMS42NjUgMzAuNTIzNCAzMDMuNzY0IDMwLjkzODIgMzA1LjQ5IDMxLjc2NzZDMzA3LjIxNyAzMi41OTcgMzA4LjUyOSAzMy43NzM0IDMwOS40MjYgMzUuMjk2OUMzMTAuMzQgMzYuODIwMyAzMTAuNzk3IDM4LjYyMyAzMTAuNzk3IDQwLjcwNTFDMzEwLjc5NyA0MS44NTYxIDMxMC42MTEgNDIuOTk4NyAzMTAuMjM4IDQ0LjEzMjhDMzA5Ljg2NiA0NS4yNjY5IDMwOS4zMzMgNDYuNDAxIDMwOC42MzkgNDcuNTM1MkMzMDcuOTYyIDQ4LjY1MjMgMzA3LjE1OCA0OS43NzggMzA2LjIyNyA1MC45MTIxQzMwNS4yOTYgNTIuMDI5MyAzMDQuMjcyIDUzLjE2MzQgMzAzLjE1NCA1NC4zMTQ1TDI5NS4xNTYgNjMuMTI1SDMxMi4yMTlaTTMxNi41NjUgMzcuMzAyN0MzMTYuNTY1IDM2LjA2NzEgMzE2Ljg2OSAzNC45MzI5IDMxNy40NzkgMzMuOTAwNEMzMTguMDg4IDMyLjg2NzggMzE4LjkwMSAzMi4wNDY5IDMxOS45MTYgMzEuNDM3NUMzMjAuOTQ5IDMwLjgxMTIgMzIyLjA2NiAzMC40OTggMzIzLjI2OCAzMC40OThDMzI0LjQ4NyAzMC40OTggMzI1LjU5NSAzMC44MTEyIDMyNi41OTQgMzEuNDM3NUMzMjcuNTkzIDMyLjA0NjkgMzI4LjM4OCAzMi44Njc4IDMyOC45ODEgMzMuOTAwNEMzMjkuNTkgMzQuOTMyOSAzMjkuODk1IDM2LjA2NzEgMzI5Ljg5NSAzNy4zMDI3QzMyOS44OTUgMzguNTM4NCAzMjkuNTkgMzkuNjcyNSAzMjguOTgxIDQwLjcwNTFDMzI4LjM4OCA0MS43MjA3IDMyNy41OTMgNDIuNTI0NyAzMjYuNTk0IDQzLjExNzJDMzI1LjU5NSA0My43MDk2IDMyNC40ODcgNDQuMDA1OSAzMjMuMjY4IDQ0LjAwNTlDMzIyLjA2NiA0NC4wMDU5IDMyMC45NDkgNDMuNzA5NiAzMTkuOTE2IDQzLjExNzJDMzE4LjkwMSA0Mi41MjQ3IDMxOC4wODggNDEuNzIwNyAzMTcuNDc5IDQwLjcwNTFDMzE2Ljg2OSAzOS42NzI1IDMxNi41NjUgMzguNTM4NCAzMTYuNTY1IDM3LjMwMjdaTTMxOS45OTMgMzcuMzAyN0MzMTkuOTkzIDM4LjIxNjggMzIwLjMxNCAzOC45ODcgMzIwLjk1NyAzOS42MTMzQzMyMS42MDEgNDAuMjIyNyAzMjIuMzcxIDQwLjUyNzMgMzIzLjI2OCA0MC41MjczQzMyNC4xNjUgNDAuNTI3MyAzMjQuOTE4IDQwLjIyMjcgMzI1LjUyOCAzOS42MTMzQzMyNi4xMzcgMzkuMDAzOSAzMjYuNDQyIDM4LjIzMzcgMzI2LjQ0MiAzNy4zMDI3QzMyNi40NDIgMzYuMzU0OCAzMjYuMTM3IDM1LjU2NzcgMzI1LjUyOCAzNC45NDE0QzMyNC45MTggMzQuMzE1MSAzMjQuMTY1IDM0LjAwMiAzMjMuMjY4IDM0LjAwMkMzMjIuMzcxIDM0LjAwMiAzMjEuNjAxIDM0LjMxNTEgMzIwLjk1NyAzNC45NDE0QzMyMC4zMTQgMzUuNTY3NyAzMTkuOTkzIDM2LjM1NDggMzE5Ljk5MyAzNy4zMDI3Wk0zNTcuODc5IDU1Ljk2NDhIMzY0LjIyN0MzNjQuMDI0IDU4LjM4NTQgMzYzLjM0NyA2MC41NDM2IDM2Mi4xOTYgNjIuNDM5NUMzNjEuMDQ1IDY0LjMxODQgMzU5LjQyOCA2NS43OTk1IDM1Ny4zNDYgNjYuODgyOEMzNTUuMjY0IDY3Ljk2NjEgMzUyLjczNCA2OC41MDc4IDM0OS43NTQgNjguNTA3OEMzNDcuNDY5IDY4LjUwNzggMzQ1LjQxMyA2OC4xMDE2IDM0My41ODQgNjcuMjg5MUMzNDEuNzU2IDY2LjQ1OTYgMzQwLjE5MSA2NS4yOTE3IDMzOC44ODcgNjMuNzg1MkMzMzcuNTg0IDYyLjI2MTcgMzM2LjU4NSA2MC40MjUxIDMzNS44OTEgNTguMjc1NEMzMzUuMjE0IDU2LjEyNTcgMzM0Ljg3NSA1My43MjIgMzM0Ljg3NSA1MS4wNjQ1VjQ3Ljk5MjJDMzM0Ljg3NSA0NS4zMzQ2IDMzNS4yMjIgNDIuOTMxIDMzNS45MTYgNDAuNzgxMkMzMzYuNjI3IDM4LjYzMTUgMzM3LjY0MyAzNi43OTQ5IDMzOC45NjMgMzUuMjcxNUMzNDAuMjg0IDMzLjczMTEgMzQxLjg2NiAzMi41NTQ3IDM0My43MTEgMzEuNzQyMkMzNDUuNTczIDMwLjkyOTcgMzQ3LjY2NCAzMC41MjM0IDM0OS45ODMgMzAuNTIzNEMzNTIuOTI4IDMwLjUyMzQgMzU1LjQxNiAzMS4wNjUxIDM1Ny40NDggMzIuMTQ4NEMzNTkuNDc5IDMzLjIzMTggMzYxLjA1MyAzNC43Mjk4IDM2Mi4xNyAzNi42NDI2QzM2My4zMDUgMzguNTU1MyAzNjMuOTk5IDQwLjc0NzQgMzY0LjI1MiA0My4yMTg4SDM1Ny45MDVDMzU3LjczNSA0MS42Mjc2IDM1Ny4zNjMgNDAuMjY1IDM1Ni43ODggMzkuMTMwOUMzNTYuMjI5IDM3Ljk5NjcgMzU1LjQgMzcuMTMzNSAzNTQuMjk5IDM2LjU0MUMzNTMuMTk5IDM1LjkzMTYgMzUxLjc2IDM1LjYyNyAzNDkuOTgzIDM1LjYyN0MzNDguNTI3IDM1LjYyNyAzNDcuMjU4IDM1Ljg5NzggMzQ2LjE3NCAzNi40Mzk1QzM0NS4wOTEgMzYuOTgxMSAzNDQuMTg1IDM3Ljc3NjcgMzQzLjQ1NyAzOC44MjYyQzM0Mi43MyAzOS44NzU3IDM0Mi4xOCA0MS4xNzA2IDM0MS44MDcgNDIuNzEwOUMzNDEuNDUyIDQ0LjIzNDQgMzQxLjI3NCA0NS45Nzc5IDM0MS4yNzQgNDcuOTQxNFY1MS4wNjQ1QzM0MS4yNzQgNTIuOTI2NCAzNDEuNDM1IDU0LjYxOTEgMzQxLjc1NiA1Ni4xNDI2QzM0Mi4wOTUgNTcuNjQ5MSAzNDIuNjAzIDU4Ljk0NCAzNDMuMjggNjAuMDI3M0MzNDMuOTc0IDYxLjExMDcgMzQ0Ljg1NCA2MS45NDg2IDM0NS45MiA2Mi41NDFDMzQ2Ljk4NyA2My4xMzM1IDM0OC4yNjUgNjMuNDI5NyAzNDkuNzU0IDYzLjQyOTdDMzUxLjU2NiA2My40Mjk3IDM1My4wMyA2My4xNDE5IDM1NC4xNDcgNjIuNTY2NEMzNTUuMjgxIDYxLjk5MDkgMzU2LjEzNiA2MS4xNTMgMzU2LjcxMSA2MC4wNTI3QzM1Ny4zMDQgNTguOTM1NSAzNTcuNjkzIDU3LjU3MjkgMzU3Ljg3OSA1NS45NjQ4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8L2c+CjxkZWZzPgo8ZmlsdGVyIGlkPSJmaWx0ZXIwX2RfMTI0Nl80NDQ0NyIgeD0iMCIgeT0iMCIgd2lkdGg9IjM5OSIgaGVpZ2h0PSIxMDgiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz4KPGZlQ29sb3JNYXRyaXggaW49IlNvdXJjZUFscGhhIiB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMTI3IDAiIHJlc3VsdD0iaGFyZEFscGhhIi8+CjxmZU9mZnNldCBkeT0iNCIvPgo8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI0Ii8+CjxmZUNvbXBvc2l0ZSBpbjI9ImhhcmRBbHBoYSIgb3BlcmF0b3I9Im91dCIvPgo8ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMC4wNCAwIi8+CjxmZUJsZW5kIG1vZGU9Im5vcm1hbCIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0iZWZmZWN0MV9kcm9wU2hhZG93XzEyNDZfNDQ0NDciLz4KPGZlQmxlbmQgbW9kZT0ibm9ybWFsIiBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3dfMTI0Nl80NDQ0NyIgcmVzdWx0PSJzaGFwZSIvPgo8L2ZpbHRlcj4KPC9kZWZzPgo8L3N2Zz4K", + "description": "Designed to display single value of the selected attribute or timeseries data. Widget styles are customizable.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n absoluteHeader: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\"}" + } } ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/charts.json b/application/src/main/data/json/system/widget_bundles/charts.json index 7ccce1d8c6..8dac2b5f5f 100644 --- a/application/src/main/data/json/system/widget_bundles/charts.json +++ b/application/src/main/data/json/system/widget_bundles/charts.json @@ -161,7 +161,9 @@ "settingsDirective": "tb-flot-line-widget-settings", "dataKeySettingsDirective": "tb-flot-line-key-settings", "latestDataKeySettingsDirective": "tb-flot-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":0,\"max\":1.2,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"timeForComparison\":\"previousInterval\",\"comparisonCustomIntervalValue\":7200000,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"right\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"dataKeysListForLabels\":[]},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}" + "hasBasicMode": true, + "basicModeDirective": "tb-flot-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":0,\"max\":1.2,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"timeForComparison\":\"previousInterval\",\"comparisonCustomIntervalValue\":7200000,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"right\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"dataKeysListForLabels\":[]},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false},\"configMode\":\"basic\",\"showTitleIcon\":false,\"titleIcon\":\"waterfall_chart\",\"iconColor\":\"#1F6BDD\"}" } }, { @@ -183,7 +185,9 @@ "settingsDirective": "tb-flot-line-widget-settings", "dataKeySettingsDirective": "tb-flot-line-key-settings", "latestDataKeySettingsDirective": "tb-flot-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Line Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" + "hasBasicMode": true, + "basicModeDirective": "tb-flot-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Line Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":false,\"titleIcon\":\"thermostat\",\"iconColor\":\"#1F6BDD\"}" } }, { @@ -204,7 +208,9 @@ "settingsDirective": "tb-flot-bar-widget-settings", "dataKeySettingsDirective": "tb-flot-bar-key-settings", "latestDataKeySettingsDirective": "tb-flot-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":true,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"defaultBarWidth\":600,\"barAlignment\":\"left\",\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Bar Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{}}" + "hasBasicMode": true, + "basicModeDirective": "tb-flot-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":true,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"defaultBarWidth\":600,\"barAlignment\":\"left\",\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Bar Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"configMode\":\"basic\",\"showTitleIcon\":false,\"titleIcon\":\"thermostat\",\"iconColor\":\"#1F6BDD\"}" } } ] diff --git a/application/src/main/data/json/system/widget_bundles/input_widgets.json b/application/src/main/data/json/system/widget_bundles/input_widgets.json index ca2e16e4dd..e8856b5d97 100644 --- a/application/src/main/data/json/system/widget_bundles/input_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/input_widgets.json @@ -498,7 +498,7 @@ "settingsSchema": "", "dataKeySettingsSchema": "{}", "settingsDirective": "tb-update-json-attribute-widget-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"attributeScope\":\"SERVER_SCOPE\",\"showLabel\":true,\"attributeRequired\":true,\"showResultMessage\":true},\"title\":\"Update JSON attribute\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"widgetMode\":\"ATTRIBUTE\",\"attributeScope\":\"SERVER_SCOPE\",\"showLabel\":true,\"attributeRequired\":true,\"showResultMessage\":true},\"title\":\"Update JSON attribute\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" } } ] diff --git a/application/src/main/data/upgrade/3.5.1/schema_update.sql b/application/src/main/data/upgrade/3.5.1/schema_update.sql index 58031ce5c0..1655ecb978 100644 --- a/application/src/main/data/upgrade/3.5.1/schema_update.sql +++ b/application/src/main/data/upgrade/3.5.1/schema_update.sql @@ -53,6 +53,69 @@ $$; -- NOTIFICATION CONFIGS VERSION CONTROL END +-- EDGE EVENTS MIGRATION START +DO +$$ + DECLARE table_partition RECORD; + BEGIN + -- in case of running the upgrade script a second time: + IF NOT (SELECT exists(SELECT FROM pg_tables WHERE tablename = 'old_edge_event')) THEN + ALTER TABLE edge_event RENAME TO old_edge_event; + CREATE INDEX IF NOT EXISTS idx_old_edge_event_created_time_tmp ON old_edge_event(created_time); + ALTER INDEX IF EXISTS idx_edge_event_tenant_id_and_created_time RENAME TO idx_old_edge_event_tenant_id_and_created_time; + + FOR table_partition IN SELECT tablename AS name, split_part(tablename, '_', 3) AS partition_ts + FROM pg_tables WHERE tablename LIKE 'edge_event_%' + LOOP + EXECUTE format('ALTER TABLE %s RENAME TO old_edge_event_%s', table_partition.name, table_partition.partition_ts); + END LOOP; + ELSE + RAISE NOTICE 'Table old_edge_event already exists, leaving as is'; + END IF; + END; +$$; + +CREATE TABLE IF NOT EXISTS edge_event ( + seq_id INT GENERATED ALWAYS AS IDENTITY, + id uuid NOT NULL, + created_time bigint NOT NULL, + edge_id uuid, + edge_event_type varchar(255), + edge_event_uid varchar(255), + entity_id uuid, + edge_event_action varchar(255), + body varchar(10000000), + tenant_id uuid, + ts bigint NOT NULL +) PARTITION BY RANGE (created_time); +CREATE INDEX IF NOT EXISTS idx_edge_event_tenant_id_and_created_time ON edge_event(tenant_id, created_time DESC); +CREATE INDEX IF NOT EXISTS idx_edge_event_id ON edge_event(id); +ALTER TABLE IF EXISTS edge_event ALTER COLUMN seq_id SET CYCLE; + +CREATE OR REPLACE PROCEDURE migrate_edge_event(IN start_time_ms BIGINT, IN end_time_ms BIGINT, IN partition_size_ms BIGINT) + LANGUAGE plpgsql AS +$$ +DECLARE + p RECORD; + partition_end_ts BIGINT; +BEGIN + FOR p IN SELECT DISTINCT (created_time - created_time % partition_size_ms) AS partition_ts FROM old_edge_event + WHERE created_time >= start_time_ms AND created_time < end_time_ms + LOOP + partition_end_ts = p.partition_ts + partition_size_ms; + RAISE NOTICE '[edge_event] Partition to create : [%-%]', p.partition_ts, partition_end_ts; + EXECUTE format('CREATE TABLE IF NOT EXISTS edge_event_%s PARTITION OF edge_event ' || + 'FOR VALUES FROM ( %s ) TO ( %s )', p.partition_ts, p.partition_ts, partition_end_ts); + END LOOP; + + INSERT INTO edge_event (id, created_time, edge_id, edge_event_type, edge_event_uid, entity_id, edge_event_action, body, tenant_id, ts) + SELECT id, created_time, edge_id, edge_event_type, edge_event_uid, entity_id, edge_event_action, body, tenant_id, ts + FROM old_edge_event + WHERE created_time >= start_time_ms AND created_time < end_time_ms; +END; +$$; +-- EDGE EVENTS MIGRATION END + ALTER TABLE resource ADD COLUMN IF NOT EXISTS etag varchar; diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index e04c7052db..fc822ce226 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -536,6 +536,10 @@ public class ActorSystemContext { @Getter private int maxRpcRetries; + @Value("${actors.rule.external.force_ack:false}") + @Getter + private boolean externalNodeForceAck; + @Getter @Setter private TbActorSystem actorSystem; diff --git a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java index fb6fbbdff2..1461654216 100644 --- a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java @@ -73,10 +73,14 @@ public class AppActor extends ContextAwareActor { @Override protected boolean doProcess(TbActorMsg msg) { if (!ruleChainsInitialized) { - initTenantActors(); - ruleChainsInitialized = true; - if (msg.getMsgType() != MsgType.APP_INIT_MSG && msg.getMsgType() != MsgType.PARTITION_CHANGE_MSG) { - log.warn("Rule Chains initialized by unexpected message: {}", msg); + if (MsgType.APP_INIT_MSG.equals(msg.getMsgType())) { + initTenantActors(); + ruleChainsInitialized = true; + } else { + if (!msg.getMsgType().isIgnoreOnStart()) { + log.warn("Attempt to initialize Rule Chains by unexpected message: {}", msg); + } + return true; } } switch (msg.getMsgType()) { diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 8b76924d96..30d909cd5a 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -34,6 +34,7 @@ import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.rule.engine.api.ScriptEngine; import org.thingsboard.rule.engine.api.SmsService; import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.rule.engine.api.slack.SlackService; import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; @@ -214,6 +215,12 @@ class DefaultTbContext implements TbContext { enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbRelationTypes.FAILURE), failureMessage, null, null); } + @Override + public void enqueueForTellFailure(TbMsg tbMsg, Throwable th) { + TopicPartitionInfo tpi = resolvePartition(tbMsg); + enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbRelationTypes.FAILURE), getFailureMessage(th), null, null); + } + @Override public void enqueueForTellNext(TbMsg tbMsg, String relationType) { TopicPartitionInfo tpi = resolvePartition(tbMsg); @@ -311,16 +318,7 @@ class DefaultTbContext implements TbContext { if (nodeCtx.getSelf().isDebugMode()) { mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th); } - String failureMessage; - if (th != null) { - if (!StringUtils.isEmpty(th.getMessage())) { - failureMessage = th.getMessage(); - } else { - failureMessage = th.getClass().getSimpleName(); - } - } else { - failureMessage = null; - } + String failureMessage = getFailureMessage(th); nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), msg, failureMessage)); @@ -724,6 +722,11 @@ class DefaultTbContext implements TbContext { return mainCtx.getSlackService(); } + @Override + public boolean isExternalNodeForceAck() { + return mainCtx.isExternalNodeForceAck(); + } + @Override public RuleEngineRpcService getRpcService() { return mainCtx.getTbRuleEngineDeviceRpcService(); @@ -840,10 +843,24 @@ class DefaultTbContext implements TbContext { } @Override - public void checkTenantEntity(EntityId entityId) { + public void checkTenantEntity(EntityId entityId) throws TbNodeException { if (!this.getTenantId().equals(TenantIdLoader.findTenantId(this, entityId))) { - throw new RuntimeException("Entity with id: '" + entityId + "' specified in the configuration doesn't belong to the current tenant."); + throw new TbNodeException("Entity with id: '" + entityId + "' specified in the configuration doesn't belong to the current tenant.", true); + } + } + + private static String getFailureMessage(Throwable th) { + String failureMessage; + if (th != null) { + if (!StringUtils.isEmpty(th.getMessage())) { + failureMessage = th.getMessage(); + } else { + failureMessage = th.getClass().getSimpleName(); + } + } else { + failureMessage = null; } + return failureMessage; } private class SimpleTbQueueCallback implements TbQueueCallback { diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java index 9534104ec1..7f919754fc 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java @@ -23,6 +23,7 @@ import org.thingsboard.server.actors.TbEntityActorId; import org.thingsboard.server.actors.TbEntityTypeActorIdPredicate; import org.thingsboard.server.actors.service.ContextAwareActor; import org.thingsboard.server.actors.service.DefaultActorService; +import org.thingsboard.server.actors.shared.RuleChainErrorActor; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; @@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.msg.TbActorMsg; +import org.thingsboard.server.common.msg.queue.RuleEngineException; import org.thingsboard.server.dao.rule.RuleChainService; import java.util.function.Function; @@ -86,7 +88,12 @@ public abstract class RuleChainManagerActor extends ContextAwareActor { () -> DefaultActorService.RULE_DISPATCHER_NAME, () -> { RuleChain ruleChain = provider.apply(ruleChainId); - return new RuleChainActor.ActorCreator(systemContext, tenantId, ruleChain); + if (ruleChain == null) { + return new RuleChainErrorActor.ActorCreator(systemContext, tenantId, + new RuleEngineException("Rule Chain with id: " + ruleChainId + " not found!")); + } else { + return new RuleChainActor.ActorCreator(systemContext, tenantId, ruleChain); + } }); } diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/RuleChainErrorActor.java b/application/src/main/java/org/thingsboard/server/actors/shared/RuleChainErrorActor.java new file mode 100644 index 0000000000..a204c7b286 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/actors/shared/RuleChainErrorActor.java @@ -0,0 +1,78 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.actors.shared; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.actors.ActorSystemContext; +import org.thingsboard.server.actors.TbActor; +import org.thingsboard.server.actors.TbActorId; +import org.thingsboard.server.actors.TbStringActorId; +import org.thingsboard.server.actors.service.ContextAwareActor; +import org.thingsboard.server.actors.service.ContextBasedCreator; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.msg.TbActorMsg; +import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; +import org.thingsboard.server.common.msg.queue.RuleEngineException; + +import java.util.UUID; + +@Slf4j +public class RuleChainErrorActor extends ContextAwareActor { + + private final TenantId tenantId; + private final RuleEngineException error; + + private RuleChainErrorActor(ActorSystemContext systemContext, TenantId tenantId, RuleEngineException error) { + super(systemContext); + this.tenantId = tenantId; + this.error = error; + } + + @Override + protected boolean doProcess(TbActorMsg msg) { + if (msg instanceof RuleChainAwareMsg) { + log.debug("[{}] Reply with {} for message {}", tenantId, error.getMessage(), msg); + var rcMsg = (RuleChainAwareMsg) msg; + rcMsg.getMsg().getCallback().onFailure(error); + return true; + } else { + return false; + } + } + + public static class ActorCreator extends ContextBasedCreator { + + private final TenantId tenantId; + private final RuleEngineException error; + + public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleEngineException error) { + super(context); + this.tenantId = tenantId; + this.error = error; + } + + @Override + public TbActorId createActorId() { + return new TbStringActorId(UUID.randomUUID().toString()); + } + + @Override + public TbActor createActor() { + return new RuleChainErrorActor(context, tenantId, error); + } + } + +} diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java index 793670f0ab..7acc77a183 100644 --- a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java @@ -19,9 +19,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; +import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; import org.springframework.security.config.annotation.ObjectPostProcessor; @@ -29,7 +31,6 @@ import org.springframework.security.config.annotation.authentication.builders.Au import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; @@ -37,9 +38,11 @@ import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.header.writers.StaticHeadersWriter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; +import org.springframework.web.filter.ShallowEtagHeaderFilter; import org.thingsboard.server.dao.oauth2.OAuth2Configuration; import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -78,6 +81,7 @@ public class ThingsboardSecurityConfiguration { public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; public static final String MAIL_OAUTH2_PROCESSING_ENTRY_POINT = "/api/admin/mail/oauth2/code"; + public static final String DEVICE_CONNECTIVITY_CERTIFICATE_DOWNLOAD_ENTRY_POINT = "/api/device-connectivity/mqtts/certificate/download"; @Autowired private ThingsboardErrorResponseHandler restAccessDeniedHandler; @@ -119,6 +123,17 @@ public class ThingsboardSecurityConfiguration { @Autowired private RateLimitProcessingFilter rateLimitProcessingFilter; + @Bean + protected FilterRegistrationBean buildEtagFilter() throws Exception { + ShallowEtagHeaderFilter etagFilter = new ShallowEtagHeaderFilter(); + etagFilter.setWriteWeakETag(true); + FilterRegistrationBean filterRegistrationBean + = new FilterRegistrationBean<>( etagFilter); + filterRegistrationBean.addUrlPatterns("*.js","*.css","*.ico","/assets/*","/static/*"); + filterRegistrationBean.setName("etagFilter"); + return filterRegistrationBean; + } + @Bean protected RestLoginProcessingFilter buildRestLoginProcessingFilter() throws Exception { RestLoginProcessingFilter filter = new RestLoginProcessingFilter(FORM_BASED_LOGIN_ENTRY_POINT, successHandler, failureHandler); @@ -136,7 +151,8 @@ public class ThingsboardSecurityConfiguration { protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception { List pathsToSkip = new ArrayList<>(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, - PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT, MAIL_OAUTH2_PROCESSING_ENTRY_POINT)); + PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT, MAIL_OAUTH2_PROCESSING_ENTRY_POINT, + DEVICE_CONNECTIVITY_CERTIFICATE_DOWNLOAD_ENTRY_POINT)); SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT); JwtTokenAuthenticationProcessingFilter filter = new JwtTokenAuthenticationProcessingFilter(failureHandler, jwtHeaderTokenExtractor, matcher); @@ -181,8 +197,18 @@ public class ThingsboardSecurityConfiguration { private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver; @Bean - public WebSecurityCustomizer webSecurityCustomizer() { - return (web) -> web.ignoring().antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**"); + @Order(0) + SecurityFilterChain resources(HttpSecurity http) throws Exception { + http + .requestMatchers((matchers) -> matchers.antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**")) + .headers().defaultsDisabled() + .addHeaderWriter(new StaticHeadersWriter(HttpHeaders.CACHE_CONTROL, "max-age=0, public")) + .and() + .authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll()) + .requestCache().disable() + .securityContext().disable() + .sessionManagement().disable(); + return http.build(); } @Bean @@ -204,6 +230,7 @@ public class ThingsboardSecurityConfiguration { .antMatchers(PUBLIC_LOGIN_ENTRY_POINT).permitAll() // Public login end-point .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point .antMatchers(MAIL_OAUTH2_PROCESSING_ENTRY_POINT).permitAll() // Mail oauth2 code processing url + .antMatchers(DEVICE_CONNECTIVITY_CERTIFICATE_DOWNLOAD_ENTRY_POINT).permitAll() // Mail oauth2 code processing url .antMatchers(NON_TOKEN_BASED_AUTH_ENTRY_POINTS).permitAll() // static resources, user activation and password reset end-points .and() .authorizeRequests() diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index 1cb794c2ec..f31cebd258 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -24,6 +24,7 @@ public class ControllerConstants { protected static final String CUSTOMER_ID = "customerId"; protected static final String TENANT_ID = "tenantId"; protected static final String DEVICE_ID = "deviceId"; + protected static final String PROTOCOL = "protocol"; protected static final String EDGE_ID = "edgeId"; protected static final String RPC_ID = "rpcId"; protected static final String ENTITY_ID = "entityId"; @@ -34,6 +35,7 @@ public class ControllerConstants { protected static final String DASHBOARD_ID_PARAM_DESCRIPTION = "A string value representing the dashboard id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String RPC_ID_PARAM_DESCRIPTION = "A string value representing the rpc id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String PROTOCOL_PARAM_DESCRIPTION = "A string value representing the device connectivity protocol. Possible values: 'mqtt', 'mqtts', 'http', 'https', 'coap', 'coaps'"; protected static final String ENTITY_VIEW_ID_PARAM_DESCRIPTION = "A string value representing the entity view id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String DEVICE_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; @@ -207,42 +209,222 @@ public class ControllerConstants { protected static final String IS_BOOTSTRAP_SERVER_PARAM_DESCRIPTION = "A Boolean value representing the Server SecurityInfo for future Bootstrap client mode settings. Values: 'true' for Bootstrap Server; 'false' for Lwm2m Server. "; - protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION = + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_ACCESS_TOKEN_PARAM_DESCRIPTION = "{\n" + " \"device\": {\n" + - " \"name\": \"LwRpk00000000\",\n" + - " \"type\": \"lwm2mProfileRpk\"\n" + - " },\n" + + " \"name\":\"Name_DeviceWithCredantial_AccessToken\",\n" + + " \"label\":\"Label_DeviceWithCredantial_AccessToken\",\n" + + " \"deviceProfileId\":{\n" + + " \"id\":\"9d9588c0-06c9-11ee-b618-19be30fdeb60\",\n" + + " \"entityType\":\"DEVICE_PROFILE\"\n" + + " }\n" + + " },\n" + " \"credentials\": {\n" + - " \"id\": \"null\",\n" + - " \"createdTime\": 0,\n" + - " \"deviceId\": \"null\",\n" + - " \"credentialsType\": \"LWM2M_CREDENTIALS\",\n" + - " \"credentialsId\": \"LwRpk00000000\",\n" + - " \"credentialsValue\": {\n" + - " \"client\": {\n" + - " \"endpoint\": \"LwRpk00000000\",\n" + - " \"securityConfigClientMode\": \"RPK\",\n" + - " \"key\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\"\n" + - " },\n" + - " \"bootstrap\": {\n" + - " \"bootstrapServer\": {\n" + - " \"securityMode\": \"RPK\",\n" + - " \"clientPublicKeyOrId\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\",\n" + - " \"clientSecretKey\": \"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\"\n" + - " },\n" + - " \"lwm2mServer\": {\n" + - " \"securityMode\": \"RPK\",\n" + - " \"clientPublicKeyOrId\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\",\n" + - " \"clientSecretKey\": \"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\"\n" + - " }\n" + - " }\n" + - " }\n" + - " }\n" + + " \"credentialsType\": \"ACCESS_TOKEN\",\n" + + " \"credentialsId\": \"6hmxew8pmmzng4e3une2\"\n" + + " }\n" + "}"; - protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN = - MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_UPDATE_CREDENTIALS_ACCESS_TOKEN_PARAM_DESCRIPTION = + "{\n" + + " \"id\": {\n" + + " \"id\":\"c886a090-168d-11ee-87c9-6f157dbc816a\"\n" + + " },\n" + + " \"deviceId\": {\n" + + " \"id\":\"c5fb3ac0-168d-11ee-87c9-6f157dbc816a\",\n" + + " \"entityType\":\"DEVICE\"\n" + + " },\n" + + " \"credentialsType\": \"ACCESS_TOKEN\",\n" + + " \"credentialsId\": \"6hmxew8pmmzng4e3une4\"\n" + + "}"; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_ACCESS_TOKEN_DEFAULT_PARAM_DESCRIPTION = + "{\n" + + " \"device\": {\n" + + " \"name\":\"Name_DeviceWithCredantial_AccessToken_Default\",\n" + + " \"label\":\"Label_DeviceWithCredantial_AccessToken_Default\",\n" + + " \"type\": \"default\"\n" + + " },\n" + + " \"credentials\": {\n" + + " \"credentialsType\": \"ACCESS_TOKEN\",\n" + + " \"credentialsId\": \"6hmxew8pmmzng4e3une3\"\n" + + " }\n" + + "}"; + + protected static final String certificateValue = "\"-----BEGIN CERTIFICATE----- " + + "MIICMTCCAdegAwIBAgIUI9dBuwN6pTtK6uZ03rkiCwV4wEYwCgYIKoZIzj0EAwIwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlQ2VydGlmaWNhdGVAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MB4XDTIzMDMyOTE0NTYxN1oXDTI0MDMyODE0NTYxN1owbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlQ2VydGlmaWNhdGVAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9Zo791qKQiGNBm11r4ZGxh+w+ossZL3xc46ufq5QckQHP7zkD2XDAcmP5GvdkM1sBFN9AWaCkQfNnWmfERsOOKNTMFEwHQYDVR0OBBYEFFFc5uyCyglQoZiKhzXzMcQ3BKORMB8GA1UdIwQYMBaAFFFc5uyCyglQoZiKhzXzMcQ3BKORMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhANbA9CuhoOifZMMmqkpuld+65CR+ItKdXeRAhLMZuccuAiB0FSQB34zMutXrZj1g8Gl5OkE7YryFHbei1z0SveHR8g== " + + "-----END CERTIFICATE-----\""; + + protected static final String certificateId = "\"84f5911765abba1f96bf4165604e9e90338fc6214081a8e623b6ff9669aedb27\""; + + protected static final String certificateValueUpdate = "\"-----BEGIN CERTIFICATE----- " + + "MIICMTCCAdegAwIBAgIUUEKxS9hTz4l+oLUMF0LV6TC/gCIwCgYIKoZIzj0EAwIwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlUHJvZmlsZUNlcnRAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MB4XDTIzMDMyOTE0NTczNloXDTI0MDMyODE0NTczNlowbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlUHJvZmlsZUNlcnRAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECMlWO72krDoUL9FQjUmSCetkhaEGJUfQkdSfkLSNa0GyAEIMbfmzI4zITeapunu4rGet3EMyLydQzuQanBicp6NTMFEwHQYDVR0OBBYEFHpZ78tPnztNii4Da/yCw6mhEIL3MB8GA1UdIwQYMBaAFHpZ78tPnztNii4Da/yCw6mhEIL3MA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgJ7qyMFqNcwSYkH6o+UlQXzLWfwZbNjVk+aR7foAZNGsCIQDsd7v3WQIGHiArfZeDs1DLEDuV/2h6L+ZNoGNhEKL+1A== " + + "-----END CERTIFICATE-----\""; + + protected static final String certificateIdUpdate = "\"6b8adb49015500e51a527acd332b51684ab9b49b4ade03a9582a44c455e2e9b6\""; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_X509_CERTIFICATE_PARAM_DESCRIPTION = + "{\n" + + " \"device\": {\n" + + " \"name\":\"Name_DeviceWithCredantial_X509_Certificate\",\n" + + " \"label\":\"Label_DeviceWithCredantial_X509_Certificate\",\n" + + " \"deviceProfileId\":{\n" + + " \"id\":\"9d9588c0-06c9-11ee-b618-19be30fdeb60\",\n" + + " \"entityType\":\"DEVICE_PROFILE\"\n" + + " }\n" + + " },\n" + + " \"credentials\": {\n" + + " \"credentialsType\": \"X509_CERTIFICATE\",\n" + + " \"credentialsId\": " + certificateId + ",\n" + + " \"credentialsValue\": " + certificateValue + "\n" + + " }\n" + + "}"; + + protected static final String DEVICE_UPDATE_CREDENTIALS_X509_CERTIFICATE_PARAM_DESCRIPTION = + "{\n" + + " \"id\": {\n" + + " \"id\":\"309bd9c0-14f4-11ee-9fc9-d9b7463abb63\"\n" + + " },\n" + + " \"deviceId\": {\n" + + " \"id\":\"3092b200-14f4-11ee-9fc9-d9b7463abb63\",\n" + + " \"entityType\":\"DEVICE\"\n" + + " },\n" + + " \"credentialsType\": \"X509_CERTIFICATE\",\n" + + " \"credentialsId\": " + certificateIdUpdate + ",\n" + + " \"credentialsValue\": " + certificateValueUpdate + "\n" + + "}"; + + protected static final String MQTT_BASIC_VALUE = "\"{\\\"clientId\\\":\\\"5euh5nzm34bjjh1efmlt\\\",\\\"userName\\\":\\\"onasd1lgwasmjl7v2v7h\\\",\\\"password\\\":\\\"b9xtm4ny8kt9zewaga5o\\\"}\""; + + protected static final String MQTT_BASIC_VALUE_UPDATE = "\"{\\\"clientId\\\":\\\"juy03yv4owqxcmqhqtvk\\\",\\\"userName\\\":\\\"ov19fxca0cyjn7lm7w7u\\\",\\\"password\\\":\\\"twy94he114dfi9usyk1o\\\"}\""; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_MQTT_BASIC_PARAM_DESCRIPTION = + "{\n" + + " \"device\": {\n" + + " \"name\":\"Name_DeviceWithCredantial_MQTT_Basic\",\n" + + " \"label\":\"Label_DeviceWithCredantial_MQTT_Basic\",\n" + + " \"deviceProfileId\":{\n" + + " \"id\":\"9d9588c0-06c9-11ee-b618-19be30fdeb60\",\n" + + " \"entityType\":\"DEVICE_PROFILE\"\n" + + " }\n" + + " },\n" + + " \"credentials\": {\n" + + " \"credentialsType\": \"MQTT_BASIC\",\n" + + " \"credentialsValue\": " + MQTT_BASIC_VALUE + "\n" + + " }\n" + + "}"; + + protected static final String DEVICE_UPDATE_CREDENTIALS_MQTT_BASIC_PARAM_DESCRIPTION = + "{\n" + + " \"id\": {\n" + + " \"id\":\"d877ffb0-14f5-11ee-9fc9-d9b7463abb63\"\n" + + " },\n" + + " \"deviceId\": {\n" + + " \"id\":\"d875dcd0-14f5-11ee-9fc9-d9b7463abb63\",\n" + + " \"entityType\":\"DEVICE\"\n" + + " },\n" + + " \"credentialsType\": \"MQTT_BASIC\",\n" + + " \"credentialsValue\": " + MQTT_BASIC_VALUE_UPDATE + "\n" + + "}"; + + protected static final String CREDENTIALS_VALUE_LVM2M_RPK_DESCRIPTION = + " \"{" + + "\\\"client\\\":{ " + + "\\\"endpoint\\\":\\\"LwRpk00000000\\\", " + + "\\\"securityConfigClientMode\\\":\\\"RPK\\\", " + + "\\\"key\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\\\"" + + " }, " + + "\\\"bootstrap\\\":{ " + + "\\\"bootstrapServer\\\":{ " + + "\\\"securityMode\\\":\\\"RPK\\\", " + + "\\\"clientPublicKeyOrId\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\\\", " + + "\\\"clientSecretKey\\\":\\\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\\\"" + + "}, " + + "\\\"lwm2mServer\\\":{ \\\"securityMode\\\":\\\"RPK\\\", " + + "\\\"clientPublicKeyOrId\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\\\", " + + "\\\"clientSecretKey\\\":\\\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\\\"" + + "}" + + "} " + + "}\""; + + protected static final String CREDENTIALS_VALUE_UPDATE_LVM2M_RPK_DESCRIPTION = + " \"{" + + "\\\"client\\\":{ " + + "\\\"endpoint\\\":\\\"LwRpk00000000\\\", " + + "\\\"securityConfigClientMode\\\":\\\"RPK\\\", " + + "\\\"key\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdvBZZ2vQRK9wgDhctj6B1c7bxR3Z0wYg1+YdoYFnVUKWb+rIfTTyYK9tmQJx5Vlb5fxdLnVv1RJOPiwsLIQbAA==\\\"" + + " }, " + + "\\\"bootstrap\\\":{ " + + "\\\"bootstrapServer\\\":{ " + + "\\\"securityMode\\\":\\\"RPK\\\", " + + "\\\"clientPublicKeyOrId\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\\\", " + + "\\\"clientSecretKey\\\":\\\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\\\"" + + "}, " + + "\\\"lwm2mServer\\\":{ \\\"securityMode\\\":\\\"RPK\\\", " + + "\\\"clientPublicKeyOrId\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\\\", " + + "\\\"clientSecretKey\\\":\\\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\\\"" + + "}" + + "} " + + "}\""; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION = + "{\n" + + " \"device\": {\n" + + " \"name\":\"Name_LwRpk00000000\",\n" + + " \"label\":\"Label_LwRpk00000000\",\n" + + " \"deviceProfileId\":{\n" + + " \"id\":\"a660bd50-10ef-11ee-8737-b5634e73c779\",\n" + + " \"entityType\":\"DEVICE_PROFILE\"\n" + + " }\n" + + " },\n" + + " \"credentials\": {\n" + + " \"credentialsType\": \"LWM2M_CREDENTIALS\",\n" + + " \"credentialsId\": \"LwRpk00000000\",\n" + + " \"credentialsValue\":\n" + CREDENTIALS_VALUE_LVM2M_RPK_DESCRIPTION + "\n" + + " }\n" + + "}"; + + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION = + "{\n" + + " \"id\": {\n" + + " \"id\":\"e238d4d0-1689-11ee-98c6-1713c1be5a8e\"\n" + + " },\n" + + " \"deviceId\": {\n" + + " \"id\":\"e232e160-1689-11ee-98c6-1713c1be5a8e\",\n" + + " \"entityType\":\"DEVICE\"\n" + + " },\n" + + " \"credentialsType\": \"LWM2M_CREDENTIALS\",\n" + + " \"credentialsId\": \"LwRpk00000000\",\n" + + " \"credentialsValue\":\n" + CREDENTIALS_VALUE_UPDATE_LVM2M_RPK_DESCRIPTION + "\n" + + "}"; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_ACCESS_TOKEN_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_ACCESS_TOKEN_DEFAULT_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_X509_CERTIFICATE_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_MQTT_BASIC_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_UPDATE_CREDENTIALS_ACCESS_TOKEN_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_UPDATE_CREDENTIALS_X509_CERTIFICATE_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_UPDATE_CREDENTIALS_MQTT_BASIC_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + protected static final String FILTER_VALUE_TYPE = NEW_LINE + "## Value Type and Operations" + NEW_LINE + @@ -254,7 +436,7 @@ public class ControllerConstants { " * 'BOOLEAN' - used for boolean values. Operations: EQUAL, NOT_EQUAL;\n" + " * 'DATE_TIME' - similar to numeric, transforms value to milliseconds since epoch. Operations: EQUAL, NOT_EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL; \n"; - protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_SPECIFIC_TIME_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + " \"schedule\":{\n" + " \"type\":\"SPECIFIC_TIME\",\n" + @@ -269,7 +451,7 @@ public class ControllerConstants { " }\n" + "}" + MARKDOWN_CODE_BLOCK_END; - protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_CUSTOM_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + " \"schedule\":{\n" + " \"type\":\"CUSTOM\",\n" + @@ -321,9 +503,9 @@ public class ControllerConstants { " }\n" + "}" + MARKDOWN_CODE_BLOCK_END; - protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "\"schedule\": null" + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_PROFILE_ALARM_SCHEDULE_ALWAYS_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "\"schedule\": null" + MARKDOWN_CODE_BLOCK_END; - protected static final String DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + protected static final String DEVICE_PROFILE_ALARM_CONDITION_REPEATING_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + " \"spec\":{\n" + " \"type\":\"REPEATING\",\n" + @@ -339,7 +521,8 @@ public class ControllerConstants { " }\n" + "}" + MARKDOWN_CODE_BLOCK_END; - protected static final String DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START + + + protected static final String DEVICE_PROFILE_ALARM_CONDITION_DURATION_EXAMPLE = MARKDOWN_CODE_BLOCK_START + "{\n" + " \"spec\":{\n" + " \"type\":\"DURATION\",\n" + diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java new file mode 100644 index 0000000000..04b1b4c522 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java @@ -0,0 +1,107 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller; + +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.dao.device.DeviceConnectivityService; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.permission.Operation; +import org.thingsboard.server.service.security.system.SystemSecurityService; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.net.URISyntaxException; + +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL; +import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.PEM_CERT_FILE_NAME; + +@RestController +@TbCoreComponent +@RequestMapping("/api") +@RequiredArgsConstructor +@Slf4j +public class DeviceConnectivityController extends BaseController { + + private final DeviceConnectivityService deviceConnectivityService; + private final SystemSecurityService systemSecurityService; + + @ApiOperation(value = "Get commands to publish device telemetry (getDevicePublishTelemetryCommands)", + notes = "Fetch the list of commands to publish device telemetry based on device profile " + + "If the user has the authority of 'Tenant Administrator', the server checks that the device is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the device is assigned to the same customer. " + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK", + examples = @io.swagger.annotations.Example( + value = { + @io.swagger.annotations.ExampleProperty( + mediaType = "application/json", + value = "{\"http\":\"curl -v -X POST http://localhost:8080/api/v1/0ySs4FTOn5WU15XLmal8/telemetry --header Content-Type:application/json --data {temperature:25}\"," + + "\"mqtt\":\"mosquitto_pub -d -q 1 -h localhost -t v1/devices/me/telemetry -i myClient1 -u myUsername1 -P myPassword -m {temperature:25}\"," + + "\"coap\":\"coap-client -m POST coap://localhost:5683/api/v1/0ySs4FTOn5WU15XLmal8/telemetry -t json -e {temperature:25}\"}")}))}) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/device-connectivity/{deviceId}", method = RequestMethod.GET) + @ResponseBody + public JsonNode getDevicePublishTelemetryCommands(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) + @PathVariable(DEVICE_ID) String strDeviceId, HttpServletRequest request) throws ThingsboardException, URISyntaxException { + checkParameter(DEVICE_ID, strDeviceId); + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); + Device device = checkDeviceId(deviceId, Operation.READ_CREDENTIALS); + + String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request); + return deviceConnectivityService.findDevicePublishTelemetryCommands(baseUrl, device); + } + + @ApiOperation(value = "Download server certificate using file path defined in device.connectivity properties (downloadServerCertificate)", notes = "Download server certificate.") + @RequestMapping(value = "/device-connectivity/{protocol}/certificate/download", method = RequestMethod.GET) + @ResponseBody + public ResponseEntity downloadServerCertificate(@ApiParam(value = PROTOCOL_PARAM_DESCRIPTION) + @PathVariable(PROTOCOL) String protocol) throws ThingsboardException, IOException { + checkParameter(PROTOCOL, protocol); + var pemCert = + checkNotNull(deviceConnectivityService.getPemCertFile(protocol), protocol + " pem cert file is not found!"); + + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + PEM_CERT_FILE_NAME) + .header("x-filename", PEM_CERT_FILE_NAME) + .contentLength(pemCert.contentLength()) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(pemCert); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index bb34f6d5b2..d73915b617 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -75,6 +75,7 @@ import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; import javax.annotation.Nullable; +import javax.validation.Valid; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -93,7 +94,15 @@ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFI import static org.thingsboard.server.controller.ControllerConstants.DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TEXT_SEARCH_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TYPE_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION; @@ -182,18 +191,29 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Create Device (saveDevice) with credentials ", notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK + - "Requires to provide the Device Credentials object as well. Useful to create device and credentials in one request. " + - "You may find the example of LwM2M device and RPK credentials below: \n\n" + - DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_DESCRIPTION_MARKDOWN + + "Requires to provide the Device Credentials object as well as an existing device profile ID or use \"default\".\n" + + "You may find the example of device with different type of credentials below: \n\n" + + "- Credentials type: \"Access token\" with device profile ID below: \n\n" + + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" + + "- Credentials type: \"Access token\" with device profile default below: \n\n" + + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN + "\n\n" + + "- Credentials type: \"X509\" with device profile ID below: \n\n" + + "Note: credentialsId - format Sha3Hash, certificateValue - format PEM (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" + + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" + + "- Credentials type: \"MQTT_BASIC\" with device profile ID below: \n\n" + + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" + + "- You may find the example of LwM2M device and RPK credentials below: \n\n" + + "Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" + + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" + "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device-with-credentials", method = RequestMethod.POST) @ResponseBody public Device saveDeviceWithCredentials(@ApiParam(value = "The JSON object with device and credentials. See method description above for example.") - @RequestBody SaveDeviceWithCredentialsRequest deviceAndCredentials) throws ThingsboardException { - Device device = checkNotNull(deviceAndCredentials.getDevice()); - DeviceCredentials credentials = checkNotNull(deviceAndCredentials.getCredentials()); + @Valid @RequestBody SaveDeviceWithCredentialsRequest deviceAndCredentials) throws ThingsboardException { + Device device = deviceAndCredentials.getDevice(); + DeviceCredentials credentials = deviceAndCredentials.getCredentials(); device.setTenantId(getCurrentUser().getTenantId()); checkEntity(device.getId(), device, Resource.DEVICE); return tbDeviceService.saveDeviceWithCredentials(device, credentials, getCurrentUser()); @@ -277,10 +297,27 @@ public class DeviceController extends BaseController { return tbDeviceService.getDeviceCredentialsByDeviceId(device, getCurrentUser()); } - @ApiOperation(value = "Update device credentials (updateDeviceCredentials)", notes = "During device creation, platform generates random 'ACCESS_TOKEN' credentials. " + - "Use this method to update the device credentials. First use 'getDeviceCredentialsByDeviceId' to get the credentials id and value. " + - "Then use current method to update the credentials type and value. It is not possible to create multiple device credentials for the same device. " + - "The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'." + TENANT_AUTHORITY_PARAGRAPH) + @ApiOperation(value = "Update device credentials (updateDeviceCredentials)", + notes = "During device creation, platform generates random 'ACCESS_TOKEN' credentials. \" +\n" + + "Use this method to update the device credentials. First use 'getDeviceCredentialsByDeviceId' to get the credentials id and value.\n" + + "Then use current method to update the credentials type and value. It is not possible to create multiple device credentials for the same device.\n" + + "The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'.\n" + + "You may find the example of device with different type of credentials below: \n\n" + + "- Credentials type: \"Access token\" with device ID and with device ID below: \n\n" + + DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" + + "- Credentials type: \"X509\" with device profile ID below: \n\n" + + "Note: credentialsId - format Sha3Hash, certificateValue - format PEM (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" + + DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" + + "- Credentials type: \"MQTT_BASIC\" with device profile ID below: \n\n" + + DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" + + "- You may find the example of LwM2M device and RPK credentials below: \n\n" + + "Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" + + DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" + + "Update to real value:\n" + + " - 'id' (this is id of Device Credentials -> \"Get Device Credentials (getDeviceCredentialsByDeviceId)\",\n" + + " - 'deviceId.id' (this is id of Device).\n" + + "Remove 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity." + + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/device/credentials", method = RequestMethod.POST) @ResponseBody diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java index fc85f439e0..386b1eab01 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeEventController.java @@ -85,6 +85,6 @@ public class EdgeEventController extends BaseController { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); checkEdgeId(edgeId, Operation.READ); TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); - return checkNotNull(edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, false)); + return checkNotNull(edgeEventService.findEdgeEvents(tenantId, edgeId, 0L, null, pageLink)); } } diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index 08448f1d28..e1e89734b9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -117,8 +117,8 @@ public class EntityRelationController extends BaseController { tbEntityRelationService.delete(getTenantId(), getCurrentUser().getCustomerId(), relation, getCurrentUser()); } - @ApiOperation(value = "Delete Relations (deleteRelations)", - notes = "Deletes all the relation (both 'from' and 'to' direction) for the specified entity. " + + @ApiOperation(value = "Delete common relations (deleteCommonRelations)", + notes = "Deletes all the relations ('from' and 'to' direction) for the specified entity and relation type group: 'COMMON'. " + SECURITY_CHECKS_ENTITY_DESCRIPTION) @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/relations", method = RequestMethod.DELETE, params = {"entityId", "entityType"}) @@ -129,7 +129,7 @@ public class EntityRelationController extends BaseController { checkParameter("entityType", strType); EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId); checkEntityId(entityId, Operation.WRITE); - tbEntityRelationService.deleteRelations(getTenantId(), getCurrentUser().getCustomerId(), entityId, getCurrentUser()); + tbEntityRelationService.deleteCommonRelations(getTenantId(), getCurrentUser().getCustomerId(), entityId, getCurrentUser()); } @ApiOperation(value = "Get Relation (getRelation)", diff --git a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java index 91583136f6..8a68dc21cb 100644 --- a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java +++ b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java @@ -221,12 +221,12 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke .build(); } - private class SessionMetaData implements SendHandler { + class SessionMetaData implements SendHandler { private final WebSocketSession session; private final RemoteEndpoint.Async asyncRemote; private final WebSocketSessionRef sessionRef; - private final AtomicBoolean isSending = new AtomicBoolean(false); + final AtomicBoolean isSending = new AtomicBoolean(false); private final Queue> msgQueue; private volatile long lastActivityTime; @@ -241,7 +241,7 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke this.lastActivityTime = System.currentTimeMillis(); } - synchronized void sendPing(long currentTime) { + void sendPing(long currentTime) { try { long timeSinceLastActivity = currentTime - lastActivityTime; if (timeSinceLastActivity >= pingTimeout) { @@ -256,37 +256,38 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke } } - private void closeSession(CloseStatus reason) { + void closeSession(CloseStatus reason) { try { close(this.sessionRef, reason); } catch (IOException ioe) { log.trace("[{}] Session transport error", session.getId(), ioe); + } finally { + msgQueue.clear(); } } - synchronized void processPongMessage(long currentTime) { + void processPongMessage(long currentTime) { lastActivityTime = currentTime; } - synchronized void sendMsg(String msg) { + void sendMsg(String msg) { sendMsg(new TbWebSocketTextMsg(msg)); } - synchronized void sendMsg(TbWebSocketMsg msg) { - if (isSending.compareAndSet(false, true)) { - sendMsgInternal(msg); - } else { - try { - msgQueue.add(msg); - } catch (RuntimeException e) { - if (log.isTraceEnabled()) { - log.trace("[{}][{}] Session closed due to queue error", sessionRef.getSecurityCtx().getTenantId(), session.getId(), e); - } else { - log.info("[{}][{}] Session closed due to queue error", sessionRef.getSecurityCtx().getTenantId(), session.getId()); - } - closeSession(CloseStatus.POLICY_VIOLATION.withReason("Max pending updates limit reached!")); + void sendMsg(TbWebSocketMsg msg) { + try { + msgQueue.add(msg); + } catch (RuntimeException e) { + if (log.isTraceEnabled()) { + log.trace("[{}][{}] Session closed due to queue error", sessionRef.getSecurityCtx().getTenantId(), session.getId(), e); + } else { + log.info("[{}][{}] Session closed due to queue error", sessionRef.getSecurityCtx().getTenantId(), session.getId()); } + closeSession(CloseStatus.POLICY_VIOLATION.withReason("Max pending updates limit reached!")); + return; } + + processNextMsg(); } private void sendMsgInternal(TbWebSocketMsg msg) { @@ -294,9 +295,11 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke if (TbWebSocketMsgType.TEXT.equals(msg.getType())) { TbWebSocketTextMsg textMsg = (TbWebSocketTextMsg) msg; this.asyncRemote.sendText(textMsg.getMsg(), this); + // isSending status will be reset in the onResult method by call back } else { TbWebSocketPingMsg pingMsg = (TbWebSocketPingMsg) msg; - this.asyncRemote.sendPing(pingMsg.getMsg()); + this.asyncRemote.sendPing(pingMsg.getMsg()); // blocking call + isSending.set(false); processNextMsg(); } } catch (Exception e) { @@ -310,12 +313,17 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke if (!result.isOK()) { log.trace("[{}] Failed to send msg", session.getId(), result.getException()); closeSession(CloseStatus.SESSION_NOT_RELIABLE); - } else { - processNextMsg(); + return; } + + isSending.set(false); + processNextMsg(); } private void processNextMsg() { + if (msgQueue.isEmpty() || !isSending.compareAndSet(false, true)) { + return; + } TbWebSocketMsg msg = msgQueue.poll(); if (msg != null) { sendMsgInternal(msg); @@ -392,19 +400,21 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke if (tenantProfileConfiguration == null) { return true; } - + boolean limitAllowed; String sessionId = session.getId(); if (tenantProfileConfiguration.getMaxWsSessionsPerTenant() > 0) { Set tenantSessions = tenantSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getTenantId(), id -> ConcurrentHashMap.newKeySet()); synchronized (tenantSessions) { - if (tenantSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerTenant()) { + limitAllowed = tenantSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerTenant(); + if (limitAllowed) { tenantSessions.add(sessionId); - } else { + } + } + if (!limitAllowed) { log.info("[{}][{}][{}] Failed to start session. Max tenant sessions limit reached" , sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), sessionId); session.close(CloseStatus.POLICY_VIOLATION.withReason("Max tenant sessions limit reached!")); return false; - } } } @@ -412,42 +422,48 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke if (tenantProfileConfiguration.getMaxWsSessionsPerCustomer() > 0) { Set customerSessions = customerSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getCustomerId(), id -> ConcurrentHashMap.newKeySet()); synchronized (customerSessions) { - if (customerSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerCustomer()) { + limitAllowed = customerSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerCustomer(); + if (limitAllowed) { customerSessions.add(sessionId); - } else { + } + } + if (!limitAllowed) { log.info("[{}][{}][{}] Failed to start session. Max customer sessions limit reached" , sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), sessionId); session.close(CloseStatus.POLICY_VIOLATION.withReason("Max customer sessions limit reached")); return false; - } } } if (tenantProfileConfiguration.getMaxWsSessionsPerRegularUser() > 0 && UserPrincipal.Type.USER_NAME.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) { Set regularUserSessions = regularUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet()); synchronized (regularUserSessions) { - if (regularUserSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerRegularUser()) { + limitAllowed = regularUserSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerRegularUser(); + if (limitAllowed) { regularUserSessions.add(sessionId); - } else { + } + } + if (!limitAllowed) { log.info("[{}][{}][{}] Failed to start session. Max regular user sessions limit reached" , sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), sessionId); session.close(CloseStatus.POLICY_VIOLATION.withReason("Max regular user sessions limit reached")); return false; - } } } if (tenantProfileConfiguration.getMaxWsSessionsPerPublicUser() > 0 && UserPrincipal.Type.PUBLIC_ID.equals(sessionRef.getSecurityCtx().getUserPrincipal().getType())) { Set publicUserSessions = publicUserSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getId(), id -> ConcurrentHashMap.newKeySet()); synchronized (publicUserSessions) { - if (publicUserSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerPublicUser()) { + limitAllowed = publicUserSessions.size() < tenantProfileConfiguration.getMaxWsSessionsPerPublicUser(); + if (limitAllowed) { publicUserSessions.add(sessionId); - } else { + } + } + if (!limitAllowed) { log.info("[{}][{}][{}] Failed to start session. Max public user sessions limit reached" , sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), sessionId); session.close(CloseStatus.POLICY_VIOLATION.withReason("Max public user sessions limit reached")); return false; - } } } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index b7334ebf5a..e7214177d2 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -341,7 +341,10 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i sessionNewEvents.put(edgeId, false); Futures.addCallback(session.processEdgeEvents(), new FutureCallback<>() { @Override - public void onSuccess(Void result) { + public void onSuccess(Boolean newEventsAdded) { + if (Boolean.TRUE.equals(newEventsAdded)) { + sessionNewEvents.put(edgeId, true); + } scheduleEdgeEventsCheck(session); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index 1dd0f31c20..4f0f5d277a 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -24,6 +24,7 @@ import io.grpc.stub.StreamObserver; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.checkerframework.checker.nullness.qual.Nullable; +import org.springframework.data.util.Pair; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.Edge; @@ -35,6 +36,8 @@ import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.SortOrder; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.gen.edge.v1.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.v1.AttributesRequestMsg; import org.thingsboard.server.gen.edge.v1.ConnectRequestMsg; @@ -68,17 +71,15 @@ import org.thingsboard.server.service.edge.rpc.fetch.GeneralEdgeEventFetcher; import java.io.Closeable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.stream.Collectors; @Slf4j @Data @@ -89,6 +90,7 @@ public final class EdgeGrpcSession implements Closeable { private static final int MAX_DOWNLINK_ATTEMPTS = 10; // max number of attemps to send downlink message if edge connected private static final String QUEUE_START_TS_ATTR_KEY = "queueStartTs"; + private static final String QUEUE_START_SEQ_ID_ATTR_KEY = "queueStartSeqId"; private final UUID sessionId; private final BiConsumer sessionOpenListener; @@ -103,6 +105,12 @@ public final class EdgeGrpcSession implements Closeable { private boolean connected; private boolean syncCompleted; + private Long newStartTs; + private Long previousStartTs; + private Long newStartSeqId; + private Long previousStartSeqId; + private Long seqIdEnd; + private EdgeVersion edgeVersion; private int maxInboundMessageSize; @@ -204,10 +212,10 @@ public final class EdgeGrpcSession implements Closeable { EdgeEventFetcher next = cursor.getNext(); log.info("[{}][{}] starting sync process, cursor current idx = {}, class = {}", edge.getTenantId(), edge.getId(), cursor.getCurrentIdx(), next.getClass().getSimpleName()); - ListenableFuture uuidListenableFuture = startProcessingEdgeEvents(next); - Futures.addCallback(uuidListenableFuture, new FutureCallback<>() { + ListenableFuture> future = startProcessingEdgeEvents(next); + Futures.addCallback(future, new FutureCallback<>() { @Override - public void onSuccess(@Nullable UUID result) { + public void onSuccess(@Nullable Pair result) { doSync(cursor); } @@ -307,36 +315,51 @@ public final class EdgeGrpcSession implements Closeable { sendDownlinkMsg(edgeConfigMsg); } - ListenableFuture processEdgeEvents() throws Exception { - SettableFuture result = SettableFuture.create(); + ListenableFuture processEdgeEvents() throws Exception { + SettableFuture result = SettableFuture.create(); log.trace("[{}] starting processing edge events", this.sessionId); if (isConnected() && isSyncCompleted()) { - Long queueStartTs = getQueueStartTs().get(); + Pair startTsAndSeqId = getQueueStartTsAndSeqId().get(); + this.previousStartTs = startTsAndSeqId.getFirst(); + this.previousStartSeqId = startTsAndSeqId.getSecond(); GeneralEdgeEventFetcher fetcher = new GeneralEdgeEventFetcher( - queueStartTs, + this.previousStartTs, + this.previousStartSeqId, + this.seqIdEnd, + false, + Integer.toUnsignedLong(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount()), ctx.getEdgeEventService()); - ListenableFuture ifOffsetFuture = startProcessingEdgeEvents(fetcher); - Futures.addCallback(ifOffsetFuture, new FutureCallback<>() { + Futures.addCallback(startProcessingEdgeEvents(fetcher), new FutureCallback<>() { @Override - public void onSuccess(@Nullable UUID ifOffset) { - if (ifOffset != null) { - Long newStartTs = Uuids.unixTimestamp(ifOffset); - ListenableFuture> updateFuture = updateQueueStartTs(newStartTs); + public void onSuccess(@Nullable Pair newStartTsAndSeqId) { + if (newStartTsAndSeqId != null) { + ListenableFuture> updateFuture = updateQueueStartTsAndSeqId(newStartTsAndSeqId); Futures.addCallback(updateFuture, new FutureCallback<>() { @Override public void onSuccess(@Nullable List list) { - log.debug("[{}] queue offset was updated [{}][{}]", sessionId, ifOffset, newStartTs); - result.set(null); + log.debug("[{}] queue offset was updated [{}]", sessionId, newStartTsAndSeqId); + if (fetcher.isSeqIdNewCycleStarted()) { + seqIdEnd = fetcher.getSeqIdEnd(); + boolean newEventsAvailable = isNewEdgeEventsAvailable(); + result.set(newEventsAvailable); + } else { + seqIdEnd = null; + boolean newEventsAvailable = isSeqIdStartedNewCycle(); + if (!newEventsAvailable) { + newEventsAvailable = isNewEdgeEventsAvailable(); + } + result.set(newEventsAvailable); + } } @Override public void onFailure(Throwable t) { - log.error("[{}] Failed to update queue offset [{}]", sessionId, ifOffset, t); + log.error("[{}] Failed to update queue offset [{}]", sessionId, newStartTsAndSeqId, t); result.setException(t); } }, ctx.getGrpcCallbackExecutorService()); } else { - log.trace("[{}] ifOffset is null. Skipping iteration without db update", sessionId); + log.trace("[{}] newStartTsAndSeqId is null. Skipping iteration without db update", sessionId); result.set(null); } } @@ -354,14 +377,14 @@ public final class EdgeGrpcSession implements Closeable { return result; } - private ListenableFuture startProcessingEdgeEvents(EdgeEventFetcher fetcher) { - SettableFuture result = SettableFuture.create(); + private ListenableFuture> startProcessingEdgeEvents(EdgeEventFetcher fetcher) { + SettableFuture> result = SettableFuture.create(); PageLink pageLink = fetcher.getPageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount()); processEdgeEvents(fetcher, pageLink, result); return result; } - private void processEdgeEvents(EdgeEventFetcher fetcher, PageLink pageLink, SettableFuture result) { + private void processEdgeEvents(EdgeEventFetcher fetcher, PageLink pageLink, SettableFuture> result) { try { PageData pageData = fetcher.fetchEdgeEvents(edge.getTenantId(), edge, pageLink); if (isConnected() && !pageData.getData().isEmpty()) { @@ -377,8 +400,15 @@ public final class EdgeGrpcSession implements Closeable { if (isConnected() && pageData.hasNext()) { processEdgeEvents(fetcher, pageLink.nextPageLink(), result); } else { - UUID ifOffset = pageData.getData().get(pageData.getData().size() - 1).getUuidId(); - result.set(ifOffset); + EdgeEvent latestEdgeEvent = pageData.getData().get(pageData.getData().size() - 1); + UUID idOffset = latestEdgeEvent.getUuidId(); + if (idOffset != null) { + Long newStartTs = Uuids.unixTimestamp(idOffset); + long newStartSeqId = latestEdgeEvent.getSeqId(); + result.set(Pair.of(newStartTs, newStartSeqId)); + } else { + result.set(null); + } } } } @@ -461,69 +491,113 @@ public final class EdgeGrpcSession implements Closeable { } } - private DownlinkMsg convertToDownlinkMsg(EdgeEvent edgeEvent) { - log.trace("[{}][{}] converting edge event to downlink msg [{}]", edge.getTenantId(), this.sessionId, edgeEvent); - DownlinkMsg downlinkMsg = null; - try { - switch (edgeEvent.getAction()) { - case UPDATED: - case ADDED: - case DELETED: - case ASSIGNED_TO_EDGE: - case UNASSIGNED_FROM_EDGE: - case ALARM_ACK: - case ALARM_CLEAR: - case CREDENTIALS_UPDATED: - case RELATION_ADD_OR_UPDATE: - case RELATION_DELETED: - case ASSIGNED_TO_CUSTOMER: - case UNASSIGNED_FROM_CUSTOMER: - case CREDENTIALS_REQUEST: - case RPC_CALL: - downlinkMsg = convertEntityEventToDownlink(edgeEvent); - log.trace("[{}][{}] entity message processed [{}]", edgeEvent.getTenantId(), this.sessionId, downlinkMsg); - break; - case ATTRIBUTES_UPDATED: - case POST_ATTRIBUTES: - case ATTRIBUTES_DELETED: - case TIMESERIES_UPDATED: - downlinkMsg = ctx.getTelemetryProcessor().convertTelemetryEventToDownlink(edgeEvent); - break; - default: - log.warn("[{}][{}] Unsupported action type [{}]", edge.getTenantId(), this.sessionId, edgeEvent.getAction()); + private List convertToDownlinkMsgsPack(List edgeEvents) { + List result = new ArrayList<>(); + for (EdgeEvent edgeEvent : edgeEvents) { + log.trace("[{}][{}] converting edge event to downlink msg [{}]", edge.getTenantId(), this.sessionId, edgeEvent); + DownlinkMsg downlinkMsg = null; + try { + switch (edgeEvent.getAction()) { + case UPDATED: + case ADDED: + case DELETED: + case ASSIGNED_TO_EDGE: + case UNASSIGNED_FROM_EDGE: + case ALARM_ACK: + case ALARM_CLEAR: + case CREDENTIALS_UPDATED: + case RELATION_ADD_OR_UPDATE: + case RELATION_DELETED: + case CREDENTIALS_REQUEST: + case RPC_CALL: + case ASSIGNED_TO_CUSTOMER: + case UNASSIGNED_FROM_CUSTOMER: + downlinkMsg = convertEntityEventToDownlink(edgeEvent); + log.trace("[{}][{}] entity message processed [{}]", edgeEvent.getTenantId(), this.sessionId, downlinkMsg); + break; + case ATTRIBUTES_UPDATED: + case POST_ATTRIBUTES: + case ATTRIBUTES_DELETED: + case TIMESERIES_UPDATED: + downlinkMsg = ctx.getTelemetryProcessor().convertTelemetryEventToDownlink(edgeEvent); + break; + default: + log.warn("[{}][{}] Unsupported action type [{}]", edge.getTenantId(), this.sessionId, edgeEvent.getAction()); + } + } catch (Exception e) { + log.error("[{}][{}] Exception during converting edge event to downlink msg", edge.getTenantId(), this.sessionId, e); + } + if (downlinkMsg != null) { + result.add(downlinkMsg); + } + } + return result; + } + + private ListenableFuture> getQueueStartTsAndSeqId() { + ListenableFuture> future = + ctx.getAttributesService().find(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, Arrays.asList(QUEUE_START_TS_ATTR_KEY, QUEUE_START_SEQ_ID_ATTR_KEY)); + return Futures.transform(future, attributeKvEntries -> { + long startTs = 0L; + long startSeqId = 0L; + for (AttributeKvEntry attributeKvEntry : attributeKvEntries) { + if (QUEUE_START_TS_ATTR_KEY.equals(attributeKvEntry.getKey())) { + startTs = attributeKvEntry.getLongValue().isPresent() ? attributeKvEntry.getLongValue().get() : 0L; + } + if (QUEUE_START_SEQ_ID_ATTR_KEY.equals(attributeKvEntry.getKey())) { + startSeqId = attributeKvEntry.getLongValue().isPresent() ? attributeKvEntry.getLongValue().get() : 0L; + } + } + if (startSeqId == 0L) { + startSeqId = findStartSeqIdFromOldestEventIfAny(); } + return Pair.of(startTs, startSeqId); + }, ctx.getGrpcCallbackExecutorService()); + } + + private boolean isSeqIdStartedNewCycle() { + try { + TimePageLink pageLink = new TimePageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount(), 0, null, null, this.newStartTs, System.currentTimeMillis()); + PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), 0L, this.previousStartSeqId == 0 ? null : this.previousStartSeqId - 1, pageLink); + return !edgeEvents.getData().isEmpty(); } catch (Exception e) { - log.error("[{}][{}] Exception during converting edge event to downlink msg", edge.getTenantId(), this.sessionId, e); + log.error("[{}][{}][{}] Failed to execute isSeqIdStartedNewCycle", edge.getTenantId(), edge.getId(), sessionId, e); } - return downlinkMsg; + return false; } - private List convertToDownlinkMsgsPack(List edgeEvents) { - return edgeEvents - .stream() - .map(this::convertToDownlinkMsg) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + private boolean isNewEdgeEventsAvailable() { + try { + TimePageLink pageLink = new TimePageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount(), 0, null, null, this.newStartTs, System.currentTimeMillis()); + PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), this.newStartSeqId, null, pageLink); + return !edgeEvents.getData().isEmpty(); + } catch (Exception e) { + log.error("[{}][{}][{}] Failed to execute isNewEdgeEventsAvailable", edge.getTenantId(), edge.getId(), sessionId, e); + } + return false; } - private ListenableFuture getQueueStartTs() { - ListenableFuture> future = - ctx.getAttributesService().find(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, QUEUE_START_TS_ATTR_KEY); - return Futures.transform(future, attributeKvEntryOpt -> { - if (attributeKvEntryOpt != null && attributeKvEntryOpt.isPresent()) { - AttributeKvEntry attributeKvEntry = attributeKvEntryOpt.get(); - return attributeKvEntry.getLongValue().isPresent() ? attributeKvEntry.getLongValue().get() : 0L; - } else { - return 0L; + private long findStartSeqIdFromOldestEventIfAny() { + long startSeqId = 0L; + try { + TimePageLink pageLink = new TimePageLink(1, 0, null, new SortOrder("createdTime"), null, null); + PageData edgeEvents = ctx.getEdgeEventService().findEdgeEvents(edge.getTenantId(), edge.getId(), null, null, pageLink); + if (!edgeEvents.getData().isEmpty()) { + startSeqId = edgeEvents.getData().get(0).getSeqId() - 1; } - }, ctx.getGrpcCallbackExecutorService()); + } catch (Exception e) { + log.error("[{}][{}][{}] Failed to execute findStartSeqIdFromOldestEventIfAny", edge.getTenantId(), edge.getId(), sessionId, e); + } + return startSeqId; } - private ListenableFuture> updateQueueStartTs(Long newStartTs) { - log.trace("[{}] updating QueueStartTs [{}][{}]", this.sessionId, edge.getId(), newStartTs); - List attributes = Collections.singletonList( - new BaseAttributeKvEntry( - new LongDataEntry(QUEUE_START_TS_ATTR_KEY, newStartTs), System.currentTimeMillis())); + private ListenableFuture> updateQueueStartTsAndSeqId(Pair pair) { + this.newStartTs = pair.getFirst(); + this.newStartSeqId = pair.getSecond(); + log.trace("[{}] updateQueueStartTsAndSeqId [{}][{}][{}]", this.sessionId, edge.getId(), this.newStartTs, this.newStartSeqId); + List attributes = Arrays.asList( + new BaseAttributeKvEntry(new LongDataEntry(QUEUE_START_TS_ATTR_KEY, this.newStartTs), System.currentTimeMillis()), + new BaseAttributeKvEntry(new LongDataEntry(QUEUE_START_SEQ_ID_ATTR_KEY, this.newStartSeqId), System.currentTimeMillis())); return ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes); } @@ -693,8 +767,11 @@ public final class EdgeGrpcSession implements Closeable { } private void interruptPreviousSendDownlinkMsgsTask() { - log.debug("[{}][{}][{}] Previous send downlink future was not properly completed, stopping it now!", edge.getTenantId(), edge.getId(), this.sessionId); - stopCurrentSendDownlinkMsgsTask(true); + if (sessionState.getSendDownlinkMsgsFuture() != null && !sessionState.getSendDownlinkMsgsFuture().isDone() + || sessionState.getScheduledSendDownlinkTask() != null && !sessionState.getScheduledSendDownlinkTask().isCancelled()) { + log.debug("[{}][{}][{}] Previous send downlink future was not properly completed, stopping it now!", edge.getTenantId(), edge.getId(), this.sessionId); + stopCurrentSendDownlinkMsgsTask(true); + } } private void interruptGeneralProcessingOnSync() { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java index 69a83da0a0..447a73e5cf 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmMsgConstructor.java @@ -18,7 +18,10 @@ package org.thingsboard.server.service.edge.rpc.constructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityViewId; @@ -47,13 +50,22 @@ public class AlarmMsgConstructor { String entityName = null; switch (alarm.getOriginator().getEntityType()) { case DEVICE: - entityName = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId())).getName(); + Device deviceById = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId())); + if (deviceById != null) { + entityName = deviceById.getName(); + } break; case ASSET: - entityName = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId())).getName(); + Asset assetById = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId())); + if (assetById != null) { + entityName = assetById.getName(); + } break; case ENTITY_VIEW: - entityName = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId())).getName(); + EntityView entityViewById = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId())); + if (entityViewById != null) { + entityName = entityViewById.getName(); + } break; } AlarmUpdateMsg.Builder builder = AlarmUpdateMsg.newBuilder() diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/GeneralEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/GeneralEdgeEventFetcher.java index 327184e6a9..24008ece09 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/GeneralEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/GeneralEdgeEventFetcher.java @@ -16,19 +16,27 @@ package org.thingsboard.server.service.edge.rpc.fetch; import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.dao.edge.EdgeEventService; @AllArgsConstructor +@Slf4j public class GeneralEdgeEventFetcher implements EdgeEventFetcher { private final Long queueStartTs; + private Long seqIdStart; + @Getter + private Long seqIdEnd; + @Getter + private boolean seqIdNewCycleStarted; + private Long maxReadRecordsCount; private final EdgeEventService edgeEventService; @Override @@ -37,13 +45,32 @@ public class GeneralEdgeEventFetcher implements EdgeEventFetcher { pageSize, 0, null, - new SortOrder("createdTime", SortOrder.Direction.ASC), + null, queueStartTs, - null); + System.currentTimeMillis()); } @Override public PageData fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) { - return edgeEventService.findEdgeEvents(tenantId, edge.getId(), (TimePageLink) pageLink, true); + try { + PageData edgeEvents = edgeEventService.findEdgeEvents(tenantId, edge.getId(), seqIdStart, seqIdEnd, (TimePageLink) pageLink); + if (edgeEvents.getData().isEmpty()) { + this.seqIdEnd = Math.max(this.maxReadRecordsCount, seqIdStart - this.maxReadRecordsCount); + edgeEvents = edgeEventService.findEdgeEvents(tenantId, edge.getId(), 0L, seqIdEnd, (TimePageLink) pageLink); + if (edgeEvents.getData().stream().anyMatch(ee -> ee.getSeqId() < seqIdStart)) { + log.info("[{}] seqId column of edge_event table started new cycle [{}]", tenantId, edge.getId()); + this.seqIdNewCycleStarted = true; + this.seqIdStart = 0L; + } else { + edgeEvents = new PageData<>(); + log.warn("[{}] unexpected edge notification message received. " + + "no new events found and seqId column of edge_event table doesn't started new cycle [{}]", tenantId, edge.getId()); + } + } + return edgeEvents; + } catch (Exception e) { + log.error("[{}] failed to find edge events [{}]", tenantId, edge.getId()); + } + return new PageData<>(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index caf65d39ec..07c66e359a 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmCommentType; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.alarm.AlarmQueryV2; import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; @@ -36,9 +37,13 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; @Service @AllArgsConstructor @@ -210,6 +215,39 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb return alarmInfo; } + @Override + public void unassignUserAlarms(TenantId tenantId, User user, long unassignTs) { + AlarmQueryV2 alarmQuery = AlarmQueryV2.builder().assigneeId(user.getId()).pageLink(new TimePageLink(Integer.MAX_VALUE)).build(); + try { + List alarms = alarmService.findAlarmsV2(tenantId, alarmQuery).get(30, TimeUnit.SECONDS).getData(); + for (AlarmInfo alarm : alarms) { + AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(tenantId, alarm.getId(), getOrDefault(unassignTs)); + if (!result.isSuccessful()) { + continue; + } + if (result.isModified()) { + AlarmComment alarmComment = AlarmComment.builder() + .alarmId(alarm.getId()) + .type(AlarmCommentType.SYSTEM) + .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was unassigned because user %s - was deleted", + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) + .put("userId", user.getId().toString()) + .put("subtype", "ASSIGN")) + .build(); + try { + alarmCommentService.saveAlarmComment(alarm, alarmComment, user); + } catch (ThingsboardException e) { + log.error("Failed to save alarm comment", e); + } + notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user); + } + } + + } catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new RuntimeException(e); + } + } + @Override public Boolean delete(Alarm alarm, User user) { TenantId tenantId = alarm.getTenantId(); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index a2ae9c8cc7..24af185539 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -19,6 +19,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; public interface TbAlarmService { @@ -37,5 +38,7 @@ public interface TbAlarmService { AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException; + void unassignUserAlarms(TenantId tenantId, User user, long unassignTs); + Boolean delete(Alarm alarm, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java index b978b730fd..cf1733490d 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java @@ -72,9 +72,9 @@ public class DefaultTbEntityRelationService extends AbstractTbEntityService impl } @Override - public void deleteRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException { + public void deleteCommonRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException { try { - relationService.deleteEntityRelations(tenantId, entityId); + relationService.deleteEntityCommonRelations(tenantId, entityId); notificationEntityService.logEntityAction(tenantId, entityId, null, customerId, ActionType.RELATIONS_DELETED, user); } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, entityId, null, customerId, diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java index 2caee86d0c..8bf5018c95 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java @@ -28,6 +28,6 @@ public interface TbEntityRelationService { void delete(TenantId tenantId, CustomerId customerId, EntityRelation entity, User user) throws ThingsboardException; - void deleteRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException; + void deleteCommonRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java index c83c48cc8a..d9f11dacb5 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; +import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; import org.thingsboard.server.service.security.system.SystemSecurityService; import javax.servlet.http.HttpServletRequest; @@ -43,6 +44,7 @@ import static org.thingsboard.server.controller.UserController.ACTIVATE_URL_PATT public class DefaultUserService extends AbstractTbEntityService implements TbUserService { private final UserService userService; + private final TbAlarmService tbAlarmService; private final MailService mailService; private final SystemSecurityService systemSecurityService; @@ -80,6 +82,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse UserId userId = tbUser.getId(); try { + tbAlarmService.unassignUserAlarms(tbUser.getTenantId(), tbUser, System.currentTimeMillis()); userService.deleteUser(tenantId, userId); notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, userId, tbUser, user, ActionType.DELETED, true, null, customerId.toString()); diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index f832b04c21..dafccfdad6 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -202,22 +202,27 @@ public class DefaultDataUpdateService implements DataUpdateService { } else { log.info("Skipping audit logs migration"); } - boolean skipEdgeEventsMigration = getEnv("TB_SKIP_EDGE_EVENTS_MIGRATION", false); - if (!skipEdgeEventsMigration) { - log.info("Starting edge events migration. Can be skipped with TB_SKIP_EDGE_EVENTS_MIGRATION env variable set to true"); - edgeEventDao.migrateEdgeEvents(); - } else { - log.info("Skipping edge events migration"); - } + migrateEdgeEvents("Starting edge events migration. "); break; case "3.5.1": log.info("Updating data from version 3.5.1 to 3.5.2 ..."); + migrateEdgeEvents("Starting edge events migration - adding seq_id column. "); break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } } + private void migrateEdgeEvents(String logPrefix) { + boolean skipEdgeEventsMigration = getEnv("TB_SKIP_EDGE_EVENTS_MIGRATION", false); + if (!skipEdgeEventsMigration) { + log.info(logPrefix + "Can be skipped with TB_SKIP_EDGE_EVENTS_MIGRATION env variable set to true"); + edgeEventDao.migrateEdgeEvents(); + } else { + log.info("Skipping edge events migration"); + } + } + @Override public void upgradeRuleNodes() { try { diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java index d69d502aa2..a942dce736 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java @@ -108,6 +108,8 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor> consumer, Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { - consumersExecutor.execute(() -> consumerLoop(consumer, configuration, stats, threadSuffix)); + if (isReady) { + consumersExecutor.execute(() -> consumerLoop(consumer, configuration, stats, threadSuffix)); + } else { + scheduleLaunchConsumer(consumer, configuration, stats, threadSuffix); + } + } + + private void scheduleLaunchConsumer(TbQueueConsumer> consumer, Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { + repartitionExecutor.schedule(() -> { + if (isReady) { + consumersExecutor.execute(() -> consumerLoop(consumer, configuration, stats, threadSuffix)); + } else { + scheduleLaunchConsumer(consumer, configuration, stats, threadSuffix); + } + }, 10, TimeUnit.SECONDS); } void consumerLoop(TbQueueConsumer> consumer, org.thingsboard.server.common.data.queue.Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java index 2d517a2213..b59086a350 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java @@ -68,7 +68,7 @@ public abstract class AbstractConsumerService= beforeAssignmentTs); + + beforeAssignmentTs = System.currentTimeMillis(); + + Mockito.reset(tbClusterService, auditLogService); + + loginSysAdmin(); + + doDelete("/api/user/" + savedUser.getId().getId()).andExpect(status().isOk()); + + loginDifferentTenant(); + + foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + } + + @Test + public void testUnassignAlarmOnUserRemoving() throws Exception { + loginDifferentTenant(); + + User user = new User(); + user.setAuthority(Authority.TENANT_ADMIN); + user.setTenantId(tenantId); + user.setEmail("tenantForAssign@thingsboard.org"); + User savedUser = createUser(user, "password"); + + Device device = createDevice("Different tenant device", "default", "differentTenantTest"); + + Alarm alarm = Alarm.builder() + .type(TEST_ALARM_TYPE) + .tenantId(savedDifferentTenant.getId()) + .originator(device.getId()) + .severity(AlarmSeverity.MAJOR) + .build(); + alarm = doPost("/api/alarm", alarm, Alarm.class); + Assert.assertNotNull(alarm); + + alarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(alarm); + + Mockito.reset(tbClusterService, auditLogService); + long beforeAssignmentTs = System.currentTimeMillis(); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); + AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + + beforeAssignmentTs = System.currentTimeMillis(); + + Mockito.reset(tbClusterService, auditLogService); + + doDelete("/api/user/" + savedUser.getId().getId()).andExpect(status().isOk()); + + foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + } + @Test public void testFindAlarmsViaCustomerUser() throws Exception { loginCustomerUser(); diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java new file mode 100644 index 0000000000..36a4365544 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -0,0 +1,340 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.AdditionalAnswers; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.DeviceProfileType; +import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; +import org.thingsboard.server.common.data.device.profile.DeviceProfileData; +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.dao.device.DeviceDao; +import org.thingsboard.server.dao.service.DaoSqlTest; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAP; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; + +@TestPropertySource(properties = { + "device.connectivity.https.enabled=true", + "device.connectivity.mqtts.enabled=true", + "device.connectivity.coaps.enabled=true", +}) +@ContextConfiguration(classes = {DeviceConnectivityControllerTest.Config.class}) +@DaoSqlTest +public class DeviceConnectivityControllerTest extends AbstractControllerTest { + static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() { + }; + + private static final String DEVICE_TELEMETRY_TOPIC = "v1/devices/customTopic"; + private static final String CHECK_DOCUMENTATION = "Check documentation"; + + ListeningExecutorService executor; + + private Tenant savedTenant; + private User tenantAdmin; + private DeviceProfileId mqttDeviceProfileId; + private DeviceProfileId coapDeviceProfileId; + + static class Config { + @Bean + @Primary + public DeviceDao deviceDao(DeviceDao deviceDao) { + return Mockito.mock(DeviceDao.class, AdditionalAnswers.delegatesTo(deviceDao)); + } + } + + @Before + public void beforeTest() throws Exception { + executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass())); + + loginSysAdmin(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); + Assert.assertNotNull(savedTenant); + + tenantAdmin = new User(); + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setEmail("tenant2@thingsboard.org"); + tenantAdmin.setFirstName("Joe"); + tenantAdmin.setLastName("Downs"); + + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + + DeviceProfile mqttProfile = new DeviceProfile(); + mqttProfile.setName("Mqtt device profile"); + mqttProfile.setType(DeviceProfileType.DEFAULT); + mqttProfile.setTransportType(DeviceTransportType.MQTT); + DeviceProfileData deviceProfileData = new DeviceProfileData(); + deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration()); + MqttDeviceProfileTransportConfiguration transportConfiguration = new MqttDeviceProfileTransportConfiguration(); + transportConfiguration.setDeviceTelemetryTopic(DEVICE_TELEMETRY_TOPIC); + deviceProfileData.setTransportConfiguration(transportConfiguration); + mqttProfile.setProfileData(deviceProfileData); + mqttProfile.setDefault(false); + mqttProfile.setDefaultRuleChainId(null); + + mqttDeviceProfileId = doPost("/api/deviceProfile", mqttProfile, DeviceProfile.class).getId(); + + DeviceProfile coapProfile = new DeviceProfile(); + coapProfile.setName("Coap device profile"); + coapProfile.setType(DeviceProfileType.DEFAULT); + coapProfile.setTransportType(DeviceTransportType.COAP); + DeviceProfileData deviceProfileData2 = new DeviceProfileData(); + deviceProfileData2.setConfiguration(new DefaultDeviceProfileConfiguration()); + deviceProfileData2.setTransportConfiguration(new CoapDeviceProfileTransportConfiguration()); + coapProfile.setProfileData(deviceProfileData); + coapProfile.setDefault(false); + coapProfile.setDefaultRuleChainId(null); + + coapDeviceProfileId = doPost("/api/deviceProfile", coapProfile, DeviceProfile.class).getId(); + } + + @After + public void afterTest() throws Exception { + executor.shutdownNow(); + + loginSysAdmin(); + + doDelete("/api/tenant/" + savedTenant.getId().getId()) + .andExpect(status().isOk()); + } + + @Test + public void testFetchPublishTelemetryCommandsForDefaultDevice() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setType("default"); + Device savedDevice = doPost("/api/device", device, Device.class); + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); + + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + + assertThat(commands).hasSize(3); + JsonNode httpCommands = commands.get(HTTP); + assertThat(httpCommands.get(HTTP).asText()).isEqualTo(String.format("curl -v -X POST http://localhost:8080/api/v1/%s/telemetry " + + "--header Content-Type:application/json --data \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(httpCommands.get(HTTPS).asText()).isEqualTo(String.format("curl -v -X POST https://localhost:443/api/v1/%s/telemetry " + + "--header Content-Type:application/json --data \"{temperature:25}\"", + credentials.getCredentialsId())); + + + JsonNode mqttCommands = commands.get(MQTT); + assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + + "-u %s -m \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " + + "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); + + JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); + assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients mosquitto_pub -d -q 1 -h localhost" + + " -p 1883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + + "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"\"", + credentials.getCredentialsId())); + + JsonNode linuxCoapCommands = commands.get(COAP); + assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry " + + "-t json -e \"{temperature:25}\"", credentials.getCredentialsId())); + assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry" + + " -t json -e \"{temperature:25}\"", credentials.getCredentialsId())); + } + + @Test + public void testFetchPublishTelemetryCommandsForMqttDeviceWithAccessToken() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(mqttDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); + assertThat(commands).hasSize(1); + + JsonNode mqttCommands = commands.get(MQTT); + assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + + "-u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " + + "-t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + + JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); + assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients mosquitto_pub -d -q 1 -h localhost" + + " -p 1883 -t %s -u %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + + "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"\"", + DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + } + + @Test + public void testFetchPublishTelemetryCommandsForDeviceWithMqttBasicCreds() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(mqttDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + credentials.setCredentialsId(null); + credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC); + BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials(); + String clientId = "testClientId"; + String userName = "testUsername"; + String password = "testPassword"; + basicMqttCredentials.setClientId(clientId); + basicMqttCredentials.setUserName(userName); + basicMqttCredentials.setPassword(password); + credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials)); + doPost("/api/device/credentials", credentials) + .andExpect(status().isOk()); + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); + assertThat(commands).hasSize(1); + + JsonNode mqttCommands = commands.get(MQTT); + assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + + "-i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " + + "-t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + + JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); + assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients mosquitto_pub -d -q 1 -h localhost" + + " -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + + "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"\"", + DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + } + + @Test + public void testFetchPublishTelemetryCommandsForDeviceWithX509Creds() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(mqttDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + credentials.setCredentialsId(null); + credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); + credentials.setCredentialsValue("testValue"); + doPost("/api/device/credentials", credentials) + .andExpect(status().isOk()); + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); + assertThat(commands).hasSize(1); + assertThat(commands.get(MQTT).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); + assertThat(commands.get(MQTT).get(DOCKER)).isNull(); + } + + @Test + public void testFetchPublishTelemetryCommandsForCoapDevice() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(coapDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); + assertThat(commands).hasSize(1); + + JsonNode linuxCommands = commands.get(COAP); + assertThat(linuxCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(linuxCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); + } + + @Test + public void testFetchPublishTelemetryCommandsForCoapDeviceWithX509Creds() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(coapDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + credentials.setCredentialsId(null); + credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); + credentials.setCredentialsValue("testValue"); + doPost("/api/device/credentials", credentials) + .andExpect(status().isOk()); + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); + assertThat(commands).hasSize(1); + assertThat(commands.get(COAP).get(COAPS).asText()).isEqualTo(CHECK_DOCUMENTATION); + } +} diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java index 11d11eccdd..1c952bd549 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java @@ -244,6 +244,53 @@ public class DeviceControllerTest extends AbstractControllerTest { testNotificationUpdateGatewayOneTime(savedDevice, oldDevice); } + @Test + public void testSaveDeviceWithCredentials_CredentialsIsNull() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setType("default"); + + SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(device, null); + doPost("/api/device-with-credentials", saveRequest).andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Validation error: credentials must not be null"))); + } + + @Test + public void testSaveDeviceWithCredentials_DeviceIsNull() throws Exception { + String testToken = "TEST_TOKEN"; + + DeviceCredentials deviceCredentials = new DeviceCredentials(); + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); + deviceCredentials.setCredentialsId(testToken); + + SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(null, deviceCredentials); + doPost("/api/device-with-credentials", saveRequest).andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Validation error: device must not be null"))); + } + + @Test + public void testSaveDeviceWithCredentials_WithExistingName() throws Exception { + String testToken = "TEST_TOKEN"; + + Device device = new Device(); + device.setName("My device"); + device.setType("default"); + + DeviceCredentials deviceCredentials = new DeviceCredentials(); + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); + deviceCredentials.setCredentialsId(testToken); + + SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(device, deviceCredentials); + + Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService); + + Device savedDevice = readResponse(doPost("/api/device-with-credentials", saveRequest).andExpect(status().isOk()), Device.class); + Assert.assertNotNull(savedDevice); + + doPost("/api/device-with-credentials", saveRequest).andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Device with such name already exists!"))); + } + @Test public void saveDeviceWithViolationOfValidation() throws Exception { Device device = new Device(); diff --git a/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java index b4735519a5..bb542e6cf1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java @@ -38,6 +38,8 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DaoSqlTest; @@ -216,6 +218,36 @@ public class TbResourceControllerTest extends AbstractControllerTest { .andExpect(statusReason(containsString(msgErrorNoFound("Resource", resourceIdStr)))); } + @Test + public void testShoudNotDeleteTbResourceIfAssignedToWidgetType() throws Exception { + TbResource resource = new TbResource(); + resource.setResourceType(ResourceType.JKS); + resource.setTitle("My first resource"); + resource.setFileName(DEFAULT_FILE_NAME); + resource.setData(TEST_DATA); + + TbResource savedResource = save(resource); + + Mockito.reset(tbClusterService, auditLogService); + String resourceIdStr = savedResource.getId().getId().toString(); + + //create widget type + WidgetsBundle widgetsBundle = new WidgetsBundle(); + widgetsBundle.setTitle("My widgets bundle"); + WidgetsBundle savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class); + + WidgetTypeDetails widgetType = new WidgetTypeDetails(); + widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); + widgetType.setName("Widget Type"); + widgetType.setDescriptor(JacksonUtil.fromString(String.format("{ \"resources\": [{\"url\":{\"entityType\":\"TB_RESOURCE\",\"id\":\"%s\"},\"isModule\":true}]}", savedResource.getId()), JsonNode.class)); + doPost("/api/widgetType", widgetType, WidgetTypeDetails.class); + + doDelete("/api/resource/" + resourceIdStr) + .andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Following widget types uses current resource: [" + + widgetType .getName()+ "]"))); + } + @Test public void testFindTenantTbResources() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java b/application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java new file mode 100644 index 0000000000..0394e8a505 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java @@ -0,0 +1,160 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller.plugin; + +import lombok.extern.slf4j.Slf4j; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.adapter.NativeWebSocketSession; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.service.ws.WebSocketSessionRef; + +import javax.websocket.RemoteEndpoint; +import javax.websocket.SendHandler; +import javax.websocket.SendResult; +import javax.websocket.Session; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.willAnswer; +import static org.mockito.BDDMockito.willDoNothing; +import static org.mockito.BDDMockito.willReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@Slf4j +class TbWebSocketHandlerTest { + + TbWebSocketHandler wsHandler; + NativeWebSocketSession session; + Session nativeSession; + RemoteEndpoint.Async asyncRemote; + WebSocketSessionRef sessionRef; + int maxMsgQueuePerSession; + TbWebSocketHandler.SessionMetaData sendHandler; + ExecutorService executor; + + @BeforeEach + void setUp() throws IOException { + maxMsgQueuePerSession = 100; + executor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName(getClass().getSimpleName())); + wsHandler = spy(new TbWebSocketHandler()); + willDoNothing().given(wsHandler).close(any(), any()); + session = mock(NativeWebSocketSession.class); + nativeSession = mock(Session.class); + willReturn(nativeSession).given(session).getNativeSession(Session.class); + asyncRemote = mock(RemoteEndpoint.Async.class); + willReturn(asyncRemote).given(nativeSession).getAsyncRemote(); + sessionRef = mock(WebSocketSessionRef.class, Mockito.RETURNS_DEEP_STUBS); //prevent NPE on logs + sendHandler = spy(wsHandler.new SessionMetaData(session, sessionRef, maxMsgQueuePerSession)); + } + + @AfterEach + void tearDown() { + if (executor != null) { + executor.shutdownNow(); + } + } + + @Test + void sendHandler_sendMsg_parallel_no_race() throws InterruptedException { + CountDownLatch finishLatch = new CountDownLatch(maxMsgQueuePerSession * 2); + AtomicInteger sendersCount = new AtomicInteger(); + willAnswer(invocation -> { + assertThat(sendersCount.incrementAndGet()).as("no race").isEqualTo(1); + String text = invocation.getArgument(0); + SendHandler onResultHandler = invocation.getArgument(1); + SendResult sendResult = new SendResult(); + executor.submit(() -> { + sendersCount.decrementAndGet(); + onResultHandler.onResult(sendResult); + finishLatch.countDown(); + }); + return null; + }).given(asyncRemote).sendText(anyString(), any()); + + assertThat(sendHandler.isSending.get()).as("sendHandler not is in sending state").isFalse(); + //first batch + IntStream.range(0, maxMsgQueuePerSession).parallel().forEach(i -> sendHandler.sendMsg("hello " + i)); + Awaitility.await("first batch processed").atMost(30, TimeUnit.SECONDS).until(() -> finishLatch.getCount() == maxMsgQueuePerSession); + assertThat(sendHandler.isSending.get()).as("sendHandler not is in sending state").isFalse(); + //second batch - to test pause between big msg batches + IntStream.range(100, 100 + maxMsgQueuePerSession).parallel().forEach(i -> sendHandler.sendMsg("hello " + i)); + assertThat(finishLatch.await(30, TimeUnit.SECONDS)).as("all callbacks fired").isTrue(); + + verify(sendHandler, never()).closeSession(any()); + verify(sendHandler, times(maxMsgQueuePerSession * 2)).onResult(any()); + assertThat(sendHandler.isSending.get()).as("sendHandler not is in sending state").isFalse(); + } + + @Test + void sendHandler_sendMsg_message_order() throws InterruptedException { + CountDownLatch finishLatch = new CountDownLatch(maxMsgQueuePerSession); + Collection outputs = new ConcurrentLinkedQueue<>(); + willAnswer(invocation -> { + String text = invocation.getArgument(0); + outputs.add(text); + SendHandler onResultHandler = invocation.getArgument(1); + SendResult sendResult = new SendResult(); + executor.submit(() -> { + onResultHandler.onResult(sendResult); + finishLatch.countDown(); + }); + return null; + }).given(asyncRemote).sendText(anyString(), any()); + + List inputs = IntStream.range(0, maxMsgQueuePerSession).mapToObj(i -> "msg " + i).collect(Collectors.toList()); + inputs.forEach(s -> sendHandler.sendMsg(s)); + + assertThat(finishLatch.await(30, TimeUnit.SECONDS)).as("all callbacks fired").isTrue(); + assertThat(outputs).as("inputs exactly the same as outputs").containsExactlyElementsOf(inputs); + + verify(sendHandler, never()).closeSession(any()); + verify(sendHandler, times(maxMsgQueuePerSession)).onResult(any()); + } + + @Test + void sendHandler_sendMsg_queue_size_exceed() { + willDoNothing().given(asyncRemote).sendText(anyString(), any()); // send text will never call back, so queue will grow each sendMsg + sendHandler.sendMsg("first message to stay in-flight all the time during this test"); + IntStream.range(0, maxMsgQueuePerSession).parallel().forEach(i -> sendHandler.sendMsg("hello " + i)); + verify(sendHandler, never()).closeSession(any()); + sendHandler.sendMsg("excessive message"); + verify(sendHandler, times(1)).closeSession(eq(new CloseStatus(1008, "Max pending updates limit reached!"))); + verify(asyncRemote, times(1)).sendText(anyString(), any()); + } + +} 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 135b6d87c8..82b2ce3ec2 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java @@ -100,6 +100,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @TestPropertySource(properties = { "edges.enabled=true", + "queue.rule-engine.stats.enabled=false", }) abstract public class AbstractEdgeTest extends AbstractControllerTest { @@ -181,14 +182,14 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { @After public void afterTest() throws Exception { + try { + edgeImitator.disconnect(); + } catch (Exception ignored){} + loginSysAdmin(); doDelete("/api/tenant/" + savedTenant.getUuidId()) .andExpect(status().isOk()); - - try { - edgeImitator.disconnect(); - } catch (Exception ignored) {} } private void installation() { diff --git a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java index 8f05e6810f..0edf070aef 100644 --- a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java @@ -94,8 +94,6 @@ public class EdgeImitator { @Getter private UplinkResponseMsg latestResponseMsg; - private boolean connected = false; - public EdgeImitator(String host, int port, String routingKey, String routingSecret) throws NoSuchFieldException, IllegalAccessException { edgeRpcClient = new EdgeGrpcClient(); messagesLatch = new CountDownLatch(0); @@ -120,7 +118,6 @@ public class EdgeImitator { } public void connect() { - connected = true; edgeRpcClient.connect(routingKey, routingSecret, this::onUplinkResponse, this::onEdgeUpdate, @@ -131,7 +128,6 @@ public class EdgeImitator { } public void disconnect() throws InterruptedException { - connected = false; edgeRpcClient.disconnect(false); } diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index 28c13e33fb..d96af8a910 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -14,6 +14,7 @@ edges.enabled=false edges.storage.no_read_records_sleep=500 edges.storage.sleep_between_batches=500 actors.rpc.sequential=true +queue.rule-engine.stats.enabled=true # Transports disabled to speed up the context init. Particular transport will be enabled with @TestPropertySource in respective tests transport.http.enabled=false diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/TbActorMailbox.java b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorMailbox.java index 587da8f3b1..ad1604f7b0 100644 --- a/common/actor/src/main/java/org/thingsboard/server/actors/TbActorMailbox.java +++ b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorMailbox.java @@ -19,6 +19,7 @@ import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.msg.MsgType; +import org.thingsboard.server.common.msg.TbActorError; import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.TbActorStopReason; @@ -69,9 +70,14 @@ public final class TbActorMailbox implements TbActorCtx { } } } catch (Throwable t) { - log.debug("[{}] Failed to init actor, attempt: {}", selfId, attempt, t); + InitFailureStrategy strategy; int attemptIdx = attempt + 1; - InitFailureStrategy strategy = actor.onInitFailure(attempt, t); + if (isUnrecoverable(t)) { + strategy = InitFailureStrategy.stop(); + } else { + log.debug("[{}] Failed to init actor, attempt: {}", selfId, attempt, t); + strategy = actor.onInitFailure(attempt, t); + } if (strategy.isStop() || (settings.getMaxActorInitAttempts() > 0 && attemptIdx > settings.getMaxActorInitAttempts())) { log.info("[{}] Failed to init actor, attempt {}, going to stop attempts.", selfId, attempt, t); stopReason = TbActorStopReason.INIT_FAILED; @@ -88,6 +94,13 @@ public final class TbActorMailbox implements TbActorCtx { } } + private static boolean isUnrecoverable(Throwable t) { + if (t instanceof TbActorException && t.getCause() != null) { + t = t.getCause(); + } + return t instanceof TbActorError && ((TbActorError) t).isUnrecoverable(); + } + private void enqueue(TbActorMsg msg, boolean highPriority) { if (!destroyInProgress.get()) { if (highPriority) { diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCacheKey.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCacheKey.java new file mode 100644 index 0000000000..9db53f86c6 --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCacheKey.java @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache.resourceInfo; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.thingsboard.server.common.data.id.TbResourceId; +import org.thingsboard.server.common.data.id.TenantId; + +import java.io.Serializable; + +@Getter +@EqualsAndHashCode +@RequiredArgsConstructor +@Builder +public class ResourceInfoCacheKey implements Serializable { + + private final TenantId tenantId; + private final TbResourceId tbResourceId; + + @Override + public String toString() { + return tenantId + "_" + tbResourceId; + } +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCaffeineCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCaffeineCache.java new file mode 100644 index 0000000000..95754d891a --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCaffeineCache.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache.resourceInfo; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CaffeineTbTransactionalCache; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.TbResourceInfo; + + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) +@Service("ResourceInfoCache") +public class ResourceInfoCaffeineCache extends CaffeineTbTransactionalCache { + + public ResourceInfoCaffeineCache(CacheManager cacheManager) { + super(cacheManager, CacheConstants.RESOURCE_INFO_CACHE); + } + +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoEvictEvent.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoEvictEvent.java new file mode 100644 index 0000000000..11272a5e24 --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoEvictEvent.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache.resourceInfo; + +import lombok.Data; +import org.thingsboard.server.common.data.id.TbResourceId; +import org.thingsboard.server.common.data.id.TenantId; + +@Data +public class ResourceInfoEvictEvent { + private final TenantId tenantId; + private final TbResourceId resourceId; +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoRedisCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoRedisCache.java new file mode 100644 index 0000000000..fee14e1ca1 --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoRedisCache.java @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache.resourceInfo; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CacheSpecsMap; +import org.thingsboard.server.cache.RedisTbTransactionalCache; +import org.thingsboard.server.cache.TBRedisCacheConfiguration; +import org.thingsboard.server.cache.TbFSTRedisSerializer; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.TbResourceInfo; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") +@Service("ResourceInfoCache") +public class ResourceInfoRedisCache extends RedisTbTransactionalCache { + + public ResourceInfoRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { + super(CacheConstants.RESOURCE_INFO_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>()); + } +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java new file mode 100644 index 0000000000..90355d885d --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.device; + +import com.fasterxml.jackson.databind.JsonNode; +import org.springframework.core.io.Resource; +import org.thingsboard.server.common.data.Device; + +import java.net.URISyntaxException; + +public interface DeviceConnectivityService { + + JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException; + + Resource getPemCertFile(String protocol); +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java index dcb3a5232a..9055202f4f 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeEventService.java @@ -26,7 +26,7 @@ public interface EdgeEventService { ListenableFuture saveAsync(EdgeEvent edgeEvent); - PageData findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate); + PageData findEdgeEvents(TenantId tenantId, EdgeId edgeId, Long seqIdStart, Long seqIdEnd, TimePageLink pageLink); /** * Executes stored procedure to cleanup old edge events. diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java index 3ddb6187ea..39e94b3a6b 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java @@ -53,6 +53,8 @@ public interface RelationService { void deleteEntityRelations(TenantId tenantId, EntityId entity); + void deleteEntityCommonRelations(TenantId tenantId, EntityId entity); + List findByFrom(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup); ListenableFuture> findByFromAsync(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java index cb02aa1180..245e33ed14 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.widget; +import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetType; @@ -40,6 +41,8 @@ public interface WidgetTypeService extends EntityDaoService { List findWidgetTypesInfosByTenantIdAndBundleAlias(TenantId tenantId, String bundleAlias); + List findWidgetTypesInfosByTenantIdAndResourceId(TenantId tenantId, TbResourceId tbResourceId); + WidgetType findWidgetTypeByTenantIdBundleAliasAndAlias(TenantId tenantId, String bundleAlias, String alias); void deleteWidgetTypesByTenantIdAndBundleAlias(TenantId tenantId, String bundleAlias); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java index ff0032f435..f21b13a674 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java @@ -44,4 +44,5 @@ public class CacheConstants { public static final String USER_SETTINGS_CACHE = "userSettings"; public static final String DASHBOARD_TITLES_CACHE = "dashboardTitles"; public static final String ENTITY_COUNT_CACHE = "entityCount"; + public static final String RESOURCE_INFO_CACHE = "resourceInfo"; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java index 636ab0de38..4b4b9e519d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Customer.java @@ -35,9 +35,9 @@ public class Customer extends ContactBased implements HasTenantId, E @NoXss @Length(fieldName = "title") - @ApiModelProperty(position = 3, value = "Title of the customer", example = "Company A") + @ApiModelProperty(position = 3, required = true, value = "Title of the customer", example = "Company A") private String title; - @ApiModelProperty(position = 5, required = true, value = "JSON object with Tenant Id") + @ApiModelProperty(position = 5, value = "JSON object with Tenant Id") private TenantId tenantId; @Getter @Setter @@ -89,43 +89,43 @@ public class Customer extends ContactBased implements HasTenantId, E return super.getCreatedTime(); } - @ApiModelProperty(position = 6, required = true, value = "Country", example = "US") + @ApiModelProperty(position = 6, value = "Country", example = "US") @Override public String getCountry() { return super.getCountry(); } - @ApiModelProperty(position = 7, required = true, value = "State", example = "NY") + @ApiModelProperty(position = 7, value = "State", example = "NY") @Override public String getState() { return super.getState(); } - @ApiModelProperty(position = 8, required = true, value = "City", example = "New York") + @ApiModelProperty(position = 8, value = "City", example = "New York") @Override public String getCity() { return super.getCity(); } - @ApiModelProperty(position = 9, required = true, value = "Address Line 1", example = "42 Broadway Suite 12-400") + @ApiModelProperty(position = 9, value = "Address Line 1", example = "42 Broadway Suite 12-400") @Override public String getAddress() { return super.getAddress(); } - @ApiModelProperty(position = 10, required = true, value = "Address Line 2", example = "") + @ApiModelProperty(position = 10, value = "Address Line 2", example = "") @Override public String getAddress2() { return super.getAddress2(); } - @ApiModelProperty(position = 11, required = true, value = "Zip code", example = "10004") + @ApiModelProperty(position = 11, value = "Zip code", example = "10004") @Override public String getZip() { return super.getZip(); } - @ApiModelProperty(position = 12, required = true, value = "Phone number", example = "+1(415)777-7777") + @ApiModelProperty(position = 12, value = "Phone number", example = "+1(415)777-7777") @Override public String getPhone() { return super.getPhone(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java index a32c16d88a..fe08934f79 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DashboardInfo.java @@ -85,7 +85,7 @@ public class DashboardInfo extends BaseData implements HasName, Has this.tenantId = tenantId; } - @ApiModelProperty(position = 4, value = "Title of the dashboard.") + @ApiModelProperty(position = 4, required = true, value = "Title of the dashboard.") public String getTitle() { return title; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java index 45e4244bcb..f16a124ef4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java @@ -146,7 +146,7 @@ public class Device extends BaseDataWithAdditionalInfo implements HasL this.name = name; } - @ApiModelProperty(position = 6, required = true, value = "Device Profile Name", example = "Temperature Sensor") + @ApiModelProperty(position = 6, value = "Device Profile Name", example = "Temperature Sensor") public String getType() { return type; } @@ -155,7 +155,7 @@ public class Device extends BaseDataWithAdditionalInfo implements HasL this.type = type; } - @ApiModelProperty(position = 7, required = true, value = "Label that may be used in widgets", example = "Room 234 Sensor") + @ApiModelProperty(position = 7, value = "Label that may be used in widgets", example = "Room 234 Sensor") public String getLabel() { return label; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java index c0e44baeb3..99fedb9c93 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityView.java @@ -40,7 +40,7 @@ public class EntityView extends BaseDataWithAdditionalInfo private static final long serialVersionUID = 5582010124562018986L; - @ApiModelProperty(position = 7, required = true, value = "JSON object with the referenced Entity Id (Device or Asset).") + @ApiModelProperty(position = 7, value = "JSON object with the referenced Entity Id (Device or Asset).") private EntityId entityId; private TenantId tenantId; private CustomerId customerId; @@ -52,7 +52,7 @@ public class EntityView extends BaseDataWithAdditionalInfo @Length(fieldName = "type") @ApiModelProperty(position = 6, required = true, value = "Device Profile Name", example = "Temperature Sensor") private String type; - @ApiModelProperty(position = 8, required = true, value = "Set of telemetry and attribute keys to expose via Entity View.") + @ApiModelProperty(position = 8, value = "Set of telemetry and attribute keys to expose via Entity View.") private TelemetryEntityView keys; @ApiModelProperty(position = 9, value = "Represents the start time of the interval that is used to limit access to target device telemetry. Customer will not be able to see entity telemetry that is outside the specified interval;") private long startTimeMs; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java b/common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java index f8c74a5155..836a5bff93 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java @@ -20,13 +20,17 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.security.DeviceCredentials; +import javax.validation.constraints.NotNull; + @ApiModel @Data public class SaveDeviceWithCredentialsRequest { @ApiModelProperty(position = 1, value = "The JSON with device entity.", required = true) + @NotNull private final Device device; @ApiModelProperty(position = 2, value = "The JSON with credentials entity.", required = true) + @NotNull private final DeviceCredentials credentials; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java index 89cd9ec467..dd6aadbe0b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Tenant.java @@ -34,14 +34,14 @@ public class Tenant extends ContactBased implements HasTenantId, HasTi @Length(fieldName = "title") @NoXss - @ApiModelProperty(position = 3, value = "Title of the tenant", example = "Company A") + @ApiModelProperty(position = 3, required = true, value = "Title of the tenant", example = "Company A") private String title; @NoXss @Length(fieldName = "region") @ApiModelProperty(position = 5, value = "Geo region of the tenant", example = "North America") private String region; - @ApiModelProperty(position = 6, required = true, value = "JSON object with Tenant Profile Id") + @ApiModelProperty(position = 6, value = "JSON object with Tenant Profile Id") private TenantProfileId tenantProfileId; public Tenant() { @@ -111,43 +111,43 @@ public class Tenant extends ContactBased implements HasTenantId, HasTi return super.getCreatedTime(); } - @ApiModelProperty(position = 7, required = true, value = "Country", example = "US") + @ApiModelProperty(position = 7, value = "Country", example = "US") @Override public String getCountry() { return super.getCountry(); } - @ApiModelProperty(position = 8, required = true, value = "State", example = "NY") + @ApiModelProperty(position = 8, value = "State", example = "NY") @Override public String getState() { return super.getState(); } - @ApiModelProperty(position = 9, required = true, value = "City", example = "New York") + @ApiModelProperty(position = 9, value = "City", example = "New York") @Override public String getCity() { return super.getCity(); } - @ApiModelProperty(position = 10, required = true, value = "Address Line 1", example = "42 Broadway Suite 12-400") + @ApiModelProperty(position = 10, value = "Address Line 1", example = "42 Broadway Suite 12-400") @Override public String getAddress() { return super.getAddress(); } - @ApiModelProperty(position = 11, required = true, value = "Address Line 2", example = "") + @ApiModelProperty(position = 11, value = "Address Line 2", example = "") @Override public String getAddress2() { return super.getAddress2(); } - @ApiModelProperty(position = 12, required = true, value = "Zip code", example = "10004") + @ApiModelProperty(position = 12, value = "Zip code", example = "10004") @Override public String getZip() { return super.getZip(); } - @ApiModelProperty(position = 13, required = true, value = "Phone number", example = "+1(415)777-7777") + @ApiModelProperty(position = 13, value = "Phone number", example = "+1(415)777-7777") @Override public String getPhone() { return super.getPhone(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/User.java b/common/data/src/main/java/org/thingsboard/server/common/data/User.java index b3d9268c6b..2db8c83a89 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/User.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/User.java @@ -129,7 +129,7 @@ public class User extends BaseDataWithAdditionalInfo implements HasName, this.authority = authority; } - @ApiModelProperty(position = 8, required = true, value = "First name of the user", example = "John") + @ApiModelProperty(position = 8, required = false, value = "First name of the user", example = "John") public String getFirstName() { return firstName; } @@ -138,7 +138,7 @@ public class User extends BaseDataWithAdditionalInfo implements HasName, this.firstName = firstName; } - @ApiModelProperty(position = 9, required = true, value = "Last name of the user", example = "Doe") + @ApiModelProperty(position = 9, required = false, value = "Last name of the user", example = "Doe") public String getLastName() { return lastName; } @@ -147,7 +147,7 @@ public class User extends BaseDataWithAdditionalInfo implements HasName, this.lastName = lastName; } - @ApiModelProperty(position = 10, required = true, value = "Phone number of the user", example = "38012345123") + @ApiModelProperty(position = 10, required = false, value = "Phone number of the user", example = "38012345123") public String getPhone() { return phone; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java index 34fec2cd82..c96b55b61d 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java @@ -153,7 +153,6 @@ public class Alarm extends BaseData implements HasName, HasTenantId, Ha } public static AlarmStatus toStatus(boolean cleared, boolean acknowledged) { - if (cleared) { return acknowledged ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK; } else { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java index bbb56305db..a8fb0b01b1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java @@ -131,7 +131,7 @@ public class Asset extends BaseDataWithAdditionalInfo implements HasLab this.name = name; } - @ApiModelProperty(position = 6, required = true, value = "Asset type", example = "Building") + @ApiModelProperty(position = 6, value = "Asset type", example = "Building") public String getType() { return type; } @@ -140,7 +140,7 @@ public class Asset extends BaseDataWithAdditionalInfo implements HasLab this.type = type; } - @ApiModelProperty(position = 7, required = true, value = "Label that may be used in widgets", example = "NY Building") + @ApiModelProperty(position = 7, value = "Label that may be used in widgets", example = "NY Building") public String getLabel() { return label; } @@ -149,7 +149,7 @@ public class Asset extends BaseDataWithAdditionalInfo implements HasLab this.label = label; } - @ApiModelProperty(position = 8, required = true, value = "JSON object with Asset Profile Id.") + @ApiModelProperty(position = 8, value = "JSON object with Asset Profile Id.") public AssetProfileId getAssetProfileId() { return assetProfileId; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java index 71c35f4bd8..3688f5c6c2 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEvent.java @@ -31,6 +31,7 @@ import java.util.UUID; @ToString(callSuper = true) public class EdgeEvent extends BaseData { + private long seqId; private TenantId tenantId; private EdgeId edgeId; private EdgeEventActionType action; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java index d3af30907d..fd1b4ee0f8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java @@ -42,6 +42,8 @@ public class AlarmNotificationInfo implements RuleOriginatedNotificationInfo { private String alarmOriginatorName; private AlarmSeverity alarmSeverity; private AlarmStatus alarmStatus; + private boolean acknowledged; + private boolean cleared; private CustomerId alarmCustomerId; @Override diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java b/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java index 04b5d3fb35..0a39d8d51b 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.msg; +import lombok.Getter; import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; @@ -28,7 +29,7 @@ public enum MsgType { * * See {@link PartitionChangeMsg} */ - PARTITION_CHANGE_MSG, + PARTITION_CHANGE_MSG(true), APP_INIT_MSG, @@ -108,7 +109,7 @@ public enum MsgType { * Message that is sent from the Device Actor to Rule Engine. Requires acknowledgement */ - SESSION_TIMEOUT_MSG, + SESSION_TIMEOUT_MSG(true), STATS_PERSIST_TICK_MSG, @@ -130,4 +131,14 @@ public enum MsgType { EDGE_SYNC_REQUEST_TO_EDGE_SESSION_MSG, EDGE_SYNC_RESPONSE_FROM_EDGE_SESSION_MSG; + @Getter + private final boolean ignoreOnStart; + + MsgType() { + this.ignoreOnStart = false; + } + + MsgType(boolean ignoreOnStart) { + this.ignoreOnStart = ignoreOnStart; + } } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbActorError.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbActorError.java new file mode 100644 index 0000000000..fc27feb096 --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbActorError.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.msg; + +public interface TbActorError { + + boolean isUnrecoverable(); + +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index f04104bc51..17bc7c0a8f 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -277,6 +277,11 @@ public final class TbMsg implements Serializable { this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ctx, callback); } + public TbMsg copyWithNewCtx() { + return new TbMsg(this.queueName, this.id, this.ts, this.type, this.originator, this.customerId, + this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ctx.copy(), TbMsgCallback.EMPTY); + } + public TbMsgCallback getCallback() { // May be null in case of deserialization; if (callback != null) { diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/aware/RuleChainAwareMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/aware/RuleChainAwareMsg.java index d0e90ae421..5fbc857e0c 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/aware/RuleChainAwareMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/aware/RuleChainAwareMsg.java @@ -17,9 +17,12 @@ package org.thingsboard.server.common.msg.aware; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.msg.TbActorMsg; +import org.thingsboard.server.common.msg.TbMsg; public interface RuleChainAwareMsg extends TbActorMsg { RuleChainId getRuleChainId(); + + TbMsg getMsg(); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index fcf80bcf3d..44999d016a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.queue.discovery; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolStringList; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.curator.framework.CuratorFramework; @@ -44,8 +45,10 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.List; import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -66,6 +69,10 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi private Integer zkSessionTimeout; @Value("${zk.zk_dir}") private String zkDir; + @Value("${zk.recalculate_delay:60000}") + private Long recalculateDelay; + + protected final ConcurrentHashMap> delayedTasks; private final TbServiceInfoProvider serviceInfoProvider; private final PartitionService partitionService; @@ -82,6 +89,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi PartitionService partitionService) { this.serviceInfoProvider = serviceInfoProvider; this.partitionService = partitionService; + delayedTasks = new ConcurrentHashMap<>(); } @PostConstruct @@ -287,11 +295,39 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi log.error("Failed to decode server instance for node {}", data.getPath(), e); throw e; } - log.debug("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), instance.getServiceId()); + + String serviceId = instance.getServiceId(); + ProtocolStringList serviceTypesList = instance.getServiceTypesList(); + + log.trace("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), serviceId); switch (pathChildrenCacheEvent.getType()) { case CHILD_ADDED: + ScheduledFuture task = delayedTasks.remove(serviceId); + if (task != null) { + if (task.cancel(false)) { + log.debug("[{}] Recalculate partitions ignored. Service was restarted in time [{}].", + serviceId, serviceTypesList); + } else { + log.debug("[{}] Going to recalculate partitions. Service was not restarted in time [{}]!", + serviceId, serviceTypesList); + recalculatePartitions(); + } + } else { + log.trace("[{}] Going to recalculate partitions due to adding new node [{}].", + serviceId, serviceTypesList); + recalculatePartitions(); + } + break; case CHILD_REMOVED: - recalculatePartitions(); + ScheduledFuture future = zkExecutorService.schedule(() -> { + log.debug("[{}] Going to recalculate partitions due to removed node [{}]", + serviceId, serviceTypesList); + ScheduledFuture removedTask = delayedTasks.remove(serviceId); + if (removedTask != null) { + recalculatePartitions(); + } + }, recalculateDelay, TimeUnit.MILLISECONDS); + delayedTasks.put(serviceId, future); break; default: break; @@ -303,6 +339,8 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi * Synchronized to ensure that other servers info is up to date * */ synchronized void recalculatePartitions() { + delayedTasks.values().forEach(future -> future.cancel(false)); + delayedTasks.clear(); partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), getOtherServers()); } diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java new file mode 100644 index 0000000000..a8810efd0e --- /dev/null +++ b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java @@ -0,0 +1,189 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.queue.discovery; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.imps.CuratorFrameworkState; +import org.apache.curator.framework.recipes.cache.ChildData; +import org.apache.curator.framework.recipes.cache.PathChildrenCache; +import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.gen.transport.TransportProtos; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_ADDED; +import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_REMOVED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ZkDiscoveryServiceTest { + + @Mock + private TbServiceInfoProvider serviceInfoProvider; + + @Mock + private PartitionService partitionService; + + @Mock + private CuratorFramework client; + + @Mock + private PathChildrenCache cache; + + @Mock + private CuratorFramework curatorFramework; + + private ZkDiscoveryService zkDiscoveryService; + + private static final long RECALCULATE_DELAY = 100L; + + final TransportProtos.ServiceInfo currentInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-rule-engine-0").build(); + final ChildData currentData = new ChildData("/thingsboard/nodes/0000000010", null, currentInfo.toByteArray()); + final TransportProtos.ServiceInfo childInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-rule-engine-1").build(); + final ChildData childData = new ChildData("/thingsboard/nodes/0000000020", null, childInfo.toByteArray()); + + @Before + public void setup() { + zkDiscoveryService = Mockito.spy(new ZkDiscoveryService(serviceInfoProvider, partitionService)); + ScheduledExecutorService zkExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("zk-discovery")); + when(client.getState()).thenReturn(CuratorFrameworkState.STARTED); + ReflectionTestUtils.setField(zkDiscoveryService, "stopped", false); + ReflectionTestUtils.setField(zkDiscoveryService, "client", client); + ReflectionTestUtils.setField(zkDiscoveryService, "cache", cache); + ReflectionTestUtils.setField(zkDiscoveryService, "nodePath", "/thingsboard/nodes/0000000010"); + ReflectionTestUtils.setField(zkDiscoveryService, "zkExecutorService", zkExecutorService); + ReflectionTestUtils.setField(zkDiscoveryService, "recalculateDelay", RECALCULATE_DELAY); + ReflectionTestUtils.setField(zkDiscoveryService, "zkDir", "/thingsboard"); + + when(serviceInfoProvider.getServiceInfo()).thenReturn(currentInfo); + + List dataList = new ArrayList<>(); + dataList.add(currentData); + when(cache.getCurrentData()).thenReturn(dataList); + } + + @Test + public void restartNodeInTimeTest() throws Exception { + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + + stopNode(childData); + + assertEquals(1, zkDiscoveryService.delayedTasks.size()); + + verify(partitionService, never()).recalculatePartitions(any(), any()); + + startNode(childData); + + verify(partitionService, never()).recalculatePartitions(any(), any()); + + Thread.sleep(RECALCULATE_DELAY * 2); + + verify(partitionService, never()).recalculatePartitions(any(), any()); + + assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + } + + @Test + public void restartNodeNotInTimeTest() throws Exception { + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + + stopNode(childData); + + assertEquals(1, zkDiscoveryService.delayedTasks.size()); + + Thread.sleep(RECALCULATE_DELAY * 2); + + assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(Collections.emptyList())); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + } + + @Test + public void startAnotherNodeDuringRestartTest() throws Exception { + var anotherInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-transport").build(); + var anotherData = new ChildData("/thingsboard/nodes/0000000030", null, anotherInfo.toByteArray()); + + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + + stopNode(childData); + + assertEquals(1, zkDiscoveryService.delayedTasks.size()); + + startNode(anotherData); + + assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo))); + reset(partitionService); + + Thread.sleep(RECALCULATE_DELAY * 2); + + verify(partitionService, never()).recalculatePartitions(any(), any()); + + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo, childInfo))); + } + + private void startNode(ChildData data) throws Exception { + cache.getCurrentData().add(data); + zkDiscoveryService.childEvent(curatorFramework, new PathChildrenCacheEvent(CHILD_ADDED, data)); + } + + private void stopNode(ChildData data) throws Exception { + cache.getCurrentData().remove(data); + zkDiscoveryService.childEvent(curatorFramework, new PathChildrenCacheEvent(CHILD_REMOVED, data)); + } + +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index 6c50561363..b337612011 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -15,6 +15,8 @@ */ package org.thingsboard.script.api.tbel; +import com.google.common.primitives.Bytes; +import org.apache.commons.lang3.ArrayUtils; import org.mvel2.ExecutionContext; import org.mvel2.ParserConfiguration; import org.mvel2.execution.ExecutionArrayList; @@ -25,11 +27,13 @@ import org.thingsboard.server.common.data.StringUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; +import java.math.BigInteger; import java.math.RoundingMode; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Base64; import java.util.Collection; import java.util.List; @@ -61,6 +65,10 @@ public class TbUtils { String.class))); parserConfig.addImport("parseInt", new MethodStub(TbUtils.class.getMethod("parseInt", String.class, int.class))); + parserConfig.addImport("parseLong", new MethodStub(TbUtils.class.getMethod("parseLong", + String.class))); + parserConfig.addImport("parseLong", new MethodStub(TbUtils.class.getMethod("parseLong", + String.class, int.class))); parserConfig.addImport("parseFloat", new MethodStub(TbUtils.class.getMethod("parseFloat", String.class))); parserConfig.addImport("parseDouble", new MethodStub(TbUtils.class.getMethod("parseDouble", @@ -81,8 +89,58 @@ public class TbUtils { byte[].class, int.class, int.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", byte[].class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseLittleEndianHexToLong", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToLong", + String.class))); + parserConfig.addImport("parseBigEndianHexToLong", new MethodStub(TbUtils.class.getMethod("parseBigEndianHexToLong", + String.class))); + parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", + String.class))); + parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", + String.class, boolean.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + List.class, int.class, int.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + List.class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + byte[].class, int.class, int.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + byte[].class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseLittleEndianHexToFloat", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToFloat", + String.class))); + parserConfig.addImport("parseBigEndianHexToFloat", new MethodStub(TbUtils.class.getMethod("parseBigEndianHexToFloat", + String.class))); + parserConfig.addImport("parseHexToFloat", new MethodStub(TbUtils.class.getMethod("parseHexToFloat", + String.class))); + parserConfig.addImport("parseHexToFloat", new MethodStub(TbUtils.class.getMethod("parseHexToFloat", + String.class, boolean.class))); + parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", + byte[].class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", + byte[].class, int.class))); + parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", + List.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", + List.class, int.class))); + parserConfig.addImport("parseLittleEndianHexToDouble", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToDouble", + String.class))); + parserConfig.addImport("parseBigEndianHexToDouble", new MethodStub(TbUtils.class.getMethod("parseBigEndianHexToDouble", + String.class))); + parserConfig.addImport("parseHexToDouble", new MethodStub(TbUtils.class.getMethod("parseHexToDouble", + String.class))); + parserConfig.addImport("parseHexToDouble", new MethodStub(TbUtils.class.getMethod("parseHexToDouble", + String.class, boolean.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + byte[].class, int.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + byte[].class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + List.class, int.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + List.class, int.class, boolean.class))); parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", double.class, int.class))); + parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", + float.class, int.class))); parserConfig.addImport("hexToBytes", new MethodStub(TbUtils.class.getMethod("hexToBytes", ExecutionContext.class, String.class))); parserConfig.addImport("base64ToHex", new MethodStub(TbUtils.class.getMethod("base64ToHex", @@ -154,37 +212,73 @@ public class TbUtils { } public static Integer parseInt(String value) { - if (value != null) { + int radix = getRadix(value); + return parseInt(value, radix); + } + + public static Integer parseInt(String value, int radix) { + if (StringUtils.isNotBlank(value)) { try { - int radix = 10; - if (isHexadecimal(value)) { - radix = 16; + String valueP = prepareNumberString(value); + isValidRadix(valueP, radix); + try { + return Integer.parseInt(valueP, radix); + } catch (NumberFormatException e) { + BigInteger bi = new BigInteger(valueP, radix); + if (bi.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) + throw new NumberFormatException("Value \"" + value + "\" is greater than the maximum Integer value " + Integer.MAX_VALUE + " !"); + if (bi.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0) + throw new NumberFormatException("Value \"" + value + "\" is less than the minimum Integer value " + Integer.MIN_VALUE + " !"); + Float f = parseFloat(valueP); + if (f != null) { + return f.intValue(); + } else { + throw new NumberFormatException(e.getMessage()); + } } - return Integer.parseInt(prepareNumberString(value), radix); } catch (NumberFormatException e) { - Float f = parseFloat(value); - if (f != null) { - return f.intValue(); - } + throw new NumberFormatException(e.getMessage()); } } return null; } - public static Integer parseInt(String value, int radix) { - if (value != null) { + public static Long parseLong(String value) { + int radix = getRadix(value); + return parseLong(value, radix); + } + + public static Long parseLong(String value, int radix) { + if (StringUtils.isNotBlank(value)) { try { - return Integer.parseInt(prepareNumberString(value), radix); - } catch (NumberFormatException e) { - Float f = parseFloat(value); - if (f != null) { - return f.intValue(); + String valueP = prepareNumberString(value); + isValidRadix(valueP, radix); + try { + return Long.parseLong(valueP, radix); + } catch (NumberFormatException e) { + BigInteger bi = new BigInteger(valueP, radix); + if (bi.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) + throw new NumberFormatException("Value \"" + value + "\"is greater than the maximum Long value " + Long.MAX_VALUE + " !"); + if (bi.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) + throw new NumberFormatException("Value \"" + value + "\" is less than the minimum Long value " + Long.MIN_VALUE + " !"); + Double dd = parseDouble(valueP); + if (dd != null) { + return dd.longValue(); + } else { + throw new NumberFormatException(e.getMessage()); + } } + } catch (NumberFormatException e) { + throw new NumberFormatException(e.getMessage()); } } return null; } + private static int getRadix(String value, int... radixS) { + return radixS.length > 0 ? radixS[0] : isHexadecimal(value) ? 16 : 10; + } + public static Float parseFloat(String value) { if (value != null) { try { @@ -218,8 +312,64 @@ public class TbUtils { } public static int parseHexToInt(String hex, boolean bigEndian) { + byte[] data = prepareHexToBytesNumber(hex, 8); + return parseBytesToInt(data, 0, data.length, bigEndian); + } + + public static long parseLittleEndianHexToLong(String hex) { + return parseHexToLong(hex, false); + } + + public static long parseBigEndianHexToLong(String hex) { + return parseHexToLong(hex, true); + } + + public static long parseHexToLong(String hex) { + return parseHexToLong(hex, true); + } + + public static long parseHexToLong(String hex, boolean bigEndian) { + byte[] data = prepareHexToBytesNumber(hex, 16); + return parseBytesToLong(data, 0, data.length, bigEndian); + } + + public static float parseLittleEndianHexToFloat(String hex) { + return parseHexToFloat(hex, false); + } + + public static float parseBigEndianHexToFloat(String hex) { + return parseHexToFloat(hex, true); + } + + public static float parseHexToFloat(String hex) { + return parseHexToFloat(hex, true); + } + + public static float parseHexToFloat(String hex, boolean bigEndian) { + byte[] data = prepareHexToBytesNumber(hex, 8); + return parseBytesToFloat(data, 0, bigEndian); + } + + public static double parseLittleEndianHexToDouble(String hex) { + return parseHexToDouble(hex, false); + } + + public static double parseBigEndianHexToDouble(String hex) { + return parseHexToDouble(hex, true); + } + + public static double parseHexToDouble(String hex) { + return parseHexToDouble(hex, true); + } + + public static double parseHexToDouble(String hex, boolean bigEndian) { + byte[] data = prepareHexToBytesNumber(hex, 16); + return parseBytesToDouble(data, 0, bigEndian); + } + + private static byte[] prepareHexToBytesNumber(String hex, int len) { int length = hex.length(); - if (length > 8) { + if (length > len) { throw new IllegalArgumentException("Hex string is too large. Maximum 8 symbols allowed."); } if (length % 2 > 0) { @@ -229,7 +379,7 @@ public class TbUtils { for (int i = 0; i < length; i += 2) { data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); } - return parseBytesToInt(data, 0, data.length, bigEndian); + return data; } public static ExecutionArrayList hexToBytes(ExecutionContext ctx, String hex) { @@ -293,6 +443,91 @@ public class TbUtils { return bb.getInt(); } + public static long parseBytesToLong(List data, int offset, int length) { + return parseBytesToLong(data, offset, length, true); + } + + public static long parseBytesToLong(List data, int offset, int length, boolean bigEndian) { + final byte[] bytes = new byte[data.size()]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = data.get(i); + } + return parseBytesToLong(bytes, offset, length, bigEndian); + } + + public static long parseBytesToLong(byte[] data, int offset, int length) { + return parseBytesToLong(data, offset, length, true); + } + + public static long parseBytesToLong(byte[] data, int offset, int length, boolean bigEndian) { + if (offset > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); + } + if (length > 8) { + throw new IllegalArgumentException("Length: " + length + " is too large. Maximum 4 bytes is allowed!"); + } + if (offset + length > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); + } + var bb = ByteBuffer.allocate(8); + if (!bigEndian) { + bb.order(ByteOrder.LITTLE_ENDIAN); + } + bb.position(bigEndian ? 8 - length : 0); + bb.put(data, offset, length); + bb.position(0); + return bb.getLong(); + } + + public static float parseBytesToFloat(byte[] data, int offset) { + return parseBytesToFloat(data, offset, true); + } + + public static float parseBytesToFloat(List data, int offset) { + return parseBytesToFloat(data, offset, true); + } + + public static float parseBytesToFloat(List data, int offset, boolean bigEndian) { + return parseBytesToFloat(Bytes.toArray(data), offset, bigEndian); + } + + public static float parseBytesToFloat(byte[] data, int offset, boolean bigEndian) { + byte[] bytesToNumber = prepareBytesToNumber(data, offset, 4, bigEndian); + return ByteBuffer.wrap(bytesToNumber).getFloat(); + } + + + public static double parseBytesToDouble(byte[] data, int offset) { + return parseBytesToDouble(data, offset, true); + } + + public static double parseBytesToDouble(List data, int offset) { + return parseBytesToDouble(data, offset, true); + } + + public static double parseBytesToDouble(List data, int offset, boolean bigEndian) { + return parseBytesToDouble(Bytes.toArray(data), offset, bigEndian); + } + + public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) { + byte[] bytesToNumber = prepareBytesToNumber(data, offset, 8, bigEndian); + return ByteBuffer.wrap(bytesToNumber).getDouble(); + } + + private static byte[] prepareBytesToNumber(byte[] data, int offset, int length, boolean bigEndian) { + if (offset > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); + } + if ((offset + length) > data.length) { + throw new IllegalArgumentException("Default length is always " + length + " bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); + } + byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset + length)); + if (!bigEndian) { + ArrayUtils.reverse(dataBytesArray); + } + return dataBytesArray; + } + public static String bytesToHex(ExecutionArrayList bytesList) { byte[] bytes = new byte[bytesList.size()]; for (int i = 0; i < bytesList.size(); i++) { @@ -315,6 +550,10 @@ public class TbUtils { return BigDecimal.valueOf(value).setScale(precision, RoundingMode.HALF_UP).doubleValue(); } + public static float toFixed(float value, int precision) { + return BigDecimal.valueOf(value).setScale(precision, RoundingMode.HALF_UP).floatValue(); + } + private static boolean isHexadecimal(String value) { return value != null && (value.contains("0x") || value.contains("0X")); } @@ -388,4 +627,19 @@ public class TbUtils { } } } + + public static boolean isValidRadix(String value, int radix) { + for (int i = 0; i < value.length(); i++) { + if (i == 0 && value.charAt(i) == '-') { + if (value.length() == 1) + throw new NumberFormatException("Failed radix [" + radix + "] for value: \"" + value + "\"!"); + else + continue; + } + if (Character.digit(value.charAt(i), radix) < 0) + throw new NumberFormatException("Failed radix: [" + radix + "] for value: \"" + value + "\"!"); + } + return true; + } + } diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java index 82cd74ca30..b6d5395af8 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.script.api.tbel; +import com.google.common.primitives.Bytes; import lombok.extern.slf4j.Slf4j; import org.junit.After; import org.junit.Assert; @@ -26,6 +27,7 @@ import org.mvel2.SandboxedParserConfiguration; import org.mvel2.execution.ExecutionArrayList; import org.mvel2.execution.ExecutionHashMap; +import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Calendar; @@ -38,6 +40,23 @@ public class TbUtilsTest { private ExecutionContext ctx; + private final String intValHex = "41EA62CC"; + private final float floatVal = 29.29824f; + private final String floatValStr = "29.29824"; + + + private final String floatValHexRev = "CC62EA41"; + private final float floatValRev = -5.948442E7f; + + private final long longVal = 0x409B04B10CB295EAL; + private final String longValHex = "409B04B10CB295EA"; + private final long longValRev = 0xEA95B20CB1049B40L; + private final String longValHexRev = "EA95B20CB1049B40"; + private final String doubleValStr = "1729.1729"; + private final double doubleVal = 1729.1729; + private final double doubleValRev = -2.7208640774822924E205; + + @Before public void before() { SandboxedParserConfiguration parserConfig = ParserContext.enableSandboxedMode(); @@ -62,6 +81,7 @@ public class TbUtilsTest { @Test public void parseHexToInt() { Assert.assertEquals(0xAB, TbUtils.parseHexToInt("AB")); + Assert.assertEquals(0xABBA, TbUtils.parseHexToInt("ABBA", true)); Assert.assertEquals(0xBAAB, TbUtils.parseHexToInt("ABBA", false)); Assert.assertEquals(0xAABBCC, TbUtils.parseHexToInt("AABBCC", true)); @@ -182,9 +202,150 @@ public class TbUtilsTest { Assert.assertEquals(expectedMapWithoutPaths, actualMapWithoutPaths); } + @Test + public void parseInt() { + Assert.assertNull(TbUtils.parseInt(null)); + Assert.assertNull(TbUtils.parseInt("")); + Assert.assertNull(TbUtils.parseInt(" ")); + + Assert.assertEquals(java.util.Optional.of(0).get(), TbUtils.parseInt("0")); + Assert.assertEquals(java.util.Optional.of(0).get(), TbUtils.parseInt("-0")); + Assert.assertEquals(java.util.Optional.of(473).get(), TbUtils.parseInt("473")); + Assert.assertEquals(java.util.Optional.of(-255).get(), TbUtils.parseInt("-0xFF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("0xFG")); + + Assert.assertEquals(java.util.Optional.of(102).get(), TbUtils.parseInt("1100110", 2)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("1100210", 2)); + + Assert.assertEquals(java.util.Optional.of(63).get(), TbUtils.parseInt("77", 8)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("18", 8)); + + Assert.assertEquals(java.util.Optional.of(-255).get(), TbUtils.parseInt("-FF", 16)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FG", 16)); + + + Assert.assertEquals(java.util.Optional.of(Integer.MAX_VALUE).get(), TbUtils.parseInt(Integer.toString(Integer.MAX_VALUE), 10)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt(BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.valueOf(1)).toString(10), 10)); + Assert.assertEquals(java.util.Optional.of(Integer.MIN_VALUE).get(), TbUtils.parseInt(Integer.toString(Integer.MIN_VALUE), 10)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt(BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.valueOf(1)).toString(10), 10)); + + Assert.assertEquals(java.util.Optional.of(506070563).get(), TbUtils.parseInt("KonaIn", 30)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("KonaIn", 10)); + } + + @Test + public void parseFloat() { + Assert.assertEquals(java.util.Optional.of(floatVal).get(), TbUtils.parseFloat(floatValStr)); + } + + @Test + public void toFixedFloat() { + float actualF = TbUtils.toFixed(floatVal, 3); + Assert.assertEquals(1, Float.compare(floatVal, actualF)); + Assert.assertEquals(0, Float.compare(29.298f, actualF)); + } + + @Test + public void parseHexToFloat() { + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseHexToFloat(intValHex))); + Assert.assertEquals(0, Float.compare(floatValRev, TbUtils.parseHexToFloat(intValHex, false))); + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseBigEndianHexToFloat(intValHex))); + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseLittleEndianHexToFloat(floatValHexRev))); + } + + @Test + public void arseBytesToFloat() { + byte[] floatValByte = {65, -22, 98, -52}; + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValByte, 0))); + Assert.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValByte, 0, false))); + + List floatVaList = Bytes.asList(floatValByte); + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatVaList, 0))); + Assert.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatVaList, 0, false))); + } + + @Test + public void parseLong() { + Assert.assertNull(TbUtils.parseLong(null)); + Assert.assertNull(TbUtils.parseLong("")); + Assert.assertNull(TbUtils.parseLong(" ")); + + Assert.assertEquals(java.util.Optional.of(0L).get(), TbUtils.parseLong("0")); + Assert.assertEquals(java.util.Optional.of(0L).get(), TbUtils.parseLong("-0")); + Assert.assertEquals(java.util.Optional.of(473L).get(), TbUtils.parseLong("473")); + Assert.assertEquals(java.util.Optional.of(-65535L).get(), TbUtils.parseLong("-0xFFFF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("FFFFFFFF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("0xFGFFFFFF")); + + Assert.assertEquals(java.util.Optional.of(13158L).get(), TbUtils.parseLong("11001101100110", 2)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("11001101100210", 2)); + + Assert.assertEquals(java.util.Optional.of(9223372036854775807L).get(), TbUtils.parseLong("777777777777777777777", 8)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("1787", 8)); - private static String keyToValue(String key, String extraSymbol) { - return key + "Value" + (extraSymbol == null ? "" : extraSymbol); + Assert.assertEquals(java.util.Optional.of(-255L).get(), TbUtils.parseLong("-FF", 16)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("FG", 16)); + + + Assert.assertEquals(java.util.Optional.of(Long.MAX_VALUE).get(), TbUtils.parseLong(Long.toString(Long.MAX_VALUE), 10)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(1)).toString(10), 10)); + Assert.assertEquals(java.util.Optional.of(Long.MIN_VALUE).get(), TbUtils.parseLong(Long.toString(Long.MIN_VALUE), 10)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.valueOf(1)).toString(10), 10)); + + Assert.assertEquals(java.util.Optional.of(218840926543L).get(), TbUtils.parseLong("KonaLong", 27)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("KonaLong", 10)); + } + + @Test + public void parseHexToLong() { + Assert.assertEquals(longVal, TbUtils.parseHexToLong(longValHex)); + Assert.assertEquals(longVal, TbUtils.parseHexToLong(longValHexRev, false)); + Assert.assertEquals(longVal, TbUtils.parseBigEndianHexToLong(longValHex)); + Assert.assertEquals(longVal, TbUtils.parseLittleEndianHexToLong(longValHexRev)); + } + + @Test + public void parseBytesToLong() { + byte[] longValByte = {64, -101, 4, -79, 12, -78, -107, -22}; + Assert.assertEquals(longVal, TbUtils.parseBytesToLong(longValByte, 0, 8)); + Bytes.reverse(longValByte); + Assert.assertEquals(longVal, TbUtils.parseBytesToLong(longValByte, 0, 8, false)); + + List longVaList = Bytes.asList(longValByte); + Assert.assertEquals(longVal, TbUtils.parseBytesToLong(longVaList, 0, 8, false)); + Assert.assertEquals(longValRev, TbUtils.parseBytesToLong(longVaList, 0, 8)); + } + + @Test + public void parsDouble() { + Assert.assertEquals(java.util.Optional.of(doubleVal).get(), TbUtils.parseDouble(doubleValStr)); + } + + @Test + public void toFixedDouble() { + double actualD = TbUtils.toFixed(doubleVal, 3); + Assert.assertEquals(-1, Double.compare(doubleVal, actualD)); + Assert.assertEquals(0, Double.compare(1729.173, actualD)); + } + + @Test + public void parseHexToDouble() { + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseHexToDouble(longValHex))); + Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseHexToDouble(longValHex, false))); + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBigEndianHexToDouble(longValHex))); + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseLittleEndianHexToDouble(longValHexRev))); + } + + @Test + public void parseBytesToDouble() { + byte[] doubleValByte = {64, -101, 4, -79, 12, -78, -107, -22}; + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValByte, 0))); + Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, false))); + + List doubleVaList = Bytes.asList(doubleValByte); + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleVaList, 0))); + Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleVaList, 0, false))); } private static List toList(byte[] data) { @@ -194,5 +355,5 @@ public class TbUtilsTest { } return result; } - } + diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java index 302bd20c8b..eef9a53024 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java @@ -52,7 +52,7 @@ import java.util.stream.Collectors; public class LwM2MModelConfigServiceImpl implements LwM2MModelConfigService { @Autowired - private TbLwM2MModelConfigStore modelStore; + TbLwM2MModelConfigStore modelStore; @Autowired @Lazy @@ -67,14 +67,14 @@ public class LwM2MModelConfigServiceImpl implements LwM2MModelConfigService { @Autowired private LwM2MTelemetryLogService logService; - private ConcurrentMap currentModelConfigs; + ConcurrentMap currentModelConfigs; @AfterStartUp(order = AfterStartUp.BEFORE_TRANSPORT_SERVICE) - private void init() { + public void init() { List models = modelStore.getAll(); log.debug("Fetched model configs: {}", models); currentModelConfigs = models.stream() - .collect(Collectors.toConcurrentMap(LwM2MModelConfig::getEndpoint, m -> m)); + .collect(Collectors.toConcurrentMap(LwM2MModelConfig::getEndpoint, m -> m, (existing, replacement) -> existing)); } @Override diff --git a/common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.java b/common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.java new file mode 100644 index 0000000000..fc54ca9e0b --- /dev/null +++ b/common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.java @@ -0,0 +1,73 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MModelConfigStore; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.willReturn; +import static org.mockito.Mockito.mock; + +class LwM2MModelConfigServiceImplTest { + + LwM2MModelConfigServiceImpl service; + TbLwM2MModelConfigStore modelStore; + + @BeforeEach + void setUp() { + service = new LwM2MModelConfigServiceImpl(); + modelStore = mock(TbLwM2MModelConfigStore.class); + service.modelStore = modelStore; + } + + @Test + void testInitWithDuplicatedModels() { + LwM2MModelConfig config = new LwM2MModelConfig("urn:imei:951358811362976"); + List models = List.of(config, config); + willReturn(models).given(modelStore).getAll(); + service.init(); + assertThat(service.currentModelConfigs).containsExactlyEntriesOf(Map.of(config.getEndpoint(), config)); + } + + @Test + void testInitWithNonUniqueEndpoints() { + LwM2MModelConfig configAlfa = new LwM2MModelConfig("urn:imei:951358811362976"); + LwM2MModelConfig configBravo = new LwM2MModelConfig("urn:imei:151358811362976"); + LwM2MModelConfig configDelta = new LwM2MModelConfig("urn:imei:151358811362976"); + assertThat(configBravo.getEndpoint()).as("non-unique endpoints provided").isEqualTo(configDelta.getEndpoint()); + List models = List.of(configAlfa, configBravo, configDelta); + willReturn(models).given(modelStore).getAll(); + service.init(); + assertThat(service.currentModelConfigs).containsExactlyInAnyOrderEntriesOf(Map.of( + configAlfa.getEndpoint(), configAlfa, + configBravo.getEndpoint(), configBravo + )); + } + + @Test + void testInitWithEmptyModels() { + willReturn(Collections.emptyList()).given(modelStore).getAll(); + service.init(); + assertThat(service.currentModelConfigs).isEmpty(); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java new file mode 100644 index 0000000000..033aa4e0bc --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.device; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.Map; + +@Configuration +@ConfigurationProperties(prefix = "device") +@Data +public class DeviceConnectivityConfiguration { + private Map connectivity; + + public boolean isEnabled(String protocol) { + var info = connectivity.get(protocol); + return info != null && info.isEnabled(); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java new file mode 100644 index 0000000000..b243be9995 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.device; + +import lombok.Data; + +@Data +public class DeviceConnectivityInfo { + private boolean enabled; + private String host; + private String port; + private String pemCertFile; +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java new file mode 100644 index 0000000000..c06103d8f3 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java @@ -0,0 +1,268 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.device; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.ResourceUtils; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.dao.util.DeviceConnectivityUtil; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.thingsboard.server.dao.service.Validator.validateId; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CHECK_DOCUMENTATION; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAP; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; + +@Service("DeviceConnectivityDaoService") +@Slf4j +public class DeviceConnectivityServiceImpl implements DeviceConnectivityService { + + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; + public static final String INCORRECT_DEVICE_ID = "Incorrect deviceId "; + public static final String DEFAULT_DEVICE_TELEMETRY_TOPIC = "v1/devices/me/telemetry"; + + @Autowired + private DeviceCredentialsService deviceCredentialsService; + + @Autowired + private DeviceProfileService deviceProfileService; + + @Autowired + private DeviceConnectivityConfiguration deviceConnectivityConfiguration; + + @Override + public JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException { + DeviceId deviceId = device.getId(); + log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId); + validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); + + DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); + DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); + DeviceTransportType transportType = deviceProfile.getTransportType(); + + ObjectNode commands = JacksonUtil.newObjectNode(); + switch (transportType) { + case DEFAULT: + Optional.ofNullable(getHttpTransportPublishCommands(baseUrl, creds)) + .ifPresent(v -> commands.set(HTTP, v)); + Optional.ofNullable(getMqttTransportPublishCommands(baseUrl, creds)) + .ifPresent(v -> commands.set(MQTT, v)); + Optional.ofNullable(getCoapTransportPublishCommands(baseUrl, creds)) + .ifPresent(v -> commands.set(COAP, v)); + break; + case MQTT: + MqttDeviceProfileTransportConfiguration transportConfiguration = + (MqttDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); + //TODO: add sparkplug command with emulator (check SSL) + if (transportConfiguration.isSparkplug()) { + ObjectNode sparkplug = JacksonUtil.newObjectNode(); + sparkplug.put("sparkplug", CHECK_DOCUMENTATION); + commands.set(MQTT, sparkplug); + } else { + String topicName = transportConfiguration.getDeviceTelemetryTopic(); + + Optional.ofNullable(getMqttTransportPublishCommands(baseUrl, topicName, creds)) + .ifPresent(v -> commands.set(MQTT, v)); + } + break; + case COAP: + Optional.ofNullable(getCoapTransportPublishCommands(baseUrl, creds)) + .ifPresent(v -> commands.set(COAP, v)); + break; + default: + commands.put(transportType.name(), CHECK_DOCUMENTATION); + } + return commands; + } + + @Override + public Resource getPemCertFile(String protocol) { + String certFilePath = deviceConnectivityConfiguration.getConnectivity() + .get(protocol) + .getPemCertFile(); + + if (StringUtils.isNotBlank(certFilePath) && ResourceUtils.resourceExists(this, certFilePath)) { + return new ClassPathResource(certFilePath); + } else { + return null; + } + } + + private JsonNode getHttpTransportPublishCommands(String defaultHostname, DeviceCredentials deviceCredentials) throws URISyntaxException { + ObjectNode httpCommands = JacksonUtil.newObjectNode(); + Optional.ofNullable(getHttpPublishCommand(HTTP, defaultHostname, deviceCredentials)) + .ifPresent(v -> httpCommands.put(HTTP, v)); + Optional.ofNullable(getHttpPublishCommand(HTTPS, defaultHostname, deviceCredentials)) + .ifPresent(v -> httpCommands.put(HTTPS, v)); + return httpCommands.isEmpty() ? null : httpCommands; + } + + private String getHttpPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + if (properties == null || !properties.isEnabled() || + deviceCredentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) { + return null; + } + String hostName = getHost(baseUrl, properties); + String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); + + return DeviceConnectivityUtil.getHttpPublishCommand(protocol, hostName, port, deviceCredentials); + } + + private JsonNode getMqttTransportPublishCommands(String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { + return getMqttTransportPublishCommands(baseUrl, DEFAULT_DEVICE_TELEMETRY_TOPIC, deviceCredentials); + } + + private JsonNode getMqttTransportPublishCommands(String baseUrl, String topic, DeviceCredentials deviceCredentials) throws URISyntaxException { + ObjectNode mqttCommands = JacksonUtil.newObjectNode(); + + if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { + mqttCommands.put(MQTTS, CHECK_DOCUMENTATION); + return mqttCommands; + } + + ObjectNode dockerMqttCommands = JacksonUtil.newObjectNode(); + + if (deviceConnectivityConfiguration.isEnabled(MQTT)) { + Optional.ofNullable(getMqttPublishCommand(baseUrl, topic, deviceCredentials)). + ifPresent(v -> mqttCommands.put(MQTT, v)); + + Optional.ofNullable(getDockerMqttPublishCommand(MQTT, baseUrl, topic, deviceCredentials)) + .ifPresent(v -> dockerMqttCommands.put(MQTT, v)); + } + + if (deviceConnectivityConfiguration.isEnabled(MQTTS)) { + List mqttsPublishCommand = getMqttsPublishCommand(baseUrl, topic, deviceCredentials); + if (mqttsPublishCommand != null) { + ArrayNode arrayNode = mqttCommands.putArray(MQTTS); + mqttsPublishCommand.forEach(arrayNode::add); + } + + Optional.ofNullable(getDockerMqttPublishCommand(MQTTS, baseUrl, topic, deviceCredentials)) + .ifPresent(v -> dockerMqttCommands.put(MQTTS, v)); + } + + if (!dockerMqttCommands.isEmpty()) { + mqttCommands.set(DOCKER, dockerMqttCommands); + } + return mqttCommands.isEmpty() ? null : mqttCommands; + } + + private String getMqttPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(MQTT); + String mqttHost = getHost(baseUrl, properties); + String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); + return DeviceConnectivityUtil.getMqttPublishCommand(MQTT, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + } + + private List getMqttsPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(MQTTS); + String mqttHost = getHost(baseUrl, properties); + String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); + String pubCommand = DeviceConnectivityUtil.getMqttPublishCommand(MQTTS, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + + ArrayList commands = new ArrayList<>(); + if (pubCommand != null) { + commands.add(DeviceConnectivityUtil.getCurlPemCertCommand(baseUrl, MQTTS)); + commands.add(pubCommand); + return commands; + } + return null; + } + + private String getDockerMqttPublishCommand(String protocol, String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + String mqttHost = getHost(baseUrl, properties); + String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); + return DeviceConnectivityUtil.getDockerMqttPublishCommand(protocol, baseUrl, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + } + + private JsonNode getCoapTransportPublishCommands(String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { + ObjectNode coapCommands = JacksonUtil.newObjectNode(); + + if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { + coapCommands.put(COAPS, CHECK_DOCUMENTATION); + return coapCommands; + } + + ObjectNode dockerCoapCommands = JacksonUtil.newObjectNode(); + + if (deviceConnectivityConfiguration.isEnabled(COAP)) { + Optional.ofNullable(getCoapPublishCommand(COAP, baseUrl, deviceCredentials)) + .ifPresent(v -> coapCommands.put(COAP, v)); + + Optional.ofNullable(getDockerCoapPublishCommand(COAP, baseUrl, deviceCredentials)) + .ifPresent(v -> dockerCoapCommands.put(COAP, v)); + } + + if (deviceConnectivityConfiguration.isEnabled(COAPS)) { + Optional.ofNullable(getCoapPublishCommand(COAPS, baseUrl, deviceCredentials)) + .ifPresent(v -> coapCommands.put(COAPS, v)); + + Optional.ofNullable(getDockerCoapPublishCommand(COAPS, baseUrl, deviceCredentials)) + .ifPresent(v -> dockerCoapCommands.put(COAPS, v)); + } + + if (!dockerCoapCommands.isEmpty()) { + coapCommands.set(DOCKER, dockerCoapCommands); + } + + return coapCommands.isEmpty() ? null : coapCommands; + } + + private String getCoapPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + String hostName = getHost(baseUrl, properties); + String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); + return DeviceConnectivityUtil.getCoapPublishCommand(protocol, hostName, port, deviceCredentials); + } + + private String getDockerCoapPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + String host = getHost(baseUrl, properties); + String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); + return DeviceConnectivityUtil.getDockerCoapPublishCommand(protocol, host, port, deviceCredentials); + } + + private String getHost(String baseUrl, DeviceConnectivityInfo properties) throws URISyntaxException { + return properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 46830f8f76..3f9ee12dda 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -174,10 +174,6 @@ public class DeviceServiceImpl extends AbstractCachedEntityService findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate) { - return edgeEventDao.findEdgeEvents(tenantId.getId(), edgeId, pageLink, withTsUpdate); + public PageData findEdgeEvents(TenantId tenantId, EdgeId edgeId, Long seqIdStart, Long seqIdEnd, TimePageLink pageLink) { + return edgeEventDao.findEdgeEvents(tenantId.getId(), edgeId, seqIdStart, seqIdEnd, pageLink); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeEventDao.java index 84bf8c40d2..942a536674 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeEventDao.java @@ -43,10 +43,12 @@ public interface EdgeEventDao extends Dao { * * @param tenantId the tenantId * @param edgeId the edgeId + * @param seqIdStart the seq id start + * @param seqIdEnd the seq id end * @param pageLink the pageLink * @return the event list */ - PageData findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate); + PageData findEdgeEvents(UUID tenantId, EdgeId edgeId, Long seqIdStart, Long seqIdEnd, TimePageLink pageLink); /** * Executes stored procedure to cleanup old edge events. 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 102d5f181e..552f83c749 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 @@ -535,6 +535,7 @@ public class ModelConstants { */ public static final String EDGE_EVENT_TABLE_NAME = "edge_event"; public static final String EDGE_EVENT_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; + public static final String EDGE_EVENT_SEQUENTIAL_ID_PROPERTY = "seq_id"; public static final String EDGE_EVENT_EDGE_ID_PROPERTY = "edge_id"; public static final String EDGE_EVENT_TYPE_PROPERTY = "edge_event_type"; public static final String EDGE_EVENT_ACTION_PROPERTY = "edge_event_action"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java index 1edc47f197..55a30383d1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/EdgeEventEntity.java @@ -43,6 +43,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_BODY_PR import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TABLE_NAME; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_EDGE_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_ENTITY_ID_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_SEQUENTIAL_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TENANT_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.EDGE_EVENT_UID_PROPERTY; @@ -57,6 +58,9 @@ import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN; @NoArgsConstructor public class EdgeEventEntity extends BaseSqlEntity implements BaseEntity { + @Column(name = EDGE_EVENT_SEQUENTIAL_ID_PROPERTY) + protected long seqId; + @Column(name = EDGE_EVENT_TENANT_ID_PROPERTY) private UUID tenantId; @@ -120,6 +124,7 @@ public class EdgeEventEntity extends BaseSqlEntity implements BaseEnt edgeEvent.setAction(edgeEventAction); edgeEvent.setBody(entityBody); edgeEvent.setUid(edgeEventUid); + edgeEvent.setSeqId(seqId); return edgeEvent; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractAsyncDao.java b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractAsyncDao.java index 425724bf2c..92289b7178 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractAsyncDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractAsyncDao.java @@ -19,13 +19,13 @@ import com.google.common.base.Function; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.springframework.beans.factory.annotation.Value; +import org.thingsboard.common.util.ThingsBoardExecutors; import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; /** * Created by ashvayka on 21.02.17. @@ -34,9 +34,12 @@ public abstract class CassandraAbstractAsyncDao extends CassandraAbstractDao { protected ExecutorService readResultsProcessingExecutor; + @Value("${cassandra.query.result_processing_threads:50}") + private int threadPoolSize; + @PostConstruct public void startExecutor() { - readResultsProcessingExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("cassandra-callback")); + readResultsProcessingExecutor = ThingsBoardExecutors.newWorkStealingPool(threadPoolSize, "cassandra-callback"); } @PreDestroy diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index fb86e09ab3..f7ae4a1596 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -220,17 +220,36 @@ public class BaseRelationService implements RelationService { return future; } + @Transactional + @Override + public void deleteEntityCommonRelations(TenantId tenantId, EntityId entityId) { + deleteEntityRelations(tenantId, entityId, RelationTypeGroup.COMMON); + } + @Transactional @Override public void deleteEntityRelations(TenantId tenantId, EntityId entityId) { + deleteEntityRelations(tenantId, entityId, null); + } + + @Transactional + public void deleteEntityRelations(TenantId tenantId, EntityId entityId, RelationTypeGroup relationTypeGroup) { log.trace("Executing deleteEntityRelations [{}]", entityId); validate(entityId); - List inboundRelations = new ArrayList<>(relationDao.findAllByTo(tenantId, entityId)); - List outboundRelations = new ArrayList<>(relationDao.findAllByFrom(tenantId, entityId)); + List inboundRelations = relationTypeGroup == null + ? relationDao.findAllByTo(tenantId, entityId) + : relationDao.findAllByTo(tenantId, entityId, relationTypeGroup); + List outboundRelations = relationTypeGroup == null + ? relationDao.findAllByFrom(tenantId, entityId) + : relationDao.findAllByFrom(tenantId, entityId, relationTypeGroup); if (!inboundRelations.isEmpty()) { try { - relationDao.deleteInboundRelations(tenantId, entityId); + if (relationTypeGroup == null) { + relationDao.deleteInboundRelations(tenantId, entityId); + } else { + relationDao.deleteInboundRelations(tenantId, entityId, relationTypeGroup); + } } catch (ConcurrencyFailureException e) { log.debug("Concurrency exception while deleting relations [{}]", inboundRelations, e); } @@ -241,7 +260,11 @@ public class BaseRelationService implements RelationService { } if (!outboundRelations.isEmpty()) { - relationDao.deleteOutboundRelations(tenantId, entityId); + if (relationTypeGroup == null) { + relationDao.deleteOutboundRelations(tenantId, entityId); + } else { + relationDao.deleteOutboundRelations(tenantId, entityId, relationTypeGroup); + } for (EntityRelation relation : outboundRelations) { eventPublisher.publishEvent(EntityRelationEvent.from(relation)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java index 7fee4a31ff..250a0c6105 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java @@ -64,8 +64,12 @@ public interface RelationDao { void deleteOutboundRelations(TenantId tenantId, EntityId entity); + void deleteOutboundRelations(TenantId tenantId, EntityId entity, RelationTypeGroup relationTypeGroup); + void deleteInboundRelations(TenantId tenantId, EntityId entity); + void deleteInboundRelations(TenantId tenantId, EntityId entity, RelationTypeGroup relationTypeGroup); + ListenableFuture deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity); List findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit); diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 974e3665f1..7697217b6b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -20,7 +20,11 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.stereotype.Service; +import org.springframework.transaction.event.TransactionalEventListener; +import org.thingsboard.server.cache.device.DeviceCacheKey; +import org.thingsboard.server.cache.resourceInfo.ResourceInfoEvictEvent; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.cache.resourceInfo.ResourceInfoCacheKey; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResourceInfo; @@ -31,6 +35,7 @@ import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -45,7 +50,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; @Service("TbResourceDaoService") @Slf4j @AllArgsConstructor -public class BaseResourceService implements ResourceService { +public class BaseResourceService extends AbstractCachedEntityService implements ResourceService { public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId "; private final TbResourceDao resourceDao; @@ -55,10 +60,12 @@ public class BaseResourceService implements ResourceService { @Override public TbResource saveResource(TbResource resource) { resourceValidator.validate(resource, TbResourceInfo::getTenantId); - try { - return resourceDao.save(resource.getTenantId(), resource); + TbResource saved = resourceDao.save(resource.getTenantId(), resource); + publishEvictEvent(new ResourceInfoEvictEvent(resource.getTenantId(), resource.getId())); + return saved; } catch (Exception t) { + publishEvictEvent(new ResourceInfoEvictEvent(resource.getTenantId(), resource.getId())); ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("resource_unq_key")) { String field = ResourceType.LWM2M_MODEL.equals(resource.getResourceType()) ? "resourceKey" : "fileName"; @@ -86,7 +93,9 @@ public class BaseResourceService implements ResourceService { public TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId) { log.trace("Executing findResourceInfoById [{}] [{}]", tenantId, resourceId); Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId); - return resourceInfoDao.findById(tenantId, resourceId.getId()); + + return cache.getAndPutInTransaction(new ResourceInfoCacheKey(tenantId, resourceId), + () -> resourceInfoDao.findById(tenantId, resourceId.getId()), true); } @Override @@ -100,6 +109,7 @@ public class BaseResourceService implements ResourceService { public void deleteResource(TenantId tenantId, TbResourceId resourceId) { log.trace("Executing deleteResource [{}] [{}]", tenantId, resourceId); Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId); + resourceValidator.validateDelete(tenantId, resourceId); resourceDao.removeById(tenantId, resourceId.getId()); } @@ -169,13 +179,11 @@ public class BaseResourceService implements ResourceService { } }; - protected Optional extractConstraintViolationException(Exception t) { - if (t instanceof ConstraintViolationException) { - return Optional.of((ConstraintViolationException) t); - } else if (t.getCause() instanceof ConstraintViolationException) { - return Optional.of((ConstraintViolationException) (t.getCause())); - } else { - return Optional.empty(); + @TransactionalEventListener(classes = ResourceInfoEvictEvent.class) + @Override + public void handleEvictEvent(ResourceInfoEvictEvent event) { + if (event.getResourceId() != null) { + cache.evict(new ResourceInfoCacheKey(event.getTenantId(), event.getResourceId())); } } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java index 65ab189081..e4bc622354 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java @@ -22,6 +22,7 @@ import org.springframework.context.annotation.Lazy; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.TenantEntityWithDataDao; import org.thingsboard.server.dao.exception.DataValidationException; @@ -82,6 +83,9 @@ public abstract class DataValidator> { return null; } + public void validateDelete(TenantId tenantId, EntityId entityId) { + } + protected boolean isSameData(D existentData, D actualData) { return actualData.getId() != null && existentData.getId().equals(actualData.getId()); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java index c547f3c416..9939d887fa 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java @@ -20,14 +20,21 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TbResource; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; +import org.thingsboard.server.common.data.widget.BaseWidgetType; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.resource.TbResourceDao; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; +import org.thingsboard.server.dao.widget.WidgetTypeDao; + +import java.util.List; +import java.util.stream.Collectors; import static org.thingsboard.server.common.data.EntityType.TB_RESOURCE; @@ -37,6 +44,9 @@ public class ResourceDataValidator extends DataValidator { @Autowired private TbResourceDao resourceDao; + @Autowired + private WidgetTypeDao widgetTypeDao; + @Autowired private TenantService tenantService; @@ -77,4 +87,15 @@ public class ResourceDataValidator extends DataValidator { } } } + + @Override + public void validateDelete(TenantId tenantId, EntityId resourceId) { + List widgets = widgetTypeDao.findWidgetTypesInfosByTenantIdAndResourceId(tenantId.getId(), + resourceId.getId()); + if (!widgets.isEmpty()) { + List widgetNames = widgets.stream().map(BaseWidgetType::getName).collect(Collectors.toList()); + throw new DataValidationException(String.format("Following widget types uses current resource: %s", widgetNames)); + } + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java index c4827f1ffe..c3a9697ad6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/EdgeEventRepository.java @@ -30,8 +30,10 @@ public interface EdgeEventRepository extends JpaRepository :startTime) " + + "AND (:startTime IS NULL OR e.createdTime >= :startTime) " + "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + + "AND (:seqIdStart IS NULL OR e.seqId > :seqIdStart) " + + "AND (:seqIdEnd IS NULL OR e.seqId < :seqIdEnd) " + "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" ) Page findEdgeEventsByTenantIdAndEdgeId(@Param("tenantId") UUID tenantId, @@ -39,20 +41,7 @@ public interface EdgeEventRepository extends JpaRepository :startTime) " + - "AND (:endTime IS NULL OR e.createdTime <= :endTime) " + - "AND e.edgeEventAction <> 'TIMESERIES_UPDATED' " + - "AND LOWER(e.edgeEventType) LIKE LOWER(CONCAT('%', :textSearch, '%'))" - ) - Page findEdgeEventsByTenantIdAndEdgeIdWithoutTimeseriesUpdated(@Param("tenantId") UUID tenantId, - @Param("edgeId") UUID edgeId, - @Param("textSearch") String textSearch, - @Param("startTime") Long startTime, - @Param("endTime") Long endTime, - Pageable pageable); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java index bb825f504d..9f2eaae273 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.EdgeEventId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.dao.DaoUtil; @@ -43,7 +44,9 @@ import org.thingsboard.server.dao.util.SqlDao; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; +import java.util.ArrayList; import java.util.Comparator; +import java.util.List; import java.util.Objects; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -118,7 +121,7 @@ public class JpaBaseEdgeEventDao extends JpaAbstractDao(params, hashcodeFunction, 1, statsFactory); - queue.init(logExecutor, v -> edgeEventInsertRepository.save(v), + queue.init(logExecutor, edgeEventInsertRepository::save, Comparator.comparing(EdgeEventEntity::getTs) ); } @@ -171,29 +174,23 @@ public class JpaBaseEdgeEventDao extends JpaAbstractDao findEdgeEvents(UUID tenantId, EdgeId edgeId, TimePageLink pageLink, boolean withTsUpdate) { - if (withTsUpdate) { - return DaoUtil.toPageData( - edgeEventRepository - .findEdgeEventsByTenantIdAndEdgeId( - tenantId, - edgeId.getId(), - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getStartTime(), - pageLink.getEndTime(), - DaoUtil.toPageable(pageLink))); - } else { - return DaoUtil.toPageData( - edgeEventRepository - .findEdgeEventsByTenantIdAndEdgeIdWithoutTimeseriesUpdated( - tenantId, - edgeId.getId(), - Objects.toString(pageLink.getTextSearch(), ""), - pageLink.getStartTime(), - pageLink.getEndTime(), - DaoUtil.toPageable(pageLink))); - + public PageData findEdgeEvents(UUID tenantId, EdgeId edgeId, Long seqIdStart, Long seqIdEnd, TimePageLink pageLink) { + List sortOrders = new ArrayList<>(); + if (pageLink.getSortOrder() != null) { + sortOrders.add(pageLink.getSortOrder()); } + sortOrders.add(new SortOrder("seqId")); + return DaoUtil.toPageData( + edgeEventRepository + .findEdgeEventsByTenantIdAndEdgeId( + tenantId, + edgeId.getId(), + Objects.toString(pageLink.getTextSearch(), ""), + pageLink.getStartTime(), + pageLink.getEndTime(), + seqIdStart, + seqIdEnd, + DaoUtil.toPageable(pageLink, sortOrders))); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index 2135e98eed..4cf6db0fc1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -69,7 +69,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { private static final Map entityTableMap = new HashMap<>(); private static final Map entityNameColumns = new HashMap<>(); private static final String SELECT_PHONE = " CASE WHEN entity.entity_type = 'TENANT' THEN (select phone from tenant where id = entity_id)" + - " WHEN entity.entity_type = 'CUSTOMER' THEN (select phone from customer where id = entity_id) END as phone"; + " WHEN entity.entity_type = 'CUSTOMER' THEN (select phone from customer where id = entity_id)" + + " WHEN entity.entity_type = 'USER' THEN (select phone from tb_user where id = entity_id) END as phone"; private static final String SELECT_ZIP = " CASE WHEN entity.entity_type = 'TENANT' THEN (select zip from tenant where id = entity_id)" + " WHEN entity.entity_type = 'CUSTOMER' THEN (select zip from customer where id = entity_id) END as zip"; private static final String SELECT_ADDRESS_2 = " CASE WHEN entity.entity_type = 'TENANT'" + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index c1b17f160e..31125a0791 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -37,6 +37,7 @@ import org.thingsboard.server.dao.util.SqlDao; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -205,6 +206,15 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple } } + @Override + public void deleteOutboundRelations(TenantId tenantId, EntityId entity, RelationTypeGroup relationTypeGroup) { + try { + relationRepository.deleteByFromIdAndFromTypeAndRelationTypeGroupIn(entity.getId(), entity.getEntityType().name(), Collections.singletonList(relationTypeGroup.name())); + } catch (ConcurrencyFailureException e) { + log.debug("Concurrency exception while deleting relations [{}]", entity, e); + } + } + @Override public void deleteInboundRelations(TenantId tenantId, EntityId entity) { try { @@ -214,6 +224,15 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple } } + @Override + public void deleteInboundRelations(TenantId tenantId, EntityId entity, RelationTypeGroup relationTypeGroup) { + try { + relationRepository.deleteByToIdAndToTypeAndRelationTypeGroupIn(entity.getId(), entity.getEntityType().name(), Collections.singletonList(relationTypeGroup.name())); + } catch (ConcurrencyFailureException e) { + log.debug("Concurrency exception while deleting relations [{}]", entity, e); + } + } + @Override public ListenableFuture deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity) { return service.submit( diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java index a3d6d8570d..10c8c826eb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java @@ -82,4 +82,9 @@ public interface RelationRepository @Query("DELETE FROM RelationEntity r where r.toId = :toId and r.toType = :toType and r.relationTypeGroup in :relationTypeGroups") void deleteByToIdAndToTypeAndRelationTypeGroupIn(@Param("toId") UUID toId, @Param("toType") String toType, @Param("relationTypeGroups") List relationTypeGroups); + @Transactional + @Modifying + @Query("DELETE FROM RelationEntity r where r.fromId = :fromId and r.fromType = :fromType and r.relationTypeGroup in :relationTypeGroups") + void deleteByFromIdAndFromTypeAndRelationTypeGroupIn(@Param("fromId") UUID fromId, @Param("fromType") String fromType, @Param("relationTypeGroups") List relationTypeGroups); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java index b54dd371fe..689bcb0b03 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java @@ -77,6 +77,11 @@ public class JpaWidgetTypeDao extends JpaAbstractDao findWidgetTypesInfosByTenantIdAndResourceId(UUID tenantId, UUID tbResourceId) { + return DaoUtil.convertDataList(widgetTypeRepository.findWidgetTypesInfosByTenantIdAndResourceId(tenantId, tbResourceId)); + } + @Override public EntityType getEntityType() { return EntityType.WIDGET_TYPE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java index a3cba644b5..55e05fe2b4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java @@ -46,4 +46,11 @@ public interface WidgetTypeRepository extends JpaRepository> 'resources' LIKE LOWER(CONCAT('%', :resourceId, '%'))", + nativeQuery = true) + List findWidgetTypesInfosByTenantIdAndResourceId(@Param("tenantId") UUID tenantId, + @Param("resourceId") UUID resourceId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java b/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java index 4c8d0c5afe..d6c3a8efdd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java @@ -121,7 +121,7 @@ public abstract class AbstractBufferedRateExecutor taskCtx = null; @@ -169,7 +169,7 @@ public abstract class AbstractBufferedRateExecutor= printQueriesFreq) { printQueriesIdx.set(0); String query = queryToString(finalTaskCtx); - log.info("[{}] Cassandra query: {}", taskCtx.getId(), query); + log.info("[{}][{}] Cassandra query: {}", getBufferName(), taskCtx.getId(), query); } } logTask("Processing", finalTaskCtx); @@ -222,7 +222,7 @@ public abstract class AbstractBufferedRateExecutor taskCtx) { @@ -298,7 +298,7 @@ public abstract class AbstractBufferedRateExecutor { */ WidgetType findByTenantIdBundleAliasAndAlias(UUID tenantId, String bundleAlias, String alias); + /** + * Find widget types infos by tenantId and resourceId in descriptor. + * + * @param tenantId the tenantId + * @param tbResourceId the resourceId + * @return the list of widget types infos objects + */ + List findWidgetTypesInfosByTenantIdAndResourceId(UUID tenantId, UUID tbResourceId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index 0337c190a4..1ac099b075 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -21,6 +21,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.HasId; +import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetType; @@ -37,6 +38,7 @@ import java.util.Optional; public class WidgetTypeServiceImpl implements WidgetTypeService { public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; + public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId "; public static final String INCORRECT_BUNDLE_ALIAS = "Incorrect bundleAlias "; @Autowired private WidgetTypeDao widgetTypeDao; @@ -96,6 +98,14 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { return widgetTypeDao.findWidgetTypesInfosByTenantIdAndBundleAlias(tenantId.getId(), bundleAlias); } + @Override + public List findWidgetTypesInfosByTenantIdAndResourceId(TenantId tenantId, TbResourceId tbResourceId) { + log.trace("Executing findWidgetTypesInfosByTenantIdAndResourceId, tenantId [{}], tbResourceId [{}]", tenantId, tbResourceId); + Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + Validator.validateId(tbResourceId, INCORRECT_RESOURCE_ID + tbResourceId); + return widgetTypeDao.findWidgetTypesInfosByTenantIdAndResourceId(tenantId.getId(), tbResourceId.getId()); + } + @Override public WidgetType findWidgetTypeByTenantIdBundleAliasAndAlias(TenantId tenantId, String bundleAlias, String alias) { log.trace("Executing findWidgetTypeByTenantIdBundleAliasAndAlias, tenantId [{}], bundleAlias [{}], alias [{}]", tenantId, bundleAlias, alias); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 7fe3ec6e67..bfb2eed805 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -720,6 +720,7 @@ CREATE TABLE IF NOT EXISTS edge ( ); CREATE TABLE IF NOT EXISTS edge_event ( + seq_id INT GENERATED ALWAYS AS IDENTITY, id uuid NOT NULL, created_time bigint NOT NULL, edge_id uuid, @@ -731,6 +732,7 @@ CREATE TABLE IF NOT EXISTS edge_event ( tenant_id uuid, ts bigint NOT NULL ) PARTITION BY RANGE(created_time); +ALTER TABLE IF EXISTS edge_event ALTER COLUMN seq_id SET CYCLE; CREATE TABLE IF NOT EXISTS rpc ( id uuid NOT NULL CONSTRAINT rpc_pkey PRIMARY KEY, diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/EdgeEventServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/EdgeEventServiceTest.java index 63958fe1e4..26e7cc2e1f 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/EdgeEventServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/EdgeEventServiceTest.java @@ -71,7 +71,7 @@ public class EdgeEventServiceTest extends AbstractServiceTest { EdgeEvent edgeEvent = generateEdgeEvent(tenantId, edgeId, deviceId, EdgeEventActionType.ADDED); edgeEventService.saveAsync(edgeEvent).get(); - PageData edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, new TimePageLink(1), false); + PageData edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, 0L, null, new TimePageLink(1)); Assert.assertFalse(edgeEvents.getData().isEmpty()); EdgeEvent saved = edgeEvents.getData().get(0); @@ -113,7 +113,7 @@ public class EdgeEventServiceTest extends AbstractServiceTest { Futures.allAsList(futures).get(); TimePageLink pageLink = new TimePageLink(2, 0, "", new SortOrder("createdTime", SortOrder.Direction.DESC), startTime, endTime); - PageData edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, true); + PageData edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, 0L, null, pageLink); Assert.assertNotNull(edgeEvents.getData()); Assert.assertEquals(2, edgeEvents.getData().size()); @@ -122,7 +122,7 @@ public class EdgeEventServiceTest extends AbstractServiceTest { Assert.assertTrue(edgeEvents.hasNext()); Assert.assertNotNull(pageLink.nextPageLink()); - edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink.nextPageLink(), true); + edgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, 0L, null, pageLink.nextPageLink()); Assert.assertNotNull(edgeEvents.getData()); Assert.assertEquals(1, edgeEvents.getData().size()); @@ -132,26 +132,6 @@ public class EdgeEventServiceTest extends AbstractServiceTest { edgeEventService.cleanupEvents(1); } - @Test - public void findEdgeEventsWithTsUpdateAndWithout() throws Exception { - EdgeId edgeId = new EdgeId(Uuids.timeBased()); - DeviceId deviceId = new DeviceId(Uuids.timeBased()); - TenantId tenantId = TenantId.fromUUID(Uuids.timeBased()); - TimePageLink pageLink = new TimePageLink(1, 0, null, new SortOrder("createdTime", SortOrder.Direction.ASC)); - - EdgeEvent edgeEventWithTsUpdate = generateEdgeEvent(tenantId, edgeId, deviceId, EdgeEventActionType.TIMESERIES_UPDATED); - edgeEventService.saveAsync(edgeEventWithTsUpdate).get(); - - PageData allEdgeEvents = edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, true); - PageData edgeEventsWithoutTsUpdate = edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, false); - - Assert.assertNotNull(allEdgeEvents.getData()); - Assert.assertNotNull(edgeEventsWithoutTsUpdate.getData()); - Assert.assertEquals(1, allEdgeEvents.getData().size()); - Assert.assertEquals(allEdgeEvents.getData().get(0).getUuidId(), edgeEventWithTsUpdate.getUuidId()); - Assert.assertTrue(edgeEventsWithoutTsUpdate.getData().isEmpty()); - } - private ListenableFuture saveEdgeEventWithProvidedTime(long time, EdgeId edgeId, EntityId entityId, TenantId tenantId) throws Exception { EdgeEvent edgeEvent = generateEdgeEvent(tenantId, edgeId, entityId, EdgeEventActionType.ADDED); edgeEvent.setId(new EdgeEventId(Uuids.startOf(time))); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/EntityServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/EntityServiceTest.java index 77f5e87020..22d6bfcd9c 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/EntityServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/EntityServiceTest.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; @@ -70,6 +71,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.device.DeviceService; @@ -79,6 +81,7 @@ import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.sql.relation.RelationRepository; import org.thingsboard.server.dao.timeseries.TimeseriesService; +import org.thingsboard.server.dao.user.UserService; import java.util.ArrayList; import java.util.Arrays; @@ -105,6 +108,8 @@ public class EntityServiceTest extends AbstractServiceTest { @Autowired AssetService assetService; @Autowired + UserService userService; + @Autowired AttributesService attributesService; @Autowired DeviceService deviceService; @@ -227,6 +232,41 @@ public class EntityServiceTest extends AbstractServiceTest { Assert.assertEquals(0, count); } + @Test + public void testCountHierarchicalUserEntitiesByQuery() throws InterruptedException { + List users = new ArrayList<>(); + createTestUserRelations(tenantId, users); + + RelationsQueryFilter filter = new RelationsQueryFilter(); + filter.setRootEntity(tenantId); + filter.setDirection(EntitySearchDirection.FROM); + + EntityDataPageLink pageLink = new EntityDataPageLink(10, 0, null, null); + List entityFields = Arrays.asList(new EntityKey(EntityKeyType.ENTITY_FIELD, "name"), new EntityKey(EntityKeyType.ENTITY_FIELD, "phone")); + + EntityDataQuery query = new EntityDataQuery(filter, pageLink, entityFields, null, null); + + PageData entityDataByQuery = entityService.findEntityDataByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), query); + List data = entityDataByQuery.getData(); + Assert.assertEquals(data.size(), 5); + data.forEach(entityData -> Assert.assertNotNull(entityData.getLatest().get(EntityKeyType.ENTITY_FIELD).get("phone"))); + + } + + private void createTestUserRelations(TenantId tenantId, List users) { + for (int i = 0; i < ENTITY_COUNT; i++) { + User user = new User(); + user.setTenantId(tenantId); + user.setAuthority(Authority.TENANT_ADMIN); + user.setEmail(StringUtils.randomAlphabetic(10) + "@gmail.com"); + user.setPhone(StringUtils.randomNumeric(10)); + user = userService.saveUser(user); + users.add(user); + createRelation(tenantId, "Contains", tenantId, user.getId()); + } + } + + @Test public void testCountEdgeEntitiesByQuery() throws InterruptedException { List edges = new ArrayList<>(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/RelationServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/RelationServiceTest.java index 3bbb71306b..148f969d48 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/RelationServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/RelationServiceTest.java @@ -131,6 +131,31 @@ public class RelationServiceTest extends AbstractServiceTest { Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); } + @Test + public void testDeleteEntityCommonRelations() { + AssetId parentId = new AssetId(Uuids.timeBased()); + AssetId childId = new AssetId(Uuids.timeBased()); + AssetId subChildId = new AssetId(Uuids.timeBased()); + + EntityRelation relationA = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE); + EntityRelation relationB = new EntityRelation(childId, subChildId, EntityRelation.CONTAINS_TYPE); + EntityRelation relationC = new EntityRelation(parentId, childId, EntityRelation.MANAGES_TYPE, RelationTypeGroup.EDGE); + EntityRelation relationD = new EntityRelation(childId, subChildId, EntityRelation.MANAGES_TYPE, RelationTypeGroup.EDGE); + + saveRelation(relationA); + saveRelation(relationB); + saveRelation(relationC); + saveRelation(relationD); + + relationService.deleteEntityCommonRelations(SYSTEM_TENANT_ID, childId); + + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); + + Assert.assertTrue(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.MANAGES_TYPE, RelationTypeGroup.EDGE)); + Assert.assertTrue(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.MANAGES_TYPE, RelationTypeGroup.EDGE)); + } + @Test public void testFindFrom() throws ExecutionException, InterruptedException { AssetId parentA = new AssetId(Uuids.timeBased()); diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties index d89211cb2f..98f9091318 100644 --- a/dao/src/test/resources/application-test.properties +++ b/dao/src/test/resources/application-test.properties @@ -74,6 +74,9 @@ cache.specs.dashboardTitles.maxSize=10000 cache.specs.entityCount.timeToLiveInMinutes=1440 cache.specs.entityCount.maxSize=10000 +cache.specs.resourceInfo.timeToLiveInMinutes=1440 +cache.specs.resourceInfo.maxSize=10000 + redis.connection.host=localhost redis.connection.port=6379 redis.connection.db=0 diff --git a/dao/src/test/resources/sql/system-test-psql.sql b/dao/src/test/resources/sql/system-test-psql.sql index 172731b9c5..21af327f13 100644 --- a/dao/src/test/resources/sql/system-test-psql.sql +++ b/dao/src/test/resources/sql/system-test-psql.sql @@ -1,2 +1,5 @@ --PostgreSQL specific truncate to fit constraints -TRUNCATE TABLE device_credentials, device, device_profile, asset, asset_profile, ota_package, rule_node_state, rule_node, rule_chain, alarm_comment, alarm, entity_alarm; \ No newline at end of file +TRUNCATE TABLE device_credentials, device, device_profile, asset, asset_profile, ota_package, rule_node_state, rule_node, rule_chain, alarm_comment, alarm, entity_alarm; + +-- Decrease seq_id column to make sure to cover cases of new sequential cycle during the tests +ALTER SEQUENCE edge_event_seq_id_seq MAXVALUE 256; diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 094e0e2099..1c567588df 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" queue: type: "${TB_QUEUE_TYPE:kafka}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index 1561dac05e..88bf80e9f9 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -167,6 +167,8 @@ public interface TbContext { void enqueueForTellFailure(TbMsg msg, String failureMessage); + void enqueueForTellFailure(TbMsg tbMsg, Throwable t); + void enqueueForTellNext(TbMsg msg, String relationType); void enqueueForTellNext(TbMsg msg, Set relationTypes); @@ -210,7 +212,7 @@ public interface TbContext { void schedule(Runnable runnable, long delay, TimeUnit timeUnit); - void checkTenantEntity(EntityId entityId); + void checkTenantEntity(EntityId entityId) throws TbNodeException; boolean isLocalEntity(EntityId entityId); @@ -302,6 +304,8 @@ public interface TbContext { SlackService getSlackService(); + boolean isExternalNodeForceAck(); + /** * Creates JS Script Engine * @deprecated diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java index 32341dbf2b..a8ce9d7e42 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeException.java @@ -15,17 +15,33 @@ */ package org.thingsboard.rule.engine.api; +import lombok.Getter; +import org.thingsboard.server.common.msg.TbActorError; + /** * Created by ashvayka on 19.01.18. */ -public class TbNodeException extends Exception { +public class TbNodeException extends Exception implements TbActorError { + + @Getter + private final boolean unrecoverable; public TbNodeException(String message) { + this(message, false); + } + + public TbNodeException(String message, boolean unrecoverable) { super(message); + this.unrecoverable = unrecoverable; } public TbNodeException(Exception e) { + this(e, false); + } + + public TbNodeException(Exception e, boolean unrecoverable) { super(e); + this.unrecoverable = unrecoverable; } } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/util/TbNodeUtils.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/util/TbNodeUtils.java index 45ac5f30f5..bbba1855c2 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/util/TbNodeUtils.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/util/TbNodeUtils.java @@ -44,7 +44,7 @@ public class TbNodeUtils { try { return JacksonUtil.treeToValue(configuration.getData(), clazz); } catch (IllegalArgumentException e) { - throw new TbNodeException(e); + throw new TbNodeException(e, true); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java index bf146a52fb..84e82b76e8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java @@ -66,7 +66,7 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode ctx.tellFailure(processException(ctx, msg, t), t)); + var tbMsg = ackIfNeeded(ctx, msg); + withCallback(publishMessageAsync(ctx, tbMsg), + m -> tellSuccess(ctx, m), + t -> tellFailure(ctx, processException(ctx, tbMsg, t), t)); } private ListenableFuture publishMessageAsync(TbContext ctx, TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java index 7386d30c7c..2b9f8916cf 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.aws.sqs; +import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; @@ -31,6 +32,7 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -55,7 +57,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; configDirective = "tbExternalNodeSqsConfig", iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+" ) -public class TbSqsNode implements TbNode { +public class TbSqsNode extends TbAbstractExternalNode { private static final String MESSAGE_ID = "messageId"; private static final String REQUEST_ID = "requestId"; @@ -69,6 +71,7 @@ public class TbSqsNode implements TbNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); this.config = TbNodeUtils.convert(configuration, TbSqsNodeConfiguration.class); AWSCredentials awsCredentials = new BasicAWSCredentials(this.config.getAccessKeyId(), this.config.getSecretAccessKey()); AWSStaticCredentialsProvider credProvider = new AWSStaticCredentialsProvider(awsCredentials); @@ -76,6 +79,9 @@ public class TbSqsNode implements TbNode { this.sqsClient = AmazonSQSClientBuilder.standard() .withCredentials(credProvider) .withRegion(this.config.getRegion()) + .withClientConfiguration(new ClientConfiguration() + .withConnectionTimeout(10000) + .withRequestTimeout(5000)) .build(); } catch (Exception e) { throw new TbNodeException(e); @@ -84,9 +90,10 @@ public class TbSqsNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - withCallback(publishMessageAsync(ctx, msg), - ctx::tellSuccess, - t -> ctx.tellFailure(processException(ctx, msg, t), t)); + var tbMsg = ackIfNeeded(ctx, msg); + withCallback(publishMessageAsync(ctx, tbMsg), + m -> tellSuccess(ctx, m), + t -> tellFailure(ctx, processException(ctx, tbMsg, t), t)); } private ListenableFuture publishMessageAsync(TbContext ctx, TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java new file mode 100644 index 0000000000..834dbe2390 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java @@ -0,0 +1,64 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.external; + +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.server.common.msg.TbMsg; + +public abstract class TbAbstractExternalNode implements TbNode { + + private boolean forceAck; + + public void init(TbContext ctx) { + this.forceAck = ctx.isExternalNodeForceAck(); + } + + protected void tellSuccess(TbContext ctx, TbMsg tbMsg) { + if (forceAck) { + ctx.enqueueForTellNext(tbMsg.copyWithNewCtx(), TbRelationTypes.SUCCESS); + } else { + ctx.tellSuccess(tbMsg); + } + } + + protected void tellFailure(TbContext ctx, TbMsg tbMsg, Throwable t) { + if (forceAck) { + if (t == null) { + ctx.enqueueForTellNext(tbMsg.copyWithNewCtx(), TbRelationTypes.FAILURE); + } else { + ctx.enqueueForTellFailure(tbMsg.copyWithNewCtx(), t); + } + } else { + if (t == null) { + ctx.tellNext(tbMsg, TbRelationTypes.FAILURE); + } else { + ctx.tellFailure(tbMsg, t); + } + } + } + + protected TbMsg ackIfNeeded(TbContext ctx, TbMsg msg) { + if (forceAck) { + ctx.ack(msg); + return msg.copyWithNewCtx(); + } else { + return msg; + } + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java index b0198e210c..18d817fd94 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java @@ -20,6 +20,7 @@ import com.google.api.core.ApiFutureCallback; import com.google.api.core.ApiFutures; import com.google.api.gax.core.CredentialsProvider; import com.google.api.gax.core.FixedCredentialsProvider; +import com.google.api.gax.retrying.RetrySettings; import com.google.auth.oauth2.ServiceAccountCredentials; import com.google.cloud.pubsub.v1.Publisher; import com.google.protobuf.ByteString; @@ -32,9 +33,11 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.threeten.bp.Duration; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -53,7 +56,7 @@ import java.util.concurrent.TimeUnit; configDirective = "tbExternalNodePubSubConfig", iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo=" ) -public class TbPubSubNode implements TbNode { +public class TbPubSubNode extends TbAbstractExternalNode { private static final String MESSAGE_ID = "messageId"; private static final String ERROR = "error"; @@ -63,8 +66,9 @@ public class TbPubSubNode implements TbNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); + this.config = TbNodeUtils.convert(configuration, TbPubSubNodeConfiguration.class); try { - this.config = TbNodeUtils.convert(configuration, TbPubSubNodeConfiguration.class); this.pubSubClient = initPubSubClient(); } catch (Exception e) { throw new TbNodeException(e); @@ -73,6 +77,7 @@ public class TbPubSubNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { + msg = ackIfNeeded(ctx, msg); publishMessage(ctx, msg); } @@ -101,12 +106,12 @@ public class TbPubSubNode implements TbNode { ApiFutures.addCallback(messageIdFuture, new ApiFutureCallback() { public void onSuccess(String messageId) { TbMsg next = processPublishResult(ctx, msg, messageId); - ctx.tellSuccess(next); + tellSuccess(ctx, next); } public void onFailure(Throwable t) { TbMsg next = processException(ctx, msg, t); - ctx.tellFailure(next, t); + tellFailure(ctx, next, t); } }, ctx.getExternalCallExecutor()); @@ -131,8 +136,19 @@ public class TbPubSubNode implements TbNode { new ByteArrayInputStream(config.getServiceAccountKey().getBytes())); CredentialsProvider credProvider = FixedCredentialsProvider.create(credentials); + var retrySettings = RetrySettings.newBuilder() + .setTotalTimeout(Duration.ofSeconds(10)) + .setInitialRetryDelay(Duration.ofMillis(50)) + .setRetryDelayMultiplier(1.1) + .setMaxRetryDelay(Duration.ofSeconds(2)) + .setInitialRpcTimeout(Duration.ofSeconds(2)) + .setRpcTimeoutMultiplier(1) + .setMaxRpcTimeout(Duration.ofSeconds(10)) + .build(); + return Publisher.newBuilder(topicName) .setCredentialsProvider(credProvider) + .setRetrySettings(retrySettings) .build(); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java index de1abea224..760eec2421 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java @@ -33,6 +33,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.exception.ThingsboardKafkaClientError; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -56,7 +57,7 @@ import java.util.Properties; configDirective = "tbExternalNodeKafkaConfig", iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg==" ) -public class TbKafkaNode implements TbNode { +public class TbKafkaNode extends TbAbstractExternalNode { private static final String OFFSET = "offset"; private static final String PARTITION = "partition"; @@ -78,6 +79,7 @@ public class TbKafkaNode implements TbNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); this.config = TbNodeUtils.convert(configuration, TbKafkaNodeConfiguration.class); this.initError = null; Properties properties = new Properties(); @@ -113,24 +115,25 @@ public class TbKafkaNode implements TbNode { public void onMsg(TbContext ctx, TbMsg msg) { String topic = TbNodeUtils.processPattern(config.getTopicPattern(), msg); String keyPattern = config.getKeyPattern(); + var tbMsg = ackIfNeeded(ctx, msg); try { if (initError != null) { - ctx.tellFailure(msg, new RuntimeException("Failed to initialize Kafka rule node producer: " + initError.getMessage())); + ctx.tellFailure(tbMsg, new RuntimeException("Failed to initialize Kafka rule node producer: " + initError.getMessage())); } else { ctx.getExternalCallExecutor().executeAsync(() -> { publish( ctx, - msg, + tbMsg, topic, keyPattern == null || keyPattern.isEmpty() ? null - : TbNodeUtils.processPattern(config.getKeyPattern(), msg) + : TbNodeUtils.processPattern(config.getKeyPattern(), tbMsg) ); return null; }); } } catch (Exception e) { - ctx.tellFailure(msg, e); + ctx.tellFailure(tbMsg, e); } } @@ -164,11 +167,9 @@ public class TbKafkaNode implements TbNode { private void processRecord(TbContext ctx, TbMsg msg, RecordMetadata metadata, Exception e) { if (e == null) { - TbMsg next = processResponse(ctx, msg, metadata); - ctx.tellNext(next, TbRelationTypes.SUCCESS); + tellSuccess(ctx, processResponse(ctx, msg, metadata)); } else { - TbMsg next = processException(ctx, msg, e); - ctx.tellFailure(next, e); + tellFailure(ctx, processException(ctx, msg, e), e); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java index 50823a4c90..3e2d96b8f4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java @@ -22,10 +22,10 @@ import org.springframework.mail.javamail.JavaMailSenderImpl; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbEmail; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -47,7 +47,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; configDirective = "tbExternalNodeSendEmailConfig", icon = "send" ) -public class TbSendEmailNode implements TbNode { +public class TbSendEmailNode extends TbAbstractExternalNode { private static final String MAIL_PROP = "mail."; static final String SEND_EMAIL_TYPE = "SEND_EMAIL"; @@ -56,8 +56,9 @@ public class TbSendEmailNode implements TbNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); + this.config = TbNodeUtils.convert(configuration, TbSendEmailNodeConfiguration.class); try { - this.config = TbNodeUtils.convert(configuration, TbSendEmailNodeConfiguration.class); if (!this.config.isUseSystemSmtpSettings()) { mailSender = createMailSender(); } @@ -71,12 +72,13 @@ public class TbSendEmailNode implements TbNode { try { validateType(msg.getType()); TbEmail email = getEmail(msg); + var tbMsg = ackIfNeeded(ctx, msg); withCallback(ctx.getMailExecutor().executeAsync(() -> { - sendEmail(ctx, msg, email); + sendEmail(ctx, tbMsg, email); return null; }), - ok -> ctx.tellSuccess(msg), - fail -> ctx.tellFailure(msg, fail)); + ok -> tellSuccess(ctx, tbMsg), + fail -> tellFailure(ctx, tbMsg, fail)); } catch (Exception ex) { ctx.tellFailure(msg, ex); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 478e733958..121b9fb756 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -32,6 +32,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.credentials.BasicCredentials; import org.thingsboard.rule.engine.credentials.ClientCredentials; import org.thingsboard.rule.engine.credentials.CredentialsType; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.plugin.ComponentClusteringMode; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -55,7 +56,7 @@ import java.util.concurrent.TimeoutException; configDirective = "tbExternalNodeMqttConfig", icon = "call_split" ) -public class TbMqttNode implements TbNode { +public class TbMqttNode extends TbAbstractExternalNode { private static final Charset UTF8 = Charset.forName("UTF-8"); @@ -67,8 +68,9 @@ public class TbMqttNode implements TbNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); + this.mqttNodeConfiguration = TbNodeUtils.convert(configuration, TbMqttNodeConfiguration.class); try { - this.mqttNodeConfiguration = TbNodeUtils.convert(configuration, TbMqttNodeConfiguration.class); this.mqttClient = initClient(ctx); } catch (Exception e) { throw new TbNodeException(e); @@ -78,13 +80,13 @@ public class TbMqttNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { String topic = TbNodeUtils.processPattern(this.mqttNodeConfiguration.getTopicPattern(), msg); - this.mqttClient.publish(topic, Unpooled.wrappedBuffer(msg.getData().getBytes(UTF8)), MqttQoS.AT_LEAST_ONCE, mqttNodeConfiguration.isRetainedMessage()) + var tbMsg = ackIfNeeded(ctx, msg); + this.mqttClient.publish(topic, Unpooled.wrappedBuffer(tbMsg.getData().getBytes(UTF8)), MqttQoS.AT_LEAST_ONCE, mqttNodeConfiguration.isRetainedMessage()) .addListener(future -> { if (future.isSuccess()) { - ctx.tellSuccess(msg); + tellSuccess(ctx, tbMsg); } else { - TbMsg next = processException(ctx, msg, future.cause()); - ctx.tellFailure(next, future.cause()); + tellFailure(ctx, processException(ctx, tbMsg, future.cause()), future.cause()); } } ); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java index 5720f66038..3ea96fa967 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/azure/TbAzureIotHubNode.java @@ -48,8 +48,9 @@ import javax.net.ssl.SSLException; public class TbAzureIotHubNode extends TbMqttNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); + this.mqttNodeConfiguration = TbNodeUtils.convert(configuration, TbMqttNodeConfiguration.class); try { - this.mqttNodeConfiguration = TbNodeUtils.convert(configuration, TbMqttNodeConfiguration.class); mqttNodeConfiguration.setPort(8883); mqttNodeConfiguration.setCleanSession(true); ClientCredentials credentials = mqttNodeConfiguration.getCredentials(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java index 057702cb2b..f1fd9727fa 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java @@ -23,6 +23,7 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.notification.NotificationRequest; import org.thingsboard.server.common.data.notification.NotificationRequestConfig; import org.thingsboard.server.common.data.notification.info.RuleEngineOriginatedNotificationInfo; @@ -42,12 +43,13 @@ import java.util.concurrent.ExecutionException; configDirective = "tbExternalNodeNotificationConfig", icon = "notifications" ) -public class TbNotificationNode implements TbNode { +public class TbNotificationNode extends TbAbstractExternalNode { private TbNotificationNodeConfiguration config; @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); this.config = TbNodeUtils.convert(configuration, TbNotificationNodeConfiguration.class); } @@ -69,15 +71,17 @@ public class TbNotificationNode implements TbNode { .originatorEntityId(ctx.getSelf().getRuleChainId()) .build(); - DonAsynchron.withCallback(ctx.getNotificationExecutor().executeAsync(() -> { - return ctx.getNotificationCenter().processNotificationRequest(ctx.getTenantId(), notificationRequest, stats -> { - TbMsgMetaData metaData = msg.getMetaData().copy(); - metaData.putValue("notificationRequestResult", JacksonUtil.toString(stats)); - ctx.tellSuccess(TbMsg.transformMsg(msg, metaData)); - }); - }), - r -> {}, - e -> ctx.tellFailure(msg, e)); + var tbMsg = ackIfNeeded(ctx, msg); + + DonAsynchron.withCallback(ctx.getNotificationExecutor().executeAsync(() -> + ctx.getNotificationCenter().processNotificationRequest(ctx.getTenantId(), notificationRequest, stats -> { + TbMsgMetaData metaData = tbMsg.getMetaData().copy(); + metaData.putValue("notificationRequestResult", JacksonUtil.toString(stats)); + tellSuccess(ctx, TbMsg.transformMsg(tbMsg, metaData)); + })), + r -> { + }, + e -> tellFailure(ctx, tbMsg, e)); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbSlackNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbSlackNode.java index 544a864931..86e2c4bd1c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbSlackNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbSlackNode.java @@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -37,12 +38,13 @@ import java.util.concurrent.ExecutionException; configDirective = "tbExternalNodeSlackConfig", iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTYsMTVBMiwyIDAgMCwxIDQsMTdBMiwyIDAgMCwxIDIsMTVBMiwyIDAgMCwxIDQsMTNINlYxNU03LDE1QTIsMiAwIDAsMSA5LDEzQTIsMiAwIDAsMSAxMSwxNVYyMEEyLDIgMCAwLDEgOSwyMkEyLDIgMCAwLDEgNywyMFYxNU05LDdBMiwyIDAgMCwxIDcsNUEyLDIgMCAwLDEgOSwzQTIsMiAwIDAsMSAxMSw1VjdIOU05LDhBMiwyIDAgMCwxIDExLDEwQTIsMiAwIDAsMSA5LDEySDRBMiwyIDAgMCwxIDIsMTBBMiwyIDAgMCwxIDQsOEg5TTE3LDEwQTIsMiAwIDAsMSAxOSw4QTIsMiAwIDAsMSAyMSwxMEEyLDIgMCAwLDEgMTksMTJIMTdWMTBNMTYsMTBBMiwyIDAgMCwxIDE0LDEyQTIsMiAwIDAsMSAxMiwxMFY1QTIsMiAwIDAsMSAxNCwzQTIsMiAwIDAsMSAxNiw1VjEwTTE0LDE4QTIsMiAwIDAsMSAxNiwyMEEyLDIgMCAwLDEgMTQsMjJBMiwyIDAgMCwxIDEyLDIwVjE4SDE0TTE0LDE3QTIsMiAwIDAsMSAxMiwxNUEyLDIgMCAwLDEgMTQsMTNIMTlBMiwyIDAgMCwxIDIxLDE1QTIsMiAwIDAsMSAxOSwxN0gxNFoiIC8+PC9zdmc+" ) -public class TbSlackNode implements TbNode { +public class TbSlackNode extends TbAbstractExternalNode { private TbSlackNodeConfiguration config; @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); this.config = TbNodeUtils.convert(configuration, TbSlackNodeConfiguration.class); } @@ -59,11 +61,12 @@ public class TbSlackNode implements TbNode { } String message = TbNodeUtils.processPattern(config.getMessageTemplate(), msg); + var tbMsg = ackIfNeeded(ctx, msg); DonAsynchron.withCallback(ctx.getExternalCallExecutor().executeAsync(() -> { ctx.getSlackService().sendMessage(ctx.getTenantId(), token, config.getConversation().getId(), message); }), - r -> ctx.tellSuccess(msg), - e -> ctx.tellFailure(msg, e)); + r -> tellSuccess(ctx, tbMsg), + e -> tellFailure(ctx, tbMsg, e)); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index ba987678f3..e2986677b5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -76,6 +76,10 @@ public class TbDeviceProfileNode implements TbNode { this.ctx = ctx; scheduleAlarmHarvesting(ctx, null); ctx.addDeviceProfileListeners(this::onProfileUpdate, this::onDeviceUpdate); + initAlarmRuleState(false); + } + + private void initAlarmRuleState(boolean printNewlyAddedDeviceStates) { if (config.isFetchAlarmRulesStateOnStart()) { log.info("[{}] Fetching alarm rule state", ctx.getSelfId()); int fetchCount = 0; @@ -86,7 +90,7 @@ public class TbDeviceProfileNode implements TbNode { for (RuleNodeState rns : states.getData()) { fetchCount++; if (rns.getEntityId().getEntityType().equals(EntityType.DEVICE) && ctx.isLocalEntity(rns.getEntityId())) { - getOrCreateDeviceState(ctx, new DeviceId(rns.getEntityId().getId()), rns); + getOrCreateDeviceState(ctx, new DeviceId(rns.getEntityId().getId()), rns, printNewlyAddedDeviceStates); } } } @@ -130,7 +134,7 @@ public class TbDeviceProfileNode implements TbNode { removeDeviceState(deviceId); ctx.tellSuccess(msg); } else { - DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId, null); + DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId, null, false); if (deviceState != null) { deviceState.process(ctx, msg); } else { @@ -148,6 +152,7 @@ public class TbDeviceProfileNode implements TbNode { public void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) { // Cleanup the cache for all entities that are no longer assigned to current server partitions deviceStates.entrySet().removeIf(entry -> !ctx.isLocalEntity(entry.getKey())); + initAlarmRuleState(true); } @Override @@ -156,13 +161,16 @@ public class TbDeviceProfileNode implements TbNode { deviceStates.clear(); } - protected DeviceState getOrCreateDeviceState(TbContext ctx, DeviceId deviceId, RuleNodeState rns) { + protected DeviceState getOrCreateDeviceState(TbContext ctx, DeviceId deviceId, RuleNodeState rns, boolean printNewlyAddedDeviceStates) { DeviceState deviceState = deviceStates.get(deviceId); if (deviceState == null) { DeviceProfile deviceProfile = cache.get(ctx.getTenantId(), deviceId); if (deviceProfile != null) { deviceState = new DeviceState(ctx, config, deviceId, new ProfileState(deviceProfile), rns); deviceStates.put(deviceId, deviceState); + if (printNewlyAddedDeviceStates) { + log.info("[{}][{}] Device [{}] was added during PartitionChangeMsg", ctx.getTenantId(), ctx.getSelfId(), deviceId); + } } } return deviceState; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java index 41dffe2fd8..4b42ee1d18 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java @@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -48,7 +49,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; configDirective = "tbExternalNodeRabbitMqConfig", iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4=" ) -public class TbRabbitMqNode implements TbNode { +public class TbRabbitMqNode extends TbAbstractExternalNode { private static final Charset UTF8 = Charset.forName("UTF-8"); @@ -61,6 +62,7 @@ public class TbRabbitMqNode implements TbNode { @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); this.config = TbNodeUtils.convert(configuration, TbRabbitMqNodeConfiguration.class); ConnectionFactory factory = new ConnectionFactory(); factory.setHost(this.config.getHost()); @@ -82,12 +84,10 @@ public class TbRabbitMqNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - withCallback(publishMessageAsync(ctx, msg), - ctx::tellSuccess, - t -> { - TbMsg next = processException(ctx, msg, t); - ctx.tellFailure(next, t); - }); + var tbMsg = ackIfNeeded(ctx, msg); + withCallback(publishMessageAsync(ctx, tbMsg), + m -> tellSuccess(ctx, m), + t -> tellFailure(ctx, processException(ctx, tbMsg, t), t)); } private ListenableFuture publishMessageAsync(TbContext ctx, TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 6f9541f5b1..28e221b0b1 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 @@ -65,6 +65,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; +import java.util.function.Consumer; @Data @Slf4j @@ -182,14 +183,16 @@ public class TbHttpClient { } } - public void processMessage(TbContext ctx, TbMsg msg) { + public void processMessage(TbContext ctx, TbMsg msg, + Consumer onSuccess, + BiConsumer onFailure) { String endpointUrl = TbNodeUtils.processPattern(config.getRestEndpointUrlPattern(), msg); HttpHeaders headers = prepareHeaders(msg); HttpMethod method = HttpMethod.valueOf(config.getRequestMethod()); HttpEntity entity; - if(HttpMethod.GET.equals(method) || HttpMethod.HEAD.equals(method) || - HttpMethod.OPTIONS.equals(method) || HttpMethod.TRACE.equals(method) || - config.isIgnoreRequestBody()) { + if (HttpMethod.GET.equals(method) || HttpMethod.HEAD.equals(method) || + HttpMethod.OPTIONS.equals(method) || HttpMethod.TRACE.equals(method) || + config.isIgnoreRequestBody()) { entity = new HttpEntity<>(headers); } else { entity = new HttpEntity<>(getData(msg), headers); @@ -198,21 +201,18 @@ public class TbHttpClient { URI uri = buildEncodedUri(endpointUrl); ListenableFuture> future = httpClient.exchange( uri, method, entity, String.class); - future.addCallback(new ListenableFutureCallback>() { + future.addCallback(new ListenableFutureCallback<>() { @Override public void onFailure(Throwable throwable) { - TbMsg next = processException(ctx, msg, throwable); - ctx.tellFailure(next, throwable); + onFailure.accept(processException(ctx, msg, throwable), throwable); } @Override public void onSuccess(ResponseEntity responseEntity) { if (responseEntity.getStatusCode().is2xxSuccessful()) { - TbMsg next = processResponse(ctx, msg, responseEntity); - ctx.tellSuccess(next); + onSuccess.accept(processResponse(ctx, msg, responseEntity)); } else { - TbMsg next = processFailureResponse(ctx, msg, responseEntity); - ctx.tellNext(next, TbRelationTypes.FAILURE); + onFailure.accept(processFailureResponse(ctx, msg, responseEntity), null); } } }); @@ -248,7 +248,7 @@ public class TbHttpClient { if (config.isTrimDoubleQuotes()) { final String dataBefore = data; - data = data.replaceAll("^\"|\"$", "");; + data = data.replaceAll("^\"|\"$", ""); log.trace("Trimming double quotes. Before trim: [{}], after trim: [{}]", dataBefore, data); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java index d2356c69f7..c6083f1098 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java @@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -43,24 +44,26 @@ import org.thingsboard.server.common.msg.TbMsg; configDirective = "tbExternalNodeRestApiCallConfig", iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+" ) -public class TbRestApiCallNode implements TbNode { +public class TbRestApiCallNode extends TbAbstractExternalNode { - private boolean useRedisQueueForMsgPersistence; protected TbHttpClient httpClient; @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); TbRestApiCallNodeConfiguration config = TbNodeUtils.convert(configuration, TbRestApiCallNodeConfiguration.class); httpClient = new TbHttpClient(config, ctx.getSharedEventLoop()); - useRedisQueueForMsgPersistence = config.isUseRedisQueueForMsgPersistence(); - if (useRedisQueueForMsgPersistence) { + if (config.isUseRedisQueueForMsgPersistence()) { log.warn("[{}][{}] Usage of Redis Template is deprecated starting 2.5 and will have no affect", ctx.getTenantId(), ctx.getSelfId()); } } @Override public void onMsg(TbContext ctx, TbMsg msg) { - httpClient.processMessage(ctx, msg); + var tbMsg = ackIfNeeded(ctx, msg); + httpClient.processMessage(ctx, tbMsg, + m -> tellSuccess(ctx, m), + (m, t) -> tellFailure(ctx, m, t)); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java index e92b15780a..55209e1f64 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/sms/TbSendSmsNode.java @@ -23,6 +23,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.sms.SmsSender; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -39,13 +40,14 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; configDirective = "tbExternalNodeSendSmsConfig", icon = "sms" ) -public class TbSendSmsNode implements TbNode { +public class TbSendSmsNode extends TbAbstractExternalNode { private TbSendSmsNodeConfiguration config; private SmsSender smsSender; @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + super.init(ctx); try { this.config = TbNodeUtils.convert(configuration, TbSendSmsNodeConfiguration.class); if (!this.config.isUseSystemSmsSettings()) { @@ -58,15 +60,16 @@ public class TbSendSmsNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { + var tbMsg = ackIfNeeded(ctx, msg); try { withCallback(ctx.getSmsExecutor().executeAsync(() -> { - sendSms(ctx, msg); + sendSms(ctx, tbMsg); return null; }), - ok -> ctx.tellSuccess(msg), - fail -> ctx.tellFailure(msg, fail)); + ok -> tellSuccess(ctx, tbMsg), + fail -> tellFailure(ctx, tbMsg, fail)); } catch (Exception ex) { - ctx.tellFailure(msg, ex); + ctx.tellFailure(tbMsg, ex); } } 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 b143649869..2ad68f14b2 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1 +1 @@ -System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","tslib","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@angular/material/slide-toggle","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@shared/components/toggle-header.component","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,v,F,L,k,T,I,N,S,q,M,A,G,E,D,V,w,P,R,O,H,K,B,U,z,_,j,$,Q,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,ve,Fe,Le,ke,Te,Ie,Ne,Se,qe,Me,Ae,Ge,Ee,De,Ve,we,Pe,Re,Oe,He,Ke,Be,Ue,ze,_e,je,$e;return{setters:[function(e){t=e,n=e.Component,r=e.Pipe,o=e.ViewChild,a=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.coerceBoolean,C=e.MessageType,v=e.messageTypeNames,F=e,L=e.SharedModule,k=e.AggregationType,T=e.aggregationTranslations,I=e.entityFields,N=e.NotificationType,S=e.SlackChanelType,q=e.SlackChanelTypesTranslateMap,M=e.alarmStatusTranslations,A=e.AlarmStatus},function(e){G=e},function(e){E=e,D=e.Validators,V=e.NgControl,w=e.NG_VALUE_ACCESSOR,P=e.NG_VALIDATORS,R=e.FormControl,O=e.UntypedFormControl},function(e){H=e,K=e.CommonModule},function(e){B=e},function(e){U=e},function(e){z=e},function(e){_=e},function(e){j=e},function(e){$=e},function(e){Q=e},function(e){J=e},function(e){Y=e},function(e){W=e.getCurrentAuthState,X=e,Z=e.isDefinedAndNotNull,ee=e.deepTrim,te=e.isObject,ne=e.isNotEmptyStr},function(e){re=e},function(e){oe=e},function(e){ae=e},function(e){ie=e.ENTER,le=e.COMMA,se=e.SEMICOLON},function(e){me=e},function(e){ue=e},function(e){pe=e},function(e){de=e},function(e){ce=e.coerceBooleanProperty},function(e){fe=e},function(e){ge=e},function(e){ye=e},function(e){xe=e},function(e){be=e},function(e){he=e.tap,Ce=e.map,ve=e.mergeMap,Fe=e.takeUntil,Le=e.startWith,ke=e.share},function(e){Te=e},function(e){Ie=e},function(e){Ne=e.of,Se=e.Subject},function(e){qe=e},function(e){Me=e.HomeComponentsModule},function(e){Ae=e.__decorate},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){we=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e},function(e){Be=e},function(e){Ue=e},function(e){ze=e},function(e){_e=e},function(e){je=e},function(e){$e=e}],execute:function(){class Qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Qe),Qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qe,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qe,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qe,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Je{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,deps:[{token:$.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Je.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Je,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:$.DomSanitizer}]}});class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[D.required,D.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ye,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:We,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[D.required]]})}}e("CheckPointConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xe,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:Y.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Ze extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[D.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[D.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[D.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.clearAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",r=this.clearAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.clearAlarmConfigForm.get(t).setValue(e)}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ze,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[ie,le,se],this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([D.required]),this.createAlarmConfigForm.get("severity").setValidators([D.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",r=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:et,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[D.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([D.required,D.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([D.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,D.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,D.required]})}}e("DeviceProfileConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ot extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[D.required,D.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[D.required,D.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",r=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var at;e("GeneratorConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ot,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:Y.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(at||(at={}));const it=new Map([[at.CUSTOMER,"tb.rulenode.originator-customer"],[at.TENANT,"tb.rulenode.originator-tenant"],[at.RELATED,"tb.rulenode.originator-related"],[at.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[at.ENTITY,"tb.rulenode.originator-entity"]]);var lt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(lt||(lt={}));const st=new Map([[lt.CIRCLE,"tb.rulenode.perimeter-circle"],[lt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var mt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(mt||(mt={}));const ut=new Map([[mt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[mt.SECONDS,"tb.rulenode.time-unit-seconds"],[mt.MINUTES,"tb.rulenode.time-unit-minutes"],[mt.HOURS,"tb.rulenode.time-unit-hours"],[mt.DAYS,"tb.rulenode.time-unit-days"]]);var pt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(pt||(pt={}));const dt=new Map([[pt.METER,"tb.rulenode.range-unit-meter"],[pt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[pt.FOOT,"tb.rulenode.range-unit-foot"],[pt.MILE,"tb.rulenode.range-unit-mile"],[pt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var ct;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(ct||(ct={}));const ft=new Map([[ct.ID,"tb.rulenode.entity-details-id"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var gt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(gt||(gt={}));const yt=new Map([[gt.FIRST,"tb.rulenode.first"],[gt.LAST,"tb.rulenode.last"],[gt.ALL,"tb.rulenode.all"]]),xt=new Map([[gt.FIRST,"tb.rulenode.first-mode-hint"],[gt.LAST,"tb.rulenode.last-mode-hint"],[gt.ALL,"tb.rulenode.all-mode-hint"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const Ct=new Map([[ht.ATTRIBUTES,"tb.rulenode.attributes"],[ht.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[ht.FIELDS,"tb.rulenode.fields"]]),vt=new Map([[ht.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[ht.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[ht.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),Ft=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var Lt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Lt||(Lt={}));const kt=new Map([[Lt.STANDARD,"tb.rulenode.sqs-queue-standard"],[Lt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Tt=["anonymous","basic","cert.PEM"],It=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Nt=["sas","cert.PEM"],St=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var qt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(qt||(qt={}));const Mt=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],At=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Gt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Gt||(Gt={}));const Et=new Map([[Gt.CUSTOM,{value:Gt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Gt.ADD,{value:Gt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Gt.SUB,{value:Gt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Gt.MULT,{value:Gt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Gt.DIV,{value:Gt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Gt.SIN,{value:Gt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.SINH,{value:Gt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Gt.COS,{value:Gt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.COSH,{value:Gt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Gt.TAN,{value:Gt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Gt.TANH,{value:Gt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ACOS,{value:Gt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Gt.ASIN,{value:Gt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN,{value:Gt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN2,{value:Gt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Gt.EXP,{value:Gt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Gt.EXPM1,{value:Gt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Gt.SQRT,{value:Gt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Gt.CBRT,{value:Gt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Gt.GET_EXP,{value:Gt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Gt.HYPOT,{value:Gt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Gt.LOG,{value:Gt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG10,{value:Gt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG1P,{value:Gt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Gt.CEIL,{value:Gt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR,{value:Gt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR_DIV,{value:Gt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Gt.FLOOR_MOD,{value:Gt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Gt.ABS,{value:Gt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Gt.MIN,{value:Gt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Gt.MAX,{value:Gt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Gt.POW,{value:Gt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Gt.SIGNUM,{value:Gt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Gt.RAD,{value:Gt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Gt.DEG,{value:Gt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Dt,Vt,wt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Dt||(Dt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Vt||(Vt={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(wt||(wt={}));const Pt=new Map([[wt.DATA,"tb.rulenode.message"],[wt.METADATA,"tb.rulenode.metadata"]]),Rt=new Map([[Dt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Dt.TIME_SERIES,"tb.rulenode.time-series-type"],[Dt.CONSTANT,"tb.rulenode.constant-type"],[Dt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Dt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),Ot=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Ht,Kt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Ht||(Ht={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Kt||(Kt={}));const Bt=new Map([[Ht.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Ht.SERVER_SCOPE,"tb.rulenode.server-scope"],[Ht.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt,this.timeUnits=Object.keys(mt),this.timeUnitsTranslationMap=ut}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[D.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[D.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoActionConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ut,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",r=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[D.required,D.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[D.required]]})}}e("MsgCountConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_t,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([D.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([D.required,D.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]]})}}e("PushToCloudConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]]})}}e("PushToEdgeConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[D.required,D.min(0)]]})}}e("RpcRequestConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[D.required]],value:["",[D.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigOldComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:w,useExisting:a((()=>Wt)),multi:!0},{provide:P,useExisting:a((()=>Wt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:w,useExisting:a((()=>Wt)),multi:!0},{provide:P,useExisting:a((()=>Wt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[D.required,D.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[D.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[D.required,D.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class en extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[D.required,D.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:en,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[ie,le,se]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],keys:[e?e.keys:null,[D.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class nn extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=Et,this.ArgumentType=Dt,this.attributeScopeMap=Bt,this.argumentTypeResultMap=Rt,this.arguments=Object.values(Dt),this.attributeScope=Object.values(Ht),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),n=this.createArgumentControl(null,t.length);t.push(n,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Gt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([D.minLength(this.minArgs),D.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!1}),n.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Dt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Dt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Ot[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:w,useExisting:a((()=>nn)),multi:!0},{provide:P,useExisting:a((()=>nn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"],dependencies:[{kind:"directive",type:H.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:xe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:xe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:be.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:be.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:be.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:w,useExisting:a((()=>nn)),multi:!0},{provide:P,useExisting:a((()=>nn)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class rn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...Et.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(he((e=>{let t;t="string"==typeof e&&Gt[e]?Gt[e]:null,this.updateView(t)})),Ce((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=Et.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rn,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:w,useExisting:a((()=>rn)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:w,useExisting:a((()=>rn)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class on extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Gt,this.ArgumentTypeResult=Vt,this.argumentTypeResultMap=Rt,this.attributeScopeMap=Bt,this.argumentsResult=Object.values(Vt),this.attributeScopeResult=Object.values(Kt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[D.required]],arguments:[e?e.arguments:null,[D.required]],customFunction:[e?e.customFunction:"",[D.required]],result:this.fb.group({type:[e?e.result.type:null,[D.required]],attributeScope:[e?e.result.attributeScope:null,[D.required]],key:[e?e.result.key:"",[D.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result.type").value;t===Gt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Vt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:on,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:nn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:rn,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class an{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[D.required,D.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(he((e=>{this.updateView(e)})),Ce((e=>e||"")),ve((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,Ne(this.messageTypes).pipe(Ce((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:an,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:w,useExisting:a((()=>an)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:w,useExisting:a((()=>an)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class ln extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Se,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=gt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=yt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[Z(e?.interval)?e.interval:null,[D.required,D.min(1)]],strategy:[Z(e?.strategy)?e.strategy:null,[D.required]],outMsgType:[Z(e?.outMsgType)?e.outMsgType:null,[D.required]],queueName:[Z(e?.queueName)?e.queueName:null,[D.required]],maxPendingMsgs:[Z(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e3)]],maxRetries:[Z(e?.maxRetries)?e.maxRetries:null,[D.required,D.min(0),D.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ln,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Y.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:qe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:qe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:qe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:qe.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:an,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class sn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sn,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:w,useExisting:a((()=>sn)),multi:!0},{provide:P,useExisting:a((()=>sn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),Ae([h()],sn.prototype,"disabled",void 0),Ae([h()],sn.prototype,"uniqueKeyValuePairValidator",void 0),Ae([h()],sn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:w,useExisting:a((()=>sn)),multi:!0},{provide:P,useExisting:a((()=>sn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class mn{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Se}ngOnInit(){this.slideToggleControlGroup=this.fb.group({slideToggleControl:[null,[]]}),this.slideToggleControlGroup.get("slideToggleControl").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.slideToggleControlGroup.get("slideToggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.slideToggleControlGroup.disable({emitEvent:!1}):this.slideToggleControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SlideToggleComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mn,selector:"tb-slide-toggle",inputs:{slideToggleName:"slideToggleName",slideToggleTooltip:"slideToggleTooltip"},providers:[{provide:w,useExisting:a((()=>mn)),multi:!0}],ngImport:t,template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"],dependencies:[{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Ve.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-slide-toggle",providers:[{provide:w,useExisting:a((()=>mn)),multi:!0}],template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{slideToggleName:[{type:i}],slideToggleTooltip:[{type:i}]}});class un extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],relationType:[null],deviceTypes:[null,[D.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:un,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:w,useExisting:a((()=>un)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["label","required","disabled","entityType"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:w,useExisting:a((()=>un)),multi:!0}],template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class pn{constructor(){this.required=!1}}e("FieldsetComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,deps:[],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pn,selector:"tb-fieldset-component",inputs:{label:"label",required:"required"},ngImport:t,template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]}]}),Ae([h()],pn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-fieldset-component",template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],propDecorators:{label:[{type:i}],required:[{type:i}]}});class dn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:w,useExisting:a((()=>dn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:w,useExisting:a((()=>dn)),multi:!0}],template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class cn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[ie,le,se],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(C))this.messageTypesList.push({name:v.get(C[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Le(""),Ce((e=>e||"")),ve((e=>this.fetchMessageTypes(e))),ke())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ne(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,deps:[{token:G.Store},{token:j.TranslateService},{token:F.TruncatePipe},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:w,useExisting:a((()=>cn)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:w,useExisting:a((()=>cn)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n { messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:F.TruncatePipe},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=Tt,this.credentialsTypeTranslationsMap=It,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[D.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){Z(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([D.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[D.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(D.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:w,useExisting:a((()=>fn)),multi:!0},{provide:P,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:H.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:qe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:qe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:qe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:qe.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:qe.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:w,useExisting:a((()=>fn)),multi:!0},{provide:P,useExisting:a((()=>fn)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class gn{constructor(e,t,n){this.store=e,this.fb=t,this.translate=n,this.destroy$=new Se,this.selectOptions=[];for(const e of Pt.keys())this.selectOptions.push({value:e,name:this.translate.instant(Pt.get(e))})}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.chipControlGroup.disable({emitEvent:!1}):this.chipControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:w,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:w,useExisting:a((()=>gn)),multi:!0}],template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]},propDecorators:{labelText:[{type:i}]}});class yn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Se,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.updateModel()}))}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value){const n=this.selectOptions.find((t=>t.value===e.key));n&&t.push(n)}const n=[];for(const r of this.selectOptions)Z(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[D.required]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.controls[e.length-1])}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Fe(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:w,useExisting:a((()=>yn)),multi:!0},{provide:P,useExisting:a((()=>yn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),Ae([h()],yn.prototype,"disabled",void 0),Ae([h()],yn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:w,useExisting:a((()=>yn)),multi:!0},{provide:P,useExisting:a((()=>yn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class xn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigOldComponent",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:w,useExisting:a((()=>xn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:w,useExisting:a((()=>xn)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class bn{constructor(e,t,n){this.store=e,this.translate=t,this.fb=n,this.destroy$=new Se,this.separatorKeysCodes=[ie,le,se]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]}),this.attributeControlGroup.valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.attributeControlGroup.patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}removeKey(e,t){const n=this.attributeControlGroup.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.attributeControlGroup.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.attributeControlGroup.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.attributeControlGroup.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}clearChipGrid(e){this.attributeControlGroup.get(e).patchValue([],{emitEvent:!0})}}e("SelectAttributesComponent",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:bn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:w,useExisting:a((()=>bn)),multi:!0}],ngImport:t,template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:w,useExisting:a((()=>bn)),multi:!0}],template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class hn{}e("RulenodeCoreConfigCommonModule",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),hn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:hn,declarations:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn],imports:[K,L,Me],exports:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn]}),hn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,imports:[K,L,Me]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,decorators:[{type:l,args:[{declarations:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn],imports:[K,L,Me],exports:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn]}]}]});class Cn{}e("RuleNodeCoreConfigActionModule",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Cn,declarations:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln],imports:[K,L,Me,hn],exports:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln]}),Cn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,imports:[K,L,Me,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,decorators:[{type:l,args:[{declarations:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln],imports:[K,L,Me,hn],exports:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln]}]}]});class vn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[ie,le,se]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[D.min(0),D.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:Z(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:Z(e?.outputValueKey)?e.outputValueKey:null,useCache:!Z(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!Z(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:Z(e?.periodValueKey)?e.periodValueKey:null,round:Z(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!Z(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return ee(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([D.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:vn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"],dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of Ct.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ct.get(e))})}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,ee(e)}toggleChange(e){this.customerAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=Z(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:Z(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=Z(e?.attrMapping)?e.attrMapping:Z(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:sn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[D.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return te(e)&&(e.attributesControl={clientAttributeNames:Z(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:Z(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:Z(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:Z(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!Z(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:Z(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!Z(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ln,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:un,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.entityDetailsTranslationsMap=ft,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(ct))this.entityDetailsList.push(ct[e]);this.detailsFormControl=new R(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(Le(""),Ce((e=>e||"")),ve((e=>this.fetchEntityDetails(e))),ke())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],t=Z(e?.addToMetadata)?e.addToMetadata?wt.METADATA:wt.DATA:e?.fetchTo?e.fetchTo:wt.DATA,{detailsList:Z(e?.detailsList)?e.detailsList:null,fetchTo:t}}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[D.required]],fetchTo:[e.fetchTo,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(ft.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(this.entityDetailsList.filter((t=>this.translate.instant(ft.get(ct[t])).toUpperCase().includes(e))))}return Ne(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clearChipGrid(){this.detailsList=[],this.entityDetailsConfigForm.get("detailsList").patchValue([],{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kn,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]},propDecorators:{detailsInput:[{type:o,args:["detailsInput",{static:!1}]}]}});class Tn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[ie,le,se],this.aggregationTypes=k,this.aggregations=Object.keys(k),this.aggregationTypesTranslations=T,this.fetchMode=gt,this.samplingOrders=Object.keys(bt),this.samplingOrdersTranslate=Ft,this.timeUnits=Object.values(mt),this.timeUnitsTranslationMap=ut,this.deduplicationStrategiesHintTranslations=xt,this.headerOptions=[],this.timeUnitMap={[mt.MILLISECONDS]:1,[mt.SECONDS]:1e3,[mt.MINUTES]:6e4,[mt.HOURS]:36e5,[mt.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null;for(const e of yt.keys())this.headerOptions.push({value:e,name:this.translate.instant(yt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[]],aggregation:[e.aggregation,[D.required]],fetchMode:[e.fetchMode,[D.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}toggleChange(e){this.getTelemetryFromDatabaseConfigForm.get("fetchMode").patchValue(e,{emitEvent:!0})}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,delete e.interval,ee(e)}prepareInputConfig(e){return te(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:Z(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:Z(e?.aggregation)?e.aggregation:k.NONE,fetchMode:Z(e?.fetchMode)?e.fetchMode:gt.FIRST,orderBy:Z(e?.orderBy)?e.orderBy:bt.ASC,limit:Z(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!Z(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:Z(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:Z(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:mt.MINUTES,endInterval:Z(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:Z(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:mt.MINUTES},startIntervalPattern:Z(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:Z(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===gt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([D.required,D.min(2),D.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tn,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class In extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return te(e)&&(e.attributesControl={clientAttributeNames:Z(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:Z(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:Z(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:Z(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!Z(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA,tellFailureIfAbsent:!!Z(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:Z(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:In,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class Nn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of Object.keys(I))this.originatorFields.push({value:I[e].value,name:this.translate.instant(I[e].name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return ee(e)}prepareInputConfig(e){return{dataMapping:Z(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:Z(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[D.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class Sn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=ht,this.msgMetadataLabelTranslations=vt,this.originatorFields=[],this.fetchToData=[],this.destroy$=new Se,this.defaultKvMap={serialNumber:"sn"},this.defaultSvMap={[I.name.value]:`relatedEntity${this.translate.instant(I.name.name)}`},this.dataToFetchPrevValue="";for(const e of Object.keys(I))this.originatorFields.push({value:I[e].value,name:this.translate.instant(I[e].name)});for(const e of Ct.keys())this.fetchToData.push({value:e,name:this.translate.instant(Ct.get(e))})}toggleChange(e){this.relatedAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,ee(e)}prepareInputConfig(e){let t;return Z(e?.telemetry)?this.dataToFetchPrevValue=e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:this.dataToFetchPrevValue=Z(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,t=Z(e?.attrMapping)?e.attrMapping:Z(e?.dataMapping)?e.dataMapping:null,{relationsQuery:Z(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:this.dataToFetchPrevValue,dataMapping:t,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[D.required]],dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{e===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultSvMap,{emitEvent:!1}),e!==ht.FIELDS&&this.dataToFetchPrevValue===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultKvMap,{emitEvent:!1}),this.dataToFetchPrevValue=e}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sn,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:sn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class qn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of Ct.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ct.get(e))})}configForm(){return this.tenantAttributesConfigForm}toggleChange(e){this.tenantAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=Z(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:Z(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=Z(e?.attrMapping)?e.attrMapping:Z(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qn,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:sn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class An{}e("RulenodeCoreConfigEnrichmentModule",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,deps:[],target:t.ɵɵFactoryTarget.NgModule}),An.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:An,declarations:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn],imports:[K,L,hn],exports:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn]}),An.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,decorators:[{type:l,args:[{declarations:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn],imports:[K,L,hn],exports:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn]}]}]});class Gn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Nt,this.azureIotHubCredentialsTypeTranslationsMap=St}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[D.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[D.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([D.required]);break;case"cert.PEM":t.get("privateKey").setValidators([D.required]),t.get("privateKeyFileName").setValidators([D.required]),t.get("cert").setValidators([D.required]),t.get("certFileName").setValidators([D.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Gn,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:H.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:qe.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:qe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:qe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:qe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:qe.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=Mt,this.ToByteStandartCharsetTypeTranslationMap=At}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[D.required]],retries:[e?e.retries:null,[D.min(0)]],batchSize:[e?e.batchSize:null,[D.min(0)]],linger:[e?e.linger:null,[D.min(0)]],bufferMemory:[e?e.bufferMemory:null,[D.min(0)]],acks:[e?e.acks:null,[D.required]],keySerializer:[e?e.keySerializer:null,[D.required]],valueSerializer:[e?e.valueSerializer:null,[D.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([D.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:En,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&ne(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{ne(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Vn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=N,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[D.required]],targets:[e?e.targets:[],[D.required]]})}}e("NotificationConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vn,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:He.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ke.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class wn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[D.required]],topicName:[e?e.topicName:null,[D.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[D.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[D.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[D.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[D.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(qt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[D.required]],requestMethod:[e?e.requestMethod:null,[D.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[D.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[D.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[D.required,D.min(1),D.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([D.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([D.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rn,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,n=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([D.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([D.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([D.required,D.min(1),D.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([D.required,D.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[D.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[D.required,D.min(1),D.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:On,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Be.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[D.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[D.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([D.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Hn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ue.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Kn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(S),this.slackChanelTypesTranslateMap=q}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[D.required]],conversationType:[e?e.conversationType:null,[D.required]],conversation:[e?e.conversation:null,[D.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([D.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kn,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:_e.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Bn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[D.required]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SnsConfigComponent",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bn,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Un extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Lt,this.sqsQueueTypes=Object.keys(Lt),this.sqsQueueTypeTranslationsMap=kt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[D.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[D.required]],delaySeconds:[e?e.delaySeconds:null,[D.min(0),D.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SqsConfigComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Un,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zn{}e("RulenodeCoreConfigExternalModule",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:zn,declarations:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn],imports:[K,L,Me,hn],exports:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn]}),zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,imports:[K,L,Me,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,decorators:[{type:l,args:[{declarations:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn],imports:[K,L,Me,hn],exports:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn]}]}]});class _n extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.alarmStatusTranslationsMap=M,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(A))this.alarmStatusList.push(A[e]);this.statusFormControl=new O(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(Le(""),Ce((e=>e||"")),ve((e=>this.fetchAlarmStatus(e))),ke())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[D.required]]})}displayStatus(e){return e?this.translate.instant(M.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(t.filter((t=>this.translate.instant(M.get(A[t])).toUpperCase().includes(e))))}return Ne(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const n=t.indexOf(e);n>=0&&(t.splice(n,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,deps:[{token:G.Store},{token:j.TranslateService},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_n,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:o,args:["alarmStatusInput",{static:!1}]}]}});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ie,le,se]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[D.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[D.required]:[]],relationType:[e?e.relationType:null,[D.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:je.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoFilterConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[D.required]]})}}e("MessageTypeConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jn,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:cn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[D.required]]})}}e("OriginatorTypeConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:$e.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["label","floatLabel","required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Xn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",r=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Zn{}e("RuleNodeCoreConfigFilterModule",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Zn,declarations:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n],imports:[K,L,hn],exports:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n]}),Zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,decorators:[{type:l,args:[{declarations:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n],imports:[K,L,hn],exports:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n]}]}]});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=at,this.originatorSources=Object.keys(at),this.originatorSourceTranslationMap=it,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===at.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([D.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===at.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([D.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:er,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tr extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[D.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[D.required]],toTemplate:[e?e.toTemplate:null,[D.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[D.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[D.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(Le([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(D.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ie,le,se]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[D.required]]})}}e("RenameKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[D.required]]})}}e("NodeJsonPathConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ie,le,se]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class lr{}e("RulenodeCoreConfigTransformModule",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),lr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:lr,declarations:[er,tr,nr,rr,or,ar,ir],imports:[K,L,hn],exports:[er,tr,nr,rr,or,ar,ir]}),lr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:l,args:[{declarations:[er,tr,nr,rr,or,ar,ir],imports:[K,L,hn],exports:[er,tr,nr,rr,or,ar,ir]}]}]});class sr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[D.required]]})}}e("RuleChainInputComponent",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:je.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class mr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ur{}e("RuleNodeCoreConfigFlowModule",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ur.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:ur,declarations:[sr,mr],imports:[K,L,hn],exports:[sr,mr]}),ur.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:l,args:[{declarations:[sr,mr],imports:[K,L,hn],exports:[sr,mr]}]}]});class pr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. If you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required!","limit-range":"Limit should be in a range from 2 to 1000!","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647!","start-interval-value-required":"Start interval value is required!","end-interval-value-required":"End interval value is required!",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","add-timeseries-key":"Add timeseries key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Max relation level should be greater than 0 or unspecified!","relation-type":"Relation type","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required!","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required!","target-key":"Target key","target-key-required":"Target key is required!","attr-mapping-required":"At least one mapping entry should be specified!","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","source-field":"Source field","source-field-required":"Source field is required!","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required!","end-interval-required":"Interval end is required!","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","entity-details-list-empty":"No entity details selected!","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required!","output-value-key":"Output value key","output-value-key-required":"Output value key is required!","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15!","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-cashing":"Use cashing","use-cashing-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required!","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","attributes-mapping":"Attributes mapping*","latest-telemetry-mapping":"Latest telemetry mapping*","add-mapped-attribute-to":"Add mapped attributes to:","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to:","add-mapped-fields-to":"Add mapped fields to:","add-selected-details-to":"Add selected details to:","clear-selected-details":"Clear selected details","clear-selected-keys":"Clear selected keys","fetch-credentials-to":"Fetch credentials to:","add-originator-attributes-to":"Add originator attributes to:","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell Failure","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to:",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output message metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end")!',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch:","mapping-of-customers":"Mapping of customer's:",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to:","device-profiles":"Device profiles","mapping-of-tenant":"Mapping of tenant's:","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[{token:j.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:pr,declarations:[Qe],imports:[K,L],exports:[Cn,Zn,An,zn,lr,ur,Qe]}),pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,imports:[K,L,Cn,Zn,An,zn,lr,ur]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:l,args:[{declarations:[Qe],imports:[K,L],exports:[Cn,Zn,An,zn,lr,ur,Qe]}]}],ctorParameters:function(){return[{type:j.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","tslib","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@angular/material/slide-toggle","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@shared/components/toggle-header.component","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,v,F,L,k,T,I,N,S,q,M,A,G,E,D,V,w,P,R,O,H,K,B,U,z,_,j,$,Q,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,ve,Fe,Le,ke,Te,Ie,Ne,Se,qe,Me,Ae,Ge,Ee,De,Ve,we,Pe,Re,Oe,He,Ke,Be,Ue,ze,_e,je,$e,Qe;return{setters:[function(e){t=e,n=e.Component,r=e.Pipe,o=e.EventEmitter,a=e.ViewChild,i=e.forwardRef,l=e.Input,s=e.NgModule},function(e){m=e.RuleNodeConfigurationComponent,u=e.AttributeScope,p=e.telemetryTypeTranslations,d=e.ServiceType,c=e.ScriptLanguage,f=e.AlarmSeverity,g=e.alarmSeverityTranslations,y=e.EntitySearchDirection,x=e.entitySearchDirectionTranslations,b=e.EntityType,h=e.PageComponent,C=e.coerceBoolean,v=e.MessageType,F=e.messageTypeNames,L=e,k=e.SharedModule,T=e.AggregationType,I=e.aggregationTranslations,N=e.entityFields,S=e.NotificationType,q=e.SlackChanelType,M=e.SlackChanelTypesTranslateMap,A=e.alarmStatusTranslations,G=e.AlarmStatus},function(e){E=e},function(e){D=e,V=e.Validators,w=e.NgControl,P=e.NG_VALUE_ACCESSOR,R=e.NG_VALIDATORS,O=e.FormControl,H=e.UntypedFormControl},function(e){K=e,B=e.CommonModule},function(e){U=e},function(e){z=e},function(e){_=e},function(e){j=e},function(e){$=e},function(e){Q=e},function(e){J=e},function(e){Y=e},function(e){W=e},function(e){X=e.getCurrentAuthState,Z=e,ee=e.isDefinedAndNotNull,te=e.deepTrim,ne=e.isObject,re=e.isNotEmptyStr},function(e){oe=e},function(e){ae=e},function(e){ie=e},function(e){le=e.ENTER,se=e.COMMA,me=e.SEMICOLON},function(e){ue=e},function(e){pe=e},function(e){de=e},function(e){ce=e},function(e){fe=e.coerceBooleanProperty},function(e){ge=e},function(e){ye=e},function(e){xe=e},function(e){be=e},function(e){he=e},function(e){Ce=e.tap,ve=e.map,Fe=e.mergeMap,Le=e.takeUntil,ke=e.startWith,Te=e.share},function(e){Ie=e},function(e){Ne=e},function(e){Se=e.of,qe=e.Subject},function(e){Me=e},function(e){Ae=e.HomeComponentsModule},function(e){Ge=e.__decorate},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){we=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e},function(e){Be=e},function(e){Ue=e},function(e){ze=e},function(e){_e=e},function(e){je=e},function(e){$e=e},function(e){Qe=e}],execute:function(){class Je extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Je,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Ye{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,deps:[{token:Q.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Ye.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Ye,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:Q.DomSanitizer}]}});class We extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[V.required,V.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[V.required,V.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:We,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Xe extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=u,this.attributeScopes=Object.keys(u),this.telemetryTypeTranslationsMap=p}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[V.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==u.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===u.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xe,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Ze extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=d.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[V.required]]})}}e("CheckPointConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ze,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:W.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class et extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[V.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===c.JS?[V.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===c.TBEL?[V.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.clearAlarmConfigForm.get("scriptLang").value,n=t===c.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===c.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",o=this.clearAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.clearAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:et,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class tt extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(f),this.alarmSeverityTranslationMap=g,this.separatorKeysCodes=[le,se,me],this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([V.required]),this.createAlarmConfigForm.get("severity").setValidators([V.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==c.TBEL||this.tbelEnabled||(r=c.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===c.JS?[V.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===c.TBEL?[V.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.createAlarmConfigForm.get("scriptLang").value,n=t===c.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===c.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",o=this.createAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.createAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tt,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class nt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.entityType=b}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[V.required]],entityType:[e?e.entityType:null,[V.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[V.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[V.required,V.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([V.required,V.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==b.DEVICE&&t!==b.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([V.required,V.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class rt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.entityType=b}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[V.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[V.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[V.required,V.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([V.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([V.required,V.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ot extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,V.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,V.required]})}}e("DeviceProfileConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ot,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class at extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-generator-function",this.serviceType=d.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[V.required,V.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[V.required,V.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(e){const t=this.generatorConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",o=this.generatorConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.generatorConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}var it;e("GeneratorConfigComponent",at),at.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:at,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),at.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:at,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ce.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:W.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:at,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(it||(it={}));const lt=new Map([[it.CUSTOMER,"tb.rulenode.originator-customer"],[it.TENANT,"tb.rulenode.originator-tenant"],[it.RELATED,"tb.rulenode.originator-related"],[it.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[it.ENTITY,"tb.rulenode.originator-entity"]]);var st;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(st||(st={}));const mt=new Map([[st.CIRCLE,"tb.rulenode.perimeter-circle"],[st.POLYGON,"tb.rulenode.perimeter-polygon"]]);var ut;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(ut||(ut={}));const pt=new Map([[ut.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[ut.SECONDS,"tb.rulenode.time-unit-seconds"],[ut.MINUTES,"tb.rulenode.time-unit-minutes"],[ut.HOURS,"tb.rulenode.time-unit-hours"],[ut.DAYS,"tb.rulenode.time-unit-days"]]);var dt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(dt||(dt={}));const ct=new Map([[dt.METER,"tb.rulenode.range-unit-meter"],[dt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[dt.FOOT,"tb.rulenode.range-unit-foot"],[dt.MILE,"tb.rulenode.range-unit-mile"],[dt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var ft;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(ft||(ft={}));const gt=new Map([[ft.ID,"tb.rulenode.entity-details-id"],[ft.TITLE,"tb.rulenode.entity-details-title"],[ft.COUNTRY,"tb.rulenode.entity-details-country"],[ft.STATE,"tb.rulenode.entity-details-state"],[ft.CITY,"tb.rulenode.entity-details-city"],[ft.ZIP,"tb.rulenode.entity-details-zip"],[ft.ADDRESS,"tb.rulenode.entity-details-address"],[ft.ADDRESS2,"tb.rulenode.entity-details-address2"],[ft.PHONE,"tb.rulenode.entity-details-phone"],[ft.EMAIL,"tb.rulenode.entity-details-email"],[ft.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var yt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(yt||(yt={}));const xt=new Map([[yt.FIRST,"tb.rulenode.first"],[yt.LAST,"tb.rulenode.last"],[yt.ALL,"tb.rulenode.all"]]),bt=new Map([[yt.FIRST,"tb.rulenode.first-mode-hint"],[yt.LAST,"tb.rulenode.last-mode-hint"],[yt.ALL,"tb.rulenode.all-mode-hint"]]);var ht,Ct;!function(e){e.ASC="ASC",e.DESC="DESC"}(ht||(ht={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(Ct||(Ct={}));const vt=new Map([[Ct.ATTRIBUTES,"tb.rulenode.attributes"],[Ct.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[Ct.FIELDS,"tb.rulenode.fields"]]),Ft=new Map([[Ct.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[Ct.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[Ct.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),Lt=new Map([[ht.ASC,"tb.rulenode.ascending"],[ht.DESC,"tb.rulenode.descending"]]);var kt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(kt||(kt={}));const Tt=new Map([[kt.STANDARD,"tb.rulenode.sqs-queue-standard"],[kt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),It=["anonymous","basic","cert.PEM"],Nt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),St=["sas","cert.PEM"],qt=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Mt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Mt||(Mt={}));const At=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Gt=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Et;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Et||(Et={}));const Dt=new Map([[Et.CUSTOM,{value:Et.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Et.ADD,{value:Et.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Et.SUB,{value:Et.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Et.MULT,{value:Et.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Et.DIV,{value:Et.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Et.SIN,{value:Et.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Et.SINH,{value:Et.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Et.COS,{value:Et.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Et.COSH,{value:Et.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Et.TAN,{value:Et.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Et.TANH,{value:Et.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Et.ACOS,{value:Et.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Et.ASIN,{value:Et.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Et.ATAN,{value:Et.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Et.ATAN2,{value:Et.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Et.EXP,{value:Et.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Et.EXPM1,{value:Et.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Et.SQRT,{value:Et.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Et.CBRT,{value:Et.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Et.GET_EXP,{value:Et.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Et.HYPOT,{value:Et.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Et.LOG,{value:Et.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Et.LOG10,{value:Et.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Et.LOG1P,{value:Et.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Et.CEIL,{value:Et.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Et.FLOOR,{value:Et.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Et.FLOOR_DIV,{value:Et.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Et.FLOOR_MOD,{value:Et.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Et.ABS,{value:Et.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Et.MIN,{value:Et.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Et.MAX,{value:Et.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Et.POW,{value:Et.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Et.SIGNUM,{value:Et.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Et.RAD,{value:Et.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Et.DEG,{value:Et.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Vt,wt,Pt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Vt||(Vt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(wt||(wt={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Pt||(Pt={}));const Rt=new Map([[Pt.DATA,"tb.rulenode.message"],[Pt.METADATA,"tb.rulenode.metadata"]]),Ot=new Map([[Vt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Vt.TIME_SERIES,"tb.rulenode.time-series-type"],[Vt.CONSTANT,"tb.rulenode.constant-type"],[Vt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Vt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),Ht=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Kt,Bt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Kt||(Kt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Bt||(Bt={}));const Ut=new Map([[Kt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Kt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Kt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class zt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=st,this.perimeterTypes=Object.keys(st),this.perimeterTypeTranslationMap=mt,this.rangeUnits=Object.keys(dt),this.rangeUnitTranslationMap=ct,this.timeUnits=Object.keys(ut),this.timeUnitsTranslationMap=pt}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[V.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[V.required]],perimeterType:[e?e.perimeterType:null,[V.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[V.required,V.min(1),V.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[V.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[V.required,V.min(1),V.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[V.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([V.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==st.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([V.required,V.min(-90),V.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([V.required,V.min(-180),V.max(180)]),this.geoActionConfigForm.get("range").setValidators([V.required,V.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([V.required])),t||n!==st.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([V.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class _t extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-to-string-function"}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.logConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",o=this.logConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.logConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.logConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_t,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class jt extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[V.required,V.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[V.required]]})}}e("MsgCountConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class $t extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[V.required,V.min(1),V.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([V.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([V.required,V.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Qt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(u),this.telemetryTypeTranslationsMap=p}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[V.required]]})}}e("PushToCloudConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Jt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(u),this.telemetryTypeTranslationsMap=p}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[V.required]]})}}e("PushToEdgeConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Yt extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Wt extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[V.required,V.min(0)]]})}}e("RpcRequestConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Xt extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(w),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[V.required]],value:[e[n],[V.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[V.required]],value:["",[V.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigOldComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:P,useExisting:i((()=>Xt)),multi:!0},{provide:R,useExisting:i((()=>Xt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:xe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:P,useExisting:i((()=>Xt)),multi:!0},{provide:R,useExisting:i((()=>Xt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.UntypedFormBuilder}]},propDecorators:{disabled:[{type:l}],uniqueKeyValuePairValidator:[{type:l}],requiredText:[{type:l}],keyText:[{type:l}],keyRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],required:[{type:l}]}});class Zt extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[V.required,V.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[V.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class en extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[V.required,V.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:en,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class tn extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[V.required,V.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[V.required,V.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tn,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class nn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=u,this.attributeScopes=Object.keys(u),this.telemetryTypeTranslationsMap=p,this.separatorKeysCodes=[le,se,me]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[V.required]],keys:[e?e.keys:null,[V.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==u.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:a,args:["attributeChipList"]}]}});class rn extends h{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=Dt,this.ArgumentType=Vt,this.attributeScopeMap=Ut,this.argumentTypeResultMap=Ot,this.arguments=Object.values(Vt),this.attributeScope=Object.values(Kt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(w),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),n=this.createArgumentControl(null,t.length);t.push(n,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Et.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([V.minLength(this.minArgs),V.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!1}),n.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Vt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Vt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Ht[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:P,useExisting:i((()=>rn)),multi:!0},{provide:R,useExisting:i((()=>rn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"],dependencies:[{kind:"directive",type:K.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:be.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:be.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:he.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:he.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:he.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:xe.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:P,useExisting:i((()=>rn)),multi:!0},{provide:R,useExisting:i((()=>rn)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.FormBuilder}]},propDecorators:{disabled:[{type:l}],function:[{type:l}]}});class on extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...Dt.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(Ce((e=>{let t;t="string"==typeof e&&Et[e]?Et[e]:null,this.updateView(t)})),ve((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=Dt.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:on,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:P,useExisting:i((()=>on)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:Ne.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:P,useExisting:i((()=>on)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.UntypedFormBuilder}]},propDecorators:{required:[{type:l}],disabled:[{type:l}],operationInput:[{type:a,args:["operationInput",{static:!0}]}]}});class an extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Et,this.ArgumentTypeResult=wt,this.argumentTypeResultMap=Ot,this.attributeScopeMap=Ut,this.argumentsResult=Object.values(wt),this.attributeScopeResult=Object.values(Bt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[V.required]],arguments:[e?e.arguments:null,[V.required]],customFunction:[e?e.customFunction:"",[V.required]],result:this.fb.group({type:[e?e.result.type:null,[V.required]],attributeScope:[e?e.result.attributeScope:null,[V.required]],key:[e?e.result.key:"",[V.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result.type").value;t===Et.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===wt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:an,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:D.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:rn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:on,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ln{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[V.required,V.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(Ce((e=>{this.updateView(e)})),ve((e=>e||"")),Fe((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,Se(this.messageTypes).pipe(ve((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ln,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:P,useExisting:i((()=>ln)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:P,useExisting:i((()=>ln)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]},propDecorators:{messageTypeInput:[{type:a,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:l}],subscriptSizing:[{type:l}]}});class sn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new qe,this.serviceType=d.TB_RULE_ENGINE,this.deduplicationStrategie=yt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=xt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[ee(e?.interval)?e.interval:null,[V.required,V.min(1)]],strategy:[ee(e?.strategy)?e.strategy:null,[V.required]],outMsgType:[ee(e?.outMsgType)?e.outMsgType:null,[V.required]],queueName:[ee(e?.queueName)?e.queueName:null,[V.required]],maxPendingMsgs:[ee(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[V.required,V.min(1),V.max(1e3)]],maxRetries:[ee(e?.maxRetries)?e.maxRetries:null,[V.required,V.min(0),V.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:W.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Me.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Me.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Me.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Me.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class mn extends h{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(w),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mn,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:i((()=>mn)),multi:!0},{provide:R,useExisting:i((()=>mn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:xe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),Ge([C()],mn.prototype,"disabled",void 0),Ge([C()],mn.prototype,"uniqueKeyValuePairValidator",void 0),Ge([C()],mn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:P,useExisting:i((()=>mn)),multi:!0},{provide:R,useExisting:i((()=>mn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.FormBuilder}]},propDecorators:{disabled:[{type:l}],uniqueKeyValuePairValidator:[{type:l}],labelText:[{type:l}],requiredText:[{type:l}],keyText:[{type:l}],keyRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],popupHelpLink:[{type:l}],required:[{type:l}]}});class un{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new qe}ngOnInit(){this.slideToggleControlGroup=this.fb.group({slideToggleControl:[null,[]]}),this.slideToggleControlGroup.get("slideToggleControl").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.slideToggleControlGroup.get("slideToggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.slideToggleControlGroup.disable({emitEvent:!1}):this.slideToggleControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SlideToggleComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:un,selector:"tb-slide-toggle",inputs:{slideToggleName:"slideToggleName",slideToggleTooltip:"slideToggleTooltip"},providers:[{provide:P,useExisting:i((()=>un)),multi:!0}],ngImport:t,template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"],dependencies:[{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:we.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-slide-toggle",providers:[{provide:P,useExisting:i((()=>un)),multi:!0}],template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]},propDecorators:{slideToggleName:[{type:l}],slideToggleTooltip:[{type:l}]}});class pn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.entityType=b,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[V.required]],maxLevel:[null,[V.min(1)]],relationType:[null],deviceTypes:[null,[V.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pn,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:i((()=>pn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:De.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["label","required","disabled","entityType"]},{kind:"component",type:Ve.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:P,useExisting:i((()=>pn)),multi:!0}],template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class dn{constructor(){this.required=!1}}e("FieldsetComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,deps:[],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dn,selector:"tb-fieldset-component",inputs:{label:"label",required:"required"},ngImport:t,template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]}]}),Ge([C()],dn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-fieldset-component",template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],propDecorators:{label:[{type:l}],required:[{type:l}]}});class cn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[V.required]],maxLevel:[null,[V.min(1)]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:i((()=>cn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:P,useExisting:i((()=>cn)),multi:!0}],template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class fn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[le,se,me],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(v))this.messageTypesList.push({name:F.get(v[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(ke(""),ve((e=>e||"")),Fe((e=>this.fetchMessageTypes(e))),Te())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Se(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Se(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,deps:[{token:E.Store},{token:$.TranslateService},{token:L.TruncatePipe},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:P,useExisting:i((()=>fn)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n { messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Ie.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:Ne.HighlightPipe,name:"highlight"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:P,useExisting:i((()=>fn)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n { messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:L.TruncatePipe},{type:D.FormBuilder}]},propDecorators:{required:[{type:l}],label:[{type:l}],placeholder:[{type:l}],disabled:[{type:l}],chipList:[{type:a,args:["chipList",{static:!1}]}],matAutocomplete:[{type:a,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:a,args:["messageTypeInput",{static:!1}]}]}});class gn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=It,this.credentialsTypeTranslationsMap=Nt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[V.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){ee(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([V.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[V.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(V.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:P,useExisting:i((()=>gn)),multi:!0},{provide:R,useExisting:i((()=>gn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:K.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Me.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Me.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Me.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Me.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Me.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Re.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:P,useExisting:i((()=>gn)),multi:!0},{provide:R,useExisting:i((()=>gn)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]},propDecorators:{required:[{type:l}],disableCertPemCredentials:[{type:l}],passwordFieldRequired:[{type:l}]}});class yn{constructor(e,t,n){this.store=e,this.fb=t,this.translate=n,this.destroy$=new qe,this.selectOptions=[];for(const e of Rt.keys())this.selectOptions.push({value:e,name:this.translate.instant(Rt.get(e))})}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.chipControlGroup.disable({emitEvent:!1}):this.chipControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:P,useExisting:i((()=>yn)),multi:!0}],ngImport:t,template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:pe.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:pe.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:P,useExisting:i((()=>yn)),multi:!0}],template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]},propDecorators:{labelText:[{type:l}]}});class xn extends h{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new qe,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(w),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[V.required]],value:[e[n],[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.updateModel()}))}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value){const n=this.selectOptions.find((t=>t.value===e.key));n&&t.push(n)}const n=[];for(const r of this.selectOptions)ee(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[V.required]],value:["",[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.controls[e.length-1])}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Le(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:i((()=>xn)),multi:!0},{provide:R,useExisting:i((()=>xn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:xe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),Ge([C()],xn.prototype,"disabled",void 0),Ge([C()],xn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:P,useExisting:i((()=>xn)),multi:!0},{provide:R,useExisting:i((()=>xn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.FormBuilder}]},propDecorators:{selectOptions:[{type:l}],disabled:[{type:l}],labelText:[{type:l}],requiredText:[{type:l}],targetKeyPrefix:[{type:l}],selectText:[{type:l}],selectRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],popupHelpLink:[{type:l}],required:[{type:l}]}});class bn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[V.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigOldComponent",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:bn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:i((()=>bn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:P,useExisting:i((()=>bn)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class hn{constructor(e,t,n){this.store=e,this.translate=t,this.fb=n,this.destroy$=new qe,this.separatorKeysCodes=[le,se,me]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]}),this.attributeControlGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.attributeControlGroup.patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}removeKey(e,t){const n=this.attributeControlGroup.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.attributeControlGroup.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.attributeControlGroup.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.attributeControlGroup.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}clearChipGrid(e){this.attributeControlGroup.get(e).patchValue([],{emitEvent:!0})}}e("SelectAttributesComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:hn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:P,useExisting:i((()=>hn)),multi:!0}],ngImport:t,template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:P,useExisting:i((()=>hn)),multi:!0}],template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]},propDecorators:{popupHelpLink:[{type:l}]}});class Cn{}e("RulenodeCoreConfigCommonModule",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Cn,declarations:[mn,pn,cn,fn,gn,Ye,rn,on,ln,Xt,yn,un,xn,dn,bn,hn],imports:[B,k,Ae],exports:[mn,pn,cn,fn,gn,Ye,rn,on,ln,Xt,yn,un,xn,dn,bn,hn]}),Cn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,imports:[B,k,Ae]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,decorators:[{type:s,args:[{declarations:[mn,pn,cn,fn,gn,Ye,rn,on,ln,Xt,yn,un,xn,dn,bn,hn],imports:[B,k,Ae],exports:[mn,pn,cn,fn,gn,Ye,rn,on,ln,Xt,yn,un,xn,dn,bn,hn]}]}]});class vn{}e("RuleNodeCoreConfigActionModule",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),vn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:vn,declarations:[nn,Xe,en,Wt,_t,We,et,tt,nt,$t,rt,at,zt,jt,Yt,Zt,tn,Ze,ot,Jt,Qt,an,sn],imports:[B,k,Ae,Cn],exports:[nn,Xe,en,Wt,_t,We,et,tt,nt,$t,rt,at,zt,jt,Yt,Zt,tn,Ze,ot,Jt,Qt,an,sn]}),vn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,imports:[B,k,Ae,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,decorators:[{type:s,args:[{declarations:[nn,Xe,en,Wt,_t,We,et,tt,nt,$t,rt,at,zt,jt,Yt,Zt,tn,Ze,ot,Jt,Qt,an,sn],imports:[B,k,Ae,Cn],exports:[nn,Xe,en,Wt,_t,We,et,tt,nt,$t,rt,at,zt,jt,Yt,Zt,tn,Ze,ot,Jt,Qt,an,sn]}]}]});class Fn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[V.min(0),V.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:ee(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:ee(e?.outputValueKey)?e.outputValueKey:null,useCache:!ee(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!ee(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:ee(e?.periodValueKey)?e.periodValueKey:null,round:ee(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!ee(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return te(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([V.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"],dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]}});class Ln extends m{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=Ct;for(const e of vt.keys())e!==Ct.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,te(e)}toggleChange(e){this.customerAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=ee(e?.telemetry)?e.telemetry?Ct.LATEST_TELEMETRY:Ct.ATTRIBUTES:ee(e?.dataToFetch)?e.dataToFetch:Ct.ATTRIBUTES,n=ee(e?.attrMapping)?e.attrMapping:ee(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===Ct.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[V.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ln,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","name","useSelectOnMdLg","ignoreMdLgSize","appearance","disabled"],outputs:["valueChange"]},{kind:"component",type:mn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]}});class kn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[V.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ne(e)&&(e.attributesControl={clientAttributeNames:ee(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:ee(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:ee(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:ee(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!ee(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:ee(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!ee(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kn,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:pn,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:hn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]}});class Tn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.entityDetailsTranslationsMap=gt,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(ft))this.entityDetailsList.push(ft[e]);this.detailsFormControl=new O(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(ke(""),ve((e=>e||"")),Fe((e=>this.fetchEntityDetails(e))),Te())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],t=ee(e?.addToMetadata)?e.addToMetadata?Pt.METADATA:Pt.DATA:e?.fetchTo?e.fetchTo:Pt.DATA,{detailsList:ee(e?.detailsList)?e.detailsList:null,fetchTo:t}}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[V.required]],fetchTo:[e.fetchTo,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(gt.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Se(this.entityDetailsList.filter((t=>this.translate.instant(gt.get(ft[t])).toUpperCase().includes(e))))}return Se(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clearChipGrid(){this.detailsList=[],this.entityDetailsConfigForm.get("detailsList").patchValue([],{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tn,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Ie.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:Ne.HighlightPipe,name:"highlight"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]},propDecorators:{detailsInput:[{type:a,args:["detailsInput",{static:!1}]}]}});class In extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me],this.aggregationTypes=T,this.aggregations=Object.keys(T),this.aggregationTypesTranslations=I,this.fetchMode=yt,this.samplingOrders=Object.keys(ht),this.samplingOrdersTranslate=Lt,this.timeUnits=Object.values(ut),this.timeUnitsTranslationMap=pt,this.deduplicationStrategiesHintTranslations=bt,this.headerOptions=[],this.timeUnitMap={[ut.MILLISECONDS]:1,[ut.SECONDS]:1e3,[ut.MINUTES]:6e4,[ut.HOURS]:36e5,[ut.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null;for(const e of xt.keys())this.headerOptions.push({value:e,name:this.translate.instant(xt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[]],aggregation:[e.aggregation,[V.required]],fetchMode:[e.fetchMode,[V.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}toggleChange(e){this.getTelemetryFromDatabaseConfigForm.get("fetchMode").patchValue(e,{emitEvent:!0})}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,delete e.interval,te(e)}prepareInputConfig(e){return ne(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:ee(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:ee(e?.aggregation)?e.aggregation:T.NONE,fetchMode:ee(e?.fetchMode)?e.fetchMode:yt.FIRST,orderBy:ee(e?.orderBy)?e.orderBy:ht.ASC,limit:ee(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!ee(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:ee(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:ee(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:ut.MINUTES,endInterval:ee(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:ee(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:ut.MINUTES},startIntervalPattern:ee(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:ee(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===yt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([V.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([V.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([V.required,V.min(2),V.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([V.required,V.min(1),V.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([V.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([V.required,V.min(1),V.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([V.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}}e("GetTelemetryFromDatabaseConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:In,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:D.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:He.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","name","useSelectOnMdLg","ignoreMdLgSize","appearance","disabled"],outputs:["valueChange"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]}});class Nn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ne(e)&&(e.attributesControl={clientAttributeNames:ee(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:ee(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:ee(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:ee(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!ee(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA,tellFailureIfAbsent:!!ee(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:ee(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:hn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]}});class Sn extends m{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of Object.keys(N))this.originatorFields.push({value:N[e].value,name:this.translate.instant(N[e].name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return te(e)}prepareInputConfig(e){return{dataMapping:ee(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:ee(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[V.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:xn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]}});class qn extends m{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=Ct,this.msgMetadataLabelTranslations=Ft,this.originatorFields=[],this.fetchToData=[],this.destroy$=new qe,this.defaultKvMap={serialNumber:"sn"},this.defaultSvMap={[N.name.value]:`relatedEntity${this.translate.instant(N.name.name)}`},this.dataToFetchPrevValue="";for(const e of Object.keys(N))this.originatorFields.push({value:N[e].value,name:this.translate.instant(N[e].name)});for(const e of vt.keys())this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}toggleChange(e){this.relatedAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,te(e)}prepareInputConfig(e){let t;return ee(e?.telemetry)?this.dataToFetchPrevValue=e.telemetry?Ct.LATEST_TELEMETRY:Ct.ATTRIBUTES:this.dataToFetchPrevValue=ee(e?.dataToFetch)?e.dataToFetch:Ct.ATTRIBUTES,t=ee(e?.attrMapping)?e.attrMapping:ee(e?.dataMapping)?e.dataMapping:null,{relationsQuery:ee(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:this.dataToFetchPrevValue,dataMapping:t,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===Ct.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[V.required]],dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[V.required]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e===Ct.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultSvMap,{emitEvent:!1}),e!==Ct.FIELDS&&this.dataToFetchPrevValue===Ct.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultKvMap,{emitEvent:!1}),this.dataToFetchPrevValue=e}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qn,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","name","useSelectOnMdLg","ignoreMdLgSize","appearance","disabled"],outputs:["valueChange"]},{kind:"component",type:mn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:cn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:xn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]}});class Mn extends m{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=Ct;for(const e of vt.keys())e!==Ct.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.tenantAttributesConfigForm}toggleChange(e){this.tenantAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=ee(e?.telemetry)?e.telemetry?Ct.LATEST_TELEMETRY:Ct.ATTRIBUTES:ee(e?.dataToFetch)?e.dataToFetch:Ct.ATTRIBUTES,n=ee(e?.attrMapping)?e.attrMapping:ee(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===Ct.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[V.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mn,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","name","useSelectOnMdLg","ignoreMdLgSize","appearance","disabled"],outputs:["valueChange"]},{kind:"component",type:mn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]}});class An extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:An,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]}});class Gn{}e("RulenodeCoreConfigEnrichmentModule",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Gn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Gn,declarations:[Ln,Tn,kn,Nn,Sn,In,qn,Mn,Fn,An],imports:[B,k,Cn],exports:[Ln,Tn,kn,Nn,Sn,In,qn,Mn,Fn,An]}),Gn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,imports:[B,k,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,decorators:[{type:s,args:[{declarations:[Ln,Tn,kn,Nn,Sn,In,qn,Mn,Fn,An],imports:[B,k,Cn],exports:[Ln,Tn,kn,Nn,Sn,In,qn,Mn,Fn,An]}]}]});class En extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=St,this.azureIotHubCredentialsTypeTranslationsMap=qt}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[V.required]],host:[e?e.host:null,[V.required]],port:[e?e.port:null,[V.required,V.min(1),V.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[V.required,V.min(1),V.max(200)]],clientId:[e?e.clientId:null,[V.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[V.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([V.required]);break;case"cert.PEM":t.get("privateKey").setValidators([V.required]),t.get("privateKeyFileName").setValidators([V.required]),t.get("cert").setValidators([V.required]),t.get("certFileName").setValidators([V.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:En,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:K.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Me.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Me.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Me.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Me.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Me.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:D.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Re.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Dn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=At,this.ToByteStandartCharsetTypeTranslationMap=Gt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[V.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[V.required]],retries:[e?e.retries:null,[V.min(0)]],batchSize:[e?e.batchSize:null,[V.min(0)]],linger:[e?e.linger:null,[V.min(0)]],bufferMemory:[e?e.bufferMemory:null,[V.min(0)]],acks:[e?e.acks:null,[V.required]],keySerializer:[e?e.keySerializer:null,[V.required]],valueSerializer:[e?e.valueSerializer:null,[V.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([V.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dn,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Vn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[V.required]],host:[e?e.host:null,[V.required]],port:[e?e.port:null,[V.required,V.min(1),V.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[V.required,V.min(1),V.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&re(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{re(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:gn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class wn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=S,this.entityType=b}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[V.required]],targets:[e?e.targets:[],[V.required]]})}}e("NotificationConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wn,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Ke.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Be.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]}});class Pn extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[V.required]],topicName:[e?e.topicName:null,[V.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[V.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[V.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Re.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Rn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[V.required]],port:[e?e.port:null,[V.required,V.min(1),V.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[V.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[V.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class On extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Mt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[V.required]],requestMethod:[e?e.requestMethod:null,[V.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[V.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[V.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[V.required,V.min(1),V.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([V.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([V.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:On,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:gn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Hn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,n=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([V.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([V.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([V.required,V.min(1),V.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([V.required,V.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[V.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[V.required,V.min(1),V.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Hn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ue.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Kn extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[V.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[V.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([V.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ze.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Bn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(q),this.slackChanelTypesTranslateMap=M}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[V.required]],conversationType:[e?e.conversationType:null,[V.required]],conversation:[e?e.conversation:null,[V.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([V.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bn,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_e.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:_e.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:je.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]}});class Un extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[V.required]],accessKeyId:[e?e.accessKeyId:null,[V.required]],secretAccessKey:[e?e.secretAccessKey:null,[V.required]],region:[e?e.region:null,[V.required]]})}}e("SnsConfigComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Un,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class zn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=kt,this.sqsQueueTypes=Object.keys(kt),this.sqsQueueTypeTranslationsMap=Tt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[V.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[V.required]],delaySeconds:[e?e.delaySeconds:null,[V.min(0),V.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[V.required]],secretAccessKey:[e?e.secretAccessKey:null,[V.required]],region:[e?e.region:null,[V.required]]})}}e("SqsConfigComponent",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class _n{}e("RulenodeCoreConfigExternalModule",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,deps:[],target:t.ɵɵFactoryTarget.NgModule}),_n.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:_n,declarations:[Un,zn,Pn,Dn,Vn,wn,Rn,On,Hn,En,Kn,Bn],imports:[B,k,Ae,Cn],exports:[Un,zn,Pn,Dn,Vn,wn,Rn,On,Hn,En,Kn,Bn]}),_n.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,imports:[B,k,Ae,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,decorators:[{type:s,args:[{declarations:[Un,zn,Pn,Dn,Vn,wn,Rn,On,Hn,En,Kn,Bn],imports:[B,k,Ae,Cn],exports:[Un,zn,Pn,Dn,Vn,wn,Rn,On,Hn,En,Kn,Bn]}]}]});class jn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.alarmStatusTranslationsMap=A,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(G))this.alarmStatusList.push(G[e]);this.statusFormControl=new H(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(ke(""),ve((e=>e||"")),Fe((e=>this.fetchAlarmStatus(e))),Te())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[V.required]]})}displayStatus(e){return e?this.translate.instant(A.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Se(t.filter((t=>this.translate.instant(A.get(G[t])).toUpperCase().includes(e))))}return Se(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const n=t.indexOf(e);n>=0&&(t.splice(n,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jn,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Ie.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:Ne.HighlightPipe,name:"highlight"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:a,args:["alarmStatusInput",{static:!1}]}]}});class $n extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$n,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Qn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(y),this.entitySearchDirectionTranslationsMap=x}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[V.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[V.required]:[]],relationType:[e?e.relationType:null,[V.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[V.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[V.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qn,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:$e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Ve.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Jn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=st,this.perimeterTypes=Object.keys(st),this.perimeterTypeTranslationMap=mt,this.rangeUnits=Object.keys(dt),this.rangeUnitTranslationMap=ct}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[V.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[V.required]],perimeterType:[e?e.perimeterType:null,[V.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([V.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==st.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([V.required,V.min(-90),V.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([V.required,V.min(-180),V.max(180)]),this.geoFilterConfigForm.get("range").setValidators([V.required,V.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([V.required])),t||n!==st.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([V.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Yn extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[V.required]]})}}e("MessageTypeConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yn,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:fn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Wn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[b.DEVICE,b.ASSET,b.ENTITY_VIEW,b.TENANT,b.CUSTOMER,b.USER,b.DASHBOARD,b.RULE_CHAIN,b.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[V.required]]})}}e("OriginatorTypeConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:Qe.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["label","floatLabel","required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Xn extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-filter-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Zn extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-switch-function"}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.switchConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",o=this.switchConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.switchConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.switchConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class er{}e("RuleNodeCoreConfigFilterModule",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[],target:t.ɵɵFactoryTarget.NgModule}),er.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:er,declarations:[$n,Qn,Jn,Yn,Wn,Xn,Zn,jn],imports:[B,k,Cn],exports:[$n,Qn,Jn,Yn,Wn,Xn,Zn,jn]}),er.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,imports:[B,k,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:s,args:[{declarations:[$n,Qn,Jn,Yn,Wn,Xn,Zn,jn],imports:[B,k,Cn],exports:[$n,Qn,Jn,Yn,Wn,Xn,Zn,jn]}]}]});class tr extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=it,this.originatorSources=Object.keys(it),this.originatorSourceTranslationMap=lt,this.allowedEntityTypes=[b.DEVICE,b.ASSET,b.ENTITY_VIEW,b.USER,b.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[V.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===it.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([V.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===it.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([V.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([V.required,V.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:bn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class nr extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-transformer-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[V.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class rr extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[V.required]],toTemplate:[e?e.toTemplate:null,[V.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[V.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[V.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(ke([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(V.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class or extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[V.required]],keys:[e?e.keys:null,[V.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_e.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:_e.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ar extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[V.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[V.required]]})}}e("RenameKeysConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:_e.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:_e.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ir extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[V.required]]})}}e("NodeJsonPathConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class lr extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[V.required]],keys:[e?e.keys:null,[V.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:lr,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_e.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:_e.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class sr{}e("RulenodeCoreConfigTransformModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:sr,declarations:[tr,nr,rr,or,ar,ir,lr],imports:[B,k,Cn],exports:[tr,nr,rr,or,ar,ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,imports:[B,k,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:s,args:[{declarations:[tr,nr,rr,or,ar,ir,lr],imports:[B,k,Cn],exports:[tr,nr,rr,or,ar,ir,lr]}]}]});class mr extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=b}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[V.required]]})}}e("RuleChainInputComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:$e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ur extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ur,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class pr{}e("RuleNodeCoreConfigFlowModule",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:pr,declarations:[mr,ur],imports:[B,k,Cn],exports:[mr,ur]}),pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,imports:[B,k,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:s,args:[{declarations:[mr,ur],imports:[B,k,Cn],exports:[mr,ur]}]}]});class dr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. If you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required!","limit-range":"Limit should be in a range from 2 to 1000!","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647!","start-interval-value-required":"Start interval value is required!","end-interval-value-required":"End interval value is required!",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","add-timeseries-key":"Add timeseries key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Max relation level should be greater than 0 or unspecified!","relation-type":"Relation type","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required!","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required!","target-key":"Target key","target-key-required":"Target key is required!","attr-mapping-required":"At least one mapping entry should be specified!","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","source-field":"Source field","source-field-required":"Source field is required!","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required!","end-interval-required":"Interval end is required!","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","entity-details-list-empty":"No entity details selected!","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required!","output-value-key":"Output value key","output-value-key-required":"Output value key is required!","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15!","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-cashing":"Use cashing","use-cashing-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required!","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","attributes-mapping":"Attributes mapping*","latest-telemetry-mapping":"Latest telemetry mapping*","add-mapped-attribute-to":"Add mapped attributes to:","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to:","add-mapped-fields-to":"Add mapped fields to:","add-selected-details-to":"Add selected details to:","clear-selected-details":"Clear selected details","clear-selected-keys":"Clear selected keys","fetch-credentials-to":"Fetch credentials to:","add-originator-attributes-to":"Add originator attributes to:","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell Failure","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to:",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output message metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end")!',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch:","mapping-of-customers":"Mapping of customer's:",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to:","device-profiles":"Device profiles","mapping-of-tenant":"Mapping of tenant's:","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,deps:[{token:$.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),dr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:dr,declarations:[Je],imports:[B,k],exports:[vn,er,Gn,_n,sr,pr,Je]}),dr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,imports:[B,k,vn,er,Gn,_n,sr,pr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,decorators:[{type:s,args:[{declarations:[Je],imports:[B,k],exports:[vn,er,Gn,_n,sr,pr,Je]}]}],ctorParameters:function(){return[{type:$.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java index 14ab6cfbbf..7b6a54ae0b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java @@ -167,7 +167,9 @@ public class TbHttpClientTest { capturedData.capture() )).thenReturn(successMsg); - httpClient.processMessage(ctx, msg); + httpClient.processMessage(ctx, msg, + m -> ctx.tellSuccess(msg), + (m, t) -> ctx.tellFailure(m, t)); Awaitility.await() .atMost(30, TimeUnit.SECONDS) diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index b9db930657..1f8861ced9 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index bff7adb561..7c5103cfac 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -68,6 +68,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index ae8f0138a7..4ab59aec01 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 076dde0234..a103edf1f4 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index c68c9c56a8..44a86dc6dd 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index 86058d45ca..92981aa90f 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -82,6 +82,7 @@ ], "styles": [ "src/styles.scss", + "src/form.scss", "node_modules/jquery.terminal/css/jquery.terminal.min.css", "node_modules/tooltipster/dist/css/tooltipster.bundle.min.css", "node_modules/tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.css", diff --git a/ui-ngx/src/app/app.component.ts b/ui-ngx/src/app/app.component.ts index 8f612da5a1..67e2fd7b42 100644 --- a/ui-ngx/src/app/app.component.ts +++ b/ui-ngx/src/app/app.component.ts @@ -30,6 +30,7 @@ import { combineLatest } from 'rxjs'; import { selectIsAuthenticated, selectIsUserLoaded } from '@core/auth/auth.selectors'; import { distinctUntilChanged, filter, map, skip } from 'rxjs/operators'; import { AuthService } from '@core/auth/auth.service'; +import { svgIcons, svgIconsUrl } from '@shared/models/icon.models'; @Component({ selector: 'tb-root', @@ -55,44 +56,18 @@ export class AppComponent implements OnInit { } }); - this.matIconRegistry.addSvgIconLiteral( - 'google-logo', - this.domSanitizer.bypassSecurityTrustHtml( - '' - ) - ); - - this.matIconRegistry.addSvgIconLiteral( - 'github-logo', - this.domSanitizer.bypassSecurityTrustHtml( - '' - ) - ); - - this.matIconRegistry.addSvgIconLiteral( - 'facebook-logo', - this.domSanitizer.bypassSecurityTrustHtml( - '' - ) - ); - - this.matIconRegistry.addSvgIconLiteral( - 'apple-logo', - this.domSanitizer.bypassSecurityTrustHtml( - '' - ) - ); - - this.matIconRegistry.addSvgIconLiteral( - 'queues-list', - this.domSanitizer.bypassSecurityTrustHtml( - '' + - '' + - '' + - '' + - '' - ) - ); + for (const svgIcon of Object.keys(svgIcons)) { + this.matIconRegistry.addSvgIconLiteral( + svgIcon, + this.domSanitizer.bypassSecurityTrustHtml( + svgIcons[svgIcon] + ) + ); + } + + for (const svgIcon of Object.keys(svgIconsUrl)) { + this.matIconRegistry.addSvgIcon(svgIcon, this.domSanitizer.bypassSecurityTrustResourceUrl(svgIconsUrl[svgIcon])); + } this.storageService.testLocalStorage(); diff --git a/ui-ngx/src/app/core/api/alias-controller.ts b/ui-ngx/src/app/core/api/alias-controller.ts index be08d50d69..971f238d83 100644 --- a/ui-ngx/src/app/core/api/alias-controller.ts +++ b/ui-ngx/src/app/core/api/alias-controller.ts @@ -252,10 +252,9 @@ export class AliasController implements IAliasController { private resolveDatasource(datasource: Datasource, forceFilter = false): Observable { const newDatasource = deepClone(datasource); - if (newDatasource.type === DatasourceType.device) { - newDatasource.type = DatasourceType.entity; - } - if (newDatasource.type === DatasourceType.entity || newDatasource.type === DatasourceType.entityCount + if (newDatasource.type === DatasourceType.entity + || newDatasource.type === DatasourceType.device + || newDatasource.type === DatasourceType.entityCount || newDatasource.type === DatasourceType.alarmCount) { if (newDatasource.filterId) { newDatasource.keyFilters = this.getKeyFilters(newDatasource.filterId); @@ -263,7 +262,8 @@ export class AliasController implements IAliasController { if (newDatasource.type === DatasourceType.alarmCount) { newDatasource.alarmFilter = this.entityService.resolveAlarmFilter(newDatasource.alarmFilterConfig, false); } - if (newDatasource.deviceId) { + if (newDatasource.type === DatasourceType.device) { + newDatasource.type = DatasourceType.entity; newDatasource.entityFilter = singleEntityFilterFromDeviceId(newDatasource.deviceId); if (forceFilter) { return this.entityService.findSingleEntityInfoByEntityFilter(newDatasource.entityFilter, diff --git a/ui-ngx/src/app/core/auth/auth.actions.ts b/ui-ngx/src/app/core/auth/auth.actions.ts index 67b122d67f..9e5640a97d 100644 --- a/ui-ngx/src/app/core/auth/auth.actions.ts +++ b/ui-ngx/src/app/core/auth/auth.actions.ts @@ -17,6 +17,7 @@ import { Action } from '@ngrx/store'; import { User } from '@shared/models/user.model'; import { AuthPayload } from '@core/auth/auth.models'; +import { UserSettings } from '@shared/models/user-settings.models'; export enum AuthActionTypes { AUTHENTICATED = '[Auth] Authenticated', @@ -25,7 +26,9 @@ export enum AuthActionTypes { UPDATE_USER_DETAILS = '[Auth] Update User Details', UPDATE_LAST_PUBLIC_DASHBOARD_ID = '[Auth] Update Last Public Dashboard Id', UPDATE_HAS_REPOSITORY = '[Auth] Change Has Repository', - UPDATE_OPENED_MENU_SECTION = '[Preferences] Update Opened Menu Section' + UPDATE_OPENED_MENU_SECTION = '[Preferences] Update Opened Menu Section', + PUT_USER_SETTINGS = '[Preferences] Put user settings', + DELETE_USER_SETTINGS = '[Preferences] Delete user settings', } export class ActionAuthAuthenticated implements Action { @@ -68,6 +71,18 @@ export class ActionPreferencesUpdateOpenedMenuSection implements Action { constructor(readonly payload: { path: string; opened: boolean }) {} } +export class ActionPreferencesPutUserSettings implements Action { + readonly type = AuthActionTypes.PUT_USER_SETTINGS; + + constructor(readonly payload: Partial) {} +} + +export class ActionPreferencesDeleteUserSettings implements Action { + readonly type = AuthActionTypes.DELETE_USER_SETTINGS; + + constructor(readonly payload: Array>) {} +} + export type AuthActions = ActionAuthAuthenticated | ActionAuthUnauthenticated | ActionAuthLoadUser | ActionAuthUpdateUserDetails | ActionAuthUpdateLastPublicDashboardId | ActionAuthUpdateHasRepository | - ActionPreferencesUpdateOpenedMenuSection; + ActionPreferencesUpdateOpenedMenuSection | ActionPreferencesPutUserSettings | ActionPreferencesDeleteUserSettings; diff --git a/ui-ngx/src/app/core/auth/auth.effects.ts b/ui-ngx/src/app/core/auth/auth.effects.ts index d2ebe2b4c5..3e5eb28d72 100644 --- a/ui-ngx/src/app/core/auth/auth.effects.ts +++ b/ui-ngx/src/app/core/auth/auth.effects.ts @@ -39,4 +39,18 @@ export class AuthEffects { withLatestFrom(this.store.pipe(select(selectAuthState))), mergeMap(([action, state]) => this.userSettingsService.putUserSettings({ openedMenuSections: state.userSettings.openedMenuSections })) ), {dispatch: false}); + + putUserSettings = createEffect(() => this.actions$.pipe( + ofType( + AuthActionTypes.PUT_USER_SETTINGS, + ), + mergeMap((state) => this.userSettingsService.putUserSettings(state.payload)) + ), {dispatch: false}); + + deleteUserSettings = createEffect(() => this.actions$.pipe( + ofType( + AuthActionTypes.DELETE_USER_SETTINGS, + ), + mergeMap((state) => this.userSettingsService.deleteUserSettings(state.payload)) + ), {dispatch: false}); } diff --git a/ui-ngx/src/app/core/auth/auth.reducer.ts b/ui-ngx/src/app/core/auth/auth.reducer.ts index 0847654399..4bcf71104b 100644 --- a/ui-ngx/src/app/core/auth/auth.reducer.ts +++ b/ui-ngx/src/app/core/auth/auth.reducer.ts @@ -16,7 +16,8 @@ import { AuthPayload, AuthState } from './auth.models'; import { AuthActions, AuthActionTypes } from './auth.actions'; -import { initialUserSettings } from '@shared/models/user-settings.models'; +import { initialUserSettings, UserSettings } from '@shared/models/user-settings.models'; +import { unset } from '@core/utils'; const emptyUserAuthState: AuthPayload = { authUser: null, @@ -42,6 +43,7 @@ export const authReducer = ( state: AuthState = initialState, action: AuthActions ): AuthState => { + let userSettings: UserSettings; switch (action.type) { case AuthActionTypes.AUTHENTICATED: return { ...state, isAuthenticated: true, ...action.payload }; @@ -71,7 +73,16 @@ export const authReducer = ( } else { openedMenuSections.delete(action.payload.path); } - const userSettings = {...state.userSettings, ...{ openedMenuSections: Array.from(openedMenuSections)}}; + userSettings = {...state.userSettings, ...{ openedMenuSections: Array.from(openedMenuSections)}}; + return { ...state, ...{ userSettings }}; + + case AuthActionTypes.PUT_USER_SETTINGS: + userSettings = {...state.userSettings, ...action.payload}; + return { ...state, ...{ userSettings }}; + + case AuthActionTypes.DELETE_USER_SETTINGS: + userSettings = {...state.userSettings}; + action.payload.forEach(path => unset(userSettings, path)); return { ...state, ...{ userSettings }}; default: diff --git a/ui-ngx/src/app/core/auth/auth.selectors.ts b/ui-ngx/src/app/core/auth/auth.selectors.ts index 2e8406293e..4bf2f2276d 100644 --- a/ui-ngx/src/app/core/auth/auth.selectors.ts +++ b/ui-ngx/src/app/core/auth/auth.selectors.ts @@ -21,6 +21,7 @@ import { AuthState } from './auth.models'; import { take } from 'rxjs/operators'; import { AuthUser } from '@shared/models/user.model'; import { UserSettings } from '@shared/models/user-settings.models'; +import { getDescendantProp } from '@core/utils'; export const selectAuthState = createFeatureSelector< AuthState>( 'auth' @@ -76,6 +77,11 @@ export const selectUserSettings = createSelector( (state: AuthState) => state.userSettings ); +export const selectUserSettingsProperty = (path: NestedKeyOf) => createSelector( + selectAuthState, + (state: AuthState) => getDescendantProp(state.userSettings, path) +); + export const selectOpenedMenuSections = createSelector( selectAuthState, (state: AuthState) => state.userSettings.openedMenuSections diff --git a/ui-ngx/src/app/core/auth/auth.service.ts b/ui-ngx/src/app/core/auth/auth.service.ts index 50b9419c58..f1af3b745a 100644 --- a/ui-ngx/src/app/core/auth/auth.service.ts +++ b/ui-ngx/src/app/core/auth/auth.service.ts @@ -244,7 +244,7 @@ export class AuthService { if (authState && authState.authUser) { if (authState.authUser.authority === Authority.TENANT_ADMIN || authState.authUser.authority === Authority.CUSTOMER_USER) { if ((this.userHasDefaultDashboard(authState) && authState.forceFullscreen) || authState.authUser.isPublic) { - if (path === 'account' || path === 'account.profile' || path === 'account.security' || path === 'account.notificationSettings') { + if (path.startsWith('account')) { if (this.userHasProfile(authState.authUser)) { return false; } else { diff --git a/ui-ngx/src/app/core/http/device.service.ts b/ui-ngx/src/app/core/http/device.service.ts index 018e202e81..8dff1e7ebc 100644 --- a/ui-ngx/src/app/core/http/device.service.ts +++ b/ui-ngx/src/app/core/http/device.service.ts @@ -25,8 +25,10 @@ import { ClaimResult, Device, DeviceCredentials, - DeviceInfo, DeviceInfoQuery, - DeviceSearchQuery + DeviceInfo, + DeviceInfoQuery, + DeviceSearchQuery, + PublishTelemetryCommand } from '@app/shared/models/device.models'; import { EntitySubtype } from '@app/shared/models/entity-type.models'; import { AuthService } from '@core/auth/auth.service'; @@ -87,6 +89,13 @@ export class DeviceService { return this.http.post('/api/device', device, defaultHttpOptionsFromConfig(config)); } + public saveDeviceWithCredentials(device: Device, credentials: DeviceCredentials, config?: RequestConfig): Observable { + return this.http.post('/api/device-with-credentials', { + device, + credentials + }, defaultHttpOptionsFromConfig(config)); + } + public deleteDevice(deviceId: string, config?: RequestConfig) { return this.http.delete(`/api/device/${deviceId}`, defaultHttpOptionsFromConfig(config)); } @@ -201,4 +210,8 @@ export class DeviceService { return this.http.post('/api/device/bulk_import', entitiesData, defaultHttpOptionsFromConfig(config)); } + public getDevicePublishTelemetryCommands(deviceId: string, config?: RequestConfig): Observable { + return this.http.get(`/api/device-connectivity/${deviceId}`, defaultHttpOptionsFromConfig(config)); + } + } diff --git a/ui-ngx/src/app/core/public-api.ts b/ui-ngx/src/app/core/public-api.ts index bbf97cde57..cf36240cea 100644 --- a/ui-ngx/src/app/core/public-api.ts +++ b/ui-ngx/src/app/core/public-api.ts @@ -18,7 +18,7 @@ export * from './api/public-api'; export * from './http/public-api'; export * from './local-storage/local-storage.service'; export * from './services/public-api'; -export * from './ws/telemetry-websocket.service'; +export * from './ws/public-api'; export * from './core.state'; export * from './core.module'; export * from './utils'; diff --git a/ui-ngx/src/app/core/services/dashboard-utils.service.ts b/ui-ngx/src/app/core/services/dashboard-utils.service.ts index 8355ce2f61..a2a33b73a1 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -348,10 +348,8 @@ export class DashboardUtilsService { private convertDatasourcesFromWidgetType(widgetTypeDescriptor: WidgetTypeDescriptor, config: WidgetConfig, datasources?: Datasource[]): Datasource[] { const newDatasources: Datasource[] = []; - if (datasources) { - datasources.forEach(datasource => { - newDatasources.push(this.convertDatasourceFromWidgetType(widgetTypeDescriptor, config, datasource)); - }); + if (datasources?.length) { + newDatasources.push(this.convertDatasourceFromWidgetType(widgetTypeDescriptor, config, datasources[0])); } return newDatasources; } diff --git a/ui-ngx/src/app/core/services/dialog.service.ts b/ui-ngx/src/app/core/services/dialog.service.ts index be0c24a958..2ca2d6d87e 100644 --- a/ui-ngx/src/app/core/services/dialog.service.ts +++ b/ui-ngx/src/app/core/services/dialog.service.ts @@ -103,7 +103,8 @@ export class DialogService { panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { color - } + }, + autoFocus: false }).afterClosed(); } @@ -114,7 +115,8 @@ export class DialogService { panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { icon - } + }, + autoFocus: false }).afterClosed(); } diff --git a/ui-ngx/src/app/core/services/material-icons-codepoints.raw b/ui-ngx/src/app/core/services/material-icons-codepoints.raw deleted file mode 100644 index a1f9b8bbc7..0000000000 --- a/ui-ngx/src/app/core/services/material-icons-codepoints.raw +++ /dev/null @@ -1,2142 +0,0 @@ -10k e951 -10mp e952 -11mp e953 -123 eb8d -12mp e954 -13mp e955 -14mp e956 -15mp e957 -16mp e958 -17mp e959 -18mp e95a -19mp e95b -1k e95c -1k_plus e95d -1x_mobiledata efcd -20mp e95e -21mp e95f -22mp e960 -23mp e961 -24mp e962 -2k e963 -2k_plus e964 -2mp e965 -30fps efce -30fps_select efcf -360 e577 -3d_rotation e84d -3g_mobiledata efd0 -3k e966 -3k_plus e967 -3mp e968 -3p efd1 -4g_mobiledata efd2 -4g_plus_mobiledata efd3 -4k e072 -4k_plus e969 -4mp e96a -5g ef38 -5k e96b -5k_plus e96c -5mp e96d -60fps efd4 -60fps_select efd5 -6_ft_apart f21e -6k e96e -6k_plus e96f -6mp e970 -7k e971 -7k_plus e972 -7mp e973 -8k e974 -8k_plus e975 -8mp e976 -9k e977 -9k_plus e978 -9mp e979 -abc eb94 -ac_unit eb3b -access_alarm e190 -access_alarms e191 -access_time e192 -access_time_filled efd6 -accessibility e84e -accessibility_new e92c -accessible e914 -accessible_forward e934 -account_balance e84f -account_balance_wallet e850 -account_box e851 -account_circle e853 -account_tree e97a -ad_units ef39 -adb e60e -add e145 -add_a_photo e439 -add_alarm e193 -add_alert e003 -add_box e146 -add_business e729 -add_call e0e8 -add_card eb86 -add_chart e97b -add_circle e147 -add_circle_outline e148 -add_comment e266 -add_ic_call e97c -add_link e178 -add_location e567 -add_location_alt ef3a -add_moderator e97d -add_photo_alternate e43e -add_reaction e1d3 -add_road ef3b -add_shopping_cart e854 -add_task f23a -add_to_drive e65c -add_to_home_screen e1fe -add_to_photos e39d -add_to_queue e05c -addchart ef3c -adf_scanner eada -adjust e39e -admin_panel_settings ef3d -adobe ea96 -ads_click e762 -agriculture ea79 -air efd8 -airline_seat_flat e630 -airline_seat_flat_angled e631 -airline_seat_individual_suite e632 -airline_seat_legroom_extra e633 -airline_seat_legroom_normal e634 -airline_seat_legroom_reduced e635 -airline_seat_recline_extra e636 -airline_seat_recline_normal e637 -airline_stops e7d0 -airlines e7ca -airplane_ticket efd9 -airplanemode_active e195 -airplanemode_inactive e194 -airplanemode_off e194 -airplanemode_on e195 -airplay e055 -airport_shuttle eb3c -alarm e855 -alarm_add e856 -alarm_off e857 -alarm_on e858 -album e019 -align_horizontal_center e00f -align_horizontal_left e00d -align_horizontal_right e010 -align_vertical_bottom e015 -align_vertical_center e011 -align_vertical_top e00c -all_inbox e97f -all_inclusive eb3d -all_out e90b -alt_route f184 -alternate_email e0e6 -amp_stories ea13 -analytics ef3e -anchor f1cd -android e859 -animation e71c -announcement e85a -aod efda -apartment ea40 -api f1b7 -app_blocking ef3f -app_registration ef40 -app_settings_alt ef41 -app_shortcut eae4 -apple ea80 -approval e982 -apps e5c3 -apps_outage e7cc -architecture ea3b -archive e149 -area_chart e770 -arrow_back e5c4 -arrow_back_ios e5e0 -arrow_back_ios_new e2ea -arrow_circle_down f181 -arrow_circle_left eaa7 -arrow_circle_right eaaa -arrow_circle_up f182 -arrow_downward e5db -arrow_drop_down e5c5 -arrow_drop_down_circle e5c6 -arrow_drop_up e5c7 -arrow_forward e5c8 -arrow_forward_ios e5e1 -arrow_left e5de -arrow_right e5df -arrow_right_alt e941 -arrow_upward e5d8 -art_track e060 -article ef42 -aspect_ratio e85b -assessment e85c -assignment e85d -assignment_ind e85e -assignment_late e85f -assignment_return e860 -assignment_returned e861 -assignment_turned_in e862 -assistant e39f -assistant_direction e988 -assistant_navigation e989 -assistant_photo e3a0 -assured_workload eb6f -atm e573 -attach_email ea5e -attach_file e226 -attach_money e227 -attachment e2bc -attractions ea52 -attribution efdb -audio_file eb82 -audiotrack e3a1 -auto_awesome e65f -auto_awesome_mosaic e660 -auto_awesome_motion e661 -auto_delete ea4c -auto_fix_high e663 -auto_fix_normal e664 -auto_fix_off e665 -auto_graph e4fb -auto_stories e666 -autofps_select efdc -autorenew e863 -av_timer e01b -baby_changing_station f19b -back_hand e764 -backpack f19c -backspace e14a -backup e864 -backup_table ef43 -badge ea67 -bakery_dining ea53 -balance eaf6 -balcony e58f -ballot e172 -bar_chart e26b -batch_prediction f0f5 -bathroom efdd -bathtub ea41 -battery_0_bar ebdc -battery_1_bar ebd9 -battery_2_bar ebe0 -battery_3_bar ebdd -battery_4_bar ebe2 -battery_5_bar ebd4 -battery_6_bar ebd2 -battery_alert e19c -battery_charging_full e1a3 -battery_full e1a4 -battery_saver efde -battery_std e1a5 -battery_unknown e1a6 -beach_access eb3e -bed efdf -bedroom_baby efe0 -bedroom_child efe1 -bedroom_parent efe2 -bedtime ef44 -bedtime_off eb76 -beenhere e52d -bento f1f4 -bike_scooter ef45 -biotech ea3a -blender efe3 -block e14b -block_flipped ef46 -bloodtype efe4 -bluetooth e1a7 -bluetooth_audio e60f -bluetooth_connected e1a8 -bluetooth_disabled e1a9 -bluetooth_drive efe5 -bluetooth_searching e1aa -blur_circular e3a2 -blur_linear e3a3 -blur_off e3a4 -blur_on e3a5 -bolt ea0b -book e865 -book_online f217 -bookmark e866 -bookmark_add e598 -bookmark_added e599 -bookmark_border e867 -bookmark_outline e867 -bookmark_remove e59a -bookmarks e98b -border_all e228 -border_bottom e229 -border_clear e22a -border_color e22b -border_horizontal e22c -border_inner e22d -border_left e22e -border_outer e22f -border_right e230 -border_style e231 -border_top e232 -border_vertical e233 -boy eb67 -branding_watermark e06b -breakfast_dining ea54 -brightness_1 e3a6 -brightness_2 e3a7 -brightness_3 e3a8 -brightness_4 e3a9 -brightness_5 e3aa -brightness_6 e3ab -brightness_7 e3ac -brightness_auto e1ab -brightness_high e1ac -brightness_low e1ad -brightness_medium e1ae -broken_image e3ad -browse_gallery ebd1 -browser_not_supported ef47 -browser_updated e7cf -brunch_dining ea73 -brush e3ae -bubble_chart e6dd -bug_report e868 -build e869 -build_circle ef48 -bungalow e591 -burst_mode e43c -bus_alert e98f -business e0af -business_center eb3f -cabin e589 -cable efe6 -cached e86a -cake e7e9 -calculate ea5f -calendar_month ebcc -calendar_today e935 -calendar_view_day e936 -calendar_view_month efe7 -calendar_view_week efe8 -call e0b0 -call_end e0b1 -call_made e0b2 -call_merge e0b3 -call_missed e0b4 -call_missed_outgoing e0e4 -call_received e0b5 -call_split e0b6 -call_to_action e06c -camera e3af -camera_alt e3b0 -camera_enhance e8fc -camera_front e3b1 -camera_indoor efe9 -camera_outdoor efea -camera_rear e3b2 -camera_roll e3b3 -cameraswitch efeb -campaign ef49 -cancel e5c9 -cancel_presentation e0e9 -cancel_schedule_send ea39 -candlestick_chart ead4 -car_crash ebf2 -car_rental ea55 -car_repair ea56 -card_giftcard e8f6 -card_membership e8f7 -card_travel e8f8 -carpenter f1f8 -cases e992 -casino eb40 -cast e307 -cast_connected e308 -cast_for_education efec -castle eab1 -catching_pokemon e508 -category e574 -celebration ea65 -cell_tower ebba -cell_wifi e0ec -center_focus_strong e3b4 -center_focus_weak e3b5 -chair efed -chair_alt efee -chalet e585 -change_circle e2e7 -change_history e86b -charging_station f19d -chat e0b7 -chat_bubble e0ca -chat_bubble_outline e0cb -check e5ca -check_box e834 -check_box_outline_blank e835 -check_circle e86c -check_circle_outline e92d -checklist e6b1 -checklist_rtl e6b3 -checkroom f19e -chevron_left e5cb -chevron_right e5cc -child_care eb41 -child_friendly eb42 -chrome_reader_mode e86d -church eaae -circle ef4a -circle_notifications e994 -class e86e -clean_hands f21f -cleaning_services f0ff -clear e14c -clear_all e0b8 -close e5cd -close_fullscreen f1cf -closed_caption e01c -closed_caption_disabled f1dc -closed_caption_off e996 -cloud e2bd -cloud_circle e2be -cloud_done e2bf -cloud_download e2c0 -cloud_off e2c1 -cloud_queue e2c2 -cloud_sync eb5a -cloud_upload e2c3 -cloudy_snowing e810 -co2 e7b0 -co_present eaf0 -code e86f -code_off e4f3 -coffee efef -coffee_maker eff0 -collections e3b6 -collections_bookmark e431 -color_lens e3b7 -colorize e3b8 -comment e0b9 -comment_bank ea4e -comments_disabled e7a2 -commit eaf5 -commute e940 -compare e3b9 -compare_arrows e915 -compass_calibration e57c -compost e761 -compress e94d -computer e30a -confirmation_num e638 -confirmation_number e638 -connect_without_contact f223 -connected_tv e998 -connecting_airports e7c9 -construction ea3c -contact_mail e0d0 -contact_page f22e -contact_phone e0cf -contact_support e94c -contactless ea71 -contacts e0ba -content_copy e14d -content_cut e14e -content_paste e14f -content_paste_go ea8e -content_paste_off e4f8 -content_paste_search ea9b -contrast eb37 -control_camera e074 -control_point e3ba -control_point_duplicate e3bb -cookie eaac -copy_all e2ec -copyright e90c -coronavirus f221 -corporate_fare f1d0 -cottage e587 -countertops f1f7 -create e150 -create_new_folder e2cc -credit_card e870 -credit_card_off e4f4 -credit_score eff1 -crib e588 -crisis_alert ebe9 -crop e3be -crop_16_9 e3bc -crop_3_2 e3bd -crop_5_4 e3bf -crop_7_5 e3c0 -crop_din e3c1 -crop_free e3c2 -crop_landscape e3c3 -crop_original e3c4 -crop_portrait e3c5 -crop_rotate e437 -crop_square e3c6 -cruelty_free e799 -css eb93 -currency_bitcoin ebc5 -currency_exchange eb70 -currency_franc eafa -currency_lira eaef -currency_pound eaf1 -currency_ruble eaec -currency_rupee eaf7 -currency_yen eafb -currency_yuan eaf9 -cyclone ebd5 -dangerous e99a -dark_mode e51c -dashboard e871 -dashboard_customize e99b -data_array ead1 -data_exploration e76f -data_object ead3 -data_saver_off eff2 -data_saver_on eff3 -data_thresholding eb9f -data_usage e1af -date_range e916 -deblur eb77 -deck ea42 -dehaze e3c7 -delete e872 -delete_forever e92b -delete_outline e92e -delete_sweep e16c -delivery_dining ea72 -density_large eba9 -density_medium eb9e -density_small eba8 -departure_board e576 -description e873 -deselect ebb6 -design_services f10a -desktop_access_disabled e99d -desktop_mac e30b -desktop_windows e30c -details e3c8 -developer_board e30d -developer_board_off e4ff -developer_mode e1b0 -device_hub e335 -device_thermostat e1ff -device_unknown e339 -devices e1b1 -devices_fold ebde -devices_other e337 -dialer_sip e0bb -dialpad e0bc -diamond ead5 -difference eb7d -dining eff4 -dinner_dining ea57 -directions e52e -directions_bike e52f -directions_boat e532 -directions_boat_filled eff5 -directions_bus e530 -directions_bus_filled eff6 -directions_car e531 -directions_car_filled eff7 -directions_ferry e532 -directions_off f10f -directions_railway e534 -directions_railway_filled eff8 -directions_run e566 -directions_subway e533 -directions_subway_filled eff9 -directions_train e534 -directions_transit e535 -directions_transit_filled effa -directions_walk e536 -dirty_lens ef4b -disabled_by_default f230 -disabled_visible e76e -disc_full e610 -discord ea6c -discount ebc9 -display_settings eb97 -dnd_forwardslash e611 -dns e875 -do_disturb f08c -do_disturb_alt f08d -do_disturb_off f08e -do_disturb_on f08f -do_not_disturb e612 -do_not_disturb_alt e611 -do_not_disturb_off e643 -do_not_disturb_on e644 -do_not_disturb_on_total_silence effb -do_not_step f19f -do_not_touch f1b0 -dock e30e -document_scanner e5fa -domain e7ee -domain_add eb62 -domain_disabled e0ef -domain_verification ef4c -done e876 -done_all e877 -done_outline e92f -donut_large e917 -donut_small e918 -door_back effc -door_front effd -door_sliding effe -doorbell efff -double_arrow ea50 -downhill_skiing e509 -download f090 -download_done f091 -download_for_offline f000 -downloading f001 -drafts e151 -drag_handle e25d -drag_indicator e945 -draw e746 -drive_eta e613 -drive_file_move e675 -drive_file_move_outline e9a1 -drive_file_move_rtl e76d -drive_file_rename_outline e9a2 -drive_folder_upload e9a3 -dry f1b3 -dry_cleaning ea58 -duo e9a5 -dvr e1b2 -dynamic_feed ea14 -dynamic_form f1bf -e_mobiledata f002 -earbuds f003 -earbuds_battery f004 -east f1df -eco ea35 -edgesensor_high f005 -edgesensor_low f006 -edit e3c9 -edit_attributes e578 -edit_calendar e742 -edit_location e568 -edit_location_alt e1c5 -edit_note e745 -edit_notifications e525 -edit_off e950 -edit_road ef4d -egg eacc -egg_alt eac8 -eject e8fb -elderly f21a -elderly_woman eb69 -electric_bike eb1b -electric_car eb1c -electric_moped eb1d -electric_rickshaw eb1e -electric_scooter eb1f -electrical_services f102 -elevator f1a0 -email e0be -emergency e1eb -emergency_recording ebf4 -emergency_share ebf6 -emoji_emotions ea22 -emoji_events ea23 -emoji_flags ea1a -emoji_food_beverage ea1b -emoji_nature ea1c -emoji_objects ea24 -emoji_people ea1d -emoji_symbols ea1e -emoji_transportation ea1f -engineering ea3d -enhance_photo_translate e8fc -enhanced_encryption e63f -equalizer e01d -error e000 -error_outline e001 -escalator f1a1 -escalator_warning f1ac -euro ea15 -euro_symbol e926 -ev_station e56d -event e878 -event_available e614 -event_busy e615 -event_note e616 -event_repeat eb7b -event_seat e903 -exit_to_app e879 -expand e94f -expand_circle_down e7cd -expand_less e5ce -expand_more e5cf -explicit e01e -explore e87a -explore_off e9a8 -exposure e3ca -exposure_minus_1 e3cb -exposure_minus_2 e3cc -exposure_neg_1 e3cb -exposure_neg_2 e3cc -exposure_plus_1 e3cd -exposure_plus_2 e3ce -exposure_zero e3cf -extension e87b -extension_off e4f5 -face e87c -face_retouching_natural ef4e -face_retouching_off f007 -facebook f234 -fact_check f0c5 -factory ebbc -family_restroom f1a2 -fast_forward e01f -fast_rewind e020 -fastfood e57a -favorite e87d -favorite_border e87e -favorite_outline e87e -fax ead8 -featured_play_list e06d -featured_video e06e -feed f009 -feedback e87f -female e590 -fence f1f6 -festival ea68 -fiber_dvr e05d -fiber_manual_record e061 -fiber_new e05e -fiber_pin e06a -fiber_smart_record e062 -file_copy e173 -file_download e2c4 -file_download_done e9aa -file_download_off e4fe -file_open eaf3 -file_present ea0e -file_upload e2c6 -filter e3d3 -filter_1 e3d0 -filter_2 e3d1 -filter_3 e3d2 -filter_4 e3d4 -filter_5 e3d5 -filter_6 e3d6 -filter_7 e3d7 -filter_8 e3d8 -filter_9 e3d9 -filter_9_plus e3da -filter_alt ef4f -filter_alt_off eb32 -filter_b_and_w e3db -filter_center_focus e3dc -filter_drama e3dd -filter_frames e3de -filter_hdr e3df -filter_list e152 -filter_list_alt e94e -filter_list_off eb57 -filter_none e3e0 -filter_tilt_shift e3e2 -filter_vintage e3e3 -find_in_page e880 -find_replace e881 -fingerprint e90d -fire_extinguisher f1d8 -fire_hydrant f1a3 -fireplace ea43 -first_page e5dc -fit_screen ea10 -fitbit e82b -fitness_center eb43 -flag e153 -flag_circle eaf8 -flaky ef50 -flare e3e4 -flash_auto e3e5 -flash_off e3e6 -flash_on e3e7 -flashlight_off f00a -flashlight_on f00b -flatware f00c -flight e539 -flight_class e7cb -flight_land e904 -flight_takeoff e905 -flip e3e8 -flip_camera_android ea37 -flip_camera_ios ea38 -flip_to_back e882 -flip_to_front e883 -flood ebe6 -flourescent f00d -flutter_dash e00b -fmd_bad f00e -fmd_good f00f -foggy e818 -folder e2c7 -folder_copy ebbd -folder_delete eb34 -folder_off eb83 -folder_open e2c8 -folder_shared e2c9 -folder_special e617 -folder_zip eb2c -follow_the_signs f222 -font_download e167 -font_download_off e4f9 -food_bank f1f2 -forest ea99 -fork_left eba0 -fork_right ebac -format_align_center e234 -format_align_justify e235 -format_align_left e236 -format_align_right e237 -format_bold e238 -format_clear e239 -format_color_fill e23a -format_color_reset e23b -format_color_text e23c -format_indent_decrease e23d -format_indent_increase e23e -format_italic e23f -format_line_spacing e240 -format_list_bulleted e241 -format_list_numbered e242 -format_list_numbered_rtl e267 -format_overline eb65 -format_paint e243 -format_quote e244 -format_shapes e25e -format_size e245 -format_strikethrough e246 -format_textdirection_l_to_r e247 -format_textdirection_r_to_l e248 -format_underline e249 -format_underlined e249 -fort eaad -forum e0bf -forward e154 -forward_10 e056 -forward_30 e057 -forward_5 e058 -forward_to_inbox f187 -foundation f200 -free_breakfast eb44 -free_cancellation e748 -front_hand e769 -fullscreen e5d0 -fullscreen_exit e5d1 -functions e24a -g_mobiledata f010 -g_translate e927 -gamepad e30f -games e021 -garage f011 -gavel e90e -generating_tokens e749 -gesture e155 -get_app e884 -gif e908 -gif_box e7a3 -girl eb68 -gite e58b -goat 10fffd -golf_course eb45 -gpp_bad f012 -gpp_good f013 -gpp_maybe f014 -gps_fixed e1b3 -gps_not_fixed e1b4 -gps_off e1b5 -grade e885 -gradient e3e9 -grading ea4f -grain e3ea -graphic_eq e1b8 -grass f205 -grid_3x3 f015 -grid_4x4 f016 -grid_goldenratio f017 -grid_off e3eb -grid_on e3ec -grid_view e9b0 -group e7ef -group_add e7f0 -group_off e747 -group_remove e7ad -group_work e886 -groups f233 -h_mobiledata f018 -h_plus_mobiledata f019 -hail e9b1 -handshake ebcb -handyman f10b -hardware ea59 -hd e052 -hdr_auto f01a -hdr_auto_select f01b -hdr_enhanced_select ef51 -hdr_off e3ed -hdr_off_select f01c -hdr_on e3ee -hdr_on_select f01d -hdr_plus f01e -hdr_strong e3f1 -hdr_weak e3f2 -headphones f01f -headphones_battery f020 -headset e310 -headset_mic e311 -headset_off e33a -healing e3f3 -health_and_safety e1d5 -hearing e023 -hearing_disabled f104 -heart_broken eac2 -height ea16 -help e887 -help_center f1c0 -help_outline e8fd -hevc f021 -hexagon eb39 -hide_image f022 -hide_source f023 -high_quality e024 -highlight e25f -highlight_alt ef52 -highlight_off e888 -highlight_remove e888 -hiking e50a -history e889 -history_edu ea3e -history_toggle_off f17d -hive eaa6 -hls eb8a -hls_off eb8c -holiday_village e58a -home e88a -home_filled e9b2 -home_max f024 -home_mini f025 -home_repair_service f100 -home_work ea09 -horizontal_distribute e014 -horizontal_rule f108 -horizontal_split e947 -hot_tub eb46 -hotel e53a -hotel_class e743 -hourglass_bottom ea5c -hourglass_disabled ef53 -hourglass_empty e88b -hourglass_full e88c -hourglass_top ea5b -house ea44 -house_siding f202 -houseboat e584 -how_to_reg e174 -how_to_vote e175 -html eb7e -http e902 -https e88d -hub e9f4 -hvac f10e -ice_skating e50b -icecream ea69 -image e3f4 -image_aspect_ratio e3f5 -image_not_supported f116 -image_search e43f -imagesearch_roller e9b4 -import_contacts e0e0 -import_export e0c3 -important_devices e912 -inbox e156 -incomplete_circle e79b -indeterminate_check_box e909 -info e88e -info_outline e88f -input e890 -insert_chart e24b -insert_chart_outlined e26a -insert_comment e24c -insert_drive_file e24d -insert_emoticon e24e -insert_invitation e24f -insert_link e250 -insert_page_break eaca -insert_photo e251 -insights f092 -install_desktop eb71 -install_mobile eb72 -integration_instructions ef54 -interests e7c8 -interpreter_mode e83b -inventory e179 -inventory_2 e1a1 -invert_colors e891 -invert_colors_off e0c4 -invert_colors_on e891 -ios_share e6b8 -iron e583 -iso e3f6 -javascript eb7c -join_full eaeb -join_inner eaf4 -join_left eaf2 -join_right eaea -kayaking e50c -kebab_dining e842 -key e73c -key_off eb84 -keyboard e312 -keyboard_alt f028 -keyboard_arrow_down e313 -keyboard_arrow_left e314 -keyboard_arrow_right e315 -keyboard_arrow_up e316 -keyboard_backspace e317 -keyboard_capslock e318 -keyboard_command eae0 -keyboard_command_key eae7 -keyboard_control e5d3 -keyboard_control_key eae6 -keyboard_double_arrow_down ead0 -keyboard_double_arrow_left eac3 -keyboard_double_arrow_right eac9 -keyboard_double_arrow_up eacf -keyboard_hide e31a -keyboard_option eadf -keyboard_option_key eae8 -keyboard_return e31b -keyboard_tab e31c -keyboard_voice e31d -king_bed ea45 -kitchen eb47 -kitesurfing e50d -label e892 -label_important e937 -label_important_outline e948 -label_off e9b6 -label_outline e893 -lan eb2f -landscape e3f7 -landslide ebd7 -language e894 -laptop e31e -laptop_chromebook e31f -laptop_mac e320 -laptop_windows e321 -last_page e5dd -launch e895 -layers e53b -layers_clear e53c -leaderboard f20c -leak_add e3f8 -leak_remove e3f9 -leave_bags_at_home f21b -legend_toggle f11b -lens e3fa -lens_blur f029 -library_add e02e -library_add_check e9b7 -library_books e02f -library_music e030 -light f02a -light_mode e518 -lightbulb e0f0 -lightbulb_outline e90f -line_axis ea9a -line_style e919 -line_weight e91a -linear_scale e260 -link e157 -link_off e16f -linked_camera e438 -liquor ea60 -list e896 -list_alt e0ee -live_help e0c6 -live_tv e639 -living f02b -local_activity e53f -local_airport e53d -local_atm e53e -local_attraction e53f -local_bar e540 -local_cafe e541 -local_car_wash e542 -local_convenience_store e543 -local_dining e556 -local_drink e544 -local_fire_department ef55 -local_florist e545 -local_gas_station e546 -local_grocery_store e547 -local_hospital e548 -local_hotel e549 -local_laundry_service e54a -local_library e54b -local_mall e54c -local_movies e54d -local_offer e54e -local_parking e54f -local_pharmacy e550 -local_phone e551 -local_pizza e552 -local_play e553 -local_police ef56 -local_post_office e554 -local_print_shop e555 -local_printshop e555 -local_restaurant e556 -local_see e557 -local_shipping e558 -local_taxi e559 -location_city e7f1 -location_disabled e1b6 -location_history e55a -location_off e0c7 -location_on e0c8 -location_pin f1db -location_searching e1b7 -lock e897 -lock_clock ef57 -lock_open e898 -lock_outline e899 -lock_reset eade -login ea77 -logo_dev ead6 -logout e9ba -looks e3fc -looks_3 e3fb -looks_4 e3fd -looks_5 e3fe -looks_6 e3ff -looks_one e400 -looks_two e401 -loop e028 -loupe e402 -low_priority e16d -loyalty e89a -lte_mobiledata f02c -lte_plus_mobiledata f02d -luggage f235 -lunch_dining ea61 -mail e158 -mail_outline e0e1 -male e58e -man e4eb -manage_accounts f02e -manage_history ebe7 -manage_search f02f -map e55b -maps_home_work f030 -maps_ugc ef58 -margin e9bb -mark_as_unread e9bc -mark_chat_read f18b -mark_chat_unread f189 -mark_email_read f18c -mark_email_unread f18a -mark_unread_chat_alt eb9d -markunread e159 -markunread_mailbox e89b -masks f218 -maximize e930 -media_bluetooth_off f031 -media_bluetooth_on f032 -mediation efa7 -medical_information ebed -medical_services f109 -medication f033 -medication_liquid ea87 -meeting_room eb4f -memory e322 -menu e5d2 -menu_book ea19 -menu_open e9bd -merge eb98 -merge_type e252 -message e0c9 -messenger e0ca -messenger_outline e0cb -mic e029 -mic_external_off ef59 -mic_external_on ef5a -mic_none e02a -mic_off e02b -microwave f204 -military_tech ea3f -minimize e931 -minor_crash ebf1 -miscellaneous_services f10c -missed_video_call e073 -mms e618 -mobile_friendly e200 -mobile_off e201 -mobile_screen_share e0e7 -mobiledata_off f034 -mode f097 -mode_comment e253 -mode_edit e254 -mode_edit_outline f035 -mode_night f036 -mode_of_travel e7ce -mode_standby f037 -model_training f0cf -monetization_on e263 -money e57d -money_off e25c -money_off_csred f038 -monitor ef5b -monitor_heart eaa2 -monitor_weight f039 -monochrome_photos e403 -mood e7f2 -mood_bad e7f3 -moped eb28 -more e619 -more_horiz e5d3 -more_time ea5d -more_vert e5d4 -mosque eab2 -motion_photos_auto f03a -motion_photos_off e9c0 -motion_photos_on e9c1 -motion_photos_pause f227 -motion_photos_paused e9c2 -motorcycle e91b -mouse e323 -move_down eb61 -move_to_inbox e168 -move_up eb64 -movie e02c -movie_creation e404 -movie_filter e43a -moving e501 -mp e9c3 -multiline_chart e6df -multiple_stop f1b9 -multitrack_audio e1b8 -museum ea36 -music_note e405 -music_off e440 -music_video e063 -my_library_add e02e -my_library_books e02f -my_library_music e030 -my_location e55c -nat ef5c -nature e406 -nature_people e407 -navigate_before e408 -navigate_next e409 -navigation e55d -near_me e569 -near_me_disabled f1ef -nearby_error f03b -nearby_off f03c -network_cell e1b9 -network_check e640 -network_locked e61a -network_ping ebca -network_wifi e1ba -network_wifi_1_bar ebe4 -network_wifi_2_bar ebd6 -network_wifi_3_bar ebe1 -new_label e609 -new_releases e031 -newspaper eb81 -next_plan ef5d -next_week e16a -nfc e1bb -night_shelter f1f1 -nightlife ea62 -nightlight f03d -nightlight_round ef5e -nights_stay ea46 -no_accounts f03e -no_backpack f237 -no_cell f1a4 -no_crash ebf0 -no_drinks f1a5 -no_encryption e641 -no_encryption_gmailerrorred f03f -no_flash f1a6 -no_food f1a7 -no_luggage f23b -no_meals f1d6 -no_meals_ouline f229 -no_meeting_room eb4e -no_photography f1a8 -no_sim e0cc -no_stroller f1af -no_transfer f1d5 -noise_aware ebec -noise_control_off ebf3 -nordic_walking e50e -north f1e0 -north_east f1e1 -north_west f1e2 -not_accessible f0fe -not_interested e033 -not_listed_location e575 -not_started f0d1 -note e06f -note_add e89c -note_alt f040 -notes e26c -notification_add e399 -notification_important e004 -notifications e7f4 -notifications_active e7f7 -notifications_none e7f5 -notifications_off e7f6 -notifications_on e7f7 -notifications_paused e7f8 -now_wallpaper e1bc -now_widgets e1bd -numbers eac7 -offline_bolt e932 -offline_pin e90a -offline_share e9c5 -ondemand_video e63a -online_prediction f0eb -opacity e91c -open_in_browser e89d -open_in_full f1ce -open_in_new e89e -open_in_new_off e4f6 -open_with e89f -other_houses e58c -outbond f228 -outbound e1ca -outbox ef5f -outdoor_grill ea47 -outgoing_mail f0d2 -outlet f1d4 -outlined_flag e16e -output ebbe -padding e9c8 -pages e7f9 -pageview e8a0 -paid f041 -palette e40a -pan_tool e925 -pan_tool_alt ebb9 -panorama e40b -panorama_fish_eye e40c -panorama_fisheye e40c -panorama_horizontal e40d -panorama_horizontal_select ef60 -panorama_photosphere e9c9 -panorama_photosphere_select e9ca -panorama_vertical e40e -panorama_vertical_select ef61 -panorama_wide_angle e40f -panorama_wide_angle_select ef62 -paragliding e50f -park ea63 -party_mode e7fa -password f042 -pattern f043 -pause e034 -pause_circle e1a2 -pause_circle_filled e035 -pause_circle_outline e036 -pause_presentation e0ea -payment e8a1 -payments ef63 -paypal ea8d -pedal_bike eb29 -pending ef64 -pending_actions f1bb -pentagon eb50 -people e7fb -people_alt ea21 -people_outline e7fc -percent eb58 -perm_camera_mic e8a2 -perm_contact_cal e8a3 -perm_contact_calendar e8a3 -perm_data_setting e8a4 -perm_device_info e8a5 -perm_device_information e8a5 -perm_identity e8a6 -perm_media e8a7 -perm_phone_msg e8a8 -perm_scan_wifi e8a9 -person e7fd -person_add e7fe -person_add_alt ea4d -person_add_alt_1 ef65 -person_add_disabled e9cb -person_off e510 -person_outline e7ff -person_pin e55a -person_pin_circle e56a -person_remove ef66 -person_remove_alt_1 ef67 -person_search f106 -personal_injury e6da -personal_video e63b -pest_control f0fa -pest_control_rodent f0fd -pets e91d -phishing ead7 -phone e0cd -phone_android e324 -phone_bluetooth_speaker e61b -phone_callback e649 -phone_disabled e9cc -phone_enabled e9cd -phone_forwarded e61c -phone_in_talk e61d -phone_iphone e325 -phone_locked e61e -phone_missed e61f -phone_paused e620 -phonelink e326 -phonelink_erase e0db -phonelink_lock e0dc -phonelink_off e327 -phonelink_ring e0dd -phonelink_setup e0de -photo e410 -photo_album e411 -photo_camera e412 -photo_camera_back ef68 -photo_camera_front ef69 -photo_filter e43b -photo_library e413 -photo_size_select_actual e432 -photo_size_select_large e433 -photo_size_select_small e434 -php eb8f -piano e521 -piano_off e520 -picture_as_pdf e415 -picture_in_picture e8aa -picture_in_picture_alt e911 -pie_chart e6c4 -pie_chart_outline f044 -pie_chart_outlined e6c5 -pin f045 -pin_drop e55e -pin_end e767 -pin_invoke e763 -pinch eb38 -pivot_table_chart e9ce -pix eaa3 -place e55f -plagiarism ea5a -play_arrow e037 -play_circle e1c4 -play_circle_fill e038 -play_circle_filled e038 -play_circle_outline e039 -play_disabled ef6a -play_for_work e906 -play_lesson f047 -playlist_add e03b -playlist_add_check e065 -playlist_add_check_circle e7e6 -playlist_add_circle e7e5 -playlist_play e05f -playlist_remove eb80 -plumbing f107 -plus_one e800 -podcasts f048 -point_of_sale f17e -policy ea17 -poll e801 -polyline ebbb -polymer e8ab -pool eb48 -portable_wifi_off e0ce -portrait e416 -post_add ea20 -power e63c -power_input e336 -power_off e646 -power_settings_new e8ac -precision_manufacturing f049 -pregnant_woman e91e -present_to_all e0df -preview f1c5 -price_change f04a -price_check f04b -print e8ad -print_disabled e9cf -priority_high e645 -privacy_tip f0dc -private_connectivity e744 -production_quantity_limits e1d1 -psychology ea4a -public e80b -public_off f1ca -publish e255 -published_with_changes f232 -punch_clock eaa8 -push_pin f10d -qr_code ef6b -qr_code_2 e00a -qr_code_scanner f206 -query_builder e8ae -query_stats e4fc -question_answer e8af -question_mark eb8b -queue e03c -queue_music e03d -queue_play_next e066 -quick_contacts_dialer e0cf -quick_contacts_mail e0d0 -quickreply ef6c -quiz f04c -quora ea98 -r_mobiledata f04d -radar f04e -radio e03e -radio_button_checked e837 -radio_button_off e836 -radio_button_on e837 -radio_button_unchecked e836 -railway_alert e9d1 -ramen_dining ea64 -ramp_left eb9c -ramp_right eb96 -rate_review e560 -raw_off f04f -raw_on f050 -read_more ef6d -real_estate_agent e73a -receipt e8b0 -receipt_long ef6e -recent_actors e03f -recommend e9d2 -record_voice_over e91f -rectangle eb54 -recycling e760 -reddit eaa0 -redeem e8b1 -redo e15a -reduce_capacity f21c -refresh e5d5 -remember_me f051 -remove e15b -remove_circle e15c -remove_circle_outline e15d -remove_done e9d3 -remove_from_queue e067 -remove_moderator e9d4 -remove_red_eye e417 -remove_shopping_cart e928 -reorder e8fe -repeat e040 -repeat_on e9d6 -repeat_one e041 -repeat_one_on e9d7 -replay e042 -replay_10 e059 -replay_30 e05a -replay_5 e05b -replay_circle_filled e9d8 -reply e15e -reply_all e15f -report e160 -report_gmailerrorred f052 -report_off e170 -report_problem e8b2 -request_page f22c -request_quote f1b6 -reset_tv e9d9 -restart_alt f053 -restaurant e56c -restaurant_menu e561 -restore e8b3 -restore_from_trash e938 -restore_page e929 -reviews f054 -rice_bowl f1f5 -ring_volume e0d1 -rocket eba5 -rocket_launch eb9b -roller_skating ebcd -roofing f201 -room e8b4 -room_preferences f1b8 -room_service eb49 -rotate_90_degrees_ccw e418 -rotate_90_degrees_cw eaab -rotate_left e419 -rotate_right e41a -roundabout_left eb99 -roundabout_right eba3 -rounded_corner e920 -route eacd -router e328 -rowing e921 -rss_feed e0e5 -rsvp f055 -rtt e9ad -rule f1c2 -rule_folder f1c9 -run_circle ef6f -running_with_errors e51d -rv_hookup e642 -safety_check ebef -safety_divider e1cc -sailing e502 -sanitizer f21d -satellite e562 -satellite_alt eb3a -save e161 -save_alt e171 -save_as eb60 -saved_search ea11 -savings e2eb -scale eb5f -scanner e329 -scatter_plot e268 -schedule e8b5 -schedule_send ea0a -schema e4fd -school e80c -science ea4b -score e269 -scoreboard ebd0 -screen_lock_landscape e1be -screen_lock_portrait e1bf -screen_lock_rotation e1c0 -screen_rotation e1c1 -screen_rotation_alt ebee -screen_search_desktop ef70 -screen_share e0e2 -screenshot f056 -scuba_diving ebce -sd e9dd -sd_card e623 -sd_card_alert f057 -sd_storage e1c2 -search e8b6 -search_off ea76 -security e32a -security_update f058 -security_update_good f059 -security_update_warning f05a -segment e94b -select_all e162 -self_improvement ea78 -sell f05b -send e163 -send_and_archive ea0c -send_time_extension eadb -send_to_mobile f05c -sensor_door f1b5 -sensor_window f1b4 -sensors e51e -sensors_off e51f -sentiment_dissatisfied e811 -sentiment_neutral e812 -sentiment_satisfied e813 -sentiment_satisfied_alt e0ed -sentiment_very_dissatisfied e814 -sentiment_very_satisfied e815 -set_meal f1ea -settings e8b8 -settings_accessibility f05d -settings_applications e8b9 -settings_backup_restore e8ba -settings_bluetooth e8bb -settings_brightness e8bd -settings_cell e8bc -settings_display e8bd -settings_ethernet e8be -settings_input_antenna e8bf -settings_input_component e8c0 -settings_input_composite e8c1 -settings_input_hdmi e8c2 -settings_input_svideo e8c3 -settings_overscan e8c4 -settings_phone e8c5 -settings_power e8c6 -settings_remote e8c7 -settings_suggest f05e -settings_system_daydream e1c3 -settings_voice e8c8 -severe_cold ebd3 -share e80d -share_arrival_time e524 -share_location f05f -shield e9e0 -shield_moon eaa9 -shop e8c9 -shop_2 e19e -shop_two e8ca -shopify ea9d -shopping_bag f1cc -shopping_basket e8cb -shopping_cart e8cc -shopping_cart_checkout eb88 -short_text e261 -shortcut f060 -show_chart e6e1 -shower f061 -shuffle e043 -shuffle_on e9e1 -shutter_speed e43d -sick f220 -sign_language ebe5 -signal_cellular_0_bar f0a8 -signal_cellular_4_bar e1c8 -signal_cellular_alt e202 -signal_cellular_alt_1_bar ebdf -signal_cellular_alt_2_bar ebe3 -signal_cellular_connected_no_internet_0_bar f0ac -signal_cellular_connected_no_internet_4_bar e1cd -signal_cellular_no_sim e1ce -signal_cellular_nodata f062 -signal_cellular_null e1cf -signal_cellular_off e1d0 -signal_wifi_0_bar f0b0 -signal_wifi_4_bar e1d8 -signal_wifi_4_bar_lock e1d9 -signal_wifi_bad f063 -signal_wifi_connected_no_internet_4 f064 -signal_wifi_off e1da -signal_wifi_statusbar_4_bar f065 -signal_wifi_statusbar_connected_no_internet_4 f066 -signal_wifi_statusbar_null f067 -signpost eb91 -sim_card e32b -sim_card_alert e624 -sim_card_download f068 -single_bed ea48 -sip f069 -skateboarding e511 -skip_next e044 -skip_previous e045 -sledding e512 -slideshow e41b -slow_motion_video e068 -smart_button f1c1 -smart_display f06a -smart_screen f06b -smart_toy f06c -smartphone e32c -smoke_free eb4a -smoking_rooms eb4b -sms e625 -sms_failed e626 -snapchat ea6e -snippet_folder f1c7 -snooze e046 -snowboarding e513 -snowing e80f -snowmobile e503 -snowshoeing e514 -soap f1b2 -social_distance e1cb -sort e164 -sort_by_alpha e053 -sos ebf7 -soup_kitchen e7d3 -source f1c4 -south f1e3 -south_america e7e4 -south_east f1e4 -south_west f1e5 -spa eb4c -space_bar e256 -space_dashboard e66b -spatial_audio ebeb -spatial_audio_off ebe8 -spatial_tracking ebea -speaker e32d -speaker_group e32e -speaker_notes e8cd -speaker_notes_off e92a -speaker_phone e0d2 -speed e9e4 -spellcheck e8ce -splitscreen f06d -spoke e9a7 -sports ea30 -sports_bar f1f3 -sports_baseball ea51 -sports_basketball ea26 -sports_cricket ea27 -sports_esports ea28 -sports_football ea29 -sports_golf ea2a -sports_gymnastics ebc4 -sports_handball ea33 -sports_hockey ea2b -sports_kabaddi ea34 -sports_martial_arts eae9 -sports_mma ea2c -sports_motorsports ea2d -sports_rugby ea2e -sports_score f06e -sports_soccer ea2f -sports_tennis ea32 -sports_volleyball ea31 -square eb36 -square_foot ea49 -ssid_chart eb66 -stacked_bar_chart e9e6 -stacked_line_chart f22b -stadium eb90 -stairs f1a9 -star e838 -star_border e83a -star_border_purple500 f099 -star_half e839 -star_outline f06f -star_purple500 f09a -star_rate f0ec -stars e8d0 -start e089 -stay_current_landscape e0d3 -stay_current_portrait e0d4 -stay_primary_landscape e0d5 -stay_primary_portrait e0d6 -sticky_note_2 f1fc -stop e047 -stop_circle ef71 -stop_screen_share e0e3 -storage e1db -store e8d1 -store_mall_directory e563 -storefront ea12 -storm f070 -straight eb95 -straighten e41c -stream e9e9 -streetview e56e -strikethrough_s e257 -stroller f1ae -style e41d -subdirectory_arrow_left e5d9 -subdirectory_arrow_right e5da -subject e8d2 -subscript f111 -subscriptions e064 -subtitles e048 -subtitles_off ef72 -subway e56f -summarize f071 -sunny e81a -sunny_snowing e819 -superscript f112 -supervised_user_circle e939 -supervisor_account e8d3 -support ef73 -support_agent f0e2 -surfing e515 -surround_sound e049 -swap_calls e0d7 -swap_horiz e8d4 -swap_horizontal_circle e933 -swap_vert e8d5 -swap_vert_circle e8d6 -swap_vertical_circle e8d6 -swipe e9ec -swipe_down eb53 -swipe_down_alt eb30 -swipe_left eb59 -swipe_left_alt eb33 -swipe_right eb52 -swipe_right_alt eb56 -swipe_up eb2e -swipe_up_alt eb35 -swipe_vertical eb51 -switch_access_shortcut e7e1 -switch_access_shortcut_add e7e2 -switch_account e9ed -switch_camera e41e -switch_left f1d1 -switch_right f1d2 -switch_video e41f -synagogue eab0 -sync e627 -sync_alt ea18 -sync_disabled e628 -sync_lock eaee -sync_problem e629 -system_security_update f072 -system_security_update_good f073 -system_security_update_warning f074 -system_update e62a -system_update_alt e8d7 -system_update_tv e8d7 -tab e8d8 -tab_unselected e8d9 -table_bar ead2 -table_chart e265 -table_restaurant eac6 -table_rows f101 -table_view f1be -tablet e32f -tablet_android e330 -tablet_mac e331 -tag e9ef -tag_faces e420 -takeout_dining ea74 -tap_and_play e62b -tapas f1e9 -task f075 -task_alt e2e6 -taxi_alert ef74 -telegram ea6b -temple_buddhist eab3 -temple_hindu eaaf -terminal eb8e -terrain e564 -text_decrease eadd -text_fields e262 -text_format e165 -text_increase eae2 -text_rotate_up e93a -text_rotate_vertical e93b -text_rotation_angledown e93c -text_rotation_angleup e93d -text_rotation_down e93e -text_rotation_none e93f -text_snippet f1c6 -textsms e0d8 -texture e421 -theater_comedy ea66 -theaters e8da -thermostat f076 -thermostat_auto f077 -thumb_down e8db -thumb_down_alt e816 -thumb_down_off_alt e9f2 -thumb_up e8dc -thumb_up_alt e817 -thumb_up_off_alt e9f3 -thumbs_up_down e8dd -thunderstorm ebdb -tiktok ea7e -time_to_leave e62c -timelapse e422 -timeline e922 -timer e425 -timer_10 e423 -timer_10_select f07a -timer_3 e424 -timer_3_select f07b -timer_off e426 -tips_and_updates e79a -tire_repair ebc8 -title e264 -toc e8de -today e8df -toggle_off e9f5 -toggle_on e9f6 -token ea25 -toll e8e0 -tonality e427 -topic f1c8 -touch_app e913 -tour ef75 -toys e332 -track_changes e8e1 -traffic e565 -train e570 -tram e571 -transfer_within_a_station e572 -transform e428 -transgender e58d -transit_enterexit e579 -translate e8e2 -travel_explore e2db -trending_down e8e3 -trending_flat e8e4 -trending_neutral e8e4 -trending_up e8e5 -trip_origin e57b -try f07c -tsunami ebd8 -tty f1aa -tune e429 -tungsten f07d -turn_left eba6 -turn_right ebab -turn_sharp_left eba7 -turn_sharp_right ebaa -turn_slight_left eba4 -turn_slight_right eb9a -turned_in e8e6 -turned_in_not e8e7 -tv e333 -tv_off e647 -two_wheeler e9f9 -u_turn_left eba1 -u_turn_right eba2 -umbrella f1ad -unarchive e169 -undo e166 -unfold_less e5d6 -unfold_more e5d7 -unpublished f236 -unsubscribe e0eb -upcoming f07e -update e923 -update_disabled e075 -upgrade f0fb -upload f09b -upload_file e9fc -usb e1e0 -usb_off e4fa -vaccines e138 -vape_free ebc6 -vaping_rooms ebcf -verified ef76 -verified_user e8e8 -vertical_align_bottom e258 -vertical_align_center e259 -vertical_align_top e25a -vertical_distribute e076 -vertical_split e949 -vibration e62d -video_call e070 -video_camera_back f07f -video_camera_front f080 -video_collection e04a -video_file eb87 -video_label e071 -video_library e04a -video_settings ea75 -video_stable f081 -videocam e04b -videocam_off e04c -videogame_asset e338 -videogame_asset_off e500 -view_agenda e8e9 -view_array e8ea -view_carousel e8eb -view_column e8ec -view_comfortable e42a -view_comfy e42a -view_comfy_alt eb73 -view_compact e42b -view_compact_alt eb74 -view_cozy eb75 -view_day e8ed -view_headline e8ee -view_in_ar e9fe -view_kanban eb7f -view_list e8ef -view_module e8f0 -view_quilt e8f1 -view_sidebar f114 -view_stream e8f2 -view_timeline eb85 -view_week e8f3 -vignette e435 -villa e586 -visibility e8f4 -visibility_off e8f5 -voice_chat e62e -voice_over_off e94a -voicemail e0d9 -volcano ebda -volume_down e04d -volume_down_alt e79c -volume_mute e04e -volume_off e04f -volume_up e050 -volunteer_activism ea70 -vpn_key e0da -vpn_key_off eb7a -vpn_lock e62f -vrpano f082 -wallet_giftcard e8f6 -wallet_membership e8f7 -wallet_travel e8f8 -wallpaper e1bc -warehouse ebb8 -warning e002 -warning_amber f083 -wash f1b1 -watch e334 -watch_later e924 -watch_off eae3 -water f084 -water_damage f203 -water_drop e798 -waterfall_chart ea00 -waves e176 -waving_hand e766 -wb_auto e42c -wb_cloudy e42d -wb_incandescent e42e -wb_iridescent e436 -wb_shade ea01 -wb_sunny e430 -wb_twighlight ea02 -wb_twilight e1c6 -wc e63d -web e051 -web_asset e069 -web_asset_off e4f7 -web_stories e595 -webhook eb92 -wechat ea81 -weekend e16b -west f1e6 -whatsapp ea9c -whatshot e80e -wheelchair_pickup f1ab -where_to_vote e177 -widgets e1bd -wifi e63e -wifi_1_bar e4ca -wifi_2_bar e4d9 -wifi_calling ef77 -wifi_calling_3 f085 -wifi_channel eb6a -wifi_find eb31 -wifi_lock e1e1 -wifi_off e648 -wifi_password eb6b -wifi_protected_setup f0fc -wifi_tethering e1e2 -wifi_tethering_error ead9 -wifi_tethering_error_rounded f086 -wifi_tethering_off f087 -window f088 -wine_bar f1e8 -woman e13e -woo_commerce ea6d -wordpress ea9f -work e8f9 -work_off e942 -work_outline e943 -workspace_premium e7af -workspaces e1a0 -workspaces_filled ea0d -workspaces_outline ea0f -wrap_text e25b -wrong_location ef78 -wysiwyg f1c3 -yard f089 -youtube_searched_for e8fa -zoom_in e8ff -zoom_in_map eb2d -zoom_out e900 -zoom_out_map e56b diff --git a/ui-ngx/src/app/core/services/menu.models.ts b/ui-ngx/src/app/core/services/menu.models.ts index 2043eeadea..47072943be 100644 --- a/ui-ngx/src/app/core/services/menu.models.ts +++ b/ui-ngx/src/app/core/services/menu.models.ts @@ -24,7 +24,6 @@ export interface MenuSection extends HasUUID{ type: MenuSectionType; path: string; icon: string; - isMdiIcon?: boolean; pages?: Array; opened?: boolean; disabled?: boolean; @@ -39,6 +38,5 @@ export interface HomeSection { export interface HomeSectionPlace { name: string; icon: string; - isMdiIcon?: boolean; path: string; } diff --git a/ui-ngx/src/app/core/services/menu.service.ts b/ui-ngx/src/app/core/services/menu.service.ts index 2025f6e389..42431c01cb 100644 --- a/ui-ngx/src/app/core/services/menu.service.ts +++ b/ui-ngx/src/app/core/services/menu.service.ts @@ -111,8 +111,7 @@ export class MenuService { name: 'tenant-profile.tenant-profiles', type: 'link', path: '/tenantProfiles', - icon: 'mdi:alpha-t-box', - isMdiIcon: true + icon: 'mdi:alpha-t-box' }, { id: 'resources', @@ -133,8 +132,7 @@ export class MenuService { name: 'resource.resources-library', type: 'link', path: '/resources/resources-library', - icon: 'mdi:rhombus-split', - isMdiIcon: true + icon: 'mdi:rhombus-split' } ] }, @@ -180,7 +178,6 @@ export class MenuService { type: 'link', path: '/notification', icon: 'mdi:message-badge', - isMdiIcon: true, pages: [ { id: 'notification_inbox', @@ -212,8 +209,7 @@ export class MenuService { fullName: 'notification.notification-templates', type: 'link', path: '/notification/templates', - icon: 'mdi:message-draw', - isMdiIcon: true + icon: 'mdi:message-draw' }, { id: 'notification_rules', @@ -221,8 +217,7 @@ export class MenuService { fullName: 'notification.notification-rules', type: 'link', path: '/notification/rules', - icon: 'mdi:message-cog', - isMdiIcon: true + icon: 'mdi:message-cog' } ] }, @@ -254,8 +249,7 @@ export class MenuService { fullName: 'admin.notifications-settings', type: 'link', path: '/settings/notifications', - icon: 'mdi:message-badge', - isMdiIcon: true + icon: 'mdi:message-badge' }, { id: 'queues', @@ -286,16 +280,14 @@ export class MenuService { name: 'admin.2fa.2fa', type: 'link', path: '/security-settings/2fa', - icon: 'mdi:two-factor-authentication', - isMdiIcon: true + icon: 'mdi:two-factor-authentication' }, { id: 'oauth2', name: 'admin.oauth2.oauth2', type: 'link', path: '/security-settings/oauth2', - icon: 'mdi:shield-account', - isMdiIcon: true + icon: 'mdi:shield-account' } ] } @@ -317,7 +309,6 @@ export class MenuService { { name: 'tenant-profile.tenant-profiles', icon: 'mdi:alpha-t-box', - isMdiIcon: true, path: '/tenantProfiles' }, ] @@ -363,7 +354,6 @@ export class MenuService { { name: 'admin.2fa.2fa', icon: 'mdi:two-factor-authentication', - isMdiIcon: true, path: '/settings/2fa' }, { @@ -397,8 +387,7 @@ export class MenuService { name: 'alarm.alarms', type: 'link', path: '/alarms', - icon: 'mdi:alert-outline', - isMdiIcon: true + icon: 'mdi:alert-outline' }, { id: 'dashboards', @@ -449,16 +438,14 @@ export class MenuService { name: 'device-profile.device-profiles', type: 'link', path: '/profiles/deviceProfiles', - icon: 'mdi:alpha-d-box', - isMdiIcon: true + icon: 'mdi:alpha-d-box' }, { id: 'asset_profiles', name: 'asset-profile.asset-profiles', type: 'link', path: '/profiles/assetProfiles', - icon: 'mdi:alpha-a-box', - isMdiIcon: true + icon: 'mdi:alpha-a-box' } ] }, @@ -549,8 +536,7 @@ export class MenuService { name: 'resource.resources-library', type: 'link', path: '/resources/resources-library', - icon: 'mdi:rhombus-split', - isMdiIcon: true + icon: 'mdi:rhombus-split' } ] }, @@ -596,7 +582,6 @@ export class MenuService { type: 'link', path: '/notification', icon: 'mdi:message-badge', - isMdiIcon: true, pages: [ { id: 'notification_inbox', @@ -628,8 +613,7 @@ export class MenuService { fullName: 'notification.notification-templates', type: 'link', path: '/notification/templates', - icon: 'mdi:message-draw', - isMdiIcon: true + icon: 'mdi:message-draw' }, { id: 'notification_rules', @@ -637,8 +621,7 @@ export class MenuService { fullName: 'notification.notification-rules', type: 'link', path: '/notification/rules', - icon: 'mdi:message-cog', - isMdiIcon: true + icon: 'mdi:message-cog' } ] }, @@ -670,8 +653,7 @@ export class MenuService { fullName: 'admin.notifications-settings', type: 'link', path: '/settings/notifications', - icon: 'mdi:message-badge', - isMdiIcon: true + icon: 'mdi:message-badge' }, { id: 'repository_settings', @@ -745,7 +727,6 @@ export class MenuService { { name: 'asset-profile.asset-profiles', icon: 'mdi:alpha-a-box', - isMdiIcon: true, path: '/profiles/assetProfiles' } ] @@ -761,7 +742,6 @@ export class MenuService { { name: 'device-profile.device-profiles', icon: 'mdi:alpha-d-box', - isMdiIcon: true, path: '/profiles/deviceProfiles' }, { @@ -886,8 +866,7 @@ export class MenuService { name: 'alarm.alarms', type: 'link', path: '/alarms', - icon: 'mdi:alert-outline', - isMdiIcon: true + icon: 'mdi:alert-outline' }, { id: 'dashboards', @@ -974,7 +953,6 @@ export class MenuService { type: 'link', path: '/notification', icon: 'mdi:message-badge', - isMdiIcon: true, pages: [ { id: 'notification_inbox', diff --git a/ui-ngx/src/app/core/services/resources.service.ts b/ui-ngx/src/app/core/services/resources.service.ts index 70084153e8..29d86fc2fb 100644 --- a/ui-ngx/src/app/core/services/resources.service.ts +++ b/ui-ngx/src/app/core/services/resources.service.ts @@ -47,6 +47,7 @@ export interface ModulesWithFactories { }) export class ResourcesService { + private loadedJsonResources: { [url: string]: ReplaySubject } = {}; private loadedResources: { [url: string]: ReplaySubject } = {}; private loadedModules: { [url: string]: ReplaySubject[]> } = {}; private loadedModulesAndFactories: { [url: string]: ReplaySubject } = {}; @@ -61,6 +62,30 @@ export class ResourcesService { this.store.pipe(select(selectIsAuthenticated)).subscribe(() => this.clearModulesCache()); } + public loadJsonResource(url: string, postProcess?: (data: T) => T): Observable { + if (this.loadedJsonResources[url]) { + return this.loadedJsonResources[url].asObservable(); + } + const subject = new ReplaySubject(); + this.loadedJsonResources[url] = subject; + this.http.get(url).subscribe( + { + next: (o) => { + if (postProcess) { + o = postProcess(o); + } + this.loadedJsonResources[url].next(o); + this.loadedJsonResources[url].complete(); + }, + error: () => { + this.loadedJsonResources[url].error(new Error(`Unable to load ${url}`)); + delete this.loadedJsonResources[url]; + } + } + ); + return subject.asObservable(); + } + public loadResource(url: string): Observable { if (this.loadedResources[url]) { return this.loadedResources[url].asObservable(); diff --git a/ui-ngx/src/app/core/services/script/node-script-test.service.ts b/ui-ngx/src/app/core/services/script/node-script-test.service.ts index 1a33275111..fa30934f06 100644 --- a/ui-ngx/src/app/core/services/script/node-script-test.service.ts +++ b/ui-ngx/src/app/core/services/script/node-script-test.service.ts @@ -23,8 +23,8 @@ import { NodeScriptTestDialogComponent, NodeScriptTestDialogData } from '@shared/components/dialog/node-script-test-dialog.component'; -import { sortObjectKeys } from '@core/utils'; import { ScriptLanguage } from '@shared/models/rule-node.models'; +import { DebugRuleNodeEventBody } from '@shared/models/event.models'; @Injectable({ providedIn: 'root' @@ -37,56 +37,52 @@ export class NodeScriptTestService { testNodeScript(script: string, scriptType: string, functionTitle: string, functionName: string, argNames: string[], ruleNodeId: string, helpId?: string, - scriptLang?: ScriptLanguage): Observable { - if (ruleNodeId) { + scriptLang?: ScriptLanguage, debugEventBody?: DebugRuleNodeEventBody): Observable { + if (ruleNodeId && !debugEventBody) { return this.ruleChainService.getLatestRuleNodeDebugInput(ruleNodeId).pipe( switchMap((debugIn) => { - let msg: any; - let metadata: {[key: string]: string}; - let msgType: string; - if (debugIn) { - if (debugIn.data) { - try { - msg = JSON.parse(debugIn.data); - } catch (e) {} - } - if (debugIn.metadata) { - try { - metadata = JSON.parse(debugIn.metadata); - } catch (e) {} - } - msgType = debugIn.msgType; - } return this.openTestScriptDialog(script, scriptType, functionTitle, - functionName, argNames, msg, metadata, msgType, helpId, scriptLang); + functionName, argNames, debugIn, helpId, scriptLang); }) ); } else { return this.openTestScriptDialog(script, scriptType, functionTitle, - functionName, argNames, null, null, null, helpId, scriptLang); + functionName, argNames, debugEventBody, helpId, scriptLang); } } - private openTestScriptDialog(script: string, scriptType: string, - functionTitle: string, functionName: string, argNames: string[], - msg?: any, metadata?: {[key: string]: string}, msgType?: string, helpId?: string, + private openTestScriptDialog(script: string, scriptType: string, functionTitle: string, functionName: string, + argNames: string[], eventBody: DebugRuleNodeEventBody, helpId?: string, scriptLang?: ScriptLanguage): Observable { + let msg: any; + let metadata: {[key: string]: string}; + let msgType: string; + if (eventBody && eventBody.data) { + try { + msg = JSON.parse(eventBody.data); + } catch (e) {} + } if (!msg) { msg = { temperature: 22.4, humidity: 78 }; } + if (eventBody && eventBody.metadata) { + try { + metadata = JSON.parse(eventBody.metadata); + } catch (e) {} + } if (!metadata) { metadata = { deviceName: 'Test Device', deviceType: 'default', ts: new Date().getTime() + '' }; - } else { - metadata = sortObjectKeys(metadata); } - if (!msgType) { + if (eventBody && eventBody.msgType) { + msgType = eventBody.msgType; + } else { msgType = 'POST_TELEMETRY_REQUEST'; } return this.dialog.open(NodeScriptTestDialogComponent, diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index f82c6c3072..a6065dfe62 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -21,32 +21,31 @@ import { Inject, Injectable, NgZone } from '@angular/core'; import { WINDOW } from '@core/services/window.service'; import { ExceptionData } from '@app/shared/models/error.models'; import { + base64toObj, + base64toString, baseUrl, createLabelFromDatasource, deepClone, deleteNullProperties, - guid, hashCode, + guid, + hashCode, isDefined, isDefinedAndNotNull, isString, isUndefined, objToBase64, - objToBase64URI, - base64toString, - base64toObj + objToBase64URI } from '@core/utils'; import { WindowMessage } from '@shared/models/window-message.model'; import { TranslateService } from '@ngx-translate/core'; import { customTranslationsPrefix, i18nPrefix } from '@app/shared/models/constants'; import { DataKey, Datasource, DatasourceType, KeyInfo } from '@shared/models/widget.models'; -import { EntityType } from '@shared/models/entity-type.models'; import { DataKeyType } from '@app/shared/models/telemetry/telemetry.models'; -import { alarmFields } from '@shared/models/alarm.models'; +import { alarmFields, alarmSeverityTranslations, alarmStatusTranslations } from '@shared/models/alarm.models'; import { materialColors } from '@app/shared/models/material.models'; import { WidgetInfo } from '@home/models/widget-component.models'; import jsonSchemaDefaults from 'json-schema-defaults'; -import materialIconsCodepoints from '!raw-loader!./material-icons-codepoints.raw'; -import { Observable, of, ReplaySubject } from 'rxjs'; +import { Observable } from 'rxjs'; import { publishReplay, refCount } from 'rxjs/operators'; import { WidgetContext } from '@app/modules/home/models/widget-component.models'; import { @@ -56,6 +55,8 @@ import { TelemetryType } from '@shared/models/telemetry/telemetry.models'; import { EntityId } from '@shared/models/id/entity-id'; +import { DatePipe } from '@angular/common'; +import { entityTypeTranslations } from '@shared/models/entity-type.models'; const i18nRegExp = new RegExp(`{${i18nPrefix}:[^{}]+}`, 'g'); @@ -86,13 +87,6 @@ const defaultAlarmFields: Array = [ alarmFields.status.keyName ]; -const commonMaterialIcons: Array = ['more_horiz', 'more_vert', 'open_in_new', - 'visibility', 'play_arrow', 'arrow_back', 'arrow_downward', - 'arrow_forward', 'arrow_upwards', 'close', 'refresh', 'menu', 'show_chart', 'multiline_chart', 'pie_chart', 'insert_chart', 'people', - 'person', 'domain', 'devices_other', 'now_widgets', 'dashboards', 'map', 'pin_drop', 'my_location', 'extension', 'search', - 'settings', 'notifications', 'notifications_active', 'info', 'info_outline', 'warning', 'list', 'file_download', 'import_export', - 'share', 'add', 'edit', 'done', 'delete']; - // @dynamic @Injectable({ providedIn: 'root' @@ -121,10 +115,9 @@ export class UtilsService { defaultAlarmDataKeys: Array = []; - materialIcons: Array = []; - constructor(@Inject(WINDOW) private window: Window, private zone: NgZone, + private datePipe: DatePipe, private translate: TranslateService) { let frame: Element = null; try { @@ -180,6 +173,27 @@ export class UtilsService { return deepClone(this.defaultAlarmDataKeys); } + public defaultAlarmFieldContent(key: DataKey | {name: string}, value: any): string { + if (isDefined(value)) { + const alarmField = alarmFields[key.name]; + if (alarmField) { + if (alarmField.time) { + return value ? this.datePipe.transform(value, 'yyyy-MM-dd HH:mm:ss') : ''; + } else if (alarmField === alarmFields.severity) { + return this.translate.instant(alarmSeverityTranslations.get(value)); + } else if (alarmField === alarmFields.status) { + return alarmStatusTranslations.get(value) ? this.translate.instant(alarmStatusTranslations.get(value)) : value; + } else if (alarmField === alarmFields.originatorType) { + return this.translate.instant(entityTypeTranslations.get(value).type); + } else if (alarmField.value === alarmFields.assignee.value) { + return ''; + } + } + return value; + } + return ''; + } + public generateObjectFromJsonSchema(schema: any): any { const obj = jsonSchemaDefaults(schema); deleteNullProperties(obj); @@ -282,13 +296,9 @@ export class UtilsService { public validateDatasources(datasources: Array): Array { datasources.forEach((datasource) => { - // @ts-ignore - if (datasource.type === 'device') { - datasource.type = DatasourceType.entity; - datasource.entityType = EntityType.DEVICE; - if (datasource.deviceId) { - datasource.entityId = datasource.deviceId; - } else if (datasource.deviceAliasId) { + if (datasource.type === DatasourceType.device) { + if (datasource.deviceAliasId) { + datasource.type = DatasourceType.entity; datasource.entityAliasId = datasource.deviceAliasId; } if (datasource.deviceName) { @@ -310,31 +320,6 @@ export class UtilsService { return datasources; } - public getMaterialIcons(): Observable> { - if (this.materialIcons.length) { - return of(this.materialIcons); - } else { - const materialIconsSubject = new ReplaySubject>(); - this.zone.runOutsideAngular(() => { - const codepointsArray = materialIconsCodepoints - .split('\n') - .filter((codepoint) => codepoint && codepoint.length); - codepointsArray.forEach((codepoint) => { - const values = codepoint.split(' '); - if (values && values.length === 2) { - this.materialIcons.push(values[0]); - } - }); - materialIconsSubject.next(this.materialIcons); - }); - return materialIconsSubject.asObservable(); - } - } - - public getCommonMaterialIcons(): Array { - return commonMaterialIcons; - } - public getMaterialColor(index: number) { const colorIndex = index % materialColors.length; return materialColors[colorIndex].value; @@ -415,7 +400,7 @@ export class UtilsService { public stringToHslColor(str: string, saturationPercentage: number, lightnessPercentage: number): string { if (str && str.length) { - let hue = hashCode(str) % 360; + const hue = hashCode(str) % 360; return `hsl(${hue}, ${saturationPercentage}%, ${lightnessPercentage}%)`; } } diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 4018fd491f..9a369cb5aa 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -20,7 +20,7 @@ import { finalize, share } from 'rxjs/operators'; import { Datasource, DatasourceData, FormattedData, ReplaceInfo } from '@app/shared/models/widget.models'; import { EntityId } from '@shared/models/id/entity-id'; import { NULL_UUID } from '@shared/models/id/has-uuid'; -import { EntityType, baseDetailsPageByEntityType } from '@shared/models/entity-type.models'; +import { baseDetailsPageByEntityType, EntityType } from '@shared/models/entity-type.models'; import { HttpErrorResponse } from '@angular/common/http'; import { TranslateService } from '@ngx-translate/core'; import { serverErrorCodesTranslations } from '@shared/models/constants'; @@ -126,15 +126,6 @@ export function isString(value: any): boolean { return typeof value === 'string'; } -export function isEmpty(obj: any): boolean { - for (const key of Object.keys(obj)) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - return false; - } - } - return true; -} - export function isLiteralObject(value: any) { return (!!value) && (value.constructor === Object); } @@ -320,9 +311,31 @@ export function extractType(target: any, keysOfProps: (keyof T return _.pick(target, keysOfProps); } -export function isEqual(a: any, b: any): boolean { - return _.isEqual(a, b); -} +export const isEqual = (a: any, b: any): boolean => _.isEqual(a, b); + +export const isEmpty = (a: any): boolean => _.isEmpty(a); + +export const unset = (object: any, path: string | symbol): boolean => _.unset(object, path); + +export const isEqualIgnoreUndefined = (a: any, b: any): boolean => { + if (a === b) { + return true; + } + if (isDefinedAndNotNull(a) && isDefinedAndNotNull(b)) { + return isEqual(a, b); + } else { + return (isUndefinedOrNull(a) || !a) && (isUndefinedOrNull(b) || !b); + } +}; + +export const isArraysEqualIgnoreUndefined = (a: any[], b: any[]): boolean => { + const res = isEqualIgnoreUndefined(a, b); + if (!res) { + return (isUndefinedOrNull(a) || !a?.length) && (isUndefinedOrNull(b) || !b?.length); + } else { + return res; + } +}; export function mergeDeep(target: T, ...sources: T[]): T { return _.merge(target, ...sources); @@ -763,3 +776,25 @@ export function genNextLabel(name: string, datasources: Datasource[]): string { } return label; } + +export const getOS = (): string => { + const userAgent = window.navigator.userAgent.toLowerCase(); + const macosPlatforms = /(macintosh|macintel|macppc|mac68k|macos|mac_powerpc)/i; + const windowsPlatforms = /(win32|win64|windows|wince)/i; + const iosPlatforms = /(iphone|ipad|ipod|darwin|ios)/i; + let os = null; + + if (macosPlatforms.test(userAgent)) { + os = 'macos'; + } else if (iosPlatforms.test(userAgent)) { + os = 'ios'; + } else if (windowsPlatforms.test(userAgent)) { + os = 'windows'; + } else if (/android/.test(userAgent)) { + os = 'android'; + } else if (/linux/.test(userAgent)) { + os = 'linux'; + } + + return os; +}; diff --git a/ui-ngx/src/app/core/ws/public-api.ts b/ui-ngx/src/app/core/ws/public-api.ts new file mode 100644 index 0000000000..d0f5fa8832 --- /dev/null +++ b/ui-ngx/src/app/core/ws/public-api.ts @@ -0,0 +1,19 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export * from './notification-websocket.service'; +export * from './telemetry-websocket.service'; +export * from './websocket.service'; diff --git a/ui-ngx/src/app/core/ws/websocket.service.ts b/ui-ngx/src/app/core/ws/websocket.service.ts index 51545a6d54..2d2162267d 100644 --- a/ui-ngx/src/app/core/ws/websocket.service.ts +++ b/ui-ngx/src/app/core/ws/websocket.service.ts @@ -97,7 +97,9 @@ export abstract class WebsocketService implements WsServ this.dataStream.next(this.cmdWrapper.preparePublishCommands(MAX_PUBLISH_COMMANDS)); this.checkToClose(); } - this.tryOpenSocket(); + if (this.subscribersCount > 0) { + this.tryOpenSocket(); + } } private checkToClose() { diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 4c03b402ab..eab8bcf5d5 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -179,6 +179,10 @@ import * as ProtobufContentComponent from '@shared/components/protobuf-content.c import * as SlackConversationAutocompleteComponent from '@shared/components/slack-conversation-autocomplete.component'; import * as StringItemsListComponent from '@shared/components/string-items-list.component'; import * as ToggleHeaderComponent from '@shared/components/toggle-header.component'; +import * as ToggleSelectComponent from '@shared/components/toggle-select.component'; +import * as UnitInputComponent from '@shared/components/unit-input.component'; +import * as MaterialIconsComponent from '@shared/components/material-icons.component'; +import * as TbIconComponent from '@shared/components/icon.component'; import * as AddEntityDialogComponent from '@home/components/entity/add-entity-dialog.component'; import * as EntitiesTableComponent from '@home/components/entity/entities-table.component'; @@ -478,6 +482,10 @@ class ModulesMap implements IModulesMap { '@shared/components/slack-conversation-autocomplete.component': SlackConversationAutocompleteComponent, '@shared/components/string-items-list.component': StringItemsListComponent, '@shared/components/toggle-header.component': ToggleHeaderComponent, + '@shared/components/toggle-select.component': ToggleSelectComponent, + '@shared/components/unit-input.component': UnitInputComponent, + '@shared/components/material-icons.component': MaterialIconsComponent, + '@shared/components/icon.component': TbIconComponent, '@home/components/entity/add-entity-dialog.component': AddEntityDialogComponent, '@home/components/entity/entities-table.component': EntitiesTableComponent, diff --git a/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts b/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts index 12f27f2dcc..357db25e67 100644 --- a/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts +++ b/ui-ngx/src/app/modules/dashboard/dashboard-pages.routing.module.ts @@ -25,6 +25,7 @@ import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; import { DashboardResolver } from '@app/modules/home/pages/dashboard/dashboard-routing.module'; import { UtilsService } from '@core/services/utils.service'; import { Widget } from '@app/shared/models/widget.models'; +import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; @Injectable() export class WidgetEditorDashboardResolver implements Resolve { @@ -59,6 +60,7 @@ const routes: Routes = [ { path: 'dashboard/:dashboardId', component: DashboardPageComponent, + canDeactivate: [ConfirmOnExitGuard], data: { breadcrumb: { skip: true @@ -75,6 +77,7 @@ const routes: Routes = [ { path: 'widget-editor', component: DashboardPageComponent, + canDeactivate: [ConfirmOnExitGuard], data: { breadcrumb: { skip: true diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-panel.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-panel.component.html index 8f43f27964..8d178aaa2c 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-panel.component.html @@ -26,10 +26,14 @@ #userAutocomplete="matAutocomplete" [displayWith]="displayUserFn" (optionSelected)="selected($event)"> - + account_circle {{ assigneeNotSetText | translate }} + + account_circle + {{ assignedToCurrentUserText | translate }} + ('AlarmAssigneePanelData'); @@ -59,15 +60,19 @@ export interface AlarmAssigneePanelData { }) export class AlarmAssigneePanelComponent implements OnInit, AfterViewInit, OnDestroy { + assigneeOptions = AlarmAssigneeOption; + private dirty = false; alarmId: string; assigneeId?: string; + assigneeOption?: AlarmAssigneeOption = null; assigneeNotSetText = 'alarm.unassigned'; + assignedToCurrentUserText = ''; - reassigned: boolean = false; + reassigned = false; selectUserFormGroup: FormGroup; @@ -77,6 +82,14 @@ export class AlarmAssigneePanelComponent implements OnInit, AfterViewInit, OnDe searchText = ''; + get displayAssigneeNotSet(): boolean { + return !!this.assigneeId; + } + + get displayAssignedToCurrentUser(): boolean { + return false; + } + private destroy$ = new Subject(); constructor(@Inject(ALARM_ASSIGNEE_PANEL_DATA) public data: AlarmAssigneePanelData, @@ -124,8 +137,8 @@ export class AlarmAssigneePanelComponent implements OnInit, AfterViewInit, OnDe selected(event: MatAutocompleteSelectedEvent): void { this.clear(); - const user: User = event.option.value; - if (user) { + if (event.option.value?.id) { + const user: User = event.option.value; this.assign(user); } else { this.unassign(); diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select-panel.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select-panel.component.ts index 1526616833..cd8ce2ec33 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select-panel.component.ts @@ -36,11 +36,14 @@ import { emptyPageData } from '@shared/models/page/page-data'; import { OverlayRef } from '@angular/cdk/overlay'; import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { UtilsService } from '@core/services/utils.service'; +import { AlarmAssigneeOption } from '@shared/models/alarm.models'; export const ALARM_ASSIGNEE_SELECT_PANEL_DATA = new InjectionToken('AlarmAssigneeSelectPanelData'); export interface AlarmAssigneeSelectPanelData { assigneeId?: string; + assigneeOption?: AlarmAssigneeOption; + userMode?: boolean; } @Component({ @@ -50,11 +53,15 @@ export interface AlarmAssigneeSelectPanelData { }) export class AlarmAssigneeSelectPanelComponent implements OnInit, AfterViewInit, OnDestroy { + assigneeOptions = AlarmAssigneeOption; + private dirty = false; assigneeId?: string; + assigneeOption?: AlarmAssigneeOption; assigneeNotSetText = 'alarm.assignee-not-set'; + assignedToCurrentUserText = this.data.userMode ? 'alarm.assigned-to-me' : 'alarm.assigned-to-current-user'; selectUserFormGroup: FormGroup; @@ -67,6 +74,15 @@ export class AlarmAssigneeSelectPanelComponent implements OnInit, AfterViewInit userSelected = false; result?: UserEmailInfo; + optionResult?: AlarmAssigneeOption; + + get displayAssigneeNotSet(): boolean { + return this.assigneeOption !== AlarmAssigneeOption.noAssignee; + } + + get displayAssignedToCurrentUser(): boolean { + return this.assigneeOption !== AlarmAssigneeOption.currentUser; + } private destroy$ = new Subject(); @@ -77,6 +93,7 @@ export class AlarmAssigneeSelectPanelComponent implements OnInit, AfterViewInit private fb: FormBuilder, private utilsService: UtilsService) { this.assigneeId = data.assigneeId; + this.assigneeOption = data.assigneeOption; this.selectUserFormGroup = this.fb.group({ user: [null] }); @@ -112,7 +129,11 @@ export class AlarmAssigneeSelectPanelComponent implements OnInit, AfterViewInit selected(event: MatAutocompleteSelectedEvent): void { this.clear(); this.userSelected = true; - this.result = event.option.value; + if (event.option.value?.id) { + this.result = event.option.value; + } else { + this.optionResult = event.option.value; + } this.overlayRef.dispose(); } diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.html index 2ad7229365..c07a4cb3c6 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.html @@ -16,16 +16,16 @@ --> - - alarm.assignee + subscriptSizing="dynamic" [appearance]="inline ? 'outline' : 'fill'"> + alarm.assignee - {{ getUserInitials() }} - account_circle - arrow_drop_down + account_circle + arrow_drop_down diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.ts index 4d1f6021be..50918bfd0d 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.ts @@ -30,6 +30,8 @@ import { AlarmAssigneeSelectPanelComponent, AlarmAssigneeSelectPanelData } from '@home/components/alarm/alarm-assignee-select-panel.component'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { AlarmAssigneeOption } from '@shared/models/alarm.models'; @Component({ selector: 'tb-alarm-assignee-select', @@ -47,8 +49,17 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso @Input() disabled: boolean; + @coerceBoolean() + @Input() + inline = false; + + @coerceBoolean() + @Input() + userMode = false; + assigneeFormGroup: UntypedFormGroup; assignee?: User | UserEmailInfo; + assigneeOption?: AlarmAssigneeOption; private propagateChange = (_: any) => {}; @@ -82,7 +93,15 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso } } - writeValue(userId?: UserId): void { + writeValue(value?: UserId | AlarmAssigneeOption): void { + let userId: UserId; + if (value && (value as UserId).id) { + userId = value as UserId; + this.assigneeOption = null; + } else { + userId = null; + this.assigneeOption = value ? value as AlarmAssigneeOption : AlarmAssigneeOption.noAssignee; + } const userObservable = userId ? this.userService.getUser(userId.id, {ignoreErrors: true}).pipe( catchError(() => of(null)) ) : of(null); @@ -92,15 +111,31 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso }), map((user) => this.getAssignee(user)) ).subscribe((assignee) => { - this.assigneeFormGroup.get('assignee').patchValue(assignee, {emitEvent: false}); + if (assignee) { + this.assigneeFormGroup.get('assignee').patchValue(assignee, {emitEvent: false}); + } else { + if (!this.assigneeOption) { + this.assigneeOption = AlarmAssigneeOption.noAssignee; + } + assignee = this.getAssigneeOption(this.assigneeOption); + this.assigneeFormGroup.get('assignee').patchValue(assignee, {emitEvent: false}); + } }); } - private getAssignee(user?: User| UserEmailInfo): string { + private getAssignee(user?: User| UserEmailInfo): string | null { if (user) { return this.getUserDisplayName(user); } else { + return null; + } + } + + private getAssigneeOption(assigneeOption: AlarmAssigneeOption): string { + if (assigneeOption === AlarmAssigneeOption.noAssignee) { return this.translateService.instant('alarm.assignee-not-set'); + } else { + return this.translateService.instant(this.userMode ? 'alarm.assigned-to-me' : 'alarm.assigned-to-current-user'); } } @@ -169,7 +204,9 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso { provide: ALARM_ASSIGNEE_SELECT_PANEL_DATA, useValue: { - assigneeId: this.assignee?.id?.id + assigneeId: this.assignee?.id?.id, + assigneeOption: this.assigneeOption, + userMode: this.userMode } as AlarmAssigneeSelectPanelData }, { @@ -183,8 +220,14 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso component.onDestroy(() => { if (component.instance.userSelected) { this.assignee = component.instance.result; - this.assigneeFormGroup.get('assignee').patchValue(this.getAssignee(this.assignee), {emitEvent: false}); - this.propagateChange(this.assignee?.id); + this.assigneeOption = component.instance.optionResult; + if (this.assignee) { + this.assigneeFormGroup.get('assignee').patchValue(this.getAssignee(this.assignee), {emitEvent: false}); + this.propagateChange(this.assignee?.id); + } else if (this.assigneeOption) { + this.assigneeFormGroup.get('assignee').patchValue(this.getAssigneeOption(this.assigneeOption), {emitEvent: false}); + this.propagateChange(this.assigneeOption); + } } }); } diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.scss b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.scss index 82f10650cf..3aed0ccb5e 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.scss +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee.component.scss @@ -19,20 +19,14 @@ justify-content: center; align-items: center; border-radius: 50%; - width: 28px; - height: 28px; min-width: 28px; min-height: 28px; color: white; font-size: 13px; font-weight: 700; - margin-left: 12px; - margin-right: 20px; } .unassigned-icon { - width: 28px; - height: 28px; font-size: 28px; color: rgba(0, 0, 0, 0.38); overflow: visible; @@ -40,3 +34,14 @@ margin-right: 20px; padding: 0; } + +.user-avatar, .unassigned-icon { + width: 28px; + height: 28px; + margin-left: 12px; + margin-right: 20px; + &.inline { + margin-left: 0; + margin-right: 8px; + } +} diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html index a2a0c158a5..cbbcc2ccb9 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html @@ -33,6 +33,13 @@
+ + - - -
-
- - - -
- -
-
-
+
+ + + +
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss new file mode 100644 index 0000000000..3856547508 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import '../../../../../scss/constants'; + +.tb-add-widget-dialog { + .mat-mdc-dialog-content { + padding: 0; + position: relative; + } + @media #{$mat-gt-xs} { + width: 900px; + .mat-mdc-dialog-content { + height: 900px; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts index ada22bba94..67c1551d9d 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts @@ -14,12 +14,12 @@ /// limitations under the License. /// -import { Component, Inject, OnInit, SkipSelf } from '@angular/core'; +import { Component, Inject, OnInit, SkipSelf, ViewEncapsulation } from '@angular/core'; import { ErrorStateMatcher } from '@angular/material/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, FormGroupDirective, NgForm } from '@angular/forms'; +import { FormGroupDirective, NgForm, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { DialogComponent } from '@app/shared/components/dialog.component'; import { Widget, WidgetConfigMode, widgetTypesData } from '@shared/models/widget.models'; @@ -41,7 +41,8 @@ export interface AddWidgetDialogData { selector: 'tb-add-widget-dialog', templateUrl: './add-widget-dialog.component.html', providers: [/*{provide: ErrorStateMatcher, useExisting: AddWidgetDialogComponent}*/], - styleUrls: [] + styleUrls: ['./add-widget-dialog.component.scss'], + encapsulation: ViewEncapsulation.None }) export class AddWidgetDialogComponent extends DialogComponent implements OnInit, ErrorStateMatcher { diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index 9bfa9fd996..b627783d47 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -115,7 +115,7 @@ matTooltip="{{'action.save' | translate}}" matTooltipPosition="below"> done -
- - +
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss index 9777decdb0..c31f1d5791 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss @@ -14,9 +14,17 @@ * limitations under the License. */ :host { - .widget-preview-section { + .widget-preview-background { position: absolute; top: 72px; + left: 0; + right: 0; + bottom: 0; + background: #fff; + } + .widget-preview-section { + position: absolute; + top: 0; left: 16px; right: 16px; bottom: 16px; diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-mqtt-basic.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials-mqtt-basic.component.html index be71d3724e..768cea9252 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-mqtt-basic.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-mqtt-basic.component.html @@ -26,13 +26,14 @@ matTooltip="{{ 'device.generate-client-id' | translate }}" matTooltipPosition="above" (click)="generate('clientId')" - *ngIf="!deviceCredentialsMqttFormGroup.get('clientId').value; else copyClientId"> + *ngIf="!deviceCredentialsMqttFormGroup.get('clientId').value && !disabled; else copyClientId"> autorenew + *ngIf="!deviceCredentialsMqttFormGroup.get('userName').value && !disabled; else copyUserName"> autorenew @@ -85,7 +86,7 @@ matTooltip="{{ 'device.generate-password' | translate }}" matTooltipPosition="above" (click)="generate('password')" - *ngIf="!deviceCredentialsMqttFormGroup.get('password').value; else copyPassword"> + *ngIf="!deviceCredentialsMqttFormGroup.get('password').value && !disabled; else copyPassword"> autorenew diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html index 303c46ef70..fd666e1398 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html @@ -16,14 +16,14 @@ -->
- - device.credentials-type - - +
+
device.credentials-type
+ + {{ credentialTypeNamesMap.get(credentialsType) }} - - - + + +
@@ -36,13 +36,14 @@ matTooltip="{{ 'device.generate-access-token' | translate }}" matTooltipPosition="above" (click)="generate('credentialsId')" - *ngIf="!deviceCredentialsFormGroup.get('credentialsId').value; else copyAccessToken"> + *ngIf="!deviceCredentialsFormGroup.get('credentialsId').value && !disabled; else copyAccessToken"> autorenew DeviceCredentialsComponent), multi: true, }], - styleUrls: [] + styleUrls: ['./device-credentials.component.scss'] }) export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, Validator, OnDestroy { @@ -73,9 +74,13 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, } } + @Input() + @coerceBoolean() + initAccessToken = false; + private destroy$ = new Subject(); - deviceCredentialsFormGroup: UntypedFormGroup; + deviceCredentialsFormGroup: FormGroup; deviceCredentialsType = DeviceCredentialsType; @@ -83,9 +88,10 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, credentialTypeNamesMap = credentialTypeNames; - private propagateChange = (v: any) => {}; + private propagateChange = null; + private propagateChangePending = false; - constructor(public fb: UntypedFormBuilder) { + constructor(public fb: FormBuilder) { this.deviceCredentialsFormGroup = this.fb.group({ credentialsType: [DeviceCredentialsType.ACCESS_TOKEN], credentialsId: [null], @@ -98,8 +104,8 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, }); this.deviceCredentialsFormGroup.get('credentialsType').valueChanges.pipe( takeUntil(this.destroy$) - ).subscribe(() => { - this.credentialsTypeChanged(); + ).subscribe((value) => { + this.credentialsTypeChanged(value); }); } @@ -107,6 +113,10 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, if (this.disabled) { this.deviceCredentialsFormGroup.disable({emitEvent: false}); } + if (this.initAccessToken && !this.deviceCredentialsFormGroup.get('credentialsId').value && + this.deviceCredentialsFormGroup.get('credentialsType').value === DeviceCredentialsType.ACCESS_TOKEN) { + this.deviceCredentialsFormGroup.get('credentialsId').patchValue(generateSecret(20)); + } } ngOnDestroy() { @@ -128,11 +138,21 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, updateView() { const deviceCredentialsValue = this.deviceCredentialsFormGroup.value; - this.propagateChange(deviceCredentialsValue); + if (this.propagateChange) { + this.propagateChange(deviceCredentialsValue); + } else { + this.propagateChangePending = true; + } } registerOnChange(fn: any): void { this.propagateChange = fn; + if (this.propagateChangePending) { + this.propagateChangePending = false; + setTimeout(() => { + this.updateView(); + }, 0); + } } registerOnTouched(fn: any): void {} @@ -144,11 +164,10 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, } else { this.deviceCredentialsFormGroup.enable({emitEvent: false}); this.updateValidators(); - this.deviceCredentialsFormGroup.updateValueAndValidity(); } } - public validate(c: UntypedFormControl) { + public validate(c: FormControl) { return this.deviceCredentialsFormGroup.valid ? null : { deviceCredentials: { valid: false, @@ -156,12 +175,15 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, }; } - credentialsTypeChanged(): void { + credentialsTypeChanged(type: DeviceCredentialsType): void { this.deviceCredentialsFormGroup.patchValue({ credentialsId: null, credentialsValue: null }); this.updateValidators(); + if (type === DeviceCredentialsType.ACCESS_TOKEN && this.initAccessToken) { + this.deviceCredentialsFormGroup.get('credentialsId').patchValue(generateSecret(20)); + } } updateValidators(): void { diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index 65f4bed2ae..20cf8a11c7 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -86,8 +86,7 @@ matTooltip="{{ actionDescriptor.name }}" matTooltipPosition="above" (click)="actionDescriptor.onAction($event)"> - - {{actionDescriptor.icon}} + {{actionDescriptor.icon}}
-
+
- - + - {{tab.icon}} - + {{tab.icon}} {{tab.name | translate}} diff --git a/ui-ngx/src/app/modules/home/components/router-tabs.component.scss b/ui-ngx/src/app/modules/home/components/router-tabs.component.scss index 8fe2c2b305..bd252f6832 100644 --- a/ui-ngx/src/app/modules/home/components/router-tabs.component.scss +++ b/ui-ngx/src/app/modules/home/components/router-tabs.component.scss @@ -26,7 +26,7 @@ line-height: 40px; min-width: 200px; border-bottom: none; - mat-icon { + .mat-icon { margin-right: 8px; margin-left: 0; } diff --git a/ui-ngx/src/app/modules/home/components/router-tabs.component.ts b/ui-ngx/src/app/modules/home/components/router-tabs.component.ts index 65c0074227..bd38275432 100644 --- a/ui-ngx/src/app/modules/home/components/router-tabs.component.ts +++ b/ui-ngx/src/app/modules/home/components/router-tabs.component.ts @@ -20,8 +20,8 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { MenuService } from '@core/services/menu.service'; -import { distinctUntilChanged, filter, map, mergeMap, take } from 'rxjs/operators'; -import { merge } from 'rxjs'; +import { distinctUntilChanged, filter, map, mergeMap, startWith, take } from 'rxjs/operators'; +import { merge, Observable } from 'rxjs'; import { MenuSection } from '@core/services/menu.models'; import { ActiveComponentService } from '@core/services/active-component.service'; import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; @@ -39,14 +39,9 @@ export class RouterTabsComponent extends PageComponent implements OnInit { hideCurrentTabs = false; - tabs$ = merge(this.menuService.menuSections(), - this.router.events.pipe( - filter((event) => event instanceof NavigationEnd ), - distinctUntilChanged()) - ).pipe( - mergeMap(() => this.menuService.menuSections().pipe(take(1))), - map((sections) => this.buildTabs(this.activatedRoute, sections)) - ); + replaceUrl = false; + + tabs$: Observable>; constructor(protected store: Store, private activatedRoute: ActivatedRoute, @@ -57,6 +52,27 @@ export class RouterTabsComponent extends PageComponent implements OnInit { } ngOnInit() { + if (this.activatedRoute.snapshot.data.useChildrenRoutesForTabs) { + this.tabs$ = this.router.events.pipe( + filter((event) => event instanceof NavigationEnd), + startWith(''), + map(() => this.buildTabsForRoutes(this.activatedRoute)) + ); + } else { + this.tabs$ = merge(this.menuService.menuSections(), + this.router.events.pipe( + filter((event) => event instanceof NavigationEnd ), + distinctUntilChanged()) + ).pipe( + mergeMap(() => this.menuService.menuSections().pipe(take(1))), + map((sections) => this.buildTabs(this.activatedRoute, sections)) + ); + } + + if (this.activatedRoute.snapshot.data.replaceUrl) { + this.replaceUrl = true; + } + this.activatedRoute.data.subscribe( (data) => this.buildTabsHeaderComponent(data) ); @@ -80,18 +96,36 @@ export class RouterTabsComponent extends PageComponent implements OnInit { } } - private buildTabs(activatedRoute: ActivatedRoute, sections: MenuSection[]): Array { - const sectionPath = '/' + activatedRoute.pathFromRoot.map(r => r.snapshot.url) + private getSectionPath(activatedRoute: ActivatedRoute): string { + return '/' + activatedRoute.pathFromRoot.map(r => r.snapshot.url) .filter(f => !!f[0]).map(f => f.map(f1 => f1.path).join('/')).join('/'); + } + + private buildTabs(activatedRoute: ActivatedRoute, sections: MenuSection[]): Array { + const sectionPath = this.getSectionPath(activatedRoute); const found = this.findRootSection(sections, sectionPath); if (found) { const rootPath = sectionPath.substring(0, sectionPath.length - found.path.length); const isRoot = rootPath === ''; const tabs: Array = found ? found.pages.filter(page => !page.disabled && (!page.rootOnly || isRoot)) : []; return tabs.map((tab) => ({...tab, path: rootPath + tab.path})); - } else { - return []; } + return []; + } + + private buildTabsForRoutes(activatedRoute: ActivatedRoute): Array { + const sectionPath = this.getSectionPath(activatedRoute); + if (activatedRoute.routeConfig.children.length) { + const activeRouterChildren = activatedRoute.routeConfig.children.filter(page => page.path !== ''); + return activeRouterChildren.map(tab => ({ + id: tab.component.name, + type: 'link', + name: tab.data?.breadcrumb?.label ?? '', + icon: tab.data?.breadcrumb?.icon ?? '', + path: `${sectionPath}/${tab.path}` + })); + } + return []; } private findRootSection(sections: MenuSection[], sectionPath: string): MenuSection { diff --git a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html index 1c29a715b6..4642133477 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/action/manage-widget-actions.component.html @@ -96,7 +96,7 @@ {{ 'widget-config.action-icon' | translate }} - {{ action.icon }} + {{ action.icon }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html new file mode 100644 index 0000000000..18cd34609e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html @@ -0,0 +1,100 @@ + + + + +
+
+
alarm.filter
+ +
+ +
+ + + + +
+
widget-config.card-appearance
+
+ + {{ 'widget-config.card-title' | translate }} + + + + +
+
+ + {{ 'widget-config.card-icon' | translate }} + +
+ + + + +
+
+
+
widget-config.show-card-buttons
+ + {{ 'action.search' | translate }} + {{ 'alarm.alarm-filter' | translate }} + {{ 'widgets.table.columns-to-display' | translate }} + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.text-color' | translate }}
+ + +
+
+
{{ 'widget-config.background-color' | translate }}
+ + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts new file mode 100644 index 0000000000..33abc0670c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts @@ -0,0 +1,160 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { isUndefined } from '@core/utils'; +import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; + +@Component({ + selector: 'tb-alarms-table-basic-config', + templateUrl: './alarms-table-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent { + + public get alarmSource(): Datasource { + const datasources: Datasource[] = this.alarmsTableWidgetConfigForm.get('datasources').value; + if (datasources && datasources.length) { + return datasources[0]; + } else { + return null; + } + } + + alarmsTableWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.alarmsTableWidgetConfigForm; + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + this.alarmsTableWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + alarmFilterConfig: [configData.config.alarmFilterConfig, []], + datasources: [[configData.config.alarmSource], []], + columns: [this.getColumns(configData.config.alarmSource), []], + showTitle: [configData.config.showTitle, []], + title: [configData.config.settings?.alarmsTitle, []], + showTitleIcon: [configData.config.showTitleIcon, []], + titleIcon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + color: [configData.config.color, []], + backgroundColor: [configData.config.backgroundColor, []], + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; + this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; + this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + this.widgetConfig.config.alarmFilterConfig = config.alarmFilterConfig; + this.widgetConfig.config.alarmSource = config.datasources[0]; + this.setColumns(config.columns, this.widgetConfig.config.alarmSource); + this.widgetConfig.config.actions = config.actions; + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.widgetConfig.config.settings.alarmsTitle = config.title; + this.widgetConfig.config.showTitleIcon = config.showTitleIcon; + this.widgetConfig.config.titleIcon = config.titleIcon; + this.widgetConfig.config.iconColor = config.iconColor; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.color = config.color; + this.widgetConfig.config.backgroundColor = config.backgroundColor; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showTitleIcon']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.alarmsTableWidgetConfigForm.get('showTitle').value; + const showTitleIcon: boolean = this.alarmsTableWidgetConfigForm.get('showTitleIcon').value; + if (showTitle) { + this.alarmsTableWidgetConfigForm.get('title').enable(); + this.alarmsTableWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); + if (showTitleIcon) { + this.alarmsTableWidgetConfigForm.get('titleIcon').enable(); + this.alarmsTableWidgetConfigForm.get('iconColor').enable(); + } else { + this.alarmsTableWidgetConfigForm.get('titleIcon').disable(); + this.alarmsTableWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.alarmsTableWidgetConfigForm.get('title').disable(); + this.alarmsTableWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); + this.alarmsTableWidgetConfigForm.get('titleIcon').disable(); + this.alarmsTableWidgetConfigForm.get('iconColor').disable(); + } + this.alarmsTableWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.alarmsTableWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); + this.alarmsTableWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); + this.alarmsTableWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); + } + + private getColumns(alarmSource?: Datasource): DataKey[] { + if (alarmSource) { + return alarmSource.dataKeys || []; + } + return []; + } + + private setColumns(columns: DataKey[], alarmSource?: Datasource) { + if (alarmSource) { + alarmSource.dataKeys = columns; + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.settings?.enableSearch) || config.settings?.enableSearch) { + buttons.push('search'); + } + if (isUndefined(config.settings?.enableFilter) || config.settings?.enableFilter) { + buttons.push('filter'); + } + if (isUndefined(config.settings?.enableSelectColumnDisplay) || config.settings?.enableSelectColumnDisplay) { + buttons.push('columnsToDisplay'); + } + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.settings.enableSearch = buttons.includes('search'); + config.settings.enableFilter = buttons.includes('filter'); + config.settings.enableSelectColumnDisplay = buttons.includes('columnsToDisplay'); + config.enableFullscreen = buttons.includes('fullscreen'); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 73ebfb37c7..3a3425975b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -30,24 +30,44 @@ import { } from '@home/components/widget/config/basic/cards/entities-table-basic-config.component'; import { DataKeysPanelComponent } from '@home/components/widget/config/basic/common/data-keys-panel.component'; import { DataKeyRowComponent } from '@home/components/widget/config/basic/common/data-key-row.component'; +import { + TimeseriesTableBasicConfigComponent +} from '@home/components/widget/config/basic/cards/timeseries-table-basic-config.component'; +import { FlotBasicConfigComponent } from '@home/components/widget/config/basic/chart/flot-basic-config.component'; +import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widget-settings.module'; +import { + AlarmsTableBasicConfigComponent +} from '@home/components/widget/config/basic/alarm/alarms-table-basic-config.component'; +import { + ValueCardBasicConfigComponent +} from '@home/components/widget/config/basic/cards/value-card-basic-config.component'; @NgModule({ declarations: [ WidgetActionsPanelComponent, SimpleCardBasicConfigComponent, EntitiesTableBasicConfigComponent, + TimeseriesTableBasicConfigComponent, + FlotBasicConfigComponent, + AlarmsTableBasicConfigComponent, + ValueCardBasicConfigComponent, DataKeyRowComponent, DataKeysPanelComponent ], imports: [ CommonModule, SharedModule, + WidgetSettingsModule, WidgetConfigComponentsModule ], exports: [ WidgetActionsPanelComponent, SimpleCardBasicConfigComponent, EntitiesTableBasicConfigComponent, + TimeseriesTableBasicConfigComponent, + FlotBasicConfigComponent, + AlarmsTableBasicConfigComponent, + ValueCardBasicConfigComponent, DataKeyRowComponent, DataKeysPanelComponent ] @@ -57,5 +77,9 @@ export class BasicWidgetConfigModule { export const basicWidgetConfigComponentsMap: {[key: string]: Type} = { 'tb-simple-card-basic-config': SimpleCardBasicConfigComponent, - 'tb-entities-table-basic-config': EntitiesTableBasicConfigComponent + 'tb-entities-table-basic-config': EntitiesTableBasicConfigComponent, + 'tb-timeseries-table-basic-config': TimeseriesTableBasicConfigComponent, + 'tb-flot-basic-config': FlotBasicConfigComponent, + 'tb-alarms-table-basic-config': AlarmsTableBasicConfigComponent, + 'tb-value-card-basic-config': ValueCardBasicConfigComponent }; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html index ee76bdf472..c5501ae830 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html @@ -28,6 +28,7 @@ -
-
widget-config.appearance
-
- +
+
widget-config.card-appearance
+
+ {{ 'widget-config.card-title' | translate }}
-
+
{{ 'widget-config.card-icon' | translate }} -
+
-
-
+
+
widget-config.show-card-buttons
+ + {{ 'action.search' | translate }} + {{ 'widgets.table.columns-to-display' | translate }} + {{ 'fullscreen.fullscreen' | translate }} + +
+
{{ 'widget-config.text-color' | translate }}
-
- - - -
+ +
-
-
{{ 'widget-config.background' | translate }}
-
- - - -
+
+
{{ 'widget-config.background-color' | translate }}
+ +
-
-
widget-config.appearance
-
-
widgets.simple-card.label
+
+
widget-config.appearance
+
+
widgets.simple-card.label
-
+
widgets.simple-card.label-position
@@ -49,35 +49,35 @@
-
+
widget-config.units-short
- - +
-
+
widget-config.decimals-short
- +
-
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
{{ 'widget-config.text-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.background' | translate }}
-
- - - -
+ +
+ + + + + + + +
+
widget-config.card-appearance
+
+ + {{ 'widget-config.card-title' | translate }} + + + + +
+
+ + {{ 'widget-config.card-icon' | translate }} + +
+ + + + +
+
+
+
widget-config.show-card-buttons
+ + {{ 'action.search' | translate }} + {{ 'widgets.table.columns-to-display' | translate }} + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.text-color' | translate }}
+ + +
+
+
{{ 'widget-config.background-color' | translate }}
+ + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts new file mode 100644 index 0000000000..ac1b12167c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts @@ -0,0 +1,173 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { deepClone, isUndefined } from '@core/utils'; +import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; + +@Component({ + selector: 'tb-timeseries-table-basic-config', + templateUrl: './timeseries-table-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigComponent { + + public get datasource(): Datasource { + const datasources: Datasource[] = this.timeseriesTableWidgetConfigForm.get('datasources').value; + if (datasources && datasources.length) { + return datasources[0]; + } else { + return null; + } + } + + timeseriesTableWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.timeseriesTableWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + this.setupDefaultDatasource(configData, + [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }]); + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + this.timeseriesTableWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + datasources: [configData.config.datasources, []], + columns: [this.getColumns(configData.config.datasources), []], + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + showTitleIcon: [configData.config.showTitleIcon, []], + titleIcon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + color: [configData.config.color, []], + backgroundColor: [configData.config.backgroundColor, []], + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; + this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; + this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + this.widgetConfig.config.datasources = config.datasources; + this.setColumns(config.columns, this.widgetConfig.config.datasources); + this.widgetConfig.config.actions = config.actions; + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.title = config.title; + this.widgetConfig.config.showTitleIcon = config.showTitleIcon; + this.widgetConfig.config.titleIcon = config.titleIcon; + this.widgetConfig.config.iconColor = config.iconColor; + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.color = config.color; + this.widgetConfig.config.backgroundColor = config.backgroundColor; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showTitleIcon']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.timeseriesTableWidgetConfigForm.get('showTitle').value; + const showTitleIcon: boolean = this.timeseriesTableWidgetConfigForm.get('showTitleIcon').value; + if (showTitle) { + this.timeseriesTableWidgetConfigForm.get('title').enable(); + this.timeseriesTableWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); + if (showTitleIcon) { + this.timeseriesTableWidgetConfigForm.get('titleIcon').enable(); + this.timeseriesTableWidgetConfigForm.get('iconColor').enable(); + } else { + this.timeseriesTableWidgetConfigForm.get('titleIcon').disable(); + this.timeseriesTableWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.timeseriesTableWidgetConfigForm.get('title').disable(); + this.timeseriesTableWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); + this.timeseriesTableWidgetConfigForm.get('titleIcon').disable(); + this.timeseriesTableWidgetConfigForm.get('iconColor').disable(); + } + this.timeseriesTableWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.timeseriesTableWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); + this.timeseriesTableWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); + this.timeseriesTableWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); + } + + private getColumns(datasources?: Datasource[]): DataKey[] { + if (datasources && datasources.length) { + const dataKeys = deepClone(datasources[0].dataKeys) || []; + dataKeys.forEach(k => { + (k as any).latest = false; + }); + const latestDataKeys = deepClone(datasources[0].latestDataKeys) || []; + latestDataKeys.forEach(k => { + (k as any).latest = true; + }); + return dataKeys.concat(latestDataKeys); + } + return []; + } + + private setColumns(columns: DataKey[], datasources?: Datasource[]) { + if (datasources && datasources.length) { + const dataKeys = deepClone(columns.filter(c => !(c as any).latest)); + dataKeys.forEach(k => delete (k as any).latest); + const latestDataKeys = deepClone(columns.filter(c => (c as any).latest)); + latestDataKeys.forEach(k => delete (k as any).latest); + datasources[0].dataKeys = dataKeys; + datasources[0].latestDataKeys = latestDataKeys; + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.settings?.enableSearch) || config.settings?.enableSearch) { + buttons.push('search'); + } + if (isUndefined(config.settings?.enableSelectColumnDisplay) || config.settings?.enableSelectColumnDisplay) { + buttons.push('columnsToDisplay'); + } + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.settings.enableSearch = buttons.includes('search'); + config.settings.enableSelectColumnDisplay = buttons.includes('columnsToDisplay'); + config.enableFullscreen = buttons.includes('fullscreen'); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/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 new file mode 100644 index 0000000000..51bb854826 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html @@ -0,0 +1,124 @@ + + + + + + +
+
widget-config.appearance
+ + + {{ valueCardLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.value-card.label' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widgets.value-card.icon' | translate }} + +
+ + + + + + + + +
+
+
+
widgets.value-card.value
+
+ + + +
widget-config.decimals-suffix
+
+ + + + +
+
+
+ + {{ 'widgets.value-card.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts new file mode 100644 index 0000000000..f00ec8e2e6 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts @@ -0,0 +1,286 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ChangeDetectorRef, Component, Injector } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { + datasourcesHasAggregation, + datasourcesHasOnlyComparisonAggregation, + WidgetConfig, +} from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; +import { formatValue, isDefinedAndNotNull, isUndefined } from '@core/utils'; +import { + DateFormatProcessor, + DateFormatSettings, + getLabel, + setLabel +} from '@home/components/widget/config/widget-settings.models'; +import { + valueCardDefaultSettings, + ValueCardLayout, + valueCardLayoutImages, + valueCardLayouts, + valueCardLayoutTranslations, + ValueCardWidgetSettings +} from '@home/components/widget/lib/cards/value-card-widget.models'; + +@Component({ + selector: 'tb-value-card-basic-config', + templateUrl: './value-card-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class ValueCardBasicConfigComponent extends BasicWidgetConfigComponent { + + public get displayTimewindowConfig(): boolean { + const datasources = this.valueCardWidgetConfigForm.get('datasources').value; + return datasourcesHasAggregation(datasources); + } + + public onlyHistoryTimewindow(): boolean { + const datasources = this.valueCardWidgetConfigForm.get('datasources').value; + return datasourcesHasOnlyComparisonAggregation(datasources); + } + + valueCardLayouts: ValueCardLayout[] = []; + + valueCardLayoutTranslationMap = valueCardLayoutTranslations; + valueCardLayoutImageMap = valueCardLayoutImages; + + horizontal = false; + + valueCardWidgetConfigForm: UntypedFormGroup; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + datePreviewFn = this._datePreviewFn.bind(this); + + get dateEnabled(): boolean { + const layout: ValueCardLayout = this.valueCardWidgetConfigForm.get('layout').value; + return ![ValueCardLayout.vertical, ValueCardLayout.simplified].includes(layout); + } + + get iconEnabled(): boolean { + const layout: ValueCardLayout = this.valueCardWidgetConfigForm.get('layout').value; + return layout !== ValueCardLayout.simplified; + } + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private cd: ChangeDetectorRef, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.valueCardWidgetConfigForm; + } + + protected setupConfig(widgetConfig: WidgetConfigComponentData) { + const params = widgetConfig.typeParameters as any; + this.horizontal = isDefinedAndNotNull(params.horizontal) ? params.horizontal : false; + this.valueCardLayouts = valueCardLayouts(this.horizontal); + super.setupConfig(widgetConfig); + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + this.setupDefaultDatasource(configData, [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries }]); + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: ValueCardWidgetSettings = {...valueCardDefaultSettings(this.horizontal), ...(configData.config.settings || {})}; + this.valueCardWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + datasources: [configData.config.datasources, []], + layout: [settings.layout, []], + + showLabel: [settings.showLabel, []], + label: [getLabel(configData.config.datasources), []], + labelFont: [settings.labelFont, []], + labelColor: [settings.labelColor, []], + + showIcon: [settings.showIcon, []], + iconSize: [settings.iconSize, [Validators.min(0)]], + iconSizeUnit: [settings.iconSizeUnit, []], + icon: [settings.icon, []], + iconColor: [settings.iconColor, []], + + units: [configData.config.units, []], + decimals: [configData.config.decimals, []], + valueFont: [settings.valueFont, []], + valueColor: [settings.valueColor, []], + + showDate: [settings.showDate, []], + dateFormat: [settings.dateFormat, []], + dateFont: [settings.dateFont, []], + dateColor: [settings.dateColor, []], + + background: [settings.background, []], + + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; + this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; + this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + this.widgetConfig.config.datasources = config.datasources; + + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + + this.widgetConfig.config.settings.layout = config.layout; + + this.widgetConfig.config.settings.showLabel = config.showLabel; + setLabel(config.label, this.widgetConfig.config.datasources); + this.widgetConfig.config.settings.labelFont = config.labelFont; + this.widgetConfig.config.settings.labelColor = config.labelColor; + + this.widgetConfig.config.settings.showIcon = config.showIcon; + this.widgetConfig.config.settings.iconSize = config.iconSize; + this.widgetConfig.config.settings.iconSizeUnit = config.iconSizeUnit; + this.widgetConfig.config.settings.icon = config.icon; + this.widgetConfig.config.settings.iconColor = config.iconColor; + + this.widgetConfig.config.units = config.units; + this.widgetConfig.config.decimals = config.decimals; + this.widgetConfig.config.settings.valueFont = config.valueFont; + this.widgetConfig.config.settings.valueColor = config.valueColor; + + this.widgetConfig.config.settings.showDate = config.showDate; + this.widgetConfig.config.settings.dateFormat = config.dateFormat; + this.widgetConfig.config.settings.dateFont = config.dateFont; + this.widgetConfig.config.settings.dateColor = config.dateColor; + + this.widgetConfig.config.settings.background = config.background; + + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['layout', 'showLabel', 'showIcon', 'showDate']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const layout: ValueCardLayout = this.valueCardWidgetConfigForm.get('layout').value; + const showLabel: boolean = this.valueCardWidgetConfigForm.get('showLabel').value; + const showIcon: boolean = this.valueCardWidgetConfigForm.get('showIcon').value; + const showDate: boolean = this.valueCardWidgetConfigForm.get('showDate').value; + + const dateEnabled = ![ValueCardLayout.vertical, ValueCardLayout.simplified].includes(layout); + const iconEnabled = layout !== ValueCardLayout.simplified; + + if (showLabel) { + this.valueCardWidgetConfigForm.get('label').enable(); + this.valueCardWidgetConfigForm.get('labelFont').enable(); + this.valueCardWidgetConfigForm.get('labelColor').enable(); + } else { + this.valueCardWidgetConfigForm.get('label').disable(); + this.valueCardWidgetConfigForm.get('labelFont').disable(); + this.valueCardWidgetConfigForm.get('labelColor').disable(); + } + + if (iconEnabled) { + this.valueCardWidgetConfigForm.get('showIcon').enable({emitEvent: false}); + if (showIcon) { + this.valueCardWidgetConfigForm.get('iconSize').enable(); + this.valueCardWidgetConfigForm.get('iconSizeUnit').enable(); + this.valueCardWidgetConfigForm.get('icon').enable(); + this.valueCardWidgetConfigForm.get('iconColor').enable(); + } else { + this.valueCardWidgetConfigForm.get('iconSize').disable(); + this.valueCardWidgetConfigForm.get('iconSizeUnit').disable(); + this.valueCardWidgetConfigForm.get('icon').disable(); + this.valueCardWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.valueCardWidgetConfigForm.get('showIcon').disable({emitEvent: false}); + this.valueCardWidgetConfigForm.get('iconSize').disable(); + this.valueCardWidgetConfigForm.get('iconSizeUnit').disable(); + this.valueCardWidgetConfigForm.get('icon').disable(); + this.valueCardWidgetConfigForm.get('iconColor').disable(); + } + + if (dateEnabled) { + this.valueCardWidgetConfigForm.get('showDate').enable({emitEvent: false}); + if (showDate) { + this.valueCardWidgetConfigForm.get('dateFormat').enable(); + this.valueCardWidgetConfigForm.get('dateFont').enable(); + this.valueCardWidgetConfigForm.get('dateColor').enable(); + } else { + this.valueCardWidgetConfigForm.get('dateFormat').disable(); + this.valueCardWidgetConfigForm.get('dateFont').disable(); + this.valueCardWidgetConfigForm.get('dateColor').disable(); + } + } else { + this.valueCardWidgetConfigForm.get('showDate').disable({emitEvent: false}); + this.valueCardWidgetConfigForm.get('dateFormat').disable(); + this.valueCardWidgetConfigForm.get('dateFont').disable(); + this.valueCardWidgetConfigForm.get('dateColor').disable(); + } + this.valueCardWidgetConfigForm.get('showIcon').updateValueAndValidity({emitEvent: false}); + this.valueCardWidgetConfigForm.get('showDate').updateValueAndValidity({emitEvent: false}); + this.valueCardWidgetConfigForm.get('label').updateValueAndValidity({emitEvent}); + this.valueCardWidgetConfigForm.get('labelFont').updateValueAndValidity({emitEvent}); + this.valueCardWidgetConfigForm.get('labelColor').updateValueAndValidity({emitEvent}); + this.valueCardWidgetConfigForm.get('iconSize').updateValueAndValidity({emitEvent}); + this.valueCardWidgetConfigForm.get('iconSizeUnit').updateValueAndValidity({emitEvent}); + this.valueCardWidgetConfigForm.get('icon').updateValueAndValidity({emitEvent}); + this.valueCardWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); + this.valueCardWidgetConfigForm.get('dateFormat').updateValueAndValidity({emitEvent}); + this.valueCardWidgetConfigForm.get('dateFont').updateValueAndValidity({emitEvent}); + this.valueCardWidgetConfigForm.get('dateColor').updateValueAndValidity({emitEvent}); + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + + private _valuePreviewFn(): string { + const units: string = this.valueCardWidgetConfigForm.get('units').value; + const decimals: number = this.valueCardWidgetConfigForm.get('decimals').value; + return formatValue(22, decimals, units, true); + } + + private _datePreviewFn(): string { + const dateFormat: DateFormatSettings = this.valueCardWidgetConfigForm.get('dateFormat').value; + const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat); + processor.update(Date.now()); + return processor.formatted; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html new file mode 100644 index 0000000000..1439f74931 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html @@ -0,0 +1,115 @@ + + + + + + + + +
+
widget-config.card-appearance
+
+ + {{ 'widget-config.card-title' | translate }} + + + + +
+
+ + {{ 'widget-config.card-icon' | translate }} + +
+ + + + +
+
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.text-color' | translate }}
+ + +
+
+
{{ 'widget-config.background-color' | translate }}
+ + +
+
+
+
widgets.chart.chart-appearance
+
+ + {{ 'widgets.chart.vertical-grid-lines' | translate }} + +
+
+ + {{ 'widgets.chart.horizontal-grid-lines' | translate }} + +
+
+ + + + + {{ 'widget-config.legend' | translate }} + + + + + + + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts new file mode 100644 index 0000000000..9d3dc4f1dd --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts @@ -0,0 +1,168 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { isUndefined } from '@core/utils'; +import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; + +@Component({ + selector: 'tb-flot-basic-config', + templateUrl: './flot-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { + + public get datasource(): Datasource { + const datasources: Datasource[] = this.flotWidgetConfigForm.get('datasources').value; + if (datasources && datasources.length) { + return datasources[0]; + } else { + return null; + } + } + + flotWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.flotWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + this.setupDefaultDatasource(configData, + [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }]); + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + this.flotWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + datasources: [configData.config.datasources, []], + series: [this.getSeries(configData.config.datasources), []], + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + showTitleIcon: [configData.config.showTitleIcon, []], + titleIcon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + color: [configData.config.color, []], + backgroundColor: [configData.config.backgroundColor, []], + verticalLines: [configData.config.settings?.grid?.verticalLines, []], + horizontalLines: [configData.config.settings?.grid?.horizontalLines, []], + showLegend: [configData.config.settings?.showLegend, []], + legendConfig: [configData.config.settings?.legendConfig, []], + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; + this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; + this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + this.widgetConfig.config.datasources = config.datasources; + this.setSeries(config.series, this.widgetConfig.config.datasources); + this.widgetConfig.config.actions = config.actions; + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.title = config.title; + this.widgetConfig.config.showTitleIcon = config.showTitleIcon; + this.widgetConfig.config.titleIcon = config.titleIcon; + this.widgetConfig.config.iconColor = config.iconColor; + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.color = config.color; + this.widgetConfig.config.backgroundColor = config.backgroundColor; + this.widgetConfig.config.settings.grid = this.widgetConfig.config.settings.grid || {}; + this.widgetConfig.config.settings.grid.verticalLines = config.verticalLines; + this.widgetConfig.config.settings.grid.horizontalLines = config.horizontalLines; + this.widgetConfig.config.settings.showLegend = config.showLegend; + this.widgetConfig.config.settings.legendConfig = config.legendConfig; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showTitleIcon', 'showLegend']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.flotWidgetConfigForm.get('showTitle').value; + const showTitleIcon: boolean = this.flotWidgetConfigForm.get('showTitleIcon').value; + const showLegend: boolean = this.flotWidgetConfigForm.get('showLegend').value; + if (showTitle) { + this.flotWidgetConfigForm.get('title').enable(); + this.flotWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); + if (showTitleIcon) { + this.flotWidgetConfigForm.get('titleIcon').enable(); + this.flotWidgetConfigForm.get('iconColor').enable(); + } else { + this.flotWidgetConfigForm.get('titleIcon').disable(); + this.flotWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.flotWidgetConfigForm.get('title').disable(); + this.flotWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); + this.flotWidgetConfigForm.get('titleIcon').disable(); + this.flotWidgetConfigForm.get('iconColor').disable(); + } + if (showLegend) { + this.flotWidgetConfigForm.get('legendConfig').enable(); + } else { + this.flotWidgetConfigForm.get('legendConfig').disable(); + } + this.flotWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.flotWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); + this.flotWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); + this.flotWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); + this.flotWidgetConfigForm.get('legendConfig').updateValueAndValidity({emitEvent}); + } + + private getSeries(datasources?: Datasource[]): DataKey[] { + if (datasources && datasources.length) { + return datasources[0].dataKeys || []; + } + return []; + } + + private setSeries(series: DataKey[], datasources?: Datasource[]) { + if (datasources && datasources.length) { + datasources[0].dataKeys = series; + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html index 0ae6ffb05e..22c4c2aace 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html @@ -15,8 +15,14 @@ limitations under the License. --> -
- +
+ + + {{ 'datakey.timeseries' | translate }} + {{ 'datakey.latest' | translate }} + + + @@ -38,7 +44,7 @@ matTooltipPosition="above">timeline
-
+
@@ -133,7 +139,7 @@ - +
@@ -141,16 +147,32 @@ formControlName="color">
-
- + - +
-
- +
+
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss index 5b3d4f1a80..fabd561a97 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss @@ -14,12 +14,6 @@ * limitations under the License. */ .tb-data-key-row { - height: 38px; - display: flex; - flex-direction: row; - gap: 12px; - padding-left: 12px; - .mat-mdc-form-field.tb-inline-field.tb-key-field { .mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) { .mat-mdc-form-field-infix { @@ -43,11 +37,33 @@ } } + .tb-source-field { + width: 120px; + min-width: 120px; + } + + .tb-key-field { + flex: 1 1 60%; + } + + .tb-label-field { + flex: 1 1 40%; + } + .tb-color-field, .tb-units-field, .tb-decimals-field { - width: 60px; display: flex; flex-direction: row; place-content: center; align-items: center; } + + .tb-units-field { + width: 80px; + min-width: 80px; + } + + .tb-color-field, .tb-decimals-field { + width: 60px; + min-width: 60px; + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts index d434ef74e3..7cdf277631 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts @@ -18,10 +18,12 @@ import { ChangeDetectorRef, Component, ElementRef, + EventEmitter, forwardRef, Input, OnChanges, OnInit, + Output, SimpleChanges, ViewChild, ViewEncapsulation @@ -37,7 +39,14 @@ import { } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; -import { DataKey, DatasourceType, JsonSettingsSchema, Widget, widgetType } from '@shared/models/widget.models'; +import { + DataKey, + DataKeyConfigMode, + DatasourceType, + JsonSettingsSchema, + Widget, + widgetType +} from '@shared/models/widget.models'; import { DataKeysPanelComponent } from '@home/components/widget/config/basic/common/data-keys-panel.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { AggregationType } from '@shared/models/time/time.models'; @@ -104,6 +113,9 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan @Input() deviceId: string; + @Output() + keyRemoved = new EventEmitter(); + keyFormControl: UntypedFormControl; keyRowFormGroup: UntypedFormGroup; @@ -133,6 +145,14 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan return this.dataKeysPanelComponent.hideDataKeyColor; } + get hideUnits(): boolean { + return this.dataKeysPanelComponent.hideUnits; + } + + get hideDecimals(): boolean { + return this.dataKeysPanelComponent.hideDecimals; + } + get widgetType(): widgetType { return this.widgetConfigComponent.widgetType; } @@ -141,6 +161,10 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan return this.widgetConfigComponent.widgetConfigCallbacks; } + get hasAdditionalLatestDataKeys(): boolean { + return this.dataKeysPanelComponent.hasAdditionalLatestDataKeys; + } + get widget(): Widget { return this.widgetConfigComponent.widget; } @@ -153,7 +177,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan return this.widgetConfigComponent.aliasController; } - get datakeySettingsSchema(): JsonSettingsSchema { + get dataKeySettingsSchema(): JsonSettingsSchema { return this.widgetConfigComponent.modelValue?.dataKeySettingsSchema; } @@ -161,6 +185,14 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan return this.widgetConfigComponent.modelValue?.dataKeySettingsDirective; } + get latestDataKeySettingsSchema(): JsonSettingsSchema { + return this.widgetConfigComponent.modelValue?.latestDataKeySettingsSchema; + } + + get latestDataKeySettingsDirective(): string { + return this.widgetConfigComponent.modelValue?.latestDataKeySettingsDirective; + } + get isEntityDatasource(): boolean { return [DatasourceType.device, DatasourceType.entity].includes(this.datasourceType); } @@ -169,6 +201,22 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan return this.modelValue.type && ![ DataKeyType.alarm, DataKeyType.entityField, DataKeyType.count ].includes(this.modelValue.type); } + get keySettingsTitle(): string { + return this.dataKeysPanelComponent.keySettingsTitle; + } + + get removeKeyTitle(): string { + return this.dataKeysPanelComponent.removeKeyTitle; + } + + get dragEnabled(): boolean { + return this.dataKeysPanelComponent.dragEnabled; + } + + get isLatestDataKeys(): boolean { + return this.hasAdditionalLatestDataKeys && this.keyRowFormGroup.get('latest').value === true; + } + private propagateChange = (_val: any) => {}; constructor(private fb: UntypedFormBuilder, @@ -188,6 +236,12 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan units: [null, []], decimals: [null, []], }); + if (this.hasAdditionalLatestDataKeys) { + this.keyRowFormGroup.addControl('latest', this.fb.control(false)); + this.keyRowFormGroup.valueChanges.subscribe( + () => this.clearKeySearchCache() + ); + } this.keyRowFormGroup.valueChanges.subscribe( () => this.updateModel() ); @@ -262,6 +316,11 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan decimals: value?.decimals }, {emitEvent: false} ); + if (this.hasAdditionalLatestDataKeys) { + this.keyRowFormGroup.patchValue({ + latest: (value as any)?.latest + }, {emitEvent: false}); + } this.cd.markForCheck(); } @@ -291,15 +350,16 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan } } - editKey() { + editKey(advanced = false) { this.dialog.open(DataKeyConfigDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { dataKey: deepClone(this.modelValue), - dataKeySettingsSchema: this.datakeySettingsSchema, - dataKeySettingsDirective: this.dataKeySettingsDirective, + dataKeyConfigMode: advanced ? DataKeyConfigMode.advanced : DataKeyConfigMode.general, + dataKeySettingsSchema: this.isLatestDataKeys ? this.latestDataKeySettingsSchema : this.dataKeySettingsSchema, + dataKeySettingsDirective: this.isLatestDataKeys ? this.latestDataKeySettingsDirective : this.dataKeySettingsDirective, dashboard: this.dashboard, aliasController: this.aliasController, widget: this.widget, @@ -374,7 +434,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan } else if (this.datasourceType === DatasourceType.entity && this.entityAliasId || this.datasourceType === DatasourceType.device && this.deviceId) { const dataKeyTypes = [DataKeyType.timeseries]; - if (this.widgetType === widgetType.latest || this.widgetType === widgetType.alarm) { + if (this.isLatestDataKeys || this.widgetType === widgetType.latest || this.widgetType === widgetType.alarm) { dataKeyTypes.push(DataKeyType.attribute); dataKeyTypes.push(DataKeyType.entityField); if (this.widgetType === widgetType.alarm) { @@ -403,7 +463,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan } private addKeyFromChipValue(chip: DataKey) { - this.modelValue = this.callbacks.generateDataKey(chip.name, chip.type, this.datakeySettingsSchema); + this.modelValue = this.callbacks.generateDataKey(chip.name, chip.type, this.dataKeySettingsSchema); if (!this.keyRowFormGroup.get('label').value) { this.keyRowFormGroup.get('label').patchValue(this.modelValue.label, {emitEvent: false}); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html index 754f0052c9..a2cddcde90 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html @@ -15,38 +15,37 @@ limitations under the License. --> -
-
{{ panelTitle }}
-
-
-
datakey.key
-
datakey.label
-
datakey.color
-
widget-config.units-short
-
widget-config.decimals-short
-
+
+
{{ panelTitle }}
+
+
+
datakey.source
+
datakey.key
+
datakey.label
+
datakey.color
+
widget-config.units-short
+
widget-config.decimals-short
+
-
-
+
+ [entityAliasId]="entityAliasId" + (keyRemoved)="removeKey($index)"> -
- +
+
-
+
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-quick-link-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-quick-link-dialog.component.html index 6eaf4ca205..75d60e046f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-quick-link-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-quick-link-dialog.component.html @@ -22,7 +22,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-link.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-link.component.html index 2d6ea9b3fa..52e6b54519 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-link.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-link.component.html @@ -38,8 +38,8 @@
- - + +
@@ -47,7 +47,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html index 1ccc2e8b24..e4b56e491b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html @@ -23,7 +23,7 @@ matTooltipPosition="above" mat-icon-button (click)="edit()"> - edit + edit
@@ -32,7 +32,7 @@ [href]="docLink.link" target="_blank"> @@ -43,7 +43,7 @@ matTooltip="{{ 'widgets.documentation.add-link' | translate }}" matTooltipPosition="above" (click)="addLink()"> - add + add
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-links-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-links-dialog.component.html index e70e8cd5c2..baddc057c2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-links-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-links-dialog.component.html @@ -22,7 +22,7 @@
@@ -60,7 +60,7 @@ matTooltip="{{ 'action.drag' | translate }}" matTooltipPosition="above" class="tb-drag-handle"> - drag_indicator + drag_indicator
@@ -71,7 +71,7 @@ matTooltip="{{ (mode === 'docs' ? 'widgets.documentation.add-link' : 'widgets.quick-links.add-link') | translate }}" matTooltipPosition="above" (click)="addLink()"> - add + add
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.html index 17ede099dc..9a575b001a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/getting-started-widget.component.html @@ -111,21 +111,10 @@
- + + Ubuntu + MacOS + Windows diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page-widget.scss b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page-widget.scss index 4cad7a6971..912ebbb63e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page-widget.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page-widget.scss @@ -67,50 +67,4 @@ color: inherit; } } - - .tb-no-data-available { - flex: 1; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - } - - .tb-no-data-bg { - margin: 10px; - position: relative; - flex: 1; - width: 100%; - max-height: 100px; - &:before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: #305680; - -webkit-mask-image: url(/assets/home/no_data_folder_bg.svg); - -webkit-mask-repeat: no-repeat; - -webkit-mask-size: contain; - -webkit-mask-position: center; - mask-image: url(/assets/home/no_data_folder_bg.svg); - mask-repeat: no-repeat; - mask-size: contain; - mask-position: center; - } - } - - .tb-no-data-text { - font-weight: 500; - font-size: 14px; - line-height: 20px; - letter-spacing: 0.25px; - color: rgba(0, 0, 0, 0.54); - @media #{$mat-md-lg} { - font-size: 12px; - line-height: 16px; - } - } - } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page.scss b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page.scss index a488d77c6e..4adf70d97d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page.scss @@ -23,6 +23,7 @@ letter-spacing: 0.2px; color: rgba(0, 0, 0, 0.76); .mat-icon { + vertical-align: bottom; margin-right: 10px; color: rgba(0, 0, 0, 0.54); font-size: 20px; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-link.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-link.component.html index 0dec41e71d..da1e9977a1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-link.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-link.component.html @@ -25,21 +25,19 @@ (focusin)="onFocus()" required [matAutocomplete]="linkAutocomplete"> - {{ quickLink.icon }} - + {{ quickLink.icon }} - {{ link.icon }} - + {{ link.icon }} @@ -58,8 +56,8 @@
- - + +
@@ -67,8 +65,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-links-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-links-widget.component.html index 95c2818f1c..58d3d98ee3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-links-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-links-widget.component.html @@ -23,7 +23,7 @@ matTooltipPosition="above" mat-icon-button (click)="edit()"> - edit + edit
@@ -32,8 +32,7 @@ [routerLink]="quickLink.path"> @@ -44,7 +43,7 @@ matTooltip="{{ 'widgets.quick-links.add-link' | translate }}" matTooltipPosition="above" (click)="addLink()"> - add + add
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/recent-dashboards-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/recent-dashboards-widget.component.html index ba7614934d..b2a085b917 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/recent-dashboards-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/recent-dashboards-widget.component.html @@ -20,16 +20,9 @@
{{ 'widgets.recent-dashboards.title' | translate }}
- + + {{ 'widgets.recent-dashboards.last' | translate }} + {{ 'widgets.recent-dashboards.starred' | translate }} {{ 'dashboard.add' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.html index a0beeacdb2..61e7c448b4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.html @@ -19,16 +19,9 @@
{{ 'widgets.usage-info.title' | translate }} - + + {{ 'widgets.usage-info.entities' | translate }} + {{ 'widgets.usage-info.api-calls' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/legend.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/legend.component.scss index ae61340873..a12903ff47 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/legend.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/legend.component.scss @@ -72,6 +72,7 @@ text-align: left; white-space: nowrap; outline: none; + cursor: pointer; &.tb-horizontal { width: 95%; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 0a757fd34f..ae739332be 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -23,12 +23,12 @@
{{ getGroupTitle(source.datasource) }} -
- + {{key.label}} - {{key.settings.icon}} + {{key.settings.icon}} icon @@ -50,7 +50,7 @@
- + {{key.label}} - {{key.settings.icon}} + {{key.settings.icon}} icon @@ -86,7 +86,7 @@
- + {{key.label}} - {{key.settings.icon}} + {{key.settings.icon}} icon @@ -123,7 +123,7 @@ [labelPosition]="key.settings.slideToggleLabelPosition" (change)="inputChanged(source, key)"> - {{key.settings.icon}} + {{key.settings.icon}} icon @@ -134,7 +134,7 @@
- + {{key.label}}
- + {{key.label}}
+ +
+
+ + {{key.settings.icon}} + + icon + + + {{key.label}} +
+ + +
-
-
-
+
+
{{ 'widgets.input-widgets.no-entity-selected' | translate }}
-
+
{{ 'widgets.input-widgets.not-allowed-entity' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss index d0dd324e52..3185bc8b17 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss @@ -21,7 +21,7 @@ flex-direction: column; .tb-multiple-input-container { - padding: 0 8px; + padding: 8px 8px 0; flex: 1 1 100%; overflow-x: hidden; overflow-y: auto; @@ -37,6 +37,28 @@ } } + .tb-multiple-input-layout { + display: flex; + flex-direction: row; + align-items: start; + } + + .color-picker-input { + padding: 7px 16px 7px 12px; + margin: 0 10px 22px 0; + border-color: rgba(0, 0, 0, 0.4); + + .label-container { + display: flex; + flex-direction: row; + align-items: center; + } + + .mat-icon, img { + margin-right: 5px; + } + } + .input-field { padding-right: 10px; @@ -61,6 +83,30 @@ .vertical-alignment { flex-direction: column; } + + &--buttons-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: end; + &__button { + max-height: 50px; + margin-right:20px; + } + } + + &--errors-container { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + &__error { + text-align: center; + font-size: 18px; + color: #a0a0a0; + } + } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index 534be7c676..6f29a495cf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -54,7 +54,7 @@ type FieldAlignment = 'row' | 'column'; type MultipleInputWidgetDataKeyType = 'server' | 'shared' | 'timeseries'; export type MultipleInputWidgetDataKeyValueType = 'string' | 'double' | 'integer' | 'JSON' | 'booleanCheckbox' | 'booleanSwitch' | - 'dateTime' | 'date' | 'time' | 'select'; + 'dateTime' | 'date' | 'time' | 'select' | 'color'; type MultipleInputWidgetDataKeyEditableType = 'editable' | 'disabled' | 'readonly'; type ConvertGetValueFunction = (value: any, ctx: WidgetContext) => any; @@ -390,6 +390,12 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } }); } + } else if (key.settings.dataKeyValueType === 'color') { + formControl.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => { + this.inputChanged(source, key); + }); } this.multipleInputFormGroup.addControl(key.formId, formControl); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.html index 0d33c487b7..dadf3317d8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.html @@ -16,6 +16,6 @@ --> - {{settings.icon}} + {{settings.icon}} {{translatedName}} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss index a04f82dce7..b9c3e034a7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss @@ -31,7 +31,7 @@ display: flex; flex-direction: column; align-items: center; - mat-icon { + .mat-icon { margin: auto !important; } span.mdc-button__label { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html index dbd4d50981..d63a4ef76f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html @@ -25,8 +25,7 @@ - {{place.icon}} - + {{place.icon}} {{place.name}} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss index f3710fbc81..7d41450655 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss @@ -55,7 +55,7 @@ display: flex; flex-direction: column; align-items: center; - mat-icon { + .mat-icon { margin: auto; } span.mdc-button__label { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html index 93b0742930..66f19f717a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html @@ -80,7 +80,7 @@ matTooltip="{{ actionDescriptor.displayName }}" matTooltipPosition="above" (click)="onActionButtonClick($event, column, actionDescriptor)"> - {{ actionDescriptor.icon }} + {{ actionDescriptor.icon }}
@@ -88,14 +88,14 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.html index a2ccedb34c..9baf6c998f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.html @@ -15,21 +15,56 @@ limitations under the License. --> -
- - widgets.table.custom-title - - - - widgets.table.column-width - - -
- widgets.table.cell-style + +
+
widgets.table.column-settings
+
+
{{ 'widgets.table.custom-title' | translate }}
+ + + +
+
+
{{ 'widgets.table.column-width' | translate }}
+ + + +
+
+
{{ 'widgets.table.default-column-visibility' | translate }}
+ + + + {{ 'widgets.table.column-visibility-visible' | translate }} + + + {{ 'widgets.table.column-visibility-hidden' | translate }} + + + {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} + + + +
+
+
{{ 'widgets.table.column-selection-to-display' | translate }}
+ + + + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} + + + {{ 'widgets.table.column-selection-to-display-disabled' | translate }} + + + +
+
+
- + - {{ 'widgets.table.use-cell-style-function' | translate }} @@ -48,13 +83,12 @@ -
-
- widgets.table.cell-content +
+
- + - {{ 'widgets.table.use-cell-content-function' | translate }} @@ -73,27 +107,5 @@ - - - widgets.table.default-column-visibility - - - {{ 'widgets.table.column-visibility-visible' | translate }} - - - {{ 'widgets.table.column-visibility-hidden' | translate }} - - - - - widgets.table.column-selection-to-display - - - {{ 'widgets.table.column-selection-to-display-enabled' | translate }} - - - {{ 'widgets.table.column-selection-to-display-disabled' | translate }} - - - -
+
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html index 534f12493d..4ec8f31be6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html @@ -15,38 +15,65 @@ limitations under the License. --> -
-
- widgets.table.common-table-settings - - widgets.table.alarms-table-title - - -
-
- - {{ 'widgets.table.enable-alarms-selection' | translate }} - - - {{ 'widgets.table.enable-alarms-search' | translate }} - - - {{ 'widgets.table.enable-select-column-display' | translate }} - - - {{ 'widgets.table.enable-alarm-filter' | translate }} - -
-
- - {{ 'widgets.table.enable-sticky-header' | translate }} - - - {{ 'widgets.table.enable-sticky-action' | translate }} - -
-
- + +
+
widgets.table.table-header
+
+
{{ 'widgets.table.alarms-table-title' | translate }}
+ + + +
+
+ + {{ 'widgets.table.enable-sticky-header' | translate }} + +
+
+
widgets.table.header-buttons
+ + {{ 'widgets.table.enable-alarms-search' | translate }} + + + {{ 'widgets.table.enable-select-column-display' | translate }} + + + {{ 'widgets.table.enable-alarm-filter' | translate }} + +
+
+
+
widgets.table.columns
+ + {{ 'widgets.table.enable-alarms-selection' | translate }} + +
+ + {{ 'widgets.table.enable-sticky-action' | translate }} + + + {{ 'widgets.table.show-cell-actions-menu-mobile' | translate }} + +
+
+
widgets.table.table-buttons
+ + {{ 'widgets.table.display-alarm-activity' | translate }} + + + {{ 'widgets.table.display-alarm-details' | translate }} + + + {{ 'widgets.table.allow-alarms-assign' | translate }} + + + {{ 'widgets.table.allow-alarms-ack' | translate }} + + + {{ 'widgets.table.allow-alarms-clear' | translate }} + +
+ widgets.table.hidden-cell-button-display-mode @@ -57,48 +84,34 @@ -
- - {{ 'widgets.table.display-alarm-activity' | translate }} - - - {{ 'widgets.table.display-alarm-details' | translate }} - - - {{ 'widgets.table.allow-alarms-ack' | translate }} - - - {{ 'widgets.table.allow-alarms-clear' | translate }} - - - {{ 'widgets.table.allow-alarms-assign' | translate }} - -
- - {{ 'widgets.table.display-pagination' | translate }} - - - widgets.table.default-page-size - - -
- - widgets.table.default-sort-order - + + widgets.table.default-sort-order + + +
+
+
widgets.table.pagination
+ + {{ 'widgets.table.display-pagination' | translate }} + +
+
widgets.table.default-page-size
+ + -
- -
- widgets.table.row-style + + +
+
widgets.table.rows
- - - + + {{ 'widgets.table.use-row-style-function' | translate }} - + widget-config.advanced-settings @@ -112,5 +125,5 @@ -
- + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts index 73dd5bfec0..223cf93e77 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts @@ -47,6 +47,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent enableFilter: true, enableStickyHeader: true, enableStickyAction: true, + showCellActionsMenu: true, reserveSpaceForHiddenAction: 'true', displayDetails: true, allowAcknowledgment: true, @@ -69,6 +70,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent enableFilter: [settings.enableFilter, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], + showCellActionsMenu: [settings.showCellActionsMenu, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], displayDetails: [settings.displayDetails, []], allowAcknowledgment: [settings.allowAcknowledgment, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html index d57f56cb59..02d51ee325 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html @@ -15,21 +15,56 @@ limitations under the License. --> -
- - widgets.table.custom-title - - - - widgets.table.column-width - - -
- widgets.table.cell-style + +
+
widgets.table.column-settings
+
+
{{ 'widgets.table.custom-title' | translate }}
+ + + +
+
+
{{ 'widgets.table.column-width' | translate }}
+ + + +
+
+
{{ 'widgets.table.default-column-visibility' | translate }}
+ + + + {{ 'widgets.table.column-visibility-visible' | translate }} + + + {{ 'widgets.table.column-visibility-hidden' | translate }} + + + {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} + + + +
+
+
{{ 'widgets.table.column-selection-to-display' | translate }}
+ + + + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} + + + {{ 'widgets.table.column-selection-to-display-disabled' | translate }} + + + +
+
+
- + - {{ 'widgets.table.use-cell-style-function' | translate }} @@ -48,13 +83,12 @@ -
-
- widgets.table.cell-content + +
- + - {{ 'widgets.table.use-cell-content-function' | translate }} @@ -73,30 +107,5 @@ -
- - widgets.table.default-column-visibility - - - {{ 'widgets.table.column-visibility-visible' | translate }} - - - {{ 'widgets.table.column-visibility-hidden' | translate }} - - - {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} - - - - - widgets.table.column-selection-to-display - - - {{ 'widgets.table.column-selection-to-display-enabled' | translate }} - - - {{ 'widgets.table.column-selection-to-display-disabled' | translate }} - - - -
+ + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html index c0680dfeb9..f8867b9f6a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html @@ -15,32 +15,62 @@ limitations under the License. --> -
-
- widgets.table.common-table-settings - - widgets.table.entities-table-title - - -
-
- - {{ 'widgets.table.enable-search' | translate }} - - - {{ 'widgets.table.enable-select-column-display' | translate }} - -
-
- - {{ 'widgets.table.enable-sticky-header' | translate }} - - - {{ 'widgets.table.enable-sticky-action' | translate }} - -
-
- + +
+
widgets.table.table-header
+
+
{{ 'widgets.table.entities-table-title' | translate }}
+ + + +
+
+ + {{ 'widgets.table.enable-sticky-header' | translate }} + +
+
+
widgets.table.header-buttons
+ + {{ 'widgets.table.enable-search' | translate }} + + + {{ 'widgets.table.enable-select-column-display' | translate }} + +
+
+
+
widgets.table.columns
+
+ + {{ 'widgets.table.display-entity-name' | translate }} + + + + +
+
+ + {{ 'widgets.table.display-entity-label' | translate }} + + + + +
+
+ + {{ 'widgets.table.display-entity-type' | translate }} + +
+
+ + {{ 'widgets.table.enable-sticky-action' | translate }} + + + {{ 'widgets.table.show-cell-actions-menu-mobile' | translate }} + +
+ widgets.table.hidden-cell-button-display-mode @@ -51,54 +81,34 @@ -
-
- - {{ 'widgets.table.display-entity-name' | translate }} - - - widgets.table.entity-name-column-title - - -
-
- - {{ 'widgets.table.display-entity-label' | translate }} - - - widgets.table.entity-label-column-title - - -
- - {{ 'widgets.table.display-entity-type' | translate }} - -
- - {{ 'widgets.table.display-pagination' | translate }} - - - widgets.table.default-page-size - - -
- - widgets.table.default-sort-order - + + widgets.table.default-sort-order + + +
+
+
widgets.table.pagination
+ + {{ 'widgets.table.display-pagination' | translate }} + +
+
widgets.table.default-page-size
+ + -
- -
- widgets.table.row-style + + +
+
widgets.table.rows
- - - + + {{ 'widgets.table.use-row-style-function' | translate }} - + widget-config.advanced-settings @@ -112,5 +122,5 @@ -
- + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts index a65422ae2d..402d6bba4f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts @@ -45,6 +45,7 @@ export class EntitiesTableWidgetSettingsComponent extends WidgetSettingsComponen enableSelectColumnDisplay: true, enableStickyHeader: true, enableStickyAction: true, + showCellActionsMenu: true, reserveSpaceForHiddenAction: 'true', displayEntityName: true, entityNameColumnTitle: '', @@ -66,6 +67,7 @@ export class EntitiesTableWidgetSettingsComponent extends WidgetSettingsComponen enableSelectColumnDisplay: [settings.enableSelectColumnDisplay, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], + showCellActionsMenu: [settings.showCellActionsMenu, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], displayEntityName: [settings.displayEntityName, []], entityNameColumnTitle: [settings.entityNameColumnTitle, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts index d91baebb53..af32954e62 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts @@ -33,7 +33,7 @@ export interface LabelWidgetLabel { @Component({ selector: 'tb-label-widget-label', templateUrl: './label-widget-label.component.html', - styleUrls: ['./label-widget-label.component.scss', './../widget-settings.scss'], + styleUrls: ['./label-widget-label.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/simple-card-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/simple-card-widget-settings.component.html index 1ee182f923..dc201c1cc6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/simple-card-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/simple-card-widget-settings.component.html @@ -15,9 +15,9 @@ limitations under the License. --> -
-
widgets.simple-card.label
-
+
+
widgets.simple-card.label
+
widgets.simple-card.label-position
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html index 2dbedf96bd..6c79eed622 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html @@ -15,18 +15,49 @@ limitations under the License. --> -
-
- widgets.table.cell-style + +
+
widgets.table.column-settings
+
+
{{ 'widgets.table.default-column-visibility' | translate }}
+ + + + {{ 'widgets.table.column-visibility-visible' | translate }} + + + {{ 'widgets.table.column-visibility-hidden' | translate }} + + + {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} + + + +
+
+
{{ 'widgets.table.column-selection-to-display' | translate }}
+ + + + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} + + + {{ 'widgets.table.column-selection-to-display-disabled' | translate }} + + + +
+
+
- - - + + {{ 'widgets.table.use-cell-style-function' | translate }} - + widget-config.advanced-settings @@ -40,18 +71,17 @@ -
-
- widgets.table.cell-content +
+
- - - + + {{ 'widgets.table.use-cell-content-function' | translate }} - + widget-config.advanced-settings @@ -65,30 +95,5 @@ - - - widgets.table.default-column-visibility - - - {{ 'widgets.table.column-visibility-visible' | translate }} - - - {{ 'widgets.table.column-visibility-hidden' | translate }} - - - {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} - - - - - widgets.table.column-selection-to-display - - - {{ 'widgets.table.column-selection-to-display-enabled' | translate }} - - - {{ 'widgets.table.column-selection-to-display-disabled' | translate }} - - - - +
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html index 8fb1629b13..97cbe28ae9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html @@ -15,25 +15,58 @@ limitations under the License. --> -
- - {{ 'widgets.table.show-latest-data-column' | translate }} - - - widgets.table.latest-data-column-order - - -
- widgets.table.cell-style + +
+
widgets.table.column-settings
+ + {{ 'widgets.table.show-latest-data-column' | translate }} + +
+
widgets.table.latest-data-column-order
+ + + +
+
+
{{ 'widgets.table.default-column-visibility' | translate }}
+ + + + {{ 'widgets.table.column-visibility-visible' | translate }} + + + {{ 'widgets.table.column-visibility-hidden' | translate }} + + + {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} + + + +
+
+
{{ 'widgets.table.column-selection-to-display' | translate }}
+ + + + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} + + + {{ 'widgets.table.column-selection-to-display-disabled' | translate }} + + + +
+
+
- - - + + {{ 'widgets.table.use-cell-style-function' | translate }} - + widget-config.advanced-settings @@ -47,18 +80,17 @@ -
-
- widgets.table.cell-content +
+
- - - + + {{ 'widgets.table.use-cell-content-function' | translate }} - + widget-config.advanced-settings @@ -72,30 +104,6 @@ - - - widgets.table.default-column-visibility - - - {{ 'widgets.table.column-visibility-visible' | translate }} - - - {{ 'widgets.table.column-visibility-hidden' | translate }} - - - {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} - - - - - widgets.table.column-selection-to-display - - - {{ 'widgets.table.column-selection-to-display-enabled' | translate }} - - - {{ 'widgets.table.column-selection-to-display-disabled' | translate }} - - - - +
+ + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index ed4428fe45..170d460f92 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -15,28 +15,34 @@ limitations under the License. --> -
-
- widgets.table.common-table-settings -
-
- - {{ 'widgets.table.enable-search' | translate }} - - - {{ 'widgets.table.enable-select-column-display' | translate }} - -
-
- - {{ 'widgets.table.enable-sticky-header' | translate }} - - - {{ 'widgets.table.enable-sticky-action' | translate }} - -
-
- + +
+
widgets.table.table-header
+ + {{ 'widgets.table.enable-sticky-header' | translate }} + + + {{ 'widgets.table.enable-search' | translate }} + + + {{ 'widgets.table.enable-select-column-display' | translate }} + +
+
+
widgets.table.columns
+ + {{ 'widgets.table.display-timestamp' | translate }} + + + {{ 'widgets.table.display-milliseconds' | translate }} + + + {{ 'widgets.table.enable-sticky-action' | translate }} + + + {{ 'widgets.table.show-cell-actions-menu-mobile' | translate }} + + widgets.table.hidden-cell-button-display-mode @@ -47,41 +53,39 @@ -
- - {{ 'widgets.table.display-timestamp' | translate }} - - - {{ 'widgets.table.display-milliseconds' | translate }} - -
- - {{ 'widgets.table.display-pagination' | translate }} - - - widgets.table.default-page-size - - -
- - {{ 'widgets.table.use-entity-label-tab-name' | translate }} - - - {{ 'widgets.table.hide-empty-lines' | translate }} - -
-
-
- widgets.table.row-style +
+
+
widgets.table.pagination
+ + {{ 'widgets.table.display-pagination' | translate }} + +
+
widgets.table.default-page-size
+ + + +
+
+
+
widgets.table.table-tabs
+ + {{ 'widgets.table.use-entity-label-tab-name' | translate }} + +
+
+
widgets.table.rows
+ + {{ 'widgets.table.hide-empty-lines' | translate }} + - - - + + {{ 'widgets.table.use-row-style-function' | translate }} - + widget-config.advanced-settings @@ -95,5 +99,5 @@ - - +
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts index 0a57402870..eaa86f6503 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts @@ -44,6 +44,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon enableSelectColumnDisplay: true, enableStickyHeader: true, enableStickyAction: true, + showCellActionsMenu: true, reserveSpaceForHiddenAction: 'true', showTimestamp: true, showMilliseconds: false, @@ -63,6 +64,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon enableSelectColumnDisplay: [settings.enableSelectColumnDisplay, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], + showCellActionsMenu: [settings.showCellActionsMenu, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], showTimestamp: [settings.showTimestamp, []], showMilliseconds: [settings.showMilliseconds, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html new file mode 100644 index 0000000000..423c727a8d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html @@ -0,0 +1,89 @@ + + +
+
widgets.value-card.value-card-style
+ + + {{ valueCardLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.value-card.label' | translate }} + +
+ + + + +
+
+
+ + {{ 'widgets.value-card.icon' | translate }} + +
+ + + + + + + + +
+
+
+
widgets.value-card.value
+
+ + + + +
+
+
+ + {{ 'widgets.value-card.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts new file mode 100644 index 0000000000..6f76546ac1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts @@ -0,0 +1,200 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Injector } from '@angular/core'; +import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { + valueCardDefaultSettings, + ValueCardLayout, valueCardLayoutImages, + valueCardLayouts, valueCardLayoutTranslations +} from '@home/components/widget/lib/cards/value-card-widget.models'; +import { formatValue, isDefinedAndNotNull } from '@core/utils'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { + DateFormatProcessor, + DateFormatSettings, + getLabel +} from '@home/components/widget/config/widget-settings.models'; + +@Component({ + selector: 'tb-value-card-widget-settings', + templateUrl: './value-card-widget-settings.component.html', + styleUrls: [] +}) +export class ValueCardWidgetSettingsComponent extends WidgetSettingsComponent { + + valueCardLayouts: ValueCardLayout[] = []; + + valueCardLayoutTranslationMap = valueCardLayoutTranslations; + valueCardLayoutImageMap = valueCardLayoutImages; + + horizontal = false; + + valueCardWidgetSettingsForm: UntypedFormGroup; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + datePreviewFn = this._datePreviewFn.bind(this); + + + get label(): string { + return getLabel(this.widgetConfig.config.datasources); + } + + get dateEnabled(): boolean { + const layout: ValueCardLayout = this.valueCardWidgetSettingsForm.get('layout').value; + return ![ValueCardLayout.vertical, ValueCardLayout.simplified].includes(layout); + } + + get iconEnabled(): boolean { + const layout: ValueCardLayout = this.valueCardWidgetSettingsForm.get('layout').value; + return layout !== ValueCardLayout.simplified; + } + + constructor(protected store: Store, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.valueCardWidgetSettingsForm; + } + + protected onWidgetConfigSet(widgetConfig: WidgetConfigComponentData) { + const params = widgetConfig.typeParameters as any; + this.horizontal = isDefinedAndNotNull(params.horizontal) ? params.horizontal : false; + this.valueCardLayouts = valueCardLayouts(this.horizontal); + } + + protected defaultSettings(): WidgetSettings { + return valueCardDefaultSettings(this.horizontal); + } + + protected onSettingsSet(settings: WidgetSettings) { + this.valueCardWidgetSettingsForm = this.fb.group({ + layout: [settings.layout, []], + + showLabel: [settings.showLabel, []], + labelFont: [settings.labelFont, []], + labelColor: [settings.labelColor, []], + + showIcon: [settings.showIcon, []], + iconSize: [settings.iconSize, [Validators.min(0)]], + iconSizeUnit: [settings.iconSizeUnit, []], + icon: [settings.icon, []], + iconColor: [settings.iconColor, []], + + valueFont: [settings.valueFont, []], + valueColor: [settings.valueColor, []], + + showDate: [settings.showDate, []], + dateFormat: [settings.dateFormat, []], + dateFont: [settings.dateFont, []], + dateColor: [settings.dateColor, []], + + background: [settings.background, []] + }); + } + + protected validatorTriggers(): string[] { + return ['layout', 'showLabel', 'showIcon', 'showDate']; + } + + protected updateValidators(emitEvent: boolean) { + const layout: ValueCardLayout = this.valueCardWidgetSettingsForm.get('layout').value; + const showLabel: boolean = this.valueCardWidgetSettingsForm.get('showLabel').value; + const showIcon: boolean = this.valueCardWidgetSettingsForm.get('showIcon').value; + const showDate: boolean = this.valueCardWidgetSettingsForm.get('showDate').value; + + const dateEnabled = ![ValueCardLayout.vertical, ValueCardLayout.simplified].includes(layout); + const iconEnabled = layout !== ValueCardLayout.simplified; + + if (showLabel) { + this.valueCardWidgetSettingsForm.get('labelFont').enable(); + this.valueCardWidgetSettingsForm.get('labelColor').enable(); + } else { + this.valueCardWidgetSettingsForm.get('labelFont').disable(); + this.valueCardWidgetSettingsForm.get('labelColor').disable(); + } + + if (iconEnabled) { + this.valueCardWidgetSettingsForm.get('showIcon').enable({emitEvent: false}); + if (showIcon) { + this.valueCardWidgetSettingsForm.get('iconSize').enable(); + this.valueCardWidgetSettingsForm.get('iconSizeUnit').enable(); + this.valueCardWidgetSettingsForm.get('icon').enable(); + this.valueCardWidgetSettingsForm.get('iconColor').enable(); + } else { + this.valueCardWidgetSettingsForm.get('iconSize').disable(); + this.valueCardWidgetSettingsForm.get('iconSizeUnit').disable(); + this.valueCardWidgetSettingsForm.get('icon').disable(); + this.valueCardWidgetSettingsForm.get('iconColor').disable(); + } + } else { + this.valueCardWidgetSettingsForm.get('showIcon').disable({emitEvent: false}); + this.valueCardWidgetSettingsForm.get('iconSize').disable(); + this.valueCardWidgetSettingsForm.get('iconSizeUnit').disable(); + this.valueCardWidgetSettingsForm.get('icon').disable(); + this.valueCardWidgetSettingsForm.get('iconColor').disable(); + } + + if (dateEnabled) { + this.valueCardWidgetSettingsForm.get('showDate').enable({emitEvent: false}); + if (showDate) { + this.valueCardWidgetSettingsForm.get('dateFormat').enable(); + this.valueCardWidgetSettingsForm.get('dateFont').enable(); + this.valueCardWidgetSettingsForm.get('dateColor').enable(); + } else { + this.valueCardWidgetSettingsForm.get('dateFormat').disable(); + this.valueCardWidgetSettingsForm.get('dateFont').disable(); + this.valueCardWidgetSettingsForm.get('dateColor').disable(); + } + } else { + this.valueCardWidgetSettingsForm.get('showDate').disable({emitEvent: false}); + this.valueCardWidgetSettingsForm.get('dateFormat').disable(); + this.valueCardWidgetSettingsForm.get('dateFont').disable(); + this.valueCardWidgetSettingsForm.get('dateColor').disable(); + } + this.valueCardWidgetSettingsForm.get('showIcon').updateValueAndValidity({emitEvent: false}); + this.valueCardWidgetSettingsForm.get('showDate').updateValueAndValidity({emitEvent: false}); + this.valueCardWidgetSettingsForm.get('labelFont').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('labelColor').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('iconSize').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('iconSizeUnit').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('icon').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('iconColor').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('dateFormat').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('dateFont').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('dateColor').updateValueAndValidity({emitEvent}); + } + + private _valuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(22, decimals, units, true); + } + + private _datePreviewFn(): string { + const dateFormat: DateFormatSettings = this.valueCardWidgetSettingsForm.get('dateFormat').value; + const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat); + processor.update(Date.now()); + return processor.formatted; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html index 2bebfeef8a..96ff4d8559 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html @@ -15,81 +15,85 @@ limitations under the License. --> -
-
- widgets.chart.common-settings - + +
+ {{ 'widgets.chart.data-is-hidden-by-default' | translate }} - - + + {{ 'widgets.chart.disable-data-hiding' | translate }} - - + + {{ 'widgets.chart.remove-from-legend' | translate }} - - + + {{ 'widgets.chart.exclude-from-stacking' | translate }} - -
-
- widgets.chart.line-settings + +
+
- - - + + {{ 'widgets.chart.show-line' | translate }} - + widget-config.advanced-settings -
- - widgets.chart.line-width - +
+
{{ 'widgets.chart.line-width' | translate }}
+ + + px - - {{ 'widgets.chart.fill-line' | translate }} - - - widgets.chart.fill-line-opacity - +
+ + {{ 'widgets.chart.fill-line' | translate }} + +
+
{{ 'widgets.chart.fill-line-opacity' | translate }}
+ + -
+
- -
- widgets.chart.points-settings + +
- - - + + {{ 'widgets.chart.show-points' | translate }} - + widget-config.advanced-settings -
-
- - widgets.chart.points-line-width - - - - widgets.chart.points-radius - - -
- - widgets.chart.point-shape +
+
{{ 'widgets.chart.points-line-width' | translate }}
+ + + px + +
+
+
{{ 'widgets.chart.points-radius' | translate }}
+ + + px + +
+
+
{{ 'widgets.chart.point-shape' | translate }}
+ {{ 'widgets.chart.point-shape-circle' | translate }} @@ -111,19 +115,19 @@ - - -
+
+ + -
-
- widgets.chart.tooltip-settings + +
+
widgets.chart.tooltip-settings
-
-
- widgets.chart.yaxis-settings - + +
+
widgets.chart.vertical-axis
+ {{ 'widgets.chart.show-separate-axis' | translate }} - - widgets.chart.axis-title - - -
- - widgets.chart.min-scale-value - +
+
widgets.chart.axis-title
+ + - - widgets.chart.max-scale-value - +
+
+
widgets.chart.min-scale-value
+ + -
- - widgets.chart.axis-position - - - {{ 'widgets.chart.axis-position-left' | translate }} - - - {{ 'widgets.chart.axis-position-right' | translate }} - - - -
- widgets.chart.yaxis-tick-labels-settings -
- - widgets.chart.tick-step-size - +
+
+
widgets.chart.max-scale-value
+ + + +
+
+
{{ 'widgets.chart.axis-position' | translate }}
+ + + + {{ 'widgets.chart.axis-position-left' | translate }} + + + {{ 'widgets.chart.axis-position-right' | translate }} + + + +
+
+
widgets.chart.ticks
+
+
widget-config.decimals-short
+ + - - widgets.chart.number-of-decimals - +
+
+
widgets.chart.tick-step-size
+ + - +
-
- -
- widgets.chart.thresholds -
-
-
- - -
-
-
- widgets.chart.no-thresholds -
-
- +
+
+
+
+
widgets.chart.thresholds
+ +
+
+
+ +
-
-
- widgets.chart.comparison-settings - + +
+
widgets.chart.comparison-settings
+ - - + {{ 'widgets.chart.show-values-for-comparison' | translate }} - - widget-config.advanced-settings - -
- - widgets.chart.comparison-values-label - +
+
widgets.chart.comparison-values-label
+ + - +
+
+
{{ 'widgets.chart.comparison-line-color' | translate }}
+ -
+
-
- + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts index b2c88e5fcb..f254eaeb2e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts @@ -225,6 +225,7 @@ export class FlotKeySettingsComponent extends PageComponent implements OnInit, C this.flotKeySettingsFormGroup.disable({emitEvent: false}); } else { this.flotKeySettingsFormGroup.enable({emitEvent: false}); + this.updateValidators(false); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html index 61f1587306..286d26481b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html @@ -15,34 +15,34 @@ limitations under the License. --> -
-
- widgets.chart.threshold-settings - + +
+
widgets.chart.threshold-settings
+ - {{ 'widgets.chart.use-as-threshold' | translate }} - - widget-config.advanced-settings - -
- - widgets.chart.threshold-line-width - +
+
widgets.chart.threshold-line-width
+ + + px - +
+
+
{{ 'widgets.chart.threshold-color' | translate }}
+ -
+
-
-
+ + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html index 353e716ad9..6f08b5f3f7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html @@ -15,44 +15,34 @@ limitations under the License. --> - - -
- -
-
{{ thresholdText() }}
-
-
-
-
-
- - -
-
- -
- -
- -
- - widgets.chart.line-width - - - - -
-
-
-
-
+
+ + +
+
{{ thresholdText() }}
+ + + + +
+
+ + +
+
widgets.chart.line-width
+ + + px + +
+
+
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss index 53eeafb799..150d516894 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss @@ -13,28 +13,60 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -:host { - display: block; - .mat-expansion-panel { + +.tb-flot-threshold { + display: flex; + flex-direction: row; + align-items: start; + gap: 4px; + .mat-expansion-panel.tb-settings.tb-flot-threshold-settings { box-shadow: none; - &.flot-threshold { - border: 1px groove rgba(0, 0, 0, .25); - .mat-expansion-panel-header { - padding: 0 24px 0 8px; - &.mat-expanded { - height: 48px; + border-radius: 6px; + border: 1px solid rgba(0, 0, 0, 0.12); + .mat-expansion-panel-header { + height: 56px; + border-radius: 0; + display: flex; + flex-direction: row; + align-items: stretch; + .tb-threshold-header { + flex: 1; + display: flex; + flex-direction: row; + gap: 16px; + align-items: center; + padding-left: 16px; + .mat-divider-vertical { + height: 100%; } } + .tb-threshold-text { + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.15px; + } + .mat-expansion-indicator { + margin-right: 22px; + margin-left: 22px; + margin-top: 12px; + } } - } -} - -:host ::ng-deep { - .mat-expansion-panel { - &.flot-threshold { - .mat-expansion-panel-body { - padding: 0 8px 8px; + > .mat-expansion-panel-content { + > .mat-expansion-panel-body { + padding: 16px !important; } } + &.mat-expanded { + .mat-expansion-panel-header { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); + } + } + } + > .mdc-icon-button { + margin-top: 4px; + color: rgba(0, 0, 0, 0.54); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts index 9b997ed424..eb55c12f86 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts @@ -15,8 +15,14 @@ /// import { ValueSourceProperty } from '@home/components/widget/lib/settings/common/value-source.component'; -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { Component, EventEmitter, forwardRef, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { + ControlValueAccessor, + NG_VALUE_ACCESSOR, + UntypedFormBuilder, + UntypedFormGroup, + Validators +} from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -28,14 +34,15 @@ import { TbFlotKeyThreshold } from '@home/components/widget/lib/flot-widget.mode @Component({ selector: 'tb-flot-threshold', templateUrl: './flot-threshold.component.html', - styleUrls: ['./flot-threshold.component.scss', './../widget-settings.scss'], + styleUrls: ['./flot-threshold.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FlotThresholdComponent), multi: true } - ] + ], + encapsulation: ViewEncapsulation.None }) export class FlotThresholdComponent extends PageComponent implements OnInit, ControlValueAccessor { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html index 5422c034f6..5dd7eaa2dc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html @@ -15,30 +15,33 @@ limitations under the License. --> -
-
- widgets.chart.common-settings - + +
+
widgets.chart.common-settings
+ {{ 'widgets.chart.enable-stacking-mode' | translate }} - -
- - widgets.chart.line-shadow-size - + + + {{ 'widgets.chart.enable-selection-mode' | translate }} + + + {{ 'widgets.chart.display-smooth-lines' | translate }} + +
+
widgets.chart.line-shadow-size
+ + - - {{ 'widgets.chart.display-smooth-lines' | translate }} - -
-
- - widgets.chart.default-bar-width - +
+
+
widgets.chart.default-bar-width
+ + - - widgets.chart.bar-alignment +
+
+
{{ 'widgets.chart.bar-alignment' | translate }}
+ {{ 'widgets.chart.bar-alignment-left' | translate }} @@ -51,211 +54,241 @@ -
-
- - widgets.chart.default-font-size - + +
+
widgets.chart.thresholds-line-width
+ + - - -
- - widgets.chart.thresholds-line-width - - - -
- widget-config.legend + +
+
{{ 'widgets.chart.default-font' | translate }}
+
+ + + px + + + +
+
+ +
+
widget-config.legend
- + - - {{ 'widget-config.display-legend' | translate }} + + {{ 'widget-config.legend' | translate }} - + widget-config.advanced-settings - + + -
-
- widgets.chart.tooltip-settings + +
+
widgets.chart.axis
+
+
widgets.chart.vertical-axis
+
+
widgets.chart.axis-title
+ + + +
+
+
widgets.chart.min-scale-value
+ + + +
+
+
widgets.chart.max-scale-value
+ + + +
+
+
widgets.chart.ticks
+ + + + + {{ 'widgets.chart.ticks' | translate }} + + + + widget-config.advanced-settings + + + +
+
{{ 'widget-config.color' | translate }}
+ + +
+
+
widget-config.decimals-short
+ + + +
+
+
widgets.chart.tick-step-size
+ + + +
+ + +
+
+
+
+
+
widgets.chart.horizontal-axis
+
+
widgets.chart.axis-title
+ + + +
+
+
widgets.chart.ticks
+ + + + + {{ 'widgets.chart.ticks' | translate }} + + + + widget-config.advanced-settings + + + +
+
{{ 'widget-config.color' | translate }}
+ + +
+
+
+
+
+
+
+
widgets.chart.chart-background
+
+ + {{ 'widgets.chart.vertical-grid-lines' | translate }} + +
+
+ + {{ 'widgets.chart.horizontal-grid-lines' | translate }} + +
+
+
{{ 'widgets.chart.grid-lines-color' | translate }}
+ + +
+
+
{{ 'widgets.chart.border' | translate }}
+
+ + + px + + + +
+
+
+
{{ 'widgets.chart.background-color' | translate }}
+ + +
+
+
+
widgets.chart.tooltip
- - - + + - {{ 'widgets.chart.show-tooltip' | translate }} + {{ 'widgets.chart.tooltip' | translate }} - + widget-config.advanced-settings -
- +
+ {{ 'widgets.chart.hover-individual-points' | translate }} - +
+
+ {{ 'widgets.chart.show-cumulative-values' | translate }} - +
+
+ {{ 'widgets.chart.hide-zero-false-values' | translate }} - - -
+
+ + -
-
- widgets.chart.grid-settings - - {{ 'widgets.chart.show-vertical-lines' | translate }} - - - {{ 'widgets.chart.show-horizontal-lines' | translate }} - - - widgets.chart.grid-outline-border-width - - - - - - - - -
-
- widgets.chart.xaxis-settings - - widgets.chart.axis-title - - -
- widgets.chart.xaxis-tick-labels-settings - - - - - {{ 'widgets.chart.show-tick-labels' | translate }} - - - - widget-config.advanced-settings - - - - - - - -
-
-
- widgets.chart.yaxis-settings - - widgets.chart.axis-title - - -
- - widgets.chart.min-scale-value - - - - widgets.chart.max-scale-value - - -
-
- widgets.chart.yaxis-tick-labels-settings - - - - - {{ 'widgets.chart.show-tick-labels' | translate }} - - - - widget-config.advanced-settings - - - - - -
- - widgets.chart.tick-step-size - - - - widgets.chart.number-of-decimals - - -
- - -
-
-
-
-
- widgets.chart.comparison-settings + +
+
widgets.chart.comparison-settings
- - - + + {{ 'widgets.chart.enable-comparison' | translate }} - + widget-config.advanced-settings -
- - widgets.chart.time-for-comparison +
+
{{ 'widgets.chart.time-for-comparison' | translate }}
+ {{ 'widgets.chart.time-for-comparison-previous-interval' | translate }} @@ -277,18 +310,29 @@ - - widgets.chart.custom-interval-value - +
+
+
widgets.chart.custom-interval-value
+ + -
- widgets.chart.comparison-x-axis-settings - - widgets.chart.axis-title - +
+
+
widgets.chart.comparison-x-axis-settings
+
+
widgets.chart.axis-title
+ + - - widgets.chart.axis-position +
+
+ + {{ 'widgets.chart.show-tick-labels' | translate }} + +
+
+
{{ 'widgets.chart.axis-position' | translate }}
+ {{ 'widgets.chart.axis-position-top' | translate }} @@ -298,31 +342,28 @@ - - {{ 'widgets.chart.show-tick-labels' | translate }} - -
- + + - -
- widgets.chart.custom-legend-settings + +
+
widgets.chart.custom-legend-settings
- + - + {{ 'widgets.chart.enable-custom-legend' | translate }} - + widget-config.advanced-settings -
- widgets.chart.label-keys-list +
+
widgets.chart.label-keys-list
@@ -348,8 +389,8 @@
-
+
-
- + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts index 98c4acd62b..46454937f6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts @@ -45,6 +45,7 @@ import { defaultLegendConfig, widgetType } from '@shared/models/widget.models'; export const flotDefaultSettings = (chartType: ChartType): Partial => { const settings: Partial = { stack: false, + enableSelection: true, fontColor: '#545454', fontSize: 10, showTooltip: true, @@ -148,6 +149,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit // Common settings stack: [false, []], + enableSelection: [true, []], fontSize: [10, [Validators.min(0)]], fontColor: ['#545454', []], @@ -282,6 +284,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit this.flotSettingsFormGroup.disable({emitEvent: false}); } else { this.flotSettingsFormGroup.enable({emitEvent: false}); + this.updateValidators(false); } } @@ -377,9 +380,11 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit } else { this.flotSettingsFormGroup.get('comparisonCustomIntervalValue').disable({emitEvent}); } + this.flotSettingsFormGroup.get('xaxisSecond').enable({emitEvent: false}); } else { this.flotSettingsFormGroup.get('timeForComparison').disable({emitEvent: false}); this.flotSettingsFormGroup.get('comparisonCustomIntervalValue').disable({emitEvent}); + this.flotSettingsFormGroup.get('xaxisSecond').disable({emitEvent: false}); } if (customLegendEnabled) { this.flotSettingsFormGroup.get('dataKeysListForLabels').enable({emitEvent}); @@ -390,6 +395,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit this.flotSettingsFormGroup.get('legendConfig').updateValueAndValidity({emitEvent: false}); this.flotSettingsFormGroup.get('timeForComparison').updateValueAndValidity({emitEvent: false}); this.flotSettingsFormGroup.get('comparisonCustomIntervalValue').updateValueAndValidity({emitEvent: false}); + this.flotSettingsFormGroup.get('xaxisSecond').updateValueAndValidity({emitEvent: false}); this.flotSettingsFormGroup.get('dataKeysListForLabels').updateValueAndValidity({emitEvent: false}); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts index 0cd2cad7c7..0cc661cb44 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts @@ -47,7 +47,7 @@ export function labelDataKeyValidator(control: AbstractControl): ValidationError @Component({ selector: 'tb-label-data-key', templateUrl: './label-data-key.component.html', - styleUrls: ['./label-data-key.component.scss', './../widget-settings.scss'], + styleUrls: ['./label-data-key.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.html new file mode 100644 index 0000000000..ca5d4bc8b9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.html @@ -0,0 +1,87 @@ + +
+
widgets.background.background-settings
+
+
+
widgets.background.background
+ + + {{ backgroundTypeTranslationsMap.get(type) | translate }} + + +
+ +
+
widgets.background.image-url
+ + + +
+
+
widgets.color.color
+ + +
+
+
+
widgets.background.overlay
+ + {{ 'widgets.background.enable-overlay' | translate }} + +
+
widgets.color.color
+ + +
+
+
widgets.background.blur
+ + +
px
+
+
+
+
+
+ widgets.background.preview +
+
+
+
+
+
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss new file mode 100644 index 0000000000..258117512a --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss @@ -0,0 +1,73 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import '../../../../../../../../scss/constants'; + +.tb-background-settings-panel { + width: 620px; + display: flex; + flex-direction: column; + gap: 16px; + @media #{$mat-lt-md} { + width: 90vw; + } + .tb-background-settings-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-background-settings-preview { + flex: 1; + background: rgba(0, 0, 0, 0.04); + display: flex; + flex-direction: column; + padding: 12px 16px 24px 16px; + align-items: center; + gap: 12px; + } + .tb-background-settings-preview-title { + align-self: stretch; + font-size: 16px; + font-style: normal; + font-weight: 500; + line-height: 24px; + color: rgba(0, 0, 0, 0.38); + } + .tb-background-settings-preview-box { + position: relative; + width: 136px; + height: 118px; + border-radius: 2.666px; + } + .tb-background-settings-preview-overlay { + position: absolute; + border-radius: 2.666px; + top: 7.998px; + bottom: 7.998px; + left: 7.998px; + right: 7.998px; + } + .tb-background-settings-panel-buttons { + height: 40px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts new file mode 100644 index 0000000000..51d2ddec1b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts @@ -0,0 +1,120 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { + backgroundStyle, + overlayStyle, + BackgroundSettings, + BackgroundType, + backgroundTypeTranslations, ComponentStyle +} from '@home/components/widget/config/widget-settings.models'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; + +@Component({ + selector: 'tb-background-settings-panel', + templateUrl: './background-settings-panel.component.html', + providers: [], + styleUrls: ['./background-settings-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class BackgroundSettingsPanelComponent extends PageComponent implements OnInit { + + @Input() + backgroundSettings: BackgroundSettings; + + @Input() + popover: TbPopoverComponent; + + @Output() + backgroundSettingsApplied = new EventEmitter(); + + backgroundType = BackgroundType; + + backgroundTypes = Object.keys(BackgroundType) as BackgroundType[]; + + backgroundTypeTranslationsMap = backgroundTypeTranslations; + + backgroundSettingsFormGroup: UntypedFormGroup; + + backgroundStyle: ComponentStyle = {}; + overlayStyle: ComponentStyle = {}; + + constructor(private fb: UntypedFormBuilder, + protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.backgroundSettingsFormGroup = this.fb.group( + { + type: [this.backgroundSettings?.type, []], + imageBase64: [this.backgroundSettings?.imageBase64, []], + imageUrl: [this.backgroundSettings?.imageUrl, []], + color: [this.backgroundSettings?.color, []], + overlay: this.fb.group({ + enabled: [this.backgroundSettings?.overlay?.enabled, []], + color: [this.backgroundSettings?.overlay?.color, []], + blur: [this.backgroundSettings?.overlay?.blur, []] + }) + } + ); + this.backgroundSettingsFormGroup.get('type').valueChanges.subscribe(() => { + setTimeout(() => {this.popover?.updatePosition();}, 0); + }); + this.backgroundSettingsFormGroup.get('overlay').get('enabled').valueChanges.subscribe(() => { + this.updateValidators(); + }); + this.backgroundSettingsFormGroup.valueChanges.subscribe(() => { + this.updateBackgroundStyle(); + }); + this.updateValidators(); + this.updateBackgroundStyle(); + } + + cancel() { + this.popover?.hide(); + } + + applyColorSettings() { + const backgroundSettings = this.backgroundSettingsFormGroup.value; + this.backgroundSettingsApplied.emit(backgroundSettings); + } + + private updateValidators() { + const overlayEnabled: boolean = this.backgroundSettingsFormGroup.get('overlay').get('enabled').value; + if (overlayEnabled) { + this.backgroundSettingsFormGroup.get('overlay').get('color').enable(); + this.backgroundSettingsFormGroup.get('overlay').get('blur').enable(); + } else { + this.backgroundSettingsFormGroup.get('overlay').get('color').disable(); + this.backgroundSettingsFormGroup.get('overlay').get('blur').disable(); + } + this.backgroundSettingsFormGroup.get('overlay').get('color').updateValueAndValidity({emitEvent: false}); + this.backgroundSettingsFormGroup.get('overlay').get('blur').updateValueAndValidity({emitEvent: false}); + } + + private updateBackgroundStyle() { + const background: BackgroundSettings = this.backgroundSettingsFormGroup.value; + this.backgroundStyle = backgroundStyle(background); + this.overlayStyle = overlayStyle(background.overlay); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.html new file mode 100644 index 0000000000..e9e1b99b0e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.html @@ -0,0 +1,30 @@ + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.scss new file mode 100644 index 0000000000..6f73fbffa4 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.scss @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +button.mat-mdc-button-base.tb-box-button.tb-background-settings { + padding: 0; + .mat-mdc-button-persistent-ripple { + z-index: 2; + } + .tb-color-preview { + width: 38px; + min-width: 38px; + height: 38px; + &.box { + .tb-color-result { + &:after { + border: none; + } + } + .tb-color-overlay { + position: absolute; + border-radius: 3px; + top: 4px; + bottom: 4px; + left: 4px; + right: 4px; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts new file mode 100644 index 0000000000..f8162575a3 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts @@ -0,0 +1,120 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef, ViewEncapsulation } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { + BackgroundSettings, + backgroundStyle, + BackgroundType, + ComponentStyle, + overlayStyle +} from '@home/components/widget/config/widget-settings.models'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { + BackgroundSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/background-settings-panel.component'; + +@Component({ + selector: 'tb-background-settings', + templateUrl: './background-settings.component.html', + styleUrls: ['./background-settings.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => BackgroundSettingsComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None +}) +export class BackgroundSettingsComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + backgroundType = BackgroundType; + + modelValue: BackgroundSettings; + + backgroundStyle: ComponentStyle = {}; + + overlayStyle: ComponentStyle = {}; + + private propagateChange = null; + + constructor(private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + this.updateBackgroundStyle(); + } + + writeValue(value: BackgroundSettings): void { + this.modelValue = value; + this.updateBackgroundStyle(); + } + + openBackgroundSettingsPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + backgroundSettings: this.modelValue + }; + const backgroundSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, BackgroundSettingsPanelComponent, 'left', true, null, + ctx, + {}, + {}, {}, true); + backgroundSettingsPanelPopover.tbComponentRef.instance.popover = backgroundSettingsPanelPopover; + backgroundSettingsPanelPopover.tbComponentRef.instance.backgroundSettingsApplied.subscribe((backgroundSettings) => { + backgroundSettingsPanelPopover.hide(); + this.modelValue = backgroundSettings; + this.updateBackgroundStyle(); + this.propagateChange(this.modelValue); + }); + } + } + + private updateBackgroundStyle() { + if (!this.disabled) { + this.backgroundStyle = backgroundStyle(this.modelValue); + this.overlayStyle = overlayStyle(this.modelValue.overlay); + } else { + this.backgroundStyle = {}; + this.overlayStyle = {}; + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.html new file mode 100644 index 0000000000..cd8cf1bc06 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.html @@ -0,0 +1,105 @@ + +
+
widgets.color.color-settings
+
+ + + {{ colorTypeTranslationsMap.get(type) | translate }} + + +
+
+
widgets.color.color
+ + +
+
+
+
+ +
+
+ +
+
+ + +
+
+ + +
+
widgets.color.value-range
+
+
+
+
+
widgets.color.from
+ + + +
widgets.color.to
+ + + + + +
+ +
+
+
+ +
+
+ +
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.scss new file mode 100644 index 0000000000..0036723b92 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.scss @@ -0,0 +1,85 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import '../../../../../../../../scss/constants'; + +.tb-color-settings-panel { + width: 500px; + height: 470px; + display: flex; + flex-direction: column; + gap: 16px; + @media #{$mat-xs} { + width: 90vw; + } + .tb-color-settings-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-color-ranges-panel { + flex: 1; + min-height: 0; + gap: 16px; + display: flex; + flex-direction: column; + } + .tb-color-ranges { + flex: 1; + gap: 12px; + display: flex; + flex-direction: column; + overflow: auto; + } + .tb-form-row { + height: auto; + .tb-value-range-text { + width: 64px; + font-size: 14px; + color: rgba(0, 0, 0, 0.38); + @media #{$mat-xs} { + width: auto; + } + &.tb-value-range-text-to { + text-align: center; + } + } + } + button.mat-mdc-button-base.tb-add-color-range { + &:not(:disabled) { + color: rgba(0, 0, 0, 0.54); + } + &:disabled { + color: rgba(0, 0, 0, 0.12); + } + } + .tb-color-settings-panel-body { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; + } + .tb-color-settings-panel-buttons { + height: 40px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts new file mode 100644 index 0000000000..2118bde6df --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts @@ -0,0 +1,133 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { + ColorRange, + ColorSettings, + ColorType, + colorTypeTranslations +} from '@home/components/widget/config/widget-settings.models'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { + AbstractControl, + FormControl, + FormGroup, + UntypedFormArray, + UntypedFormBuilder, + UntypedFormGroup +} from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Datasource, DatasourceType } from '@shared/models/widget.models'; +import { deepClone } from '@core/utils'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { WidgetService } from '@core/http/widget.service'; + +@Component({ + selector: 'tb-color-settings-panel', + templateUrl: './color-settings-panel.component.html', + providers: [], + styleUrls: ['./color-settings-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ColorSettingsPanelComponent extends PageComponent implements OnInit { + + @Input() + colorSettings: ColorSettings; + + @Input() + popover: TbPopoverComponent; + + @Output() + colorSettingsApplied = new EventEmitter(); + + colorType = ColorType; + + colorTypes = Object.keys(ColorType) as ColorType[]; + + colorTypeTranslationsMap = colorTypeTranslations; + + colorSettingsFormGroup: UntypedFormGroup; + + functionScopeVariables = this.widgetService.getWidgetScopeVariables(); + + constructor(private fb: UntypedFormBuilder, + private widgetService: WidgetService, + protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.colorSettingsFormGroup = this.fb.group( + { + type: [this.colorSettings?.type, []], + color: [this.colorSettings?.color, []], + rangeList: this.fb.array((this.colorSettings?.rangeList || []).map(r => this.colorRangeControl(r))), + colorFunction: [this.colorSettings?.colorFunction, []] + } + ); + this.colorSettingsFormGroup.get('type').valueChanges.subscribe(() => { + setTimeout(() => {this.popover?.updatePosition();}, 0); + }); + } + + private colorRangeControl(range: ColorRange): AbstractControl { + return this.fb.group({ + from: [range?.from, []], + to: [range?.to, []], + color: [range?.color, []] + }); + } + + get rangeListFormArray(): UntypedFormArray { + return this.colorSettingsFormGroup.get('rangeList') as UntypedFormArray; + } + + get rangeListFormGroups(): FormGroup[] { + return this.rangeListFormArray.controls as FormGroup[]; + } + + trackByRange(index: number, rangeControl: AbstractControl): any { + return rangeControl; + } + + removeRange(index: number) { + this.rangeListFormArray.removeAt(index); + this.colorSettingsFormGroup.markAsDirty(); + setTimeout(() => {this.popover?.updatePosition();}, 0); + } + + addRange() { + const newRange: ColorRange = { + color: 'rgba(0,0,0,0.87)' + }; + this.rangeListFormArray.push(this.colorRangeControl(newRange)); + this.colorSettingsFormGroup.markAsDirty(); + setTimeout(() => {this.popover?.updatePosition();}, 0); + } + + cancel() { + this.popover?.hide(); + } + + applyColorSettings() { + const colorSettings = this.colorSettingsFormGroup.value; + this.colorSettingsApplied.emit(colorSettings); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.html new file mode 100644 index 0000000000..3c058113e1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.html @@ -0,0 +1,30 @@ + + + +
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts new file mode 100644 index 0000000000..bffad41080 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts @@ -0,0 +1,124 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ColorSettings, ColorType, ComponentStyle } from '@home/components/widget/config/widget-settings.models'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { + ColorSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/color-settings-panel.component'; + +@Component({ + selector: 'tb-color-settings', + templateUrl: './color-settings.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ColorSettingsComponent), + multi: true + } + ] +}) +export class ColorSettingsComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + colorType = ColorType; + + modelValue: ColorSettings; + + colorStyle: ComponentStyle = {}; + + private propagateChange = null; + + constructor(private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + this.updateColorStyle(); + } + + writeValue(value: ColorSettings): void { + this.modelValue = value; + this.updateColorStyle(); + } + + openColorSettingsPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + colorSettings: this.modelValue + }; + const colorSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, ColorSettingsPanelComponent, 'left', true, null, + ctx, + {}, + {}, {}, true); + colorSettingsPanelPopover.tbComponentRef.instance.popover = colorSettingsPanelPopover; + colorSettingsPanelPopover.tbComponentRef.instance.colorSettingsApplied.subscribe((colorSettings) => { + colorSettingsPanelPopover.hide(); + this.modelValue = colorSettings; + this.updateColorStyle(); + this.propagateChange(this.modelValue); + }); + } + } + + private updateColorStyle() { + if (!this.disabled) { + let colors: string[] = [this.modelValue.color]; + if (this.modelValue.type === ColorType.range && this.modelValue.rangeList?.length) { + const rangeColors = this.modelValue.rangeList.slice(0, Math.min(2, this.modelValue.rangeList.length)).map(r => r.color); + colors = colors.concat(rangeColors); + } + if (colors.length === 1) { + this.colorStyle = {backgroundColor: colors[0]}; + } else { + const gradientValues: string[] = []; + const step = 100 / colors.length; + for (let i = 0; i < colors.length; i++) { + gradientValues.push(`${colors[i]} ${step*i}%`); + gradientValues.push(`${colors[i]} ${step*(i+1)}%`); + } + this.colorStyle = {background: `linear-gradient(90deg, ${gradientValues.join(', ')})`}; + } + } else { + this.colorStyle = {}; + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-units.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html similarity index 72% rename from ui-ngx/src/app/modules/home/components/widget/config/widget-units.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html index a2ed480388..eaca1b6d40 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-units.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html @@ -15,6 +15,8 @@ limitations under the License. --> - - + + + {{ cssUnit }} + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts new file mode 100644 index 0000000000..dc593e9564 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts @@ -0,0 +1,82 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; +import { cssUnit, cssUnits } from '@home/components/widget/config/widget-settings.models'; + +@Component({ + selector: 'tb-css-unit-select', + templateUrl: './css-unit-select.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CssUnitSelectComponent), + multi: true + } + ] +}) +export class CssUnitSelectComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + cssUnitsList = cssUnits; + + cssUnitFormControl: UntypedFormControl; + + modelValue: cssUnit; + + private propagateChange = null; + + constructor() {} + + ngOnInit(): void { + this.cssUnitFormControl = new UntypedFormControl(); + this.cssUnitFormControl.valueChanges.subscribe((value: cssUnit) => { + this.updateModel(value); + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.cssUnitFormControl.disable(); + } else { + this.cssUnitFormControl.enable(); + } + } + + writeValue(value: cssUnit): void { + this.modelValue = value; + this.cssUnitFormControl.patchValue(this.modelValue, {emitEvent: false}); + } + + updateModel(value: cssUnit): void { + if (this.modelValue !== value) { + this.modelValue = value; + this.propagateChange(this.modelValue); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.html new file mode 100644 index 0000000000..7310d0c403 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.html @@ -0,0 +1,26 @@ + + + + {{ dateFormatDisplayValue(dateFormat) }} + + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts new file mode 100644 index 0000000000..413111ad1e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts @@ -0,0 +1,148 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input, OnInit, Renderer2, ViewChild, ViewContainerRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; +import { + compareDateFormats, + dateFormats, + DateFormatSettings +} from '@home/components/widget/config/widget-settings.models'; +import { TranslateService } from '@ngx-translate/core'; +import { DatePipe } from '@angular/common'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { deepClone } from '@core/utils'; +import { + DateFormatSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/date-format-settings-panel.component'; + +@Component({ + selector: 'tb-date-format-select', + templateUrl: './date-format-select.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DateFormatSelectComponent), + multi: true + } + ] +}) +export class DateFormatSelectComponent implements OnInit, ControlValueAccessor { + + @ViewChild('customFormatButton', {static: false}) + customFormatButton: MatButton; + + @Input() + disabled: boolean; + + dateFormatList = dateFormats; + + dateFormatsCompare = compareDateFormats; + + dateFormatFormControl: UntypedFormControl; + + modelValue: DateFormatSettings; + + private propagateChange = null; + + private formatCache: {[format: string]: string} = {}; + + constructor(private translate: TranslateService, + private date: DatePipe, + private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void { + this.dateFormatFormControl = new UntypedFormControl(); + this.dateFormatFormControl.valueChanges.subscribe((value: DateFormatSettings) => { + this.updateModel(value); + if (value?.custom) { + setTimeout(() => { + this.openDateFormatSettingsPopup(null, this.customFormatButton); + }, 0); + } + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.dateFormatFormControl.disable(); + } else { + this.dateFormatFormControl.enable(); + } + } + + writeValue(value: DateFormatSettings): void { + this.modelValue = value; + this.dateFormatFormControl.patchValue(this.modelValue, {emitEvent: false}); + } + + updateModel(value: DateFormatSettings): void { + if (!compareDateFormats(this.modelValue, value)) { + this.modelValue = value; + this.propagateChange(this.modelValue); + } + } + + dateFormatDisplayValue(value: DateFormatSettings): string { + if (value.custom) { + return this.translate.instant('date.custom-date'); + } else if (value.lastUpdateAgo) { + return this.translate.instant('date.last-update-n-ago'); + } else { + if (!this.formatCache[value.format]) { + this.formatCache[value.format] = this.date.transform(Date.now(), value.format); + } + return this.formatCache[value.format]; + } + } + + openDateFormatSettingsPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + dateFormat: deepClone(this.modelValue) + }; + const dateFormatSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, DateFormatSettingsPanelComponent, 'top', true, null, + ctx, + {}, + {}, {}, true); + dateFormatSettingsPanelPopover.tbComponentRef.instance.popover = dateFormatSettingsPanelPopover; + dateFormatSettingsPanelPopover.tbComponentRef.instance.dateFormatApplied.subscribe((dateFormat) => { + dateFormatSettingsPanelPopover.hide(); + this.modelValue = dateFormat; + this.propagateChange(this.modelValue); + }); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html new file mode 100644 index 0000000000..ee332924f0 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html @@ -0,0 +1,47 @@ + +
+
date.custom-date
+
+
date.format
+ + +
+
+
+ +
+
date.preview
+
{{ previewText }}
+
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss new file mode 100644 index 0000000000..ec6a762966 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss @@ -0,0 +1,67 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import '../../../../../../../../scss/constants'; + +.tb-date-format-settings-panel { + width: 500px; + display: flex; + flex-direction: column; + gap: 16px; + @media #{$mat-xs} { + width: 90vw; + } + .tb-date-format-settings-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-form-row { + .fixed-title-width { + min-width: 120px; + } + &.date-format-preview { + align-items: flex-start; + .preview-text { + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; + letter-spacing: 0.2px; + color: rgba(0, 0, 0, 0.38); + } + } + .mat-mdc-form-field.tb-date-format-input { + .mat-mdc-text-field-wrapper.mdc-text-field--outlined { + .mat-mdc-form-field-icon-suffix { + display: flex; + align-items: center; + line-height: normal; + } + } + } + } + .tb-date-format-settings-panel-buttons { + height: 60px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts new file mode 100644 index 0000000000..47f54fd5d5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts @@ -0,0 +1,70 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { DateFormatSettings } from '@home/components/widget/config/widget-settings.models'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { UntypedFormControl, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { DatePipe } from '@angular/common'; + +@Component({ + selector: 'tb-date-format-settings-panel', + templateUrl: './date-format-settings-panel.component.html', + providers: [], + styleUrls: ['./date-format-settings-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class DateFormatSettingsPanelComponent extends PageComponent implements OnInit { + + @Input() + dateFormat: DateFormatSettings; + + @Input() + popover: TbPopoverComponent; + + @Output() + dateFormatApplied = new EventEmitter(); + + dateFormatFormControl: UntypedFormControl; + + previewText = ''; + + constructor(private date: DatePipe, + protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.dateFormatFormControl = new UntypedFormControl(this.dateFormat.format, [Validators.required]); + this.dateFormatFormControl.valueChanges.subscribe((value: string) => { + this.previewText = this.date.transform(Date.now(), value); + }); + this.previewText = this.date.transform(Date.now(), this.dateFormat.format); + } + + cancel() { + this.popover?.hide(); + } + + applyDateFormat() { + this.dateFormat.format = this.dateFormatFormControl.value; + this.dateFormatApplied.emit(this.dateFormat); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html new file mode 100644 index 0000000000..140c525ac2 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html @@ -0,0 +1,91 @@ + +
+
widgets.widget-font.font-settings
+
+
widgets.widget-font.size
+
+ + + + +
+
+
+
widgets.widget-font.font-family
+ + + + + + + + + +
+
+
widgets.widget-font.font-weight
+ + + + {{ fontWeightTranslationsMap.has(weight) ? (fontWeightTranslationsMap.get(weight) | translate) : weight }} + + + +
+
+
widgets.widget-font.font-style
+ + + + {{ fontStyleTranslationsMap.get(style) | translate }} + + + +
+ +
+
widgets.widget-font.preview
+
{{ previewText }}
+
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.scss new file mode 100644 index 0000000000..3475a14e8c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.scss @@ -0,0 +1,51 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.tb-font-settings-panel { + width: 100%; + display: flex; + flex-direction: column; + gap: 16px; + .tb-font-settings-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-form-row { + .fixed-title-width { + min-width: 120px; + } + &.font-preview { + align-items: flex-start; + .preview-text { + max-height: 300px; + max-width: 400px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + } + .tb-font-settings-panel-buttons { + height: 60px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts new file mode 100644 index 0000000000..91a71bc8d7 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts @@ -0,0 +1,133 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + Component, + ElementRef, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { + commonFonts, + ComponentStyle, + Font, + fontStyles, + fontStyleTranslations, + fontWeights, + fontWeightTranslations, + textStyle +} from '@home/components/widget/config/widget-settings.models'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Observable } from 'rxjs'; +import { map, startWith, tap } from 'rxjs/operators'; + +@Component({ + selector: 'tb-font-settings-panel', + templateUrl: './font-settings-panel.component.html', + providers: [], + styleUrls: ['./font-settings-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class FontSettingsPanelComponent extends PageComponent implements OnInit { + + @Input() + font: Font; + + @Input() + previewText = 'AaBbCcDd'; + + @Input() + popover: TbPopoverComponent; + + @Output() + fontApplied = new EventEmitter(); + + @ViewChild('familyInput', {static: true}) familyInput: ElementRef; + + fontWeightsList = fontWeights; + + fontWeightTranslationsMap = fontWeightTranslations; + + fontStylesList = fontStyles; + + fontStyleTranslationsMap = fontStyleTranslations; + + fontFormGroup: UntypedFormGroup; + + filteredFontFamilies: Observable>; + + familySearchText = ''; + + previewStyle: ComponentStyle = {}; + + constructor(private fb: UntypedFormBuilder, + protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.fontFormGroup = this.fb.group( + { + size: [this.font?.size, [Validators.required, Validators.min(0)]], + sizeUnit: [this.font?.sizeUnit, [Validators.required]], + family: [this.font?.family, [Validators.required]], + weight: [this.font?.weight, [Validators.required]], + style: [this.font?.style, [Validators.required]] + } + ); + if (this.font) { + this.previewStyle = textStyle(this.font, '1'); + } + this.fontFormGroup.valueChanges.subscribe((value: Font) => { + if (this.fontFormGroup.valid) { + this.previewStyle = textStyle(value, '1'); + setTimeout(() => {this.popover?.updatePosition();}, 0); + } + }); + this.filteredFontFamilies = this.fontFormGroup.get('family').valueChanges + .pipe( + startWith(''), + tap((searchText) => { this.familySearchText = searchText || ''; }), + map(() => commonFonts.filter(f => f.toUpperCase().includes(this.familySearchText.toUpperCase()))) + ); + } + + clearFamily() { + this.fontFormGroup.get('family').patchValue(null, {emitEvent: true}); + setTimeout(() => { + this.familyInput.nativeElement.blur(); + this.familyInput.nativeElement.focus(); + }, 0); + } + + cancel() { + this.popover?.hide(); + } + + applyFont() { + const font = this.fontFormGroup.value; + this.fontApplied.emit(font); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.html new file mode 100644 index 0000000000..574ce98c1d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.html @@ -0,0 +1,25 @@ + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts new file mode 100644 index 0000000000..fdeccb1f15 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts @@ -0,0 +1,102 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Font } from '@home/components/widget/config/widget-settings.models'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { FontSettingsPanelComponent } from '@home/components/widget/lib/settings/common/font-settings-panel.component'; +import { isDefinedAndNotNull } from '@core/utils'; + +@Component({ + selector: 'tb-font-settings', + templateUrl: './font-settings.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => FontSettingsComponent), + multi: true + } + ] +}) +export class FontSettingsComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + @Input() + previewText: string | (() => string); + + private modelValue: Font; + + private propagateChange = null; + + constructor(private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + writeValue(value: Font): void { + this.modelValue = value; + } + + openFontSettingsPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + font: this.modelValue + }; + if (isDefinedAndNotNull(this.previewText)) { + const previewText = typeof this.previewText === 'string' ? this.previewText : this.previewText(); + if (previewText) { + ctx.previewText = previewText; + } + } + const fontSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, FontSettingsPanelComponent, 'left', true, null, + ctx, + {}, + {}, {}, true); + fontSettingsPanelPopover.tbComponentRef.instance.popover = fontSettingsPanelPopover; + fontSettingsPanelPopover.tbComponentRef.instance.fontApplied.subscribe((font) => { + fontSettingsPanelPopover.hide(); + this.modelValue = font; + this.propagateChange(this.modelValue); + }); + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html new file mode 100644 index 0000000000..eb2bbd6711 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html @@ -0,0 +1,43 @@ + +
+ + +
+
{{ label }}
+ + + {{ expanded ? 'expand_less' : 'expand_more' }} + +
+
+ + + +
+
+
{{ option.name }}
+
+ +
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.scss new file mode 100644 index 0000000000..37c06ed239 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.scss @@ -0,0 +1,116 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.tb-image-cards-select.tb-form-panel { + .tb-form-row { + transition: all .3s; + &.expanded { + padding: 11px 7px 11px 16px; + } + } + .tb-image-cards-value-field { + cursor: pointer; + user-select: none; + input { + cursor: pointer; + pointer-events: none; + } + } + .mat-expansion-panel { + &.tb-settings { + > .mat-expansion-panel-header { + height: auto; + .mat-content { + margin: 0; + } + .tb-form-row { + font-weight: normal; + font-size: 16px; + color: rgba(0, 0, 0, 0.87); + } + .mat-expansion-indicator { + display: none; + } + } + > .mat-expansion-panel-content { + > .mat-expansion-panel-body { + padding: 0 16px 16px !important; + } + } + } + } + .tb-image-cards-option { + width: 100%; + height: 100%; + cursor: pointer; + padding: 8px 12px 12px 12px; + display: flex; + flex-direction: column; + gap: 8px; + align-items: start; + position: relative; + .tb-image-cards-option-background { + border-radius: 4px; + position: absolute; + top: 1px; + left: 1px; + right: 1px; + bottom: 1px; + background: rgba(0, 0, 0, 0.04); + } + &:before { + content: unset; + border-radius: 4px; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + .tb-image-cards-option-title { + z-index: 1; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.54); + } + .tb-image-cards-option-image-container { + z-index: 1; + flex: 1; + width: 100%; + min-height: 0; + display: flex; + justify-content: center; + } + &.selected { + .tb-image-cards-option-background { + background: #305680; + opacity: 0.04; + } + &:before { + content: ""; + border: 1px solid #305680; + opacity: 0.32; + } + .tb-image-cards-option-title { + font-size: 13px; + font-weight: 500; + color: #305680; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts new file mode 100644 index 0000000000..d75c4a5fc9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts @@ -0,0 +1,203 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + AfterContentInit, + Component, + ContentChildren, + Directive, + ElementRef, + forwardRef, + Input, OnChanges, + OnDestroy, OnInit, + QueryList, SimpleChanges, + ViewEncapsulation +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs'; +import { map, share, startWith, takeUntil } from 'rxjs/operators'; +import { BreakpointObserver } from '@angular/cdk/layout'; +import { MediaBreakpoints } from '@shared/models/constants'; + +export interface ImageCardsSelectOption { + name: string; + value: any; + image: string; +} + +@Directive( + { + // eslint-disable-next-line @angular-eslint/directive-selector + selector: 'tb-image-cards-select-option', + } +) +export class ImageCardsSelectOptionDirective { + + @Input() value: any; + + @Input() image: string; + + get viewValue(): string { + return (this._element?.nativeElement.textContent || '').trim(); + } + + constructor( + private _element: ElementRef + ) {} +} + +@Component({ + selector: 'tb-image-cards-select', + templateUrl: './image-cards-select.component.html', + styleUrls: ['./image-cards-select.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ImageCardsSelectComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None +}) +export class ImageCardsSelectComponent implements ControlValueAccessor, OnInit, OnChanges, AfterContentInit, OnDestroy { + + @ContentChildren(ImageCardsSelectOptionDirective) imageCardsSelectOptions: QueryList; + + @Input() + @coerceBoolean() + disabled: boolean; + + @Input() + cols = 4; + + @Input() + colsLtMd = 2; + + @Input() + rowHeight = '9:5'; + + @Input() + label: string; + + valueFormControl: UntypedFormControl; + + options: ImageCardsSelectOption[] = []; + + modelValue: any; + + expanded = false; + + cols$: Observable; + + private propagateChange = null; + + private _destroyed = new Subject(); + + private _colsChanged = new BehaviorSubject(null); + + constructor(private breakpointObserver: BreakpointObserver) { + this.valueFormControl = new UntypedFormControl(''); + } + + ngOnInit(): void { + const gridColumns = this.breakpointObserver.isMatched(MediaBreakpoints['lt-md']) ? this.colsLtMd : this.cols; + this.cols$ = combineLatest({state: this.breakpointObserver + .observe(MediaBreakpoints['lt-md']), colsChanged: this._colsChanged.asObservable()}).pipe( + map((data) => data.state.matches ? this.colsLtMd : this.cols), + startWith(gridColumns), + share() + ); + } + + ngOnChanges(changes: SimpleChanges): void { + for (const propName of Object.keys(changes)) { + const change = changes[propName]; + if (!change.firstChange && change.currentValue !== change.previousValue) { + if (['cols', 'colsLtMd'].includes(propName)) { + this._colsChanged.next(null); + } + } + } + } + + ngAfterContentInit(): void { + this.imageCardsSelectOptions.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => { + this.syncImageCardsSelectOptions(); + }); + } + + ngOnDestroy() { + this._destroyed.next(); + this._destroyed.complete(); + } + + private syncImageCardsSelectOptions() { + if (this.imageCardsSelectOptions?.length) { + this.options.length = 0; + this.imageCardsSelectOptions.forEach(option => { + this.options.push( + { name: option.viewValue, + value: option.value, + image: option.image + } + ); + }); + this.updateDisplayValue(); + } + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.valueFormControl.disable(); + } else { + this.valueFormControl.enable(); + } + } + + writeValue(value: any): void { + this.modelValue = value; + this.updateDisplayValue(); + } + + updateModel(value: any) { + this.modelValue = value; + this.updateDisplayValue(); + this.propagateChange(this.modelValue); + this.expanded = false; + } + + toggleSelectPanel($event: Event) { + $event.stopPropagation(); + if (!this.disabled) { + this.expanded = !this.expanded; + } + } + + private updateDisplayValue() { + const currentOption = this.options.find(o => o.value === this.modelValue); + const displayValue = currentOption ? currentOption.name : ''; + this.valueFormControl.patchValue(displayValue, {emitEvent: false}); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html index f7e2234afd..10bfa058da 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html @@ -15,20 +15,21 @@ limitations under the License. --> -
-
- - legend.direction - + +
+
{{ 'legend.direction' | translate }}
+ + {{ legendDirectionTranslations.get(legendDirection[direction]) | translate }} - - legend.position - +
+
+
{{ 'legend.position' | translate }}
+ + @@ -37,28 +38,17 @@
-
- - {{ 'legend.show-min' | translate }} - - - {{ 'legend.show-max' | translate }} - -
-
- - {{ 'legend.show-avg' | translate }} - - - {{ 'legend.show-total' | translate }} - -
-
- - {{ 'legend.show-latest' | translate }} - - - {{ 'legend.sort-legend' | translate }} - +
+
legend.show-values
+ + {{ 'legend.min-option' | translate }} + {{ 'legend.max-option' | translate }} + {{ 'legend.average-option' | translate }} + {{ 'legend.total-option' | translate }} + {{ 'legend.latest-option' | translate }} +
- + + {{ 'legend.sort-legend' | translate }} + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts index c8de7872e8..15b2bbe316 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts @@ -15,7 +15,7 @@ /// import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { isDefined } from '@core/utils'; import { LegendConfig, @@ -30,7 +30,7 @@ import { Subscription } from 'rxjs'; @Component({ selector: 'tb-legend-config', templateUrl: './legend-config.component.html', - styleUrls: [], + styleUrls: ['./../widget-settings.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -62,12 +62,8 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc this.legendConfigForm = this.fb.group({ direction: [null, []], position: [null, []], - sortDataKeys: [null, []], - showMin: [null, []], - showMax: [null, []], - showAvg: [null, []], - showTotal: [null, []], - showLatest: [null, []] + showValues: [[], []], + sortDataKeys: [null, []] }); this.legendSettingsFormDirectionChanges$ = this.legendConfigForm.get('direction').valueChanges .subscribe((direction: LegendDirection) => { @@ -121,18 +117,49 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc this.legendConfigForm.patchValue({ direction: legendConfig.direction, position: legendConfig.position, - sortDataKeys: isDefined(legendConfig.sortDataKeys) ? legendConfig.sortDataKeys : false, - showMin: isDefined(legendConfig.showMin) ? legendConfig.showMin : false, - showMax: isDefined(legendConfig.showMax) ? legendConfig.showMax : false, - showAvg: isDefined(legendConfig.showAvg) ? legendConfig.showAvg : false, - showTotal: isDefined(legendConfig.showTotal) ? legendConfig.showTotal : false, - showLatest: isDefined(legendConfig.showLatest) ? legendConfig.showLatest : false + showValues: this.getShowValues(legendConfig), + sortDataKeys: isDefined(legendConfig.sortDataKeys) ? legendConfig.sortDataKeys : false }, {emitEvent: false}); } this.onDirectionChanged(legendConfig.direction); } private legendConfigUpdated() { - this.propagateChange(this.legendConfigForm.value); + const configValue = this.legendConfigForm.value; + const legendConfig: Partial = { + direction: configValue.direction, + position: configValue.position, + sortDataKeys: configValue.sortDataKeys + }; + this.setShowValues(configValue.showValues, legendConfig); + this.propagateChange(legendConfig); + } + + private getShowValues(legendConfig: LegendConfig): string[] { + const showValues: string[] = []; + if (isDefined(legendConfig.showMin) && legendConfig.showMin) { + showValues.push('min'); + } + if (isDefined(legendConfig.showMax) && legendConfig.showMax) { + showValues.push('max'); + } + if (isDefined(legendConfig.showAvg) && legendConfig.showAvg) { + showValues.push('average'); + } + if (isDefined(legendConfig.showTotal) && legendConfig.showTotal) { + showValues.push('total'); + } + if (isDefined(legendConfig.showLatest) && legendConfig.showLatest) { + showValues.push('latest'); + } + return showValues; + } + + private setShowValues(showValues: string[], legendConfig: Partial) { + legendConfig.showMin = showValues.includes('min'); + legendConfig.showMax = showValues.includes('max'); + legendConfig.showAvg = showValues.includes('average'); + legendConfig.showTotal = showValues.includes('total'); + legendConfig.showLatest = showValues.includes('latest'); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html index 46e3f87664..3cc771e94f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html @@ -15,27 +15,27 @@ limitations under the License. --> -
- - widgets.value-source.value-source - - + +
+ + {{ 'widgets.value-source.predefined-value' | translate }} - - + + {{ 'widgets.value-source.entity-attribute' | translate }} - - - - - widgets.value-source.value - - -
- - {{ 'widgets.value-source.source-entity-alias' | translate }} - + +
+
+
widgets.value-source.value
+ + + +
+
+
widgets.value-source.source-entity-alias
+ + @@ -53,9 +53,11 @@ - - {{ 'widgets.value-source.source-entity-attribute' | translate }} - +
+
widgets.value-source.source-entity-attribute
+ + @@ -73,5 +75,5 @@ -
- +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts index 6417ae4bcb..603b12bcb5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts @@ -14,8 +14,8 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, HostBinding, Input, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -39,7 +39,7 @@ export interface ValueSourceProperty { @Component({ selector: 'tb-value-source', templateUrl: './value-source.component.html', - styleUrls: [], + styleUrls: ['./../widget-settings.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -50,8 +50,6 @@ export interface ValueSourceProperty { }) export class ValueSourceComponent extends PageComponent implements OnInit, ControlValueAccessor { - @HostBinding('style.display') display = 'block'; - @ViewChild('entityAliasInput') entityAliasInput: ElementRef; @ViewChild('keyInput') keyInput: ElementRef; @@ -212,15 +210,13 @@ export class ValueSourceComponent extends PageComponent implements OnInit, Contr private fetchEntityKeys(entityAliasId: string, dataKeyTypes: Array): Observable> { return this.aliasController.getAliasInfo(entityAliasId).pipe( - mergeMap((aliasInfo) => { - return this.entityService.getEntityKeysByEntityFilter( + mergeMap((aliasInfo) => this.entityService.getEntityKeysByEntityFilter( aliasInfo.entityFilter, dataKeyTypes, [], {ignoreLoading: true, ignoreErrors: true} ).pipe( catchError(() => of([])) - ); - }), + )), catchError(() => of([] as Array)) ); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/fixed-color-level.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/fixed-color-level.component.ts index 9baad9677c..8bd92dca8a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/fixed-color-level.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/fixed-color-level.component.ts @@ -50,7 +50,7 @@ export function fixedColorLevelValidator(control: AbstractControl): ValidationEr @Component({ selector: 'tb-fixed-color-level', templateUrl: './fixed-color-level.component.html', - styleUrls: ['./fixed-color-level.component.scss', './../widget-settings.scss'], + styleUrls: ['./fixed-color-level.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts index 33f44f0111..e5c1ec9fbc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts @@ -31,7 +31,7 @@ export interface GaugeHighlight { @Component({ selector: 'tb-gauge-highlight', templateUrl: './gauge-highlight.component.html', - styleUrls: ['./gauge-highlight.component.scss', './../widget-settings.scss'], + styleUrls: ['./gauge-highlight.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts index ef334d6ee2..51665a3afa 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts @@ -27,7 +27,7 @@ import { IAliasController } from '@core/api/widget-api.models'; @Component({ selector: 'tb-tick-value', templateUrl: './tick-value.component.html', - styleUrls: ['./tick-value.component.scss', './../widget-settings.scss'], + styleUrls: ['./tick-value.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts index d6e6d675ad..636fd9f0fe 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts @@ -56,7 +56,7 @@ export const gpioItemValidator = (hasColor: boolean): ValidatorFn => (control: A @Component({ selector: 'tb-gpio-item', templateUrl: './gpio-item.component.html', - styleUrls: ['./gpio-item.component.scss', './../widget-settings.scss'], + styleUrls: ['./gpio-item.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts index a546537bf7..1d304aef64 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts @@ -46,7 +46,7 @@ export const dataKeySelectOptionValidator = (control: AbstractControl) => { @Component({ selector: 'tb-datakey-select-option', templateUrl: './datakey-select-option.component.html', - styleUrls: ['./datakey-select-option.component.scss', './../widget-settings.scss'], + styleUrls: ['./datakey-select-option.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html index 3c62810000..d69a4b0713 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html @@ -69,6 +69,9 @@ {{ 'widgets.input-widgets.datakey-value-type-json' | translate }} + + {{ 'widgets.input-widgets.datakey-value-type-color' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index 2dae32a922..748d90649d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -266,6 +266,28 @@ import { QuickLinksWidgetSettingsComponent } from '@home/components/widget/lib/settings/home-page/quick-links-widget-settings.component'; import { LegendConfigComponent } from '@home/components/widget/lib/settings/common/legend-config.component'; +import { + ImageCardsSelectOptionDirective, + ImageCardsSelectComponent +} from '@home/components/widget/lib/settings/common/image-cards-select.component'; +import { FontSettingsComponent } from '@home/components/widget/lib/settings/common/font-settings.component'; +import { FontSettingsPanelComponent } from '@home/components/widget/lib/settings/common/font-settings-panel.component'; +import { ColorSettingsComponent } from '@home/components/widget/lib/settings/common/color-settings.component'; +import { + ColorSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/color-settings-panel.component'; +import { CssUnitSelectComponent } from '@home/components/widget/lib/settings/common/css-unit-select.component'; +import { DateFormatSelectComponent } from '@home/components/widget/lib/settings/common/date-format-select.component'; +import { + DateFormatSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/date-format-settings-panel.component'; +import { BackgroundSettingsComponent } from '@home/components/widget/lib/settings/common/background-settings.component'; +import { + BackgroundSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/background-settings-panel.component'; +import { + ValueCardWidgetSettingsComponent +} from '@home/components/widget/lib/settings/cards/value-card-widget-settings.component'; @NgModule({ declarations: [ @@ -367,7 +389,19 @@ import { LegendConfigComponent } from '@home/components/widget/lib/settings/comm RouteMapWidgetSettingsComponent, TripAnimationWidgetSettingsComponent, DocLinksWidgetSettingsComponent, - QuickLinksWidgetSettingsComponent + QuickLinksWidgetSettingsComponent, + ImageCardsSelectOptionDirective, + ImageCardsSelectComponent, + FontSettingsComponent, + FontSettingsPanelComponent, + ColorSettingsComponent, + ColorSettingsPanelComponent, + CssUnitSelectComponent, + DateFormatSelectComponent, + DateFormatSettingsPanelComponent, + BackgroundSettingsComponent, + BackgroundSettingsPanelComponent, + ValueCardWidgetSettingsComponent ], imports: [ CommonModule, @@ -473,7 +507,19 @@ import { LegendConfigComponent } from '@home/components/widget/lib/settings/comm RouteMapWidgetSettingsComponent, TripAnimationWidgetSettingsComponent, DocLinksWidgetSettingsComponent, - QuickLinksWidgetSettingsComponent + QuickLinksWidgetSettingsComponent, + ImageCardsSelectOptionDirective, + ImageCardsSelectComponent, + FontSettingsComponent, + FontSettingsPanelComponent, + ColorSettingsComponent, + ColorSettingsPanelComponent, + CssUnitSelectComponent, + DateFormatSelectComponent, + DateFormatSettingsPanelComponent, + BackgroundSettingsComponent, + BackgroundSettingsPanelComponent, + ValueCardWidgetSettingsComponent ] }) export class WidgetSettingsModule { @@ -542,5 +588,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type -
+
-
+
+
+
-
-
widget-config.target-device
+
widget-config.target-device
-
widget-config.alarm-source
+ [formGroup]="dataSettings" class="tb-form-panel" > +
widget-config.alarm-source
-
-
widget-config.limits
-
+
+
widget-config.limits
+
widget-config.data-page-size
- +
-
-
widget-config.data-settings
-
+
+
widget-config.data-settings
+
widget-config.units
- - +
-
+
widget-config.decimals
- +
-
-
widget-config.no-data-display-message
+
+
widget-config.no-data-display-message
@@ -274,6 +282,7 @@ [aliasController]="aliasController" [dashboard]="dashboard" [widget]="widget" + [widgetConfig]="modelValue" formControlName="settings">
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 999e7e55ff..1f418224dd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -224,6 +224,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe color: [null, []], padding: [null, []], margin: [null, []], + borderRadius: [null, []], widgetStyle: [null, []], widgetCss: [null, []], titleStyle: [null, []], @@ -484,6 +485,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe color: config.color, padding: config.padding, margin: config.margin, + borderRadius: config.borderRadius, widgetStyle: isDefined(config.widgetStyle) ? config.widgetStyle : {}, widgetCss: isDefined(config.widgetCss) ? config.widgetCss : '', titleStyle: isDefined(config.titleStyle) ? config.titleStyle : { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html index 23082a121b..43b54884ec 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html @@ -19,7 +19,6 @@ [fullscreenBackgroundStyle]="dashboardStyle" [fullscreenBackgroundImage]="backgroundImage" (fullscreenChanged)="onFullscreenChanged($event)" - fxLayout="column" class="tb-widget" [ngClass]="{ 'tb-highlighted': isHighlighted(widget), @@ -32,8 +31,11 @@ (mousedown)="onMouseDown($event)" (click)="onClicked($event)" (contextmenu)="onContextMenu($event)"> -
-
+
+
- {{widget.titleIcon}} + {{widget.titleIcon}} {{widget.customTranslatedTitle}}
-
- + diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss index 4c7264ce29..52caeb2a5c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss @@ -14,9 +14,14 @@ * limitations under the License. */ -tb-widget.tb-widget { - position: relative; - height: 100%; +.tb-widget-container { + position: absolute; + inset: 0; +} + +.tb-widget { + position: absolute; + inset: 0; margin: 0; overflow: hidden; outline: none; @@ -25,15 +30,27 @@ tb-widget.tb-widget { } div.tb-widget { - position: relative; - height: 100%; - margin: 0; - overflow: hidden; - outline: none; - - transition: all .2s ease-in-out; + display: flex; + flex-direction: column; + .tb-widget-header { + display: flex; + flex-direction: row; + place-content: flex-start space-between; + align-items: flex-start; + &-absolute { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 1; + } + } .tb-widget-title { + display: flex; + flex-direction: column; + place-content: flex-start center; + align-items: flex-start; max-height: 65px; padding-top: 5px; padding-left: 5px; @@ -63,6 +80,10 @@ div.tb-widget { } .tb-widget-actions { + display: flex; + flex-direction: row; + place-content: center flex-start; + align-items: center; z-index: 19; margin: 5px 0 0; @@ -82,7 +103,7 @@ div.tb-widget { margin: 0 !important; line-height: 20px; - mat-icon { + .mat-icon { width: 20px; min-width: 20px; height: 20px; @@ -104,13 +125,11 @@ div.tb-widget { } .tb-widget-content { + flex: 1; + position: relative; &.tb-no-interaction { pointer-events: none; } - tb-widget { - position: relative; - width: 100%; - } } &.tb-highlighted { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts index bf7042d233..c022015c8f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts @@ -15,6 +15,7 @@ /// import { + AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, @@ -62,7 +63,7 @@ export class WidgetComponentAction { encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush }) -export class WidgetContainerComponent extends PageComponent implements OnInit, OnDestroy { +export class WidgetContainerComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy { @HostBinding('class') widgetContainerClass = 'tb-widget-container'; @@ -131,6 +132,10 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, O } } + ngAfterViewInit(): void { + this.widget.widgetContext.$widgetElement = $(this.tbWidgetElement.nativeElement); + } + ngOnDestroy(): void { if (this.cssClass) { const el = this.document.getElementById(this.cssClass); diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html index 870cb08513..74ba76bae1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html @@ -16,8 +16,11 @@ --> ) { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 7e9b9cb6e7..c276999d83 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -409,6 +409,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI elem.classList.add(this.widgetContext.widgetNamespace); this.widgetType = this.widgetInfo.widgetTypeFunction; this.typeParameters = this.widgetInfo.typeParameters; + this.widgetContext.absoluteHeader = this.typeParameters.absoluteHeader; if (!this.widgetType) { this.widgetTypeInstance = {}; diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index c1485cf450..fd427923f7 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -27,9 +27,12 @@ -
- + check @@ -54,133 +57,49 @@ {{ 'device.label-max-length' | translate }} -
- - - device.wizard.existing-device-profile - - - device.wizard.new-device-profile - - -
- - - - device-profile.new-device-profile-name - - - {{ 'device-profile.new-device-profile-name-required' | translate }} - - -
-
- - -
-
- - -
-
-
- + + +
+ {{ 'device.is-gateway' | translate }} - - + + {{ 'device.overwrite-activity-time' | translate }} - +
- + + + device.description - + - -
- {{ 'device-profile.transport-configuration' | translate }} - device-profile.transport-type - - - {{deviceTransportTypeTranslations.get(type) | translate}} - - - - {{deviceTransportTypeHints.get(transportConfigFormGroup.get('transportType').value) | translate}} - - - {{ 'device-profile.transport-type-required' | translate }} - - - - -
-
- -
- {{'device-profile.alarm-rules-with-count' | translate: - {count: alarmRulesFormGroup.get('alarms').value ? - alarmRulesFormGroup.get('alarms').value.length : 0} }} - - -
-
- -
- {{ 'device-profile.device-provisioning' | translate }} - - -
-
- + {{ 'device.credentials' | translate }}
- {{ 'device.wizard.add-credentials' | translate }}
- - {{ 'customer.customer' | translate }} -
- - -
-
-
-
+
+
@@ -192,7 +111,7 @@ (click)="nextStep()">{{ 'action.next-with-label' | translate:{label: (getFormLabel(this.selectedIndex+1) | translate)} }}
-
+
diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss index 0fe18467fd..2f35b3e60d 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss @@ -18,49 +18,62 @@ :host { height: 100%; display: grid; + grid-template-rows: min-content 4px auto min-content; - .dialog-actions-row { - padding: 8px; + .toggle-group { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 16px; + margin-bottom: 16px; + } + + @media #{$mat-sm} { + min-width: 470px; + } + + @media #{$mat-gt-sm} { + min-width: 650px; } } -:host-context(.tb-fullscreen-dialog .mat-mdc-dialog-container) { - @media #{$mat-lt-sm} { - .mat-mdc-dialog-content { - max-height: 75vh; +:host-context(.mat-mdc-dialog-container) { + .tb-dialog-actions { + padding: 0; + grid-row: 4; + + .dialog-actions-row { + padding: 8px; + display: flex; + gap: 8px; + justify-content: flex-end; + flex: 1; } } - .invisible{ - visibility: hidden; + .mat-mdc-dialog-content { + grid-row: 3; + padding: 0; } + } :host ::ng-deep { .mat-mdc-dialog-content { - display: flex; - flex-direction: column; - height: 100%; - padding: 0 !important; - .mat-stepper-horizontal { display: flex; height: 100%; overflow: hidden; .mat-horizontal-stepper-wrapper { - flex: 1 1 100%; + width: 100%; } .mat-horizontal-content-container { - height: 680px; + height: 500px; max-height: 100%; - width: 100%;; overflow-y: auto; scrollbar-gutter: stable; - @media #{$mat-gt-sm} { - min-width: 500px; - } } } } diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 77916d379c..8210f9a533 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -14,201 +14,82 @@ /// limitations under the License. /// -import { Component, Inject, OnDestroy, SkipSelf, ViewChild } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Component, ViewChild } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { DialogComponent } from '@shared/components/dialog.component'; import { Router } from '@angular/router'; -import { - createDeviceProfileConfiguration, - createDeviceProfileTransportConfiguration, - DeviceProfile, - DeviceProfileInfo, - DeviceProfileType, - DeviceProvisionConfiguration, - DeviceProvisionType, - DeviceTransportType, - deviceTransportTypeHintMap, - deviceTransportTypeTranslationMap -} from '@shared/models/device.models'; -import { MatStepper } from '@angular/material/stepper'; -import { AddEntityDialogData } from '@home/models/entity/entity-component.models'; -import { BaseData, HasId } from '@shared/models/base-data'; +import { Device, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; +import { MatStepper, StepperOrientation } from '@angular/material/stepper'; import { EntityType } from '@shared/models/entity-type.models'; -import { DeviceProfileService } from '@core/http/device-profile.service'; -import { EntityId } from '@shared/models/id/entity-id'; -import { Observable, of, Subscription, throwError } from 'rxjs'; -import { catchError, map, mergeMap, tap } from 'rxjs/operators'; +import { Observable, throwError } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; import { DeviceService } from '@core/http/device.service'; -import { ErrorStateMatcher } from '@angular/material/core'; import { StepperSelectionEvent } from '@angular/cdk/stepper'; -import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; +import { BreakpointObserver } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; -import { RuleChainId } from '@shared/models/id/rule-chain-id'; -import { ServiceType } from '@shared/models/queue.models'; import { deepTrim } from '@core/utils'; +import { CustomerId } from '@shared/models/id/customer-id'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'tb-device-wizard', templateUrl: './device-wizard-dialog.component.html', - providers: [], styleUrls: ['./device-wizard-dialog.component.scss'] }) -export class DeviceWizardDialogComponent extends - DialogComponent implements OnDestroy, ErrorStateMatcher { +export class DeviceWizardDialogComponent extends DialogComponent { @ViewChild('addDeviceWizardStepper', {static: true}) addDeviceWizardStepper: MatStepper; - selectedIndex = 0; - - showNext = true; - - createProfile = false; - - entityType = EntityType; - - deviceTransportTypes = Object.values(DeviceTransportType); - - deviceTransportTypeTranslations = deviceTransportTypeTranslationMap; + stepperOrientation: Observable; - deviceTransportTypeHints = deviceTransportTypeHintMap; + stepperLabelPosition: Observable<'bottom' | 'end'>; - deviceWizardFormGroup: UntypedFormGroup; - - transportConfigFormGroup: UntypedFormGroup; - - alarmRulesFormGroup: UntypedFormGroup; + selectedIndex = 0; - provisionConfigFormGroup: UntypedFormGroup; + credentialsOptionalStep = true; - credentialsFormGroup: UntypedFormGroup; + showNext = true; - customerFormGroup: UntypedFormGroup; + entityType = EntityType; - labelPosition: MatStepper['labelPosition'] = 'end'; + deviceWizardFormGroup: FormGroup; - serviceType = ServiceType.TB_RULE_ENGINE; + credentialsFormGroup: FormGroup; - private subscriptions: Subscription[] = []; private currentDeviceProfileTransportType = DeviceTransportType.DEFAULT; constructor(protected store: Store, protected router: Router, - @Inject(MAT_DIALOG_DATA) public data: AddEntityDialogData>, - @SkipSelf() private errorStateMatcher: ErrorStateMatcher, - public dialogRef: MatDialogRef, - private deviceProfileService: DeviceProfileService, + public dialogRef: MatDialogRef, private deviceService: DeviceService, private breakpointObserver: BreakpointObserver, - private fb: UntypedFormBuilder) { + private fb: FormBuilder) { super(store, router, dialogRef); + + this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-sm']) + .pipe(map(({matches}) => matches ? 'horizontal' : 'vertical')); + + this.stepperLabelPosition = this.breakpointObserver.observe(MediaBreakpoints['gt-sm']) + .pipe(map(({matches}) => matches ? 'end' : 'bottom')); + this.deviceWizardFormGroup = this.fb.group({ name: ['', [Validators.required, Validators.maxLength(255)]], label: ['', Validators.maxLength(255)], gateway: [false], overwriteActivityTime: [false], - addProfileType: [0], + customerId: [null], deviceProfileId: [null, Validators.required], - newDeviceProfileTitle: [{value: null, disabled: true}], - defaultRuleChainId: [{value: null, disabled: true}], - defaultQueueName: [{value: null, disabled: true}], description: [''] } ); - this.subscriptions.push(this.deviceWizardFormGroup.get('addProfileType').valueChanges.subscribe( - (addProfileType: number) => { - if (addProfileType === 0) { - this.deviceWizardFormGroup.get('deviceProfileId').setValidators([Validators.required]); - this.deviceWizardFormGroup.get('deviceProfileId').enable(); - this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators(null); - this.deviceWizardFormGroup.get('newDeviceProfileTitle').disable(); - this.deviceWizardFormGroup.get('defaultRuleChainId').disable(); - this.deviceWizardFormGroup.get('defaultQueueName').disable(); - this.deviceWizardFormGroup.updateValueAndValidity(); - this.createProfile = false; - } else { - this.deviceWizardFormGroup.get('deviceProfileId').setValidators(null); - this.deviceWizardFormGroup.get('deviceProfileId').disable(); - this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators([Validators.required]); - this.deviceWizardFormGroup.get('newDeviceProfileTitle').enable(); - this.deviceWizardFormGroup.get('defaultRuleChainId').enable(); - this.deviceWizardFormGroup.get('defaultQueueName').enable(); - - this.deviceWizardFormGroup.updateValueAndValidity(); - this.createProfile = true; - } - } - )); - - this.transportConfigFormGroup = this.fb.group( - { - transportType: [DeviceTransportType.DEFAULT, Validators.required], - transportConfiguration: [createDeviceProfileTransportConfiguration(DeviceTransportType.DEFAULT), Validators.required] - } - ); - - this.subscriptions.push(this.transportConfigFormGroup.get('transportType').valueChanges.subscribe((transportType) => { - this.deviceProfileTransportTypeChanged(transportType); - })); - - this.alarmRulesFormGroup = this.fb.group({ - alarms: [null] - } - ); - - this.provisionConfigFormGroup = this.fb.group( - { - provisionConfiguration: [{ - type: DeviceProvisionType.DISABLED - } as DeviceProvisionConfiguration, [Validators.required]] - } - ); - this.credentialsFormGroup = this.fb.group({ - setCredential: [false], - credential: [{value: null, disabled: true}] - } - ); - - this.subscriptions.push(this.credentialsFormGroup.get('setCredential').valueChanges.subscribe((value) => { - if (value) { - this.credentialsFormGroup.get('credential').enable(); - } else { - this.credentialsFormGroup.get('credential').disable(); - } - })); - - this.customerFormGroup = this.fb.group({ - customerId: [null] + credential: [] } ); - - this.labelPosition = this.breakpointObserver.isMatched(MediaBreakpoints['gt-sm']) ? 'end' : 'bottom'; - - this.subscriptions.push(this.breakpointObserver - .observe(MediaBreakpoints['gt-sm']) - .subscribe((state: BreakpointState) => { - if (state.matches) { - this.labelPosition = 'end'; - } else { - this.labelPosition = 'bottom'; - } - } - )); - } - - ngOnDestroy() { - super.ngOnDestroy(); - this.subscriptions.forEach(s => s.unsubscribe()); - } - - isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean { - const originalErrorState = this.errorStateMatcher.isErrorState(control, form); - const customErrorState = !!(control && control.invalid); - return originalErrorState || customErrorState; } cancel(): void { @@ -224,24 +105,11 @@ export class DeviceWizardDialogComponent extends } getFormLabel(index: number): string { - if (index > 0) { - if (!this.createProfile) { - index += 3; - } - } switch (index) { case 0: return 'device.wizard.device-details'; case 1: - return 'device-profile.transport-configuration'; - case 2: - return 'device-profile.alarm-rules'; - case 3: - return 'device-profile.device-provisioning'; - case 4: return 'device.credentials'; - case 5: - return 'customer.customer'; } } @@ -249,88 +117,30 @@ export class DeviceWizardDialogComponent extends return this.addDeviceWizardStepper?._steps?.length - 1; } - private deviceProfileTransportTypeChanged(deviceTransportType: DeviceTransportType): void { - this.transportConfigFormGroup.patchValue( - {transportConfiguration: createDeviceProfileTransportConfiguration(deviceTransportType)}); - const setCredentialBox = this.credentialsFormGroup.get('setCredential'); - if (deviceTransportType === DeviceTransportType.LWM2M) { - setCredentialBox.patchValue(true); - setCredentialBox.disable(); - } else { - setCredentialBox.patchValue(false); - setCredentialBox.enable(); - } - } - add(): void { if (this.allValid()) { - this.createDeviceProfile().pipe( - mergeMap(profileId => this.createDevice(profileId)), - mergeMap(device => this.saveCredentials(device)) - ).subscribe( - (created) => { - this.dialogRef.close(created); - } + this.createDevice().subscribe( + (device) => this.dialogRef.close(device) ); } } get deviceTransportType(): DeviceTransportType { - if (this.deviceWizardFormGroup.get('addProfileType').value) { - return this.transportConfigFormGroup.get('transportType').value; - } else { - return this.currentDeviceProfileTransportType; - } + return this.currentDeviceProfileTransportType; } deviceProfileChanged(deviceProfile: DeviceProfileInfo) { if (deviceProfile) { this.currentDeviceProfileTransportType = deviceProfile.transportType; + this.credentialsOptionalStep = this.currentDeviceProfileTransportType !== DeviceTransportType.LWM2M; } } - private createDeviceProfile(): Observable { - if (this.deviceWizardFormGroup.get('addProfileType').value) { - const deviceProvisionConfiguration: DeviceProvisionConfiguration = this.provisionConfigFormGroup.get('provisionConfiguration').value; - const provisionDeviceKey = deviceProvisionConfiguration.provisionDeviceKey; - delete deviceProvisionConfiguration.provisionDeviceKey; - const deviceProfile: DeviceProfile = { - name: this.deviceWizardFormGroup.get('newDeviceProfileTitle').value, - type: DeviceProfileType.DEFAULT, - defaultQueueName: this.deviceWizardFormGroup.get('defaultQueueName').value, - transportType: this.transportConfigFormGroup.get('transportType').value, - provisionType: deviceProvisionConfiguration.type, - provisionDeviceKey, - profileData: { - configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT), - transportConfiguration: this.transportConfigFormGroup.get('transportConfiguration').value, - alarms: this.alarmRulesFormGroup.get('alarms').value, - provisionConfiguration: deviceProvisionConfiguration - } - }; - if (this.deviceWizardFormGroup.get('defaultRuleChainId').value) { - deviceProfile.defaultRuleChainId = new RuleChainId(this.deviceWizardFormGroup.get('defaultRuleChainId').value); - } - return this.deviceProfileService.saveDeviceProfile(deepTrim(deviceProfile)).pipe( - tap((profile) => { - this.currentDeviceProfileTransportType = profile.transportType; - this.deviceWizardFormGroup.patchValue({ - deviceProfileId: profile.id, - addProfileType: 0 - }); - }), - map(profile => profile.id) - ); - } else { - return of(this.deviceWizardFormGroup.get('deviceProfileId').value); - } - } - - private createDevice(profileId): Observable> { - const device = { + private createDevice(): Observable { + const device: Device = { name: this.deviceWizardFormGroup.get('name').value, label: this.deviceWizardFormGroup.get('label').value, - deviceProfileId: profileId, + deviceProfileId: this.deviceWizardFormGroup.get('deviceProfileId').value, additionalInfo: { gateway: this.deviceWizardFormGroup.get('gateway').value, overwriteActivityTime: this.deviceWizardFormGroup.get('overwriteActivityTime').value, @@ -338,13 +148,22 @@ export class DeviceWizardDialogComponent extends }, customerId: null }; - if (this.customerFormGroup.get('customerId').value) { - device.customerId = { - entityType: EntityType.CUSTOMER, - id: this.customerFormGroup.get('customerId').value - }; + if (this.deviceWizardFormGroup.get('customerId').value) { + device.customerId = new CustomerId(this.deviceWizardFormGroup.get('customerId').value); + } + if (this.addDeviceWizardStepper.steps.last.completed || this.addDeviceWizardStepper.selectedIndex > 0) { + return this.deviceService.saveDeviceWithCredentials(deepTrim(device), deepTrim(this.credentialsFormGroup.value.credential)).pipe( + catchError((e: HttpErrorResponse) => { + if (e.error.message.includes('Device credentials')) { + this.addDeviceWizardStepper.selectedIndex = 1; + } else { + this.addDeviceWizardStepper.selectedIndex = 0; + } + return throwError(() => e); + }) + ); } - return this.data.entitiesTableConfig.saveEntity(deepTrim(device)).pipe( + return this.deviceService.saveDevice(deepTrim(device)).pipe( catchError(e => { this.addDeviceWizardStepper.selectedIndex = 0; return throwError(e); @@ -352,31 +171,8 @@ export class DeviceWizardDialogComponent extends ); } - private saveCredentials(device: BaseData): Observable { - if (this.credentialsFormGroup.get('setCredential').value) { - return this.deviceService.getDeviceCredentials(device.id.id).pipe( - mergeMap( - (deviceCredentials) => { - const deviceCredentialsValue = {...deviceCredentials, ...this.credentialsFormGroup.value.credential}; - return this.deviceService.saveDeviceCredentials(deviceCredentialsValue).pipe( - catchError(e => { - this.addDeviceWizardStepper.selectedIndex = 1; - return this.deviceService.deleteDevice(device.id.id).pipe( - mergeMap(() => { - return throwError(e); - } - )); - }) - ); - } - ), - map(() => true)); - } - return of(true); - } - allValid(): boolean { - if (this.addDeviceWizardStepper.steps.find((item, index) => { + return !this.addDeviceWizardStepper.steps.find((item, index) => { if (item.stepControl.invalid) { item.interacted = true; this.addDeviceWizardStepper.selectedIndex = index; @@ -384,19 +180,11 @@ export class DeviceWizardDialogComponent extends } else { return false; } - } )) { - return false; - } else { - return true; - } + }); } changeStep($event: StepperSelectionEvent): void { this.selectedIndex = $event.selectedIndex; - if (this.selectedIndex === this.maxStepperIndex) { - this.showNext = false; - } else { - this.showNext = true; - } + this.showNext = this.selectedIndex !== this.maxStepperIndex; } } diff --git a/ui-ngx/src/app/modules/home/menu/menu-link.component.html b/ui-ngx/src/app/modules/home/menu/menu-link.component.html index ab5b1faa27..0efc34a31c 100644 --- a/ui-ngx/src/app/modules/home/menu/menu-link.component.html +++ b/ui-ngx/src/app/modules/home/menu/menu-link.component.html @@ -16,7 +16,6 @@ --> - {{section.icon}} - + {{section.icon}} {{section.name | translate}} diff --git a/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html b/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html index de4f16b163..448c67a513 100644 --- a/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html +++ b/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html @@ -16,8 +16,7 @@ --> - {{section.icon}} - + {{section.icon}} {{section.name | translate}} diff --git a/ui-ngx/src/app/modules/home/menu/side-menu.component.scss b/ui-ngx/src/app/modules/home/menu/side-menu.component.scss index fc9df865a1..dbba5e78a9 100644 --- a/ui-ngx/src/app/modules/home/menu/side-menu.component.scss +++ b/ui-ngx/src/app/modules/home/menu/side-menu.component.scss @@ -49,7 +49,7 @@ &.tb-active { background-color: rgba(255, 255, 255, .15); } - mat-icon { + .mat-icon { margin-right: 8px; margin-left: 0; min-width: 1.125rem; diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 2c79ef7b68..5f994e4fdc 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -328,6 +328,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { backgroundColor: string; padding: string; margin: string; + borderRadius: string; title: string; customTranslatedTitle: string; @@ -427,6 +428,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { this.backgroundColor = this.widget.config.backgroundColor || '#fff'; this.padding = this.widget.config.padding || '8px'; this.margin = this.widget.config.margin || '0px'; + this.borderRadius = this.widget.config.borderRadius; this.title = isDefined(this.widgetContext.widgetTitle) && this.widgetContext.widgetTitle.length ? this.widgetContext.widgetTitle : this.widget.config.title; @@ -444,7 +446,10 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { this.titleIconStyle.color = this.widget.config.iconColor; } if (this.widget.config.iconSize) { + this.titleIconStyle.width = this.widget.config.iconSize; + this.titleIconStyle.height = this.widget.config.iconSize; this.titleIconStyle.fontSize = this.widget.config.iconSize; + this.titleIconStyle.lineHeight = this.widget.config.iconSize; } this.dropShadow = isDefined(this.widget.config.dropShadow) ? this.widget.config.dropShadow : true; @@ -478,7 +483,8 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { color: this.color, backgroundColor: this.backgroundColor, padding: this.padding, - margin: this.margin}; + margin: this.margin, + borderRadius: this.borderRadius}; if (this.widget.config.widgetStyle) { this.style = {...this.style, ...this.widget.config.widgetStyle}; } diff --git a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts index e9fb01c54a..bcd8e793b3 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts @@ -75,7 +75,6 @@ export interface GroupActionDescriptor> { export interface HeaderActionDescriptor { name: string; icon: string; - isMdiIcon?: boolean; isEnabled: () => boolean; onAction: ($event: MouseEvent) => void; } diff --git a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts index 033747f6d3..a6e5ada7bf 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts @@ -80,6 +80,7 @@ export interface IEntitiesTableComponent { exitFilterMode(): void; resetSortAndFilter(update?: boolean, preserveTimewindow?: boolean): void; columnsUpdated(resetData?: boolean): void; + cellActionDescriptorsUpdated(): void; headerCellStyle(column: EntityColumn>): any; clearCellCache(col: number, row: number): void; cellContent(entity: BaseData, column: EntityColumn>, row: number): any; diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index c00d0a8e82..18c8ccd19e 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -243,6 +243,7 @@ export class WidgetContext { formatValue }; + $widgetElement: JQuery; $container: JQuery; $containerParent: JQuery; width: number; @@ -264,6 +265,8 @@ export class WidgetContext { hiddenData?: Array<{data: DataSet}>; timeWindow?: WidgetTimewindow; + absoluteHeader?: boolean; + hideTitlePanel = false; widgetTitle?: string; diff --git a/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts b/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts index 86e8b51d43..9fcaecddfd 100644 --- a/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts @@ -14,16 +14,15 @@ /// limitations under the License. /// -import { NgModule } from '@angular/core'; +import { inject, NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { RouterTabsComponent } from '@home/components/router-tabs.component'; import { Authority } from '@shared/models/authority.enum'; -import { SecurityRoutes, UserTwoFAProvidersResolver } from '@home/pages/security/security-routing.module'; -import { - NotificationUserSettingsResolver, - NotificationUserSettingsRoutes -} from '@home/pages/notification/settings/notification-settings-routing.modules'; -import { ProfileRoutes, UserProfileResolver } from '@home/pages/profile/profile-routing.module'; +import { securityRoutes } from '@home/pages/security/security-routing.module'; +import { profileRoutes } from '@home/pages/profile/profile-routing.module'; +import { getCurrentAuthState } from '@core/auth/auth.selectors'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; const routes: Routes = [ { @@ -34,7 +33,11 @@ const routes: Routes = [ breadcrumb: { label: 'account.account', icon: 'account_circle' - } + }, + useChildrenRoutesForTabs: true, + }, + resolve: { + replaceUrl: () => getCurrentAuthState(inject(Store)).forceFullscreen }, children: [ { @@ -45,20 +48,14 @@ const routes: Routes = [ redirectTo: '/account/profile', } }, - ...ProfileRoutes, - ...SecurityRoutes, - ...NotificationUserSettingsRoutes + ...profileRoutes, + ...securityRoutes ] } ]; @NgModule({ imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [ - UserProfileResolver, - UserTwoFAProvidersResolver, - NotificationUserSettingsResolver - ] + exports: [RouterModule] }) export class AccountRoutingModule { } diff --git a/ui-ngx/src/app/modules/home/pages/account/account.module.ts b/ui-ngx/src/app/modules/home/pages/account/account.module.ts index b11a34df41..df178607ce 100644 --- a/ui-ngx/src/app/modules/home/pages/account/account.module.ts +++ b/ui-ngx/src/app/modules/home/pages/account/account.module.ts @@ -15,16 +15,13 @@ /// import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { SharedModule } from '@shared/shared.module'; import { AccountRoutingModule } from '@home/pages/account/account-routing.module'; +import { CommonModule } from '@angular/common'; @NgModule({ - declarations: [ - ], + declarations: [ ], imports: [ CommonModule, - SharedModule, AccountRoutingModule ] }) diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts index adc87a7886..5748cc63a6 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts @@ -319,8 +319,7 @@ const routes: Routes = [ title: 'admin.2fa.2fa', breadcrumb: { label: 'admin.2fa.2fa', - icon: 'mdi:two-factor-authentication', - isMdiIcon: true + icon: 'mdi:two-factor-authentication' } } }, diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html index bc5ffd3ae5..7cc06bc4af 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html @@ -37,7 +37,7 @@
- + @@ -59,7 +59,7 @@
-
@@ -146,7 +146,7 @@ admin.oauth2.no-mobile-apps
-
@@ -203,7 +203,7 @@
admin.oauth2.providers
- diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts index 34f35611b4..d274f6728e 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts @@ -570,4 +570,8 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha trackByParams(index: number): number { return index; } + + trackByItem(i, item) { + return item; + } } diff --git a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts index a38fbf9958..7d4bb5fe14 100644 --- a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts @@ -14,10 +14,21 @@ /// limitations under the License. /// -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; +import { inject, NgModule } from '@angular/core'; +import { ActivatedRouteSnapshot, ResolveFn, RouterModule, RouterStateSnapshot, Routes } from '@angular/router'; import { Authority } from '@shared/models/authority.enum'; import { ApiUsageComponent } from '@home/pages/api-usage/api-usage.component'; +import { Dashboard } from '@shared/models/dashboard.models'; +import { ResourcesService } from '@core/services/resources.service'; +import { Observable } from 'rxjs'; + +const apiUsageDashboardJson = '/assets/dashboard/api_usage.json'; + +export const apiUsageDashboardResolver: ResolveFn = ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot, + resourcesService = inject(ResourcesService) +): Observable => resourcesService.loadJsonResource(apiUsageDashboardJson); const routes: Routes = [ { @@ -30,6 +41,9 @@ const routes: Routes = [ label: 'api-usage.api-usage', icon: 'insert_chart' } + }, + resolve: { + apiUsageDashboard: apiUsageDashboardResolver } } ]; diff --git a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts index 0bcae0801b..e84a23fb66 100644 --- a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts +++ b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts @@ -14,28 +14,24 @@ /// limitations under the License. /// -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; -import apiUsageDashboardJson from '!raw-loader!./api_usage_json.raw'; import { Dashboard } from '@shared/models/dashboard.models'; +import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'tb-api-usage', templateUrl: './api-usage.component.html', styleUrls: ['./api-usage.component.scss'] }) -export class ApiUsageComponent extends PageComponent implements OnInit { +export class ApiUsageComponent extends PageComponent { - apiUsageDashboard: Dashboard; + apiUsageDashboard: Dashboard = this.route.snapshot.data.apiUsageDashboard; - constructor(protected store: Store) { + constructor(protected store: Store, + private route: ActivatedRoute) { super(store); } - - ngOnInit() { - this.apiUsageDashboard = JSON.parse(apiUsageDashboardJson); - } - } diff --git a/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts b/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts index d2c02955c2..3f94a23a30 100644 --- a/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts @@ -251,6 +251,7 @@ const routes: Routes = [ { path: ':dashboardId', component: DashboardPageComponent, + canDeactivate: [ConfirmOnExitGuard], data: { breadcrumb: { labelFunction: dashboardBreadcumbLabelFunction, diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts index 89f66df545..6645dc6bd3 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts @@ -32,6 +32,7 @@ import { UserDashboardAction } from '@shared/models/user-settings.models'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { getCurrentAuthUser } from '@core/auth/auth.selectors'; +import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; @Injectable() export class DashboardResolver implements Resolve { @@ -85,6 +86,7 @@ const routes: Routes = [ { path: ':dashboardId', component: DashboardPageComponent, + canDeactivate: [ConfirmOnExitGuard], data: { breadcrumb: { labelFunction: dashboardBreadcumbLabelFunction, diff --git a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts index 01e5584a57..5aa9b0b317 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts @@ -17,10 +17,10 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, - UntypedFormBuilder, - UntypedFormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, + UntypedFormBuilder, + UntypedFormGroup, ValidationErrors, Validator, Validators @@ -104,9 +104,7 @@ export class DeviceTransportConfigurationComponent implements ControlValueAccess if (configuration) { delete configuration.type; } - setTimeout(() => { - this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); - }, 0); + this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); } validate(): ValidationErrors | null { diff --git a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts index 29ac39ee6a..26b70396d9 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts @@ -127,6 +127,9 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc this.snmpDeviceTransportConfigurationFormGroup.disable({emitEvent: false}); } else { this.snmpDeviceTransportConfigurationFormGroup.enable({emitEvent: false}); + this.updateDisabledFormValue( + this.snmpDeviceTransportConfigurationFormGroup.get('protocolVersion').value || SnmpDeviceProtocolVersion.V2C + ); } } diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html new file mode 100644 index 0000000000..71a8364134 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html @@ -0,0 +1,402 @@ + + +

{{ dialogTitle }}

+ + + +
+
+
+ + + {{ deviceTransportTypeTranslationMap.get(BasicTransportType.HTTP) | translate }} + + + {{ deviceTransportTypeTranslationMap.get(DeviceTransportType.MQTT) | translate }} + + + {{ deviceTransportTypeTranslationMap.get(DeviceTransportType.COAP) | translate }} + + + {{ deviceTransportTypeTranslationMap.get(DeviceTransportType.SNMP) | translate }} + + + {{ deviceTransportTypeTranslationMap.get(DeviceTransportType.LWM2M) | translate }} + + +
+ + +
device.connectivity.use-following-instructions
+ + + + + Windows + + +
+
+
device.connectivity.install-necessary-client-tools
+
device.connectivity.install-curl-windows
+
+ + +
+
+
+ + + + MacOS + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+ + + + Linux + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+
+
+ +
+ + +
+ +
device.connectivity.use-following-instructions
+ + + + + Windows + + +
+
+
device.connectivity.install-necessary-client-tools
+
+ + +
+
+ + +
+
+
+ + + + MacOS + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+ + + + Linux + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+ + + + Docker + + +
+ + +
+
+
+
+
+
+ +
device.connectivity.use-following-instructions
+ + + + + MacOS + + +
+
+
device.connectivity.install-necessary-client-tools
+
+ + +
+
+ + +
+
+
+ + + + Linux + + +
+
+
device.connectivity.install-necessary-client-tools
+
+ + +
+
+ + +
+
+
+ + + + Docker + + +
+ + +
+
+
+
+
+ +
+ + +
+
+ +
+ + +
+
+
+
+
+
+
device.state
+
+ {{ (status ? 'device.active' : 'device.inactive') | translate }} +
+
+
attribute.latest-telemetry
+
+
+
device.time
+
attribute.key
+
attribute.value
+
+
+
+
{{ telemetry.lastUpdateTs | date: 'yyyy-MM-dd HH:mm:ss' }}
+
{{ telemetry.key }}
+
{{ telemetry.value }}
+
+
+
+
+
+
+
+ {{ 'action.dont-show-again' | translate}} + + +
+ +
+ + + {{ 'device.connectivity.loading-check-connectivity-command' | translate }} + +
+
+ +
+
+
attribute.no-latest-telemetry
+
+
+ + +
+
+
device.connectivity.execute-following-command
+ + {{ cmd.noSecLabel }} + {{ cmd.secLabel }} + +
+ + + + + +
+ +
+ + + + +
+
+
+
+ + +
+ diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss new file mode 100644 index 0000000000..348fa01a26 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss @@ -0,0 +1,177 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "../../../../../scss/constants"; + +:host { + height: 100%; + max-height: 100vh; + display: grid; + grid-template-rows: min-content minmax(auto, 1fr) min-content; + + .tb-loader { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; + height: 300px; + max-height: 100%; + + .label { + margin-bottom: 0; + text-align: center; + } + } + + .status { + margin-left: 12px; + border-radius: 12px; + height: 24px; + line-height: 24px; + padding: 0 8px; + width: fit-content; + color: #198038; + background-color: rgba(25, 128, 56, 0.08); + font-size: 14px; + + &.inactive { + color: #d12730; + background-color: rgba(209, 39, 48, 0.08); + } + } + + .tb-hint-instruction { + border-radius: 6px; + background-color: rgba(48, 86, 128, 0.04); + padding: 6px 16px; + + .content { + vertical-align: middle; + } + } + + .tb-font-14 { + font-size: 14px; + } + + .tb-flex-1 { + flex: 1; + } + + .tb-form-table-body { + max-height: 108px; + min-height: 108px; + overflow-y: auto; + scrollbar-gutter: stable; + + .tb-form-table-row { + min-height: 38px; + } + } + + .tb-no-data-available { + .tb-no-data-bg { + min-height: 68px; + } + } + + .tb-install-instruction-text { + min-height: 42px; + } + + @media #{$mat-sm} { + width: 470px; + } + + @media #{$mat-gt-sm} { + width: 720px; + } +} + +:host-context(.mat-mdc-dialog-container) { + .tb-dialog-actions { + display: flex; + gap: 8px; + padding: 8px 16px; + } + + .mat-mdc-dialog-content { + max-height: 80vh; + padding: 16px; + } +} + +:host ::ng-deep { + .tb-markdown-view { + .tb-command-code { + .code-wrapper { + padding: 0; + pre[class*=language-] { + margin: 0; + background: #F3F6FA; + border-color: #305680; + padding-right: 38px; + overflow: scroll; + padding-bottom: 4px; + + &::-webkit-scrollbar { + width: 4px; + height: 4px; + } + } + } + button.clipboard-btn { + right: -2px; + p { + color: #305680; + } + p, div { + background-color: #F3F6FA; + } + div { + img { + display: none; + } + &:after { + content: ""; + position: initial; + display: block; + width: 18px; + height: 18px; + background: #305680; + mask-image: url(/assets/copy-code-icon.svg); + mask-repeat: no-repeat; + } + } + } + } + } + .mdc-button__label > span { + .mat-icon { + vertical-align: text-bottom; + box-sizing: initial; + } + } + + .tabs-icon { + margin-right: 8px; + } + + .tb-form-panel.tb-tab-body { + padding: 16px 0 0; + } +} diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts new file mode 100644 index 0000000000..7516e0f3e1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts @@ -0,0 +1,222 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, Inject, NgZone, OnDestroy, OnInit } from '@angular/core'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { select, Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { DeviceService } from '@core/http/device.service'; +import { + AttributeData, + AttributeScope, + AttributesSubscriptionCmd, + LatestTelemetry, + TelemetrySubscriber +} from '@shared/models/telemetry/telemetry.models'; +import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service'; +import { EntityId } from '@shared/models/id/entity-id'; +import { EntityType } from '@shared/models/entity-type.models'; +import { selectPersistDeviceStateToTelemetry } from '@core/auth/auth.selectors'; +import { take } from 'rxjs/operators'; +import { + BasicTransportType, + DeviceTransportType, + deviceTransportTypeTranslationMap, + NetworkTransportType, + PublishTelemetryCommand +} from '@shared/models/device.models'; +import { ActionPreferencesPutUserSettings } from '@core/auth/auth.actions'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { getOS } from '@core/utils'; + +export interface DeviceCheckConnectivityDialogData { + deviceId: EntityId; + afterAdd: boolean; +} + +@Component({ + selector: 'tb-device-check-connectivity-dialog', + templateUrl: './device-check-connectivity-dialog.component.html', + styleUrls: ['./device-check-connectivity-dialog.component.scss'] +}) +export class DeviceCheckConnectivityDialogComponent extends + DialogComponent implements OnInit, OnDestroy { + + loadedCommand = false; + + status: boolean; + + latestTelemetry: Array = []; + + commands: PublishTelemetryCommand; + + allowTransportType = new Set(); + selectTransportType: NetworkTransportType; + + BasicTransportType = BasicTransportType; + DeviceTransportType = DeviceTransportType; + deviceTransportTypeTranslationMap = deviceTransportTypeTranslationMap; + + showDontShowAgain: boolean; + dialogTitle: string; + closeButtonLabel: string; + + notShowAgain = false; + + httpTabIndex = 0; + mqttTabIndex = 0; + coapTabIndex = 0; + + private telemetrySubscriber: TelemetrySubscriber; + + private currentTime = Date.now(); + + private transportTypes = [...Object.keys(BasicTransportType), ...Object.keys(DeviceTransportType)] as Array; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) private data: DeviceCheckConnectivityDialogData, + public dialogRef: MatDialogRef, + private deviceService: DeviceService, + private telemetryWsService: TelemetryWebsocketService, + private zone: NgZone) { + super(store, router, dialogRef); + + if (this.data.afterAdd) { + this.dialogTitle = 'device.connectivity.device-created-check-connectivity'; + this.closeButtonLabel = 'action.skip'; + this.showDontShowAgain = true; + } else { + this.dialogTitle = 'device.connectivity.check-connectivity'; + this.closeButtonLabel = 'action.close'; + this.showDontShowAgain = false; + } + } + + ngOnInit() { + this.loadCommands(); + this.subscribeToLatestTelemetry(); + } + + ngOnDestroy() { + super.ngOnDestroy(); + this.telemetrySubscriber?.complete(); + this.telemetrySubscriber?.unsubscribe(); + } + + close(): void { + if (this.notShowAgain && this.showDontShowAgain) { + this.store.dispatch(new ActionPreferencesPutUserSettings({ notDisplayConnectivityAfterAddDevice: true })); + this.dialogRef.close(null); + } else { + this.dialogRef.close(null); + } + } + + createMarkDownCommand(commands: string | string[]): string { + if (Array.isArray(commands)) { + const formatCommands: Array = []; + commands.forEach(command => formatCommands.push(this.createMarkDownSingleCommand(command))); + return formatCommands.join(`\n
\n\n`); + } else { + return this.createMarkDownSingleCommand(commands); + } + } + + private createMarkDownSingleCommand(command: string): string { + return '```bash\n' + + command + + '{:copy-code}\n' + + '```'; + } + + private loadCommands() { + this.deviceService.getDevicePublishTelemetryCommands(this.data.deviceId.id).subscribe( + commands => { + this.commands = commands; + const commandsProtocols = Object.keys(commands); + this.transportTypes.forEach(transport => { + const findCommand = commandsProtocols.find(item => item.toUpperCase().startsWith(transport)); + if (findCommand) { + this.allowTransportType.add(transport); + } + }); + this.selectTransportType = this.allowTransportType.values().next().value; + this.selectTabIndexForUserOS(); + this.loadedCommand = true; + } + ); + } + + private subscribeToLatestTelemetry() { + this.store.pipe(select(selectPersistDeviceStateToTelemetry)).pipe( + take(1) + ).subscribe(persistToTelemetry => { + this.telemetrySubscriber = TelemetrySubscriber.createEntityAttributesSubscription( + this.telemetryWsService, this.data.deviceId, LatestTelemetry.LATEST_TELEMETRY, this.zone); + if (!persistToTelemetry) { + const subscriptionCommand = new AttributesSubscriptionCmd(); + subscriptionCommand.entityType = this.data.deviceId.entityType as EntityType; + subscriptionCommand.entityId = this.data.deviceId.id; + subscriptionCommand.scope = AttributeScope.SERVER_SCOPE; + subscriptionCommand.keys = 'active'; + this.telemetrySubscriber.subscriptionCommands.push(subscriptionCommand); + } + + this.telemetrySubscriber.subscribe(); + this.telemetrySubscriber.attributeData$().subscribe( + (data) => { + const telemetry = data.reduce>((accumulator, item) => { + if (item.key === 'active') { + this.status = coerceBooleanProperty(item.value); + } else if (item.lastUpdateTs > this.currentTime) { + accumulator.push(item); + } + return accumulator; + }, []); + this.latestTelemetry = telemetry.sort((a, b) => b.lastUpdateTs - a.lastUpdateTs); + } + ); + }); + } + + private selectTabIndexForUserOS() { + const currentOS = getOS(); + switch (currentOS) { + case 'linux': + case 'android': + this.httpTabIndex = 2; + this.mqttTabIndex = 2; + this.coapTabIndex = 1; + break; + case 'macos': + case 'ios': + this.httpTabIndex = 1; + this.mqttTabIndex = 1; + break; + case 'windows': + this.httpTabIndex = 0; + this.mqttTabIndex = 0; + break; + default: + this.mqttTabIndex = this.commands.mqtt?.docker ? 3 : 0; + this.coapTabIndex = this.commands.coap?.docker ? 2 : 1; + } + } + +} diff --git a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html index ff32bf68df..d7f964542e 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html @@ -15,49 +15,47 @@ limitations under the License. --> -
- -

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

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

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

+ + +
+ + +
+
+
+ + +
+
+ +
+ + + {{ 'device.loading-device-credentials' | translate }} + +
+
+
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.scss new file mode 100644 index 0000000000..f2c168e150 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.scss @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@import "../../../../../scss/constants"; + +:host { + height: 100%; + display: grid; + grid-template-rows: min-content 4px auto min-content; + + @media #{$mat-gt-xs} { + min-width: 420px; + } +} + +:host-context(.mat-mdc-dialog-container) { + .tb-dialog-actions { + grid-row: 4; + display: flex; + gap: 8px; + justify-content: flex-end; + flex: 1; + } + + .mat-mdc-dialog-content { + grid-row: 3; + padding: 24px 24px 4px; + } +} diff --git a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts index 41986b2b03..cb4a795c9e 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts @@ -37,7 +37,7 @@ export interface DeviceCredentialsDialogData { selector: 'tb-device-credentials-dialog', templateUrl: './device-credentials-dialog.component.html', providers: [{provide: ErrorStateMatcher, useExisting: DeviceCredentialsDialogComponent}], - styleUrls: [] + styleUrls: ['./device-credentials-dialog.component.scss'] }) export class DeviceCredentialsDialogComponent extends DialogComponent implements OnInit, ErrorStateMatcher { diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.html b/ui-ngx/src/app/modules/home/pages/device/device.component.html index e619fa9561..0b1ef5225c 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.html @@ -46,6 +46,12 @@ [fxShow]="!isEdit"> {{ ((deviceScope === 'customer_user' || deviceScope === 'edge_customer_user') ? 'device.view-credentials' : 'device.manage-credentials') | translate }} +
diff --git a/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.scss index 7de71586fa..d289574f15 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.scss @@ -21,7 +21,7 @@ display: flex; flex-direction: column; align-items: center; - mat-icon { + .mat-icon { margin: auto; } span.mdc-button__label { diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss index b8359b38db..f928dde955 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss @@ -185,7 +185,7 @@ mat-toolbar.tb-edit-toolbar { white-space: nowrap; height: 28px; - mat-icon { + .mat-icon { height: 20px; width: 20px; font-size: 20px; diff --git a/ui-ngx/src/app/shared/components/breadcrumb.component.html b/ui-ngx/src/app/shared/components/breadcrumb.component.html index be7f1e6b16..594578465f 100644 --- a/ui-ngx/src/app/shared/components/breadcrumb.component.html +++ b/ui-ngx/src/app/shared/components/breadcrumb.component.html @@ -37,11 +37,9 @@
- - - + {{ breadcrumb.icon }} - + {{ breadcrumb.ignoreTranslate ? (breadcrumb.labelFunction ? breadcrumb.labelFunction() : utils.customTranslation(breadcrumb.label, breadcrumb.label)) : (breadcrumb.label | translate) }} diff --git a/ui-ngx/src/app/shared/components/breadcrumb.component.ts b/ui-ngx/src/app/shared/components/breadcrumb.component.ts index 2542f58871..380ddc59ce 100644 --- a/ui-ngx/src/app/shared/components/breadcrumb.component.ts +++ b/ui-ngx/src/app/shared/components/breadcrumb.component.ts @@ -117,7 +117,6 @@ export class BreadcrumbComponent implements OnInit, OnDestroy { ignoreTranslate = false; } const icon = breadcrumbConfig.icon || 'home'; - const isMdiIcon = icon.startsWith('mdi:'); const link = [ route.pathFromRoot.map(v => v.url.map(segment => segment.toString()).join('/')).join('/') ]; const breadcrumb = { id: guid(), @@ -125,7 +124,6 @@ export class BreadcrumbComponent implements OnInit, OnDestroy { labelFunction, ignoreTranslate, icon, - isMdiIcon, link, queryParams: null }; diff --git a/ui-ngx/src/app/shared/components/breadcrumb.ts b/ui-ngx/src/app/shared/components/breadcrumb.ts index 599f8b85e8..77a832dbed 100644 --- a/ui-ngx/src/app/shared/components/breadcrumb.ts +++ b/ui-ngx/src/app/shared/components/breadcrumb.ts @@ -23,7 +23,6 @@ export interface BreadCrumb extends HasUUID{ labelFunction?: () => string; ignoreTranslate: boolean; icon: string; - isMdiIcon: boolean; link: any[]; queryParams: Params; } diff --git a/ui-ngx/src/app/shared/components/color-input.component.html b/ui-ngx/src/app/shared/components/color-input.component.html index 492a2419eb..68ec5854f2 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.html +++ b/ui-ngx/src/app/shared/components/color-input.component.html @@ -20,10 +20,10 @@ {{icon}} {{label}} -
+
- + diff --git a/ui-ngx/src/app/shared/components/color-input.component.scss b/ui-ngx/src/app/shared/components/color-input.component.scss index ca8ffedc72..2660c16dc8 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.scss +++ b/ui-ngx/src/app/shared/components/color-input.component.scss @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@import './../../../scss/mixins'; + :host { .mat-mdc-form-field { width: 100%; diff --git a/ui-ngx/src/app/shared/components/color-input.component.ts b/ui-ngx/src/app/shared/components/color-input.component.ts index 08432d6967..f22b91fde2 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.ts +++ b/ui-ngx/src/app/shared/components/color-input.component.ts @@ -14,15 +14,24 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { + ControlValueAccessor, + NG_VALUE_ACCESSOR, + UntypedFormBuilder, + UntypedFormGroup, + Validators +} from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { DialogService } from '@core/services/dialog.service'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { ColorPickerPanelComponent } from '@shared/components/color-picker/color-picker-panel.component'; +import { MatButton } from '@angular/material/button'; @Component({ selector: 'tb-color-input', @@ -100,6 +109,9 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro constructor(protected store: Store, private dialogs: DialogService, private translate: TranslateService, + private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef, private fb: UntypedFormBuilder, private cd: ChangeDetectorRef) { super(store); @@ -153,7 +165,8 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro } } - showColorPicker() { + showColorPicker($event: MouseEvent) { + $event.stopPropagation(); this.dialogs.colorPicker(this.colorFormGroup.get('color').value).subscribe( (color) => { if (color) { @@ -166,6 +179,32 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro ); } + openColorPickerPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const colorPickerPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, ColorPickerPanelComponent, 'left', true, null, + { + color: this.colorFormGroup.get('color').value + }, + {}, + {}, {}, true); + colorPickerPopover.tbComponentRef.instance.popover = colorPickerPopover; + colorPickerPopover.tbComponentRef.instance.colorSelected.subscribe((color) => { + colorPickerPopover.hide(); + this.colorFormGroup.patchValue( + {color}, {emitEvent: true} + ); + this.cd.markForCheck(); + }); + } + } + clear() { this.colorFormGroup.get('color').patchValue(null, {emitEvent: true}); this.cd.markForCheck(); diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html new file mode 100644 index 0000000000..56e4523b67 --- /dev/null +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html @@ -0,0 +1,30 @@ + +
+
color.color
+ +
+ +
+
diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss new file mode 100644 index 0000000000..e7d78b4018 --- /dev/null +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.tb-color-picker-panel { + width: 328px; + display: flex; + flex-direction: column; + gap: 16px; + .tb-color-picker-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-color-picker-panel-buttons { + height: 60px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts new file mode 100644 index 0000000000..59199388b8 --- /dev/null +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts @@ -0,0 +1,55 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { PageComponent } from '@shared/components/page.component'; +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { UntypedFormControl } from '@angular/forms'; +import { TbPopoverComponent } from '@shared/components/popover.component'; + +@Component({ + selector: 'tb-color-picker-panel', + templateUrl: './color-picker-panel.component.html', + providers: [], + styleUrls: ['./color-picker-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ColorPickerPanelComponent extends PageComponent implements OnInit { + + @Input() + color: string; + + @Input() + popover: TbPopoverComponent; + + @Output() + colorSelected = new EventEmitter(); + + colorPickerControl: UntypedFormControl; + + constructor(protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.colorPickerControl = new UntypedFormControl(this.color); + } + + selectColor() { + this.colorSelected.emit(this.colorPickerControl.value); + } +} diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html index d1432d27f5..5806037c89 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html @@ -19,7 +19,7 @@
@@ -29,7 +29,12 @@
-
+ + HEX + RGBA + HSLA + +
-
+
+ +
+
diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss index ea2bfa94ba..dc1d3b5042 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss @@ -17,12 +17,10 @@ width: 100%; display: flex; flex-direction: column; - gap: 16px; + gap: 32px; .saturation-component { - height: 100%; - min-height: 200px; - max-height: 300px; + height: 238px; border-radius: 8px; } @@ -55,6 +53,12 @@ .color-input-block { display: flex; + gap: 20px; + + .presentation-select { + font-size: 14px; + width: 56px; + } .color-input { flex: 1; @@ -63,16 +67,13 @@ color: initial; } } + } - .type-btn { - height: 26px; - width: 20px; - background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAgCAMAAAAootjDAAAAM1BMVEUAAAAzMzMzMzMzMzMzMzM0NDQzMzMzMzM0NDQzMzMzMzM0NDQzMzMzMzMyMjIrKyszMzPF8UZlAAAAEHRSTlMA1fHr4ZxxSRP45sG+sCkGH2+Z6QAAAHJJREFUKM+9kkkSgCAQA0FEVLb5/2tViqgQvNrHviSzKGCt6nDGuNass8i8NsrLiX+bZbrUtDwm7VLYE0zWUtEZ+RvUZpEvN8YhH9QmQRoC8kFpEnVHVP/DJUZVeSAem5fDKxwtms/BR+PT8gN8vwk/0wE1gQzNVYryIwAAAABJRU5ErkJggg==') no-repeat center; - background-size: 6px 12px; - - &:hover { - background-color: #eee; - } + .color-presets-block { + .color-presets-component { + display: flex; + flex-direction: column; + gap: 12px; } } } @@ -105,4 +106,16 @@ } } } + + .color-presets-component { + .presets-row { + gap: 10px; + justify-content: space-between; + } + color-preset { + height: 20px; + width: 20px; + border-radius: 4px; + } + } } diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts index ce49310b03..47a745819d 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts @@ -17,7 +17,7 @@ import { Component, forwardRef, OnDestroy } from '@angular/core'; import { Color, ColorPickerControl } from '@iplab/ngx-color-picker'; import { Subscription } from 'rxjs'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; export enum ColorType { hex = 'hex', @@ -29,6 +29,10 @@ export enum ColorType { cmyk = 'cmyk' } +const colorPresetsHex = + ['#435B63', '#F44336', '#E89623', '#F5DD00', '#8BC34A', '#4CAF50', '#009688', '#048AD3', '#673AB7', '#9C27B0', '#E91E63', + '#A1ADB1', '#F9A19B', '#FFD190', '#FFF59D', '#C5E1A4', '#A5D7A7', '#80CBC3', '#81C4E9', '#B39CDB', '#CD93D7', '#F48FB1']; + @Component({ selector: `tb-color-picker`, templateUrl: `./color-picker.component.html`, @@ -43,10 +47,13 @@ export enum ColorType { }) export class ColorPickerComponent implements ControlValueAccessor, OnDestroy { - selectedPresentation = 0; presentations = [ColorType.hex, ColorType.rgba, ColorType.hsla]; control = new ColorPickerControl(); + presentationControl = new UntypedFormControl(0); + + colorPresets: Color[] = colorPresetsHex.map(c => Color.from(c)); + private modelValue: string; private subscriptions: Array = []; @@ -65,6 +72,11 @@ export class ColorPickerComponent implements ControlValueAccessor, OnDestroy { } }) ); + this.subscriptions.push( + this.presentationControl.valueChanges.subscribe(() => { + this.updateModel(); + }) + ); } registerOnChange(fn: any): void { @@ -86,12 +98,11 @@ export class ColorPickerComponent implements ControlValueAccessor, OnDestroy { } else if (this.control.initType === ColorType.hsl) { this.control.initType = ColorType.hsla; } - - this.selectedPresentation = this.presentations.indexOf(this.control.initType); + this.presentationControl.patchValue(this.presentations.indexOf(this.control.initType), {emitEvent: false}); } private updateModel() { - const color: string = this.getValueByType(this.control.value, this.presentations[this.selectedPresentation]); + const color: string = this.getValueByType(this.control.value, this.presentations[this.presentationControl.value]); if (this.modelValue !== color) { this.modelValue = color; this.propagateChange(color); @@ -103,12 +114,6 @@ export class ColorPickerComponent implements ControlValueAccessor, OnDestroy { this.subscriptions.length = 0; } - public changePresentation(): void { - this.selectedPresentation = - this.selectedPresentation === this.presentations.length - 1 ? 0 : this.selectedPresentation + 1; - this.updateModel(); - } - getValueByType(color: Color, type: ColorType): string { switch (type) { case ColorType.hex: diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html index eaec4c0b5e..0d916f428a 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html @@ -15,22 +15,14 @@ limitations under the License. --> -
-
- -
-
- - - -
-
+
+ + + +
diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss new file mode 100644 index 0000000000..afd8d1cfcb --- /dev/null +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + .tb-close-button { + position: absolute; + top: 6px; + right: 6px; + } +} diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts index 44959023f4..219ed0ec56 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts @@ -14,11 +14,10 @@ /// limitations under the License. /// -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { DialogComponent } from '@shared/components/dialog.component'; @@ -29,33 +28,26 @@ export interface ColorPickerDialogData { @Component({ selector: 'tb-color-picker-dialog', templateUrl: './color-picker-dialog.component.html', - styleUrls: [] + styleUrls: ['./color-picker-dialog.component.scss'] }) -export class ColorPickerDialogComponent extends DialogComponent - implements OnInit { +export class ColorPickerDialogComponent extends DialogComponent { - colorPickerFormGroup: FormGroup; + color: string; constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: ColorPickerDialogData, - public dialogRef: MatDialogRef, - public fb: FormBuilder) { + public dialogRef: MatDialogRef) { super(store, router, dialogRef); + this.color = data.color; } - ngOnInit(): void { - this.colorPickerFormGroup = this.fb.group({ - color: [this.data.color, [Validators.required]] - }); + selectColor(color: string) { + this.dialogRef.close(color); } cancel(): void { this.dialogRef.close(null); } - select(): void { - const color: string = this.colorPickerFormGroup.get('color').value; - this.dialogRef.close(color); - } } diff --git a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.html index 94d256fd61..1051be6525 100644 --- a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.html @@ -15,63 +15,14 @@ limitations under the License. --> -
- -

{{ 'icon.select-icon' | translate }}

- -
- - - -
- -
- - -
-
- -
-
-
-
- - - - - - -
-
-
-
- - -
-
+
+ + + +
diff --git a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.scss b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.scss index 849b646234..afd8d1cfcb 100644 --- a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.scss +++ b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.scss @@ -14,36 +14,9 @@ * limitations under the License. */ :host { - .tb-material-icons-dialog { - position: relative; - } - .tb-icons-load { - top: 64px; - z-index: 3; - background: rgba(255, 255, 255, .75); - } -} - -:host ::ng-deep { - .tb-material-icons-dialog { - button.mat-mdc-button-base.tb-select-icon-button { - width: 56px; - min-width: 56px; - height: 56px; - padding: 16px; - margin: 10px; - border: solid 1px #ffa500; - border-radius: 0; - line-height: 0; - display: inline-block; - vertical-align: baseline; - .mat-icon { - width: 24px; - margin: 0; - height: 24px; - vertical-align: initial; - font-size: 24px; - } - } + .tb-close-button { + position: absolute; + top: 6px; + right: 6px; } } diff --git a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts index cfa4c3d44f..b6321c966d 100644 --- a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts @@ -14,16 +14,12 @@ /// limitations under the License. /// -import { AfterViewInit, Component, Inject, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Router } from '@angular/router'; import { DialogComponent } from '@shared/components/dialog.component'; -import { UtilsService } from '@core/services/utils.service'; -import { UntypedFormControl } from '@angular/forms'; -import { merge, Observable, of } from 'rxjs'; -import { delay, map, mapTo, mergeMap, share, startWith, tap } from 'rxjs/operators'; export interface MaterialIconsDialogData { icon: string; @@ -35,64 +31,16 @@ export interface MaterialIconsDialogData { providers: [], styleUrls: ['./material-icons-dialog.component.scss'] }) -export class MaterialIconsDialogComponent extends DialogComponent - implements OnInit, AfterViewInit { - - @ViewChildren('iconButtons') iconButtons: QueryList; +export class MaterialIconsDialogComponent extends DialogComponent { selectedIcon: string; - icons$: Observable>; - loadingIcons$: Observable; - - showAllControl: UntypedFormControl; constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: MaterialIconsDialogData, - private utils: UtilsService, public dialogRef: MatDialogRef) { super(store, router, dialogRef); this.selectedIcon = data.icon; - this.showAllControl = new UntypedFormControl(false); - } - - ngOnInit(): void { - this.icons$ = this.showAllControl.valueChanges.pipe( - map((showAll) => { - return {firstTime: false, showAll}; - }), - startWith<{firstTime: boolean, showAll: boolean}>({firstTime: true, showAll: false}), - mergeMap((data) => { - if (data.showAll) { - return this.utils.getMaterialIcons().pipe(delay(100)); - } else { - const res = of(this.utils.getCommonMaterialIcons()); - return data.firstTime ? res : res.pipe(delay(50)); - } - }), - share() - ); - } - - ngAfterViewInit(): void { - this.loadingIcons$ = merge( - this.showAllControl.valueChanges.pipe( - mapTo(true), - ), - this.iconButtons.changes.pipe( - delay(100), - mapTo( false), - ) - ).pipe( - tap((loadingIcons) => { - if (loadingIcons) { - this.showAllControl.disable({emitEvent: false}); - } else { - this.showAllControl.enable({emitEvent: false}); - } - }), - share() - ); } selectIcon(icon: string) { diff --git a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html index 6d8a424352..fdf6b2aeac 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html @@ -33,7 +33,7 @@ #entityAutocomplete="matAutocomplete" [displayWith]="displayEntityFn"> - + diff --git a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts index af0373b7a9..ea89a064a3 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts @@ -26,7 +26,7 @@ import { ViewChild } from '@angular/core'; import { MatFormFieldAppearance } from '@angular/material/form-field'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { merge, Observable, of, Subject } from 'rxjs'; import { catchError, debounceTime, map, share, switchMap, tap } from 'rxjs/operators'; import { Store } from '@ngrx/store'; @@ -55,7 +55,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit selectEntityFormGroup: UntypedFormGroup; - modelValue: string | null; + modelValue: string | EntityId | null; entityTypeValue: EntityType | AliasEntityType; @@ -113,6 +113,10 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit @Input() requiredText: string; + @Input() + @coerceBoolean() + useFullEntityId: boolean; + @Input() appearance: MatFormFieldAppearance = 'fill'; @@ -171,7 +175,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit if (typeof value === 'string' || !value) { modelValue = null; } else { - modelValue = value.id.id; + modelValue = this.useFullEntityId ? value.id : value.id.id; } this.updateView(modelValue, value); if (value === null) { @@ -307,7 +311,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit } catch (e) { this.propagateChange(null); } - this.modelValue = entity !== null ? entity.id.id : null; + this.modelValue = entity !== null ? (this.useFullEntityId ? entity.id : entity.id.id) : null; this.selectEntityFormGroup.get('entity').patchValue(entity !== null ? entity : '', {emitEvent: false}); this.entityChanged.emit(entity); } else { diff --git a/ui-ngx/src/app/shared/components/fab-toolbar.component.scss b/ui-ngx/src/app/shared/components/fab-toolbar.component.scss index e8e0c0b9f2..42f2e0c9eb 100644 --- a/ui-ngx/src/app/shared/components/fab-toolbar.component.scss +++ b/ui-ngx/src/app/shared/components/fab-toolbar.component.scss @@ -74,7 +74,7 @@ mat-fab-toolbar { button.mat-mdc-fab { overflow: visible !important; opacity: .5; - mat-icon { + .mat-icon { position: relative; z-index: $z-index-fab + 2; opacity: 1; @@ -146,7 +146,7 @@ mat-fab-toolbar { box-shadow: none; opacity: 1; - mat-icon { + .mat-icon { opacity: 0; } } @@ -163,7 +163,7 @@ mat-fab-toolbar { mat-fab-trigger { button.mat-mdc-fab { transition: opacity .3s cubic-bezier(.55, 0, .55, .2) .2s; - mat-icon { + .mat-icon { transition: all $icon-delay ease-in; } } diff --git a/ui-ngx/src/app/shared/components/help-markdown.component.ts b/ui-ngx/src/app/shared/components/help-markdown.component.ts index 97bd326b46..90ac325c55 100644 --- a/ui-ngx/src/app/shared/components/help-markdown.component.ts +++ b/ui-ngx/src/app/shared/components/help-markdown.component.ts @@ -24,6 +24,7 @@ import { import { BehaviorSubject } from 'rxjs'; import { share } from 'rxjs/operators'; import { HelpService } from '@core/services/help.service'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-help-markdown', @@ -36,7 +37,9 @@ export class HelpMarkdownComponent implements OnDestroy, OnInit, OnChanges { @Input() helpContent: string; - @Input() visible: boolean; + @Input() + @coerceBoolean() + visible: boolean; @Input() style: { [klass: string]: any } = {}; diff --git a/ui-ngx/src/app/shared/components/icon.component.ts b/ui-ngx/src/app/shared/components/icon.component.ts new file mode 100644 index 0000000000..d1e2c6ddcd --- /dev/null +++ b/ui-ngx/src/app/shared/components/icon.component.ts @@ -0,0 +1,281 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { CanColor, mixinColor } from '@angular/material/core'; +import { + AfterContentInit, + AfterViewChecked, + ChangeDetectionStrategy, + Component, + ElementRef, + ErrorHandler, + Inject, + OnDestroy, + Renderer2, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { MAT_ICON_LOCATION, MatIconLocation, MatIconRegistry } from '@angular/material/icon'; +import { Subscription } from 'rxjs'; +import { take } from 'rxjs/operators'; +import { isSvgIcon, splitIconName } from '@shared/models/icon.models'; +import { ContentObserver } from '@angular/cdk/observers'; + +const _TbIconBase = mixinColor( + class { + constructor(public _elementRef: ElementRef) {} + }, +); + +const funcIriAttributes = [ + 'clip-path', + 'color-profile', + 'src', + 'cursor', + 'fill', + 'filter', + 'marker', + 'marker-start', + 'marker-mid', + 'marker-end', + 'mask', + 'stroke', +]; + +const funcIriAttributeSelector = funcIriAttributes.map(attr => `[${attr}]`).join(', '); + +const funcIriPattern = /^url\(['"]?#(.*?)['"]?\)$/; + +@Component({ + template: '', + selector: 'tb-icon', + exportAs: 'tbIcon', + styleUrls: [], + // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property + inputs: ['color'], + // eslint-disable-next-line @angular-eslint/no-host-metadata-property + host: { + role: 'img', + class: 'mat-icon notranslate', + '[attr.data-mat-icon-type]': '!_useSvgIcon ? "font" : "svg"', + '[attr.data-mat-icon-name]': '_svgName', + '[attr.data-mat-icon-namespace]': '_svgNamespace', + '[class.mat-icon-no-color]': 'color !== "primary" && color !== "accent" && color !== "warn"', + }, + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TbIconComponent extends _TbIconBase + implements AfterContentInit, AfterViewChecked, CanColor, OnDestroy { + + @ViewChild('iconNameContent', {static: true}) + _iconNameContent: ElementRef; + + private icon: string; + + get viewValue(): string { + return (this._iconNameContent?.nativeElement.textContent || '').trim(); + } + + private _contentChanges: Subscription = null; + private _previousFontSetClass: string[] = []; + + _useSvgIcon = false; + _svgName: string | null; + _svgNamespace: string | null; + + private _textElement = null; + + private _previousPath?: string; + + private _elementsWithExternalReferences?: Map; + + private _currentIconFetch = Subscription.EMPTY; + + constructor(elementRef: ElementRef, + private contentObserver: ContentObserver, + private renderer: Renderer2, + private _iconRegistry: MatIconRegistry, + @Inject(MAT_ICON_LOCATION) private _location: MatIconLocation, + private readonly _errorHandler: ErrorHandler) { + super(elementRef); + } + + ngAfterContentInit(): void { + this.icon = this.viewValue; + this._updateIcon(); + this._contentChanges = this.contentObserver.observe(this._iconNameContent.nativeElement) + .subscribe(() => { + const content = this.viewValue; + if (content && this.icon !== content) { + this.icon = content; + this._updateIcon(); + } + }); + } + + ngAfterViewChecked() { + const cachedElements = this._elementsWithExternalReferences; + if (cachedElements && cachedElements.size) { + const newPath = this._location.getPathname(); + if (newPath !== this._previousPath) { + this._previousPath = newPath; + this._prependPathToReferences(newPath); + } + } + } + + ngOnDestroy() { + this._contentChanges.unsubscribe(); + this._currentIconFetch.unsubscribe(); + if (this._elementsWithExternalReferences) { + this._elementsWithExternalReferences.clear(); + } + } + + private _updateIcon() { + const useSvgIcon = isSvgIcon(this.icon); + if (this._useSvgIcon !== useSvgIcon) { + this._useSvgIcon = useSvgIcon; + if (!this._useSvgIcon) { + this._updateSvgIcon(undefined); + } else { + this._updateFontIcon(undefined); + } + } + if (this._useSvgIcon) { + this._updateSvgIcon(this.icon); + } else { + this._updateFontIcon(this.icon); + } + } + + private _updateFontIcon(rawName: string | undefined) { + if (rawName) { + this._clearFontIcon(); + const iconName = splitIconName(rawName)[1]; + this._textElement = this.renderer.createText(iconName); + const elem: HTMLElement = this._elementRef.nativeElement; + this.renderer.insertBefore(elem, this._textElement, this._iconNameContent.nativeElement); + const fontSetClasses = ( + this._iconRegistry.getDefaultFontSetClass() + ).filter(className => className.length > 0); + fontSetClasses.forEach(className => elem.classList.add(className)); + this._previousFontSetClass = fontSetClasses; + } else { + this._clearFontIcon(); + } + } + + private _clearFontIcon() { + const elem: HTMLElement = this._elementRef.nativeElement; + if (this._textElement !== null) { + this.renderer.removeChild(elem, this._textElement); + this._textElement = null; + } + this._previousFontSetClass.forEach(className => elem.classList.remove(className)); + this._previousFontSetClass = []; + } + + private _updateSvgIcon(rawName: string | undefined) { + this._svgNamespace = null; + this._svgName = null; + this._currentIconFetch.unsubscribe(); + + if (rawName) { + const [namespace, iconName] = splitIconName(rawName); + if (namespace) { + this._svgNamespace = namespace; + } + if (iconName) { + this._svgName = iconName; + } + this._iconRegistry.getDefaultFontSetClass(); + this._currentIconFetch = this._iconRegistry + .getNamedSvgIcon(iconName, namespace) + .pipe(take(1)) + .subscribe({ + next: (svg) => this._setSvgElement(svg), + error: (err: Error) => { + const errorMessage = `Error retrieving icon ${namespace}:${iconName}! ${err.message}`; + this._errorHandler.handleError(new Error(errorMessage)); + } + }); + } else { + this._clearSvgElement(); + } + } + + private _setSvgElement(svg: SVGElement) { + this._clearSvgElement(); + const path = this._location.getPathname(); + this._previousPath = path; + this._cacheChildrenWithExternalReferences(svg); + this._prependPathToReferences(path); + this.renderer.insertBefore(this._elementRef.nativeElement, svg, this._iconNameContent.nativeElement); + } + + private _clearSvgElement() { + const layoutElement: HTMLElement = this._elementRef.nativeElement; + let childCount = layoutElement.childNodes.length; + if (this._elementsWithExternalReferences) { + this._elementsWithExternalReferences.clear(); + } + while (childCount--) { + const child = layoutElement.childNodes[childCount]; + if (child.nodeType !== 1 || child.nodeName.toLowerCase() === 'svg') { + child.remove(); + } + } + } + + private _cacheChildrenWithExternalReferences(element: SVGElement) { + const elementsWithFuncIri = element.querySelectorAll(funcIriAttributeSelector); + const elements = (this._elementsWithExternalReferences = this._elementsWithExternalReferences || new Map()); + elementsWithFuncIri.forEach( + (elementWithFuncIri) => { + funcIriAttributes.forEach(attr => { + const elementWithReference = elementWithFuncIri; + const value = elementWithReference.getAttribute(attr); + const match = value ? value.match(funcIriPattern) : null; + + if (match) { + let attributes = elements.get(elementWithReference); + + if (!attributes) { + attributes = []; + elements.set(elementWithReference, attributes); + } + + attributes.push({name: attr, value: match[1]}); + } + }); + } + ); + } + + private _prependPathToReferences(path: string) { + const elements = this._elementsWithExternalReferences; + if (elements) { + elements.forEach((attrs, element) => { + attrs.forEach(attr => { + element.setAttribute(attr.name, `url('${path}#${attr.value}')`); + }); + }); + } + } + +} diff --git a/ui-ngx/src/app/shared/components/js-func.component.html b/ui-ngx/src/app/shared/components/js-func.component.html index 23ebd76918..41e834668e 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.html +++ b/ui-ngx/src/app/shared/components/js-func.component.html @@ -27,6 +27,7 @@ +
, - private raf: RafService) { + private raf: RafService, + private cd: ChangeDetectorRef) { } ngOnInit(): void { @@ -283,6 +293,7 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va } this.modelValue = data; this.propagateChange(data); + this.cd.markForCheck(); } } diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.html b/ui-ngx/src/app/shared/components/material-icon-select.component.html index 5cf7cb6de7..8f7aa303f9 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.html +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.html @@ -16,7 +16,7 @@ -->
- {{materialIconFormGroup.get('icon').value}} + {{materialIconFormGroup.get('icon').value}} {{ label }} @@ -24,12 +24,18 @@ type="button" matSuffix mat-icon-button aria-label="Clear" (click)="clear()"> - close + close
- {{materialIconFormGroup.get('icon').value}} + diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.scss b/ui-ngx/src/app/shared/components/material-icon-select.component.scss index 6bfd308ae5..78e4d235cf 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.scss +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.scss @@ -22,20 +22,5 @@ border: solid 1px rgba(0, 0, 0, .27); box-sizing: initial; } - &.icon-box { - border: 1px solid rgba(0, 0, 0, 0.12); - border-radius: 4px; - cursor: pointer; - box-sizing: border-box; - padding: 8px; - height: 40px; - width: 40px; - font-size: 22px; - vertical-align: middle; - &.disabled { - cursor: initial; - color: rgba(0, 0, 0, 0.38); - } - } } } diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.ts b/ui-ngx/src/app/shared/components/material-icon-select.component.ts index b8bb7ed25b..740bb4545a 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.ts +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.ts @@ -14,15 +14,18 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { DialogService } from '@core/services/dialog.service'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { TranslateService } from '@ngx-translate/core'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { MaterialIconsComponent } from '@shared/components/material-icons.component'; +import { MatButton } from '@angular/material/button'; @Component({ selector: 'tb-material-icon-select', @@ -81,6 +84,9 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit constructor(protected store: Store, private dialogs: DialogService, private translate: TranslateService, + private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef, private fb: UntypedFormBuilder, private cd: ChangeDetectorRef) { super(store); @@ -142,6 +148,32 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit } } + openIconPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const materialIconsPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, MaterialIconsComponent, 'left', true, null, + { + selectedIcon: this.materialIconFormGroup.get('icon').value + }, + {}, + {}, {}, true); + materialIconsPopover.tbComponentRef.instance.popover = materialIconsPopover; + materialIconsPopover.tbComponentRef.instance.iconSelected.subscribe((icon) => { + materialIconsPopover.hide(); + this.materialIconFormGroup.patchValue( + {icon}, {emitEvent: true} + ); + this.cd.markForCheck(); + }); + } + } + clear() { this.materialIconFormGroup.get('icon').patchValue(null, {emitEvent: true}); this.cd.markForCheck(); diff --git a/ui-ngx/src/app/shared/components/material-icons.component.html b/ui-ngx/src/app/shared/components/material-icons.component.html new file mode 100644 index 0000000000..d31a73ddb5 --- /dev/null +++ b/ui-ngx/src/app/shared/components/material-icons.component.html @@ -0,0 +1,65 @@ + +
+
icon.icons
+ + search + + + + +
+ + + + +
+
+ + +
+
+
{{ 'icon.no-icons-found' | translate:{iconSearch: searchIconControl.value} }}
+
+
+
diff --git a/ui-ngx/src/app/shared/components/material-icons.component.scss b/ui-ngx/src/app/shared/components/material-icons.component.scss new file mode 100644 index 0000000000..23b959d118 --- /dev/null +++ b/ui-ngx/src/app/shared/components/material-icons.component.scss @@ -0,0 +1,61 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.tb-material-icons-panel { + width: 100%; + display: flex; + flex-direction: column; + gap: 16px; + align-items: center; + .tb-material-icons-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-material-icons-title, .tb-material-icons-search, .tb-material-icons-show-more { + width: 100%; + } + .tb-material-icons-viewport { + min-height: 144px; + } + .tb-material-icons-row { + display: flex; + flex-direction: row; + gap: 12px; + } + .tb-material-icons-row + .tb-material-icons-row { + margin-top: 12px; + } + .tb-no-data-available { + min-height: 144px; + } + button.mat-mdc-button-base.tb-select-icon-button { + width: 36px; + min-width: 36px; + height: 36px; + padding: 6px; + &:not(.mat-primary) { + color: rgba(0, 0, 0, 0.54); + } + > .mat-icon { + width: 24px; + height: 24px; + font-size: 24px; + margin: 0; + } + } +} diff --git a/ui-ngx/src/app/shared/components/material-icons.component.ts b/ui-ngx/src/app/shared/components/material-icons.component.ts new file mode 100644 index 0000000000..9347243af2 --- /dev/null +++ b/ui-ngx/src/app/shared/components/material-icons.component.ts @@ -0,0 +1,135 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { PageComponent } from '@shared/components/page.component'; +import { + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { UntypedFormControl } from '@angular/forms'; +import { BehaviorSubject, combineLatest, debounce, Observable, of, timer } from 'rxjs'; +import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; +import { getMaterialIcons, MaterialIcon } from '@shared/models/icon.models'; +import { distinctUntilChanged, map, mergeMap, share, startWith, tap } from 'rxjs/operators'; +import { ResourcesService } from '@core/services/resources.service'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { BreakpointObserver } from '@angular/cdk/layout'; +import { MediaBreakpoints } from '@shared/models/constants'; + +@Component({ + selector: 'tb-material-icons', + templateUrl: './material-icons.component.html', + providers: [], + styleUrls: ['./material-icons.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class MaterialIconsComponent extends PageComponent implements OnInit { + + @ViewChild('iconsPanel') + iconsPanel: CdkVirtualScrollViewport; + + @Input() + selectedIcon: string; + + @Input() + popover: TbPopoverComponent; + + @Output() + iconSelected = new EventEmitter(); + + iconRows$: Observable; + showAllSubject = new BehaviorSubject(false); + searchIconControl: UntypedFormControl; + + iconsRowHeight = 48; + + iconsPanelHeight: string; + iconsPanelWidth: string; + + notFound = false; + + constructor(protected store: Store, + private resourcesService: ResourcesService, + private breakpointObserver: BreakpointObserver, + private cd: ChangeDetectorRef) { + super(store); + this.searchIconControl = new UntypedFormControl(''); + } + + ngOnInit(): void { + const iconsRowSize = this.breakpointObserver.isMatched(MediaBreakpoints['lt-md']) ? 8 : 11; + this.calculatePanelSize(iconsRowSize); + const iconsRowSizeObservable = this.breakpointObserver + .observe(MediaBreakpoints['lt-md']).pipe( + map((state) => state.matches ? 8 : 11), + startWith(iconsRowSize), + ); + this.iconRows$ = combineLatest({showAll: this.showAllSubject.asObservable(), + rowSize: iconsRowSizeObservable, + searchText: this.searchIconControl.valueChanges.pipe( + startWith(''), + debounce((searchText) => searchText ? timer(150) : of({})), + )}).pipe( + map((data) => { + if (data.searchText && !data.showAll) { + data.showAll = true; + this.showAllSubject.next(true); + } + return data; + }), + distinctUntilChanged((p, c) => c.showAll === p.showAll && c.searchText === p.searchText && c.rowSize === p.rowSize), + mergeMap((data) => getMaterialIcons(this.resourcesService, data.rowSize, data.showAll, data.searchText).pipe( + map(iconRows => ({iconRows, iconsRowSize: data.rowSize})) + )), + tap((data) => { + this.notFound = !data.iconRows.length; + this.calculatePanelSize(data.iconsRowSize, data.iconRows.length); + this.cd.markForCheck(); + setTimeout(() => { + this.checkSize(); + }, 0); + }), + map((data) => data.iconRows), + share() + ); + } + + clearSearch() { + this.searchIconControl.patchValue('', {emitEvent: true}); + } + + selectIcon(icon: MaterialIcon) { + this.iconSelected.emit(icon.name); + } + + private calculatePanelSize(iconsRowSize: number, iconRows = 4) { + this.iconsPanelHeight = Math.min(iconRows * this.iconsRowHeight, 10 * this.iconsRowHeight) + 'px'; + this.iconsPanelWidth = (iconsRowSize * 36 + (iconsRowSize - 1) * 12 + 6) + 'px'; + } + + private checkSize() { + this.iconsPanel?.checkViewportSize(); + this.popover?.updatePosition(); + } +} diff --git a/ui-ngx/src/app/shared/components/notification/notification.component.html b/ui-ngx/src/app/shared/components/notification/notification.component.html index 361d3589fb..ba6091eebc 100644 --- a/ui-ngx/src/app/shared/components/notification/notification.component.html +++ b/ui-ngx/src/app/shared/components/notification/notification.component.html @@ -18,14 +18,14 @@
- + {{ notification.additionalConfig.icon.icon }} - +
- + {{ notificationTypeIcons.get(notification.type) }} - +
@@ -41,7 +41,7 @@ matTooltip="{{ 'notification.mark-as-read' | translate }}" matTooltipPosition="above"> check_circle_outline -
{{alarmSeverityTranslations.get(notification.info.alarmSeverity) | translate}} diff --git a/ui-ngx/src/app/shared/components/notification/notification.component.ts b/ui-ngx/src/app/shared/components/notification/notification.component.ts index ad543c43c1..6e1ff508a7 100644 --- a/ui-ngx/src/app/shared/components/notification/notification.component.ts +++ b/ui-ngx/src/app/shared/components/notification/notification.component.ts @@ -139,7 +139,7 @@ export class NotificationComponent implements OnInit { } notificationColor(): string { - if (this.notification.type === NotificationType.ALARM) { + if (this.notification.type === NotificationType.ALARM && !this.notification.info.cleared) { return AlarmSeverityNotificationColors.get(this.notification.info.alarmSeverity); } return 'transparent'; diff --git a/ui-ngx/src/app/shared/components/popover.component.ts b/ui-ngx/src/app/shared/components/popover.component.ts index d6d092d03c..91f5a2e902 100644 --- a/ui-ngx/src/app/shared/components/popover.component.ts +++ b/ui-ngx/src/app/shared/components/popover.component.ts @@ -63,8 +63,10 @@ import { coerceBoolean } from '@shared/decorators/coercion'; export type TbPopoverTrigger = 'click' | 'focus' | 'hover' | null; @Directive({ + // eslint-disable-next-line @angular-eslint/directive-selector selector: '[tb-popover]', exportAs: 'tbPopover', + // eslint-disable-next-line @angular-eslint/no-host-metadata-property host: { '[class.tb-popover-open]': 'visible' } @@ -265,12 +267,20 @@ export class TbPopoverDirective implements OnChanges, OnDestroy, AfterViewInit { } else if (delay > 0) { this.delayTimer = setTimeout(() => { this.delayTimer = undefined; - isEnter ? this.show() : this.hide(); + if (isEnter) { + this.show(); + } else { + this.hide(); + } }, delay * 1000); } else { // `isOrigin` is used due to the tooltip will not hide immediately // (may caused by the fade-out animation). - isEnter && isOrigin ? this.show() : this.hide(); + if (isEnter && isOrigin) { + this.show(); + } else { + this.hide(); + } } } @@ -345,15 +355,15 @@ export class TbPopoverDirective implements OnChanges, OnDestroy, AfterViewInit { ` }) -export class TbPopoverComponent implements OnDestroy, OnInit { +export class TbPopoverComponent implements OnDestroy, OnInit { @ViewChild('overlay', { static: false }) overlay!: CdkConnectedOverlay; @ViewChild('popoverRoot', { static: false }) popoverRoot!: ElementRef; @ViewChild('popover', { static: false }) popover!: ElementRef; tbContent: string | TemplateRef | null = null; - tbComponentFactory: ComponentFactory | null = null; - tbComponentRef: ComponentRef | null = null; + tbComponentFactory: ComponentFactory | null = null; + tbComponentRef: ComponentRef | null = null; tbComponentContext: any; tbComponentInjector: Injector | null = null; tbComponentStyle: { [klass: string]: any } = {}; diff --git a/ui-ngx/src/app/shared/components/popover.service.ts b/ui-ngx/src/app/shared/components/popover.service.ts index f547200316..1bef922ec1 100644 --- a/ui-ngx/src/app/shared/components/popover.service.ts +++ b/ui-ngx/src/app/shared/components/popover.service.ts @@ -65,7 +65,7 @@ export class TbPopoverService { displayPopover(trigger: Element, renderer: Renderer2, hostView: ViewContainerRef, componentType: Type, preferredPlacement: PopoverPlacement = 'top', hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, popoverStyle: any = {}, style?: any, - showCloseButton = true): TbPopoverComponent { + showCloseButton = true): TbPopoverComponent { const componentRef = this.createPopoverRef(hostView); return this.displayPopoverWithComponentRef(componentRef, trigger, renderer, componentType, preferredPlacement, hideOnClickOutside, injector, context, overlayStyle, popoverStyle, style, showCloseButton); @@ -74,7 +74,7 @@ export class TbPopoverService { displayPopoverWithComponentRef(componentRef: ComponentRef, trigger: Element, renderer: Renderer2, componentType: Type, preferredPlacement: PopoverPlacement = 'top', hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, - popoverStyle: any = {}, style?: any, showCloseButton = true): TbPopoverComponent { + popoverStyle: any = {}, style?: any, showCloseButton = true): TbPopoverComponent { const component = componentRef.instance; this.popoverWithTriggers.push({ trigger, diff --git a/ui-ngx/src/app/shared/components/public-api.ts b/ui-ngx/src/app/shared/components/public-api.ts index 9ec226769a..35ab83900e 100644 --- a/ui-ngx/src/app/shared/components/public-api.ts +++ b/ui-ngx/src/app/shared/components/public-api.ts @@ -24,3 +24,7 @@ export * from './slack-conversation-autocomplete.component'; export * from './notification/template-autocomplete.component'; export * from './resource/resource-autocomplete.component'; export * from './toggle-header.component'; +export * from './toggle-select.component'; +export * from './unit-input.component'; +export * from './material-icons.component'; +export * from './icon.component'; diff --git a/ui-ngx/src/app/shared/components/rule-chain/rule-chain-select.component.html b/ui-ngx/src/app/shared/components/rule-chain/rule-chain-select.component.html index 2b9c227c30..1d699b5857 100644 --- a/ui-ngx/src/app/shared/components/rule-chain/rule-chain-select.component.html +++ b/ui-ngx/src/app/shared/components/rule-chain/rule-chain-select.component.html @@ -15,13 +15,17 @@ limitations under the License. --> - - - {{ruleChain.name}} - - + + settings_ethernet + + + {{ruleChain.name}} + + + diff --git a/ui-ngx/src/app/shared/components/rule-chain/rule-chain-select.component.scss b/ui-ngx/src/app/shared/components/rule-chain/rule-chain-select.component.scss index c538da5725..c69661ad76 100644 --- a/ui-ngx/src/app/shared/components/rule-chain/rule-chain-select.component.scss +++ b/ui-ngx/src/app/shared/components/rule-chain/rule-chain-select.component.scss @@ -19,8 +19,16 @@ padding: 0 6px; .tb-rule-chain-select { display: flex; - height: 48px; min-height: 100%; pointer-events: all; } } + +:host ::ng-deep { + .mat-mdc-form-field.tb-rule-select .mdc-text-field { + .mat-mdc-form-field-infix { + min-height: 48px; + padding: 12px 0; + } + } +} diff --git a/ui-ngx/src/app/shared/components/tb-error.component.ts b/ui-ngx/src/app/shared/components/tb-error.component.ts index 08959e2949..5ddd2d7896 100644 --- a/ui-ngx/src/app/shared/components/tb-error.component.ts +++ b/ui-ngx/src/app/shared/components/tb-error.component.ts @@ -16,11 +16,12 @@ import { Component, Input } from '@angular/core'; import { animate, state, style, transition, trigger } from '@angular/animations'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-error', template: ` -
+
{{message}} @@ -51,6 +52,10 @@ export class TbErrorComponent { state: any; message; + @Input() + @coerceBoolean() + noMargin = false; + @Input() set error(value) { if (value && !this.message) { diff --git a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.scss b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.scss index 6f38e6a6a5..f6f24e2608 100644 --- a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.scss +++ b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.scss @@ -51,7 +51,7 @@ margin: 2px; line-height: 24px; - mat-icon { + .mat-icon { width: 24px; height: 24px; @@ -93,7 +93,7 @@ margin: 0; line-height: 28px; - mat-icon { + .mat-icon { width: 24px; height: 24px; font-size: 24px; diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.html b/ui-ngx/src/app/shared/components/toggle-header.component.html index e36cdbd592..c2136558e3 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.html +++ b/ui-ngx/src/app/shared/components/toggle-header.component.html @@ -15,16 +15,34 @@ limitations under the License. --> - - {{ option.name }} - + +
+ + {{ option.name }} + +
+ - + {{ option.name }} diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.scss b/ui-ngx/src/app/shared/components/toggle-header.component.scss index a9542012d4..dd983f3de9 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.scss +++ b/ui-ngx/src/app/shared/components/toggle-header.component.scss @@ -17,8 +17,34 @@ @import "../../../theme"; @import "../../../scss/constants"; +:host { + max-width: 100%; + display: grid; + grid-template-columns: min-content minmax(auto, 1fr) min-content; + .tb-toggle-header-pagination-button { + display: none; + } + &.tb-toggle-header-pagination-controls-enabled { + .tb-toggle-header-pagination-button { + display: block; + } + } + .tb-toggle-container { + display: inline-grid; + grid-column: 2; + overflow: hidden; + &.tb-disable-pagination { + overflow: visible; + } + } + .tb-toggle-header { + transition: transform 500ms cubic-bezier(0.35, 0, 0.25, 1); + } +} + :host ::ng-deep { .mat-button-toggle-group.mat-button-toggle-group-appearance-standard.tb-toggle-header { + overflow: visible; width: 100%; border-radius: 100px; height: 32px; @@ -80,6 +106,33 @@ } } } + &.tb-disabled { + pointer-events: none; + background: rgba(0, 0, 0, 0.03); + + .mat-button-toggle.mat-button-toggle-appearance-standard { + color: rgba(0, 0, 0, 0.28); + + &.mat-button-toggle-checked { + .mat-button-toggle-button { + background: transparent; + color: rgba(0, 0, 0, 0.38); + border-color: rgba(0, 0, 0, 0.38); + } + } + } + &.tb-fill { + .mat-button-toggle.mat-button-toggle-appearance-standard { + &.mat-button-toggle-checked { + .mat-button-toggle-button { + background: rgba(0, 0, 0, 0.12); + color: rgba(0, 0, 0, 0.38); + border: transparent; + } + } + } + } + } } @media #{$mat-md-lg} { .mat-button-toggle-group.mat-button-toggle-group-appearance-standard.tb-toggle-header:not(.tb-ignore-md-lg) { diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.ts b/ui-ngx/src/app/shared/components/toggle-header.component.ts index a7f37f53a4..6599a6fe35 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.ts +++ b/ui-ngx/src/app/shared/components/toggle-header.component.ts @@ -15,30 +15,33 @@ /// import { + AfterContentChecked, AfterContentInit, AfterViewInit, ChangeDetectorRef, Component, - ContentChildren, EventEmitter, + ContentChildren, + Directive, + ElementRef, + EventEmitter, + HostBinding, Input, - OnInit, Output, + OnDestroy, + OnInit, + Output, QueryList, ViewChild } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { AdminService } from '@core/http/admin.service'; -import { UpdateMessage } from '@shared/models/settings.models'; -import { getCurrentAuthUser } from '@core/auth/auth.selectors'; -import { Authority } from '@shared/models/authority.enum'; -import { of, Subscription } from 'rxjs'; -import { MatStepper } from '@angular/material/stepper'; -import { MatButtonToggle, MatButtonToggleGroup } from '@angular/material/button-toggle'; +import { Subject, Subscription } from 'rxjs'; import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; import { coerceBoolean } from '@shared/decorators/coercion'; -import { BreadCrumb } from '@shared/components/breadcrumb'; +import { startWith, takeUntil } from 'rxjs/operators'; +import { Platform } from '@angular/cdk/platform'; +import { MatButtonToggle, MatButtonToggleGroup } from '@angular/material/button-toggle'; export interface ToggleHeaderOption { name: string; @@ -47,12 +50,101 @@ export interface ToggleHeaderOption { export type ToggleHeaderAppearance = 'fill' | 'fill-invert' | 'stroked'; +export type ScrollDirection = 'after' | 'before'; + +@Directive( + { + // eslint-disable-next-line @angular-eslint/directive-selector + selector: 'tb-toggle-option', + } +) +// eslint-disable-next-line @angular-eslint/directive-class-suffix +export class ToggleOption { + + @Input() value: any; + + get viewValue(): string { + return (this._element?.nativeElement.textContent || '').trim(); + } + + constructor( + private _element: ElementRef + ) {} +} + +@Directive() +export abstract class _ToggleBase extends PageComponent implements AfterContentInit, OnDestroy { + + @ContentChildren(ToggleOption) toggleOptions: QueryList; + + @Input() + options: ToggleHeaderOption[] = []; + + protected _destroyed = new Subject(); + + protected constructor(protected store: Store) { + super(store); + } + + ngAfterContentInit(): void { + this.toggleOptions.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => { + this.syncToggleHeaderOptions(); + }); + } + + ngOnDestroy() { + this._destroyed.next(); + this._destroyed.complete(); + } + + private syncToggleHeaderOptions() { + if (this.toggleOptions?.length) { + this.options.length = 0; + this.toggleOptions.forEach(option => { + this.options.push( + { name: option.viewValue, + value: option.value + } + ); + }); + } + } + +} + @Component({ selector: 'tb-toggle-header', templateUrl: './toggle-header.component.html', styleUrls: ['./toggle-header.component.scss'] }) -export class ToggleHeaderComponent extends PageComponent implements OnInit { +export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterViewInit, AfterContentInit, AfterContentChecked, OnDestroy { + + @ViewChild('toggleGroup', {static: false}) + toggleGroup: ElementRef; + + @ViewChild(MatButtonToggleGroup, {static: false}) + buttonToggleGroup: MatButtonToggleGroup; + + @ViewChild('toggleGroupContainer', {static: false}) + toggleGroupContainer: ElementRef; + + @HostBinding('class.tb-toggle-header-pagination-controls-enabled') + private showPaginationControls = false; + + private toggleGroupResize$: ResizeObserver; + + leftPaginationEnabled = false; + rightPaginationEnabled = false; + + private _scrollDistance = 0; + private _scrollDistanceChanged: boolean; + + get scrollDistance(): number { + return this._scrollDistance; + } + set scrollDistance(value: number) { + this._scrollTo(value); + } @Input() value: any; @@ -61,10 +153,11 @@ export class ToggleHeaderComponent extends PageComponent implements OnInit { valueChange = new EventEmitter(); @Input() - options: ToggleHeaderOption[]; + name: string; @Input() - name: string; + @coerceBoolean() + disablePagination = false; @Input() @coerceBoolean() @@ -77,12 +170,17 @@ export class ToggleHeaderComponent extends PageComponent implements OnInit { @Input() appearance: ToggleHeaderAppearance = 'stroked'; + @Input() + @coerceBoolean() + disabled = false; + isMdLg: boolean; private observeBreakpointSubscription: Subscription; constructor(protected store: Store, private cd: ChangeDetectorRef, + private platform: Platform, private breakpointObserver: BreakpointObserver) { super(store); } @@ -96,9 +194,142 @@ export class ToggleHeaderComponent extends PageComponent implements OnInit { this.cd.markForCheck(); } ); + if (!this.disablePagination) { + this.valueChange.pipe(takeUntil(this._destroyed)).subscribe(() => { + this.scrollToToggleOptionValue(); + }); + } + } + + ngOnDestroy() { + if (this.toggleGroupResize$) { + this.toggleGroupResize$.disconnect(); + } + super.ngOnDestroy(); + } + + ngAfterViewInit() { + if (!this.disablePagination && !this.useSelectOnMdLg) { + this.toggleGroupResize$ = new ResizeObserver(() => { + this.updatePagination(); + }); + this.toggleGroupResize$.observe(this.toggleGroupContainer.nativeElement); + } + } + + ngAfterContentChecked() { + if (this._scrollDistanceChanged) { + this.updateToggleHeaderScrollPosition(); + this._scrollDistanceChanged = false; + this.cd.markForCheck(); + } } trackByHeaderOption(index: number, option: ToggleHeaderOption){ return option.value; } + + handlePaginatorClick(direction: ScrollDirection, $event: Event) { + if ($event) { + $event.stopPropagation(); + } + this.scrollHeader(direction); + } + + handlePaginatorTouchStart(direction: ScrollDirection, $event: Event) { + if (direction === 'before' && !this.leftPaginationEnabled || + direction === 'after' && !this.rightPaginationEnabled) { + $event.preventDefault(); + } + } + + private scrollHeader(direction: ScrollDirection) { + const viewLength = this.toggleGroup.nativeElement.offsetWidth; + // Move the scroll distance one-third the length of the tab list's viewport. + const scrollAmount = ((direction === 'before' ? -1 : 1) * viewLength) / 3; + return this._scrollTo(this._scrollDistance + scrollAmount); + } + + private scrollToToggleOptionValue() { + if (this.buttonToggleGroup && this.buttonToggleGroup.selected) { + const selectedToggleButton = this.buttonToggleGroup.selected as MatButtonToggle; + const viewLength = this.toggleGroupContainer.nativeElement.offsetWidth; + const {offsetLeft, offsetWidth} = (selectedToggleButton._buttonElement.nativeElement.offsetParent as HTMLElement); + const labelBeforePos = offsetLeft; // this.toggleGroup.nativeElement.offsetWidth - offsetLeft; + const labelAfterPos = labelBeforePos + offsetWidth; + const beforeVisiblePos = this.scrollDistance; + const afterVisiblePos = this.scrollDistance + viewLength; + if (labelBeforePos < beforeVisiblePos) { + this.scrollDistance -= beforeVisiblePos - labelBeforePos; + } else if (labelAfterPos > afterVisiblePos) { + this.scrollDistance += Math.min( + labelAfterPos - afterVisiblePos, + labelBeforePos - beforeVisiblePos, + ); + } + } + } + + private updatePagination() { + this.checkPaginationEnabled(); + this.checkPaginationControls(); + this.updateToggleHeaderScrollPosition(); + } + + private checkPaginationEnabled() { + if (this.toggleGroupContainer) { + const isEnabled = this.toggleGroup.nativeElement.scrollWidth > this.toggleGroupContainer.nativeElement.offsetWidth; + if (isEnabled !== this.showPaginationControls) { + if (!isEnabled) { + this.scrollDistance = 0; + } else { + setTimeout(() => { + this.scrollToToggleOptionValue(); + }, 0); + } + this.cd.markForCheck(); + this.showPaginationControls = isEnabled; + } + } else { + this.showPaginationControls = false; + } + } + + private checkPaginationControls() { + if (!this.showPaginationControls) { + this.leftPaginationEnabled = this.rightPaginationEnabled = false; + } else { + // Check if the pagination arrows should be activated. + this.leftPaginationEnabled = this.scrollDistance > 0; + this.rightPaginationEnabled = this.scrollDistance < this.getMaxScrollDistance(); + this.cd.markForCheck(); + } + } + + private getMaxScrollDistance(): number { + const lengthOfToggleGroup = this.toggleGroup.nativeElement.scrollWidth; + const viewLength = this.toggleGroupContainer.nativeElement.offsetWidth; + return lengthOfToggleGroup - viewLength || 0; + } + + private _scrollTo(position: number) { + if (!this.showPaginationControls) { + return {maxScrollDistance: 0, distance: 0}; + } else { + const maxScrollDistance = this.getMaxScrollDistance(); + this._scrollDistance = Math.max(0, Math.min(maxScrollDistance, position)); + this._scrollDistanceChanged = true; + this.checkPaginationControls(); + return {maxScrollDistance, distance: this._scrollDistance}; + } + } + + private updateToggleHeaderScrollPosition() { + const scrollDistance = this.scrollDistance; + const translateX = -scrollDistance; + this.toggleGroup.nativeElement.style.transform = `translateX(${Math.round(translateX)}px)`; + if (this.platform.TRIDENT || this.platform.EDGE) { + this.toggleGroupContainer.nativeElement.scrollLeft = 0; + } + } } diff --git a/ui-ngx/src/app/shared/components/toggle-select.component.html b/ui-ngx/src/app/shared/components/toggle-select.component.html new file mode 100644 index 0000000000..819dc76ee4 --- /dev/null +++ b/ui-ngx/src/app/shared/components/toggle-select.component.html @@ -0,0 +1,27 @@ + + + diff --git a/ui-ngx/src/app/shared/components/toggle-select.component.ts b/ui-ngx/src/app/shared/components/toggle-select.component.ts new file mode 100644 index 0000000000..3eee0cf841 --- /dev/null +++ b/ui-ngx/src/app/shared/components/toggle-select.component.ts @@ -0,0 +1,79 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, HostBinding, Input } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { _ToggleBase, ToggleHeaderAppearance } from '@shared/components/toggle-header.component'; +import { coerceBoolean } from '@shared/decorators/coercion'; + +@Component({ + selector: 'tb-toggle-select', + templateUrl: './toggle-select.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ToggleSelectComponent), + multi: true + } + ] +}) +export class ToggleSelectComponent extends _ToggleBase implements ControlValueAccessor { + + @HostBinding('style.maxWidth') + get maxWidth() { return '100%'; } + + @Input() + @coerceBoolean() + disabled: boolean; + + @Input() + appearance: ToggleHeaderAppearance = 'stroked'; + + @Input() + @coerceBoolean() + disablePagination = false; + + modelValue: any; + + private propagateChange = null; + + constructor(protected store: Store) { + super(store); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + writeValue(value: any): void { + this.modelValue = value; + } + + updateModel(value: any) { + this.modelValue = value; + this.propagateChange(this.modelValue); + } +} diff --git a/ui-ngx/src/app/shared/components/unit-input.component.html b/ui-ngx/src/app/shared/components/unit-input.component.html new file mode 100644 index 0000000000..0ae14b8ba9 --- /dev/null +++ b/ui-ngx/src/app/shared/components/unit-input.component.html @@ -0,0 +1,40 @@ + + + + + + + + + + + diff --git a/ui-ngx/src/app/shared/components/unit-input.component.scss b/ui-ngx/src/app/shared/components/unit-input.component.scss new file mode 100644 index 0000000000..25280e51ec --- /dev/null +++ b/ui-ngx/src/app/shared/components/unit-input.component.scss @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.tb-autocomplete.tb-unit-input-autocomplete { + .mat-mdc-option { + border-bottom: none; + .mdc-list-item__primary-text { + flex: 1; + display: flex; + flex-direction: row; + gap: 8px; + .tb-unit-name, .tb-unit-symbol { + font-size: 14px; + font-weight: 400; + line-height: 20px; + letter-spacing: 0.2px; + } + .tb-unit-symbol { + color: rgba(0, 0, 0, 0.38); + min-width: 22px; + text-align: end; + b { + color: rgba(0, 0, 0, 0.87); + } + } + } + } +} diff --git a/ui-ngx/src/app/shared/components/unit-input.component.ts b/ui-ngx/src/app/shared/components/unit-input.component.ts new file mode 100644 index 0000000000..57dc4ea44b --- /dev/null +++ b/ui-ngx/src/app/shared/components/unit-input.component.ts @@ -0,0 +1,170 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + Component, + ElementRef, + forwardRef, + HostBinding, + Input, + OnInit, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { ControlValueAccessor, FormBuilder, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Observable, of, shareReplay, switchMap } from 'rxjs'; +import { getUnits, searchUnits, Unit, unitBySymbol } from '@shared/models/unit.models'; +import { map, mergeMap, tap } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; +import { ResourcesService } from '@core/services/resources.service'; + +@Component({ + selector: 'tb-unit-input', + templateUrl: './unit-input.component.html', + styleUrls: ['./unit-input.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => UnitInputComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None +}) +export class UnitInputComponent implements ControlValueAccessor, OnInit { + + @HostBinding('style.display') get hostDisplay() {return 'flex';}; + + unitsFormControl: FormControl; + + modelValue: string | null; + + @Input() + disabled: boolean; + + @ViewChild('unitInput', {static: true}) unitInput: ElementRef; + + filteredUnits: Observable>; + + searchText = ''; + + private dirty = false; + + private fetchUnits$: Observable> = null; + + private propagateChange = (_val: any) => {}; + + constructor(private fb: FormBuilder, + private resourcesService: ResourcesService, + private translate: TranslateService) { + } + + ngOnInit() { + this.unitsFormControl = this.fb.control('', []); + this.filteredUnits = this.unitsFormControl.valueChanges + .pipe( + tap(value => { + this.updateView(value); + }), + map(value => (value as Unit)?.symbol ? (value as Unit).symbol : (value ? value as string : '')), + mergeMap(symbol => this.fetchUnits(symbol)) + ); + } + + writeValue(symbol?: string): void { + this.searchText = ''; + this.modelValue = symbol; + of(symbol).pipe( + switchMap(value => value + ? this.unitsConstant().pipe(map(units => unitBySymbol(units, value) ?? value)) + : of(null)) + ).subscribe(result => { + this.unitsFormControl.patchValue(result, {emitEvent: false}); + this.dirty = true; + }); + } + + onFocus() { + if (this.dirty) { + this.unitsFormControl.updateValueAndValidity({onlySelf: true, emitEvent: true}); + this.dirty = false; + } + } + + updateView(value: Unit | string | null) { + const res: string = (value as Unit)?.symbol ? (value as Unit)?.symbol : (value as string); + if (this.modelValue !== res) { + this.modelValue = res; + this.propagateChange(this.modelValue); + } + } + + displayUnitFn(unit?: Unit | string): string | undefined { + if (unit) { + if ((unit as Unit).symbol) { + return (unit as Unit).symbol; + } else { + return unit as string; + } + } + return undefined; + } + + fetchUnits(searchText?: string): Observable> { + this.searchText = searchText; + return this.unitsConstant().pipe( + map(unit => searchUnits(unit, searchText)) + ); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.unitsFormControl.disable({emitEvent: false}); + } else { + this.unitsFormControl.enable({emitEvent: false}); + } + } + + clear() { + this.unitsFormControl.patchValue(null, {emitEvent: true}); + setTimeout(() => { + this.unitInput.nativeElement.blur(); + this.unitInput.nativeElement.focus(); + }, 0); + } + + private unitsConstant(): Observable> { + if (this.fetchUnits$ === null) { + this.fetchUnits$ = getUnits(this.resourcesService).pipe( + map(units => units.map(u => ({ + symbol: u.symbol, + name: this.translate.instant(u.name), + tags: u.tags + }))), + shareReplay(1) + ); + } + return this.fetchUnits$; + } +} diff --git a/ui-ngx/src/app/shared/components/user-menu.component.html b/ui-ngx/src/app/shared/components/user-menu.component.html index b0ed36f336..afb6e66437 100644 --- a/ui-ngx/src/app/shared/components/user-menu.component.html +++ b/ui-ngx/src/app/shared/components/user-menu.component.html @@ -28,7 +28,7 @@
- diff --git a/ui-ngx/src/app/shared/components/user-menu.component.scss b/ui-ngx/src/app/shared/components/user-menu.component.scss index b0d3acbf51..c435fe2867 100644 --- a/ui-ngx/src/app/shared/components/user-menu.component.scss +++ b/ui-ngx/src/app/shared/components/user-menu.component.scss @@ -36,7 +36,7 @@ } - mat-icon.tb-mini-avatar { + .mat-icon.tb-mini-avatar { width: 36px; height: 36px; margin: auto 8px; diff --git a/ui-ngx/src/app/shared/components/user-menu.component.ts b/ui-ngx/src/app/shared/components/user-menu.component.ts index a13e3a47f9..35f935ce33 100644 --- a/ui-ngx/src/app/shared/components/user-menu.component.ts +++ b/ui-ngx/src/app/shared/components/user-menu.component.ts @@ -102,7 +102,7 @@ export class UserMenuComponent implements OnInit, OnDestroy { return name; } - openProfile(): void { + openAccount(): void { this.router.navigate(['account']); } diff --git a/ui-ngx/src/app/shared/decorators/coercion.ts b/ui-ngx/src/app/shared/decorators/coercion.ts index c60cda730d..d1d00828f1 100644 --- a/ui-ngx/src/app/shared/decorators/coercion.ts +++ b/ui-ngx/src/app/shared/decorators/coercion.ts @@ -22,87 +22,128 @@ import { coerceStringArray as coerceStringArrayAngular } from '@angular/cdk/coercion'; -export const coerceBoolean = () => (target: any, key: string): void => { - const getter = function() { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceBooleanProperty(next); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceBoolean = () => (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceBooleanProperty(next)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceBooleanProperty(next); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; -export const coerceNumber = () => (target: any, key: string): void => { - const getter = function(): number { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceNumberProperty(next); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceNumber = () => (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceNumberProperty(next)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceNumberProperty(next); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; -export const coerceCssPixelValue = () => (target: any, key: string): void => { - const getter = function(): string { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceCssPixelValueAngular(next); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceCssPixelValue = () => (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceCssPixelValueAngular(next)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceCssPixelValueAngular(next); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; -export const coerceArray = () => (target: any, key: string): void => { - const getter = function(): any[] { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceArrayAngular(next); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceArray = () => (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceArrayAngular(next)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceArrayAngular(next); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; -export const coerceStringArray = (separator?: string | RegExp) => (target: any, key: string): void => { - const getter = function(): string[] { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceStringArrayAngular(next, separator); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceStringArray = (separator?: string | RegExp) => + (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceStringArrayAngular(next, separator)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceStringArrayAngular(next, separator); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; diff --git a/ui-ngx/src/app/shared/models/alarm.models.ts b/ui-ngx/src/app/shared/models/alarm.models.ts index 202b25d539..49f780beeb 100644 --- a/ui-ngx/src/app/shared/models/alarm.models.ts +++ b/ui-ngx/src/app/shared/models/alarm.models.ts @@ -145,6 +145,11 @@ export interface AlarmAssignee { email: string; } +export enum AlarmAssigneeOption { + noAssignee = 'noAssignee', + currentUser = 'currentUser' +} + export interface AlarmDataInfo extends AlarmInfo { actionCellButtons?: TableCellButtonActionDescriptor[]; hasActions?: boolean; diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index f7802b3a8b..66419a10a8 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -52,6 +52,12 @@ export enum DeviceTransportType { SNMP = 'SNMP' } +export enum BasicTransportType { + HTTP = 'HTTP' +} +export type TransportType = BasicTransportType | DeviceTransportType; +export type NetworkTransportType = BasicTransportType | Exclude; + export enum TransportPayloadType { JSON = 'JSON', PROTOBUF = 'PROTOBUF' @@ -99,13 +105,14 @@ export const deviceProfileTypeConfigurationInfoMap = new Map( +export const deviceTransportTypeTranslationMap = new Map( [ [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default'], [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt'], [DeviceTransportType.COAP, 'device-profile.transport-type-coap'], [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m'], - [DeviceTransportType.SNMP, 'device-profile.transport-type-snmp'] + [DeviceTransportType.SNMP, 'device-profile.transport-type-snmp'], + [BasicTransportType.HTTP, 'device-profile.transport-type-http'] ] ); @@ -119,13 +126,14 @@ export const deviceProvisionTypeTranslationMap = new Map( +export const deviceTransportTypeHintMap = new Map( [ [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default-hint'], [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt-hint'], [DeviceTransportType.COAP, 'device-profile.transport-type-coap-hint'], [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m-hint'], - [DeviceTransportType.SNMP, 'device-profile.transport-type-snmp-hint'] + [DeviceTransportType.SNMP, 'device-profile.transport-type-snmp-hint'], + [BasicTransportType.HTTP, ''] ] ); @@ -705,7 +713,7 @@ export interface Device extends BaseData, ExportableEntity { tenantId?: TenantId; customerId?: CustomerId; name: string; - type: string; + type?: string; label: string; firmwareId?: OtaPackageId; softwareId?: OtaPackageId; @@ -829,6 +837,32 @@ export interface ClaimResult { response: ClaimResponse; } +export interface PublishTelemetryCommand { + http?: { + http?: string; + https?: string; + }; + mqtt: { + mqtt?: string; + mqtts?: string | Array; + docker?: { + mqtt?: string; + mqtts?: string | Array; + }; + sparkplug?: string; + }; + coap: { + coap?: string; + coaps?: string | Array; + docker?: { + coap?: string; + coaps?: string | Array; + }; + }; + lwm2m?: string; + snmp?: string; +} + export const dayOfWeekTranslations = new Array( 'device-profile.schedule-day.monday', 'device-profile.schedule-day.tuesday', diff --git a/ui-ngx/src/app/shared/models/icon.models.ts b/ui-ngx/src/app/shared/models/icon.models.ts new file mode 100644 index 0000000000..85c6617aa1 --- /dev/null +++ b/ui-ngx/src/app/shared/models/icon.models.ts @@ -0,0 +1,140 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ResourcesService } from '@core/services/resources.service'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { isNotEmptyStr } from '@core/utils'; + +export const svgIcons: {[key: string]: string} = { + 'google-logo': '', + 'github-logo': '', + 'facebook-logo': '', + 'apple-logo': '', + 'queues-list': '' + + '' + + '' + + '' + + '' +}; + +export const svgIconsUrl: { [key: string]: string } = { + windows: '/assets/windows.svg', + macos: '/assets/macos.svg', + linux: '/assets/linux.svg', + docker: '/assets/docker.svg' +}; + +const svgIconNamespaces: string[] = ['mdi']; +const svgIconNames = [...Object.keys(svgIcons), ...Object.keys(svgIconsUrl)]; + +export const splitIconName = (iconName: string): [string, string] => { + if (!iconName) { + return ['', '']; + } + const parts = iconName.split(':'); + switch (parts.length) { + case 1: + return ['', parts[0]]; + case 2: + return parts as [string, string]; + default: + throw Error(`Invalid icon name: "${iconName}"`); + } +}; + +export const isSvgIcon = (icon: string): boolean => { + const [namespace, iconName] = splitIconName(icon); + return svgIconNamespaces.includes(namespace) || svgIconNames.includes(iconName); +}; + +export interface MaterialIcon { + name: string; + displayName?: string; + tags: string[]; +} + +export const iconByName = (icons: Array, name: string): MaterialIcon => icons.find(i => i.name === name); + +const searchIconTags = (icon: MaterialIcon, searchText: string): boolean => + !!icon.tags.find(t => t.toUpperCase().includes(searchText.toUpperCase())); + +const searchIcons = (_icons: Array, searchText: string): Array => _icons.filter( + i => i.name.toUpperCase().includes(searchText.toUpperCase()) || + i.displayName.toUpperCase().includes(searchText.toUpperCase()) || + searchIconTags(i, searchText) +); + +const getCommonMaterialIcons = (icons: Array, chunkSize: number): Array => icons.slice(0, chunkSize * 4); + +export const getMaterialIcons = (resourcesService: ResourcesService, chunkSize = 11, + all = false, searchText: string): Observable => + resourcesService.loadJsonResource>('/assets/metadata/material-icons.json', + (icons) => { + for (const icon of icons) { + const iconName = splitIconName(icon.name)[1]; + const words = iconName.replace(/[_\-]/g, ' ').split(' '); + for (let i = 0; i < words.length; i++) { + words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1); + } + icon.displayName = words.join(' '); + } + return icons; + } + ).pipe( + map((icons) => { + if (isNotEmptyStr(searchText)) { + return searchIcons(icons, searchText); + } else if (!all) { + return getCommonMaterialIcons(icons, chunkSize); + } else { + return icons; + } + }), + map((icons) => { + const iconChunks: MaterialIcon[][] = []; + for (let i = 0; i < icons.length; i += chunkSize) { + const chunk = icons.slice(i, i + chunkSize); + iconChunks.push(chunk); + } + return iconChunks; + }) + ); diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 9cc3033ee7..0d1a46443d 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -48,6 +48,8 @@ export interface NotificationInfo { alarmStatus?: AlarmStatus; alarmType?: string; stateEntityId?: EntityId; + acknowledged?: boolean; + cleared?: boolean; } export interface NotificationRequest extends Omit, 'label'> { @@ -114,7 +116,7 @@ export interface NotificationRule extends Omit, 'la triggerType: TriggerType; triggerConfig: NotificationRuleTriggerConfig; recipientsConfig: NotificationRuleRecipientConfig; - additionalConfig: {description: string}; + additionalConfig?: {description: string}; } export type NotificationRuleTriggerConfig = Partial { + if (filter1 === filter2) { + return true; + } + if ((isUndefinedOrNull(filter1) || isEmpty(filter1)) && (isUndefinedOrNull(filter2) || isEmpty(filter2))) { + return true; + } else if (isDefinedAndNotNull(filter1) && isDefinedAndNotNull(filter2)) { + if (!isArraysEqualIgnoreUndefined(filter1.typeList, filter2.typeList)) { + return false; + } + if (!isArraysEqualIgnoreUndefined(filter1.statusList, filter2.statusList)) { + return false; + } + if (!isArraysEqualIgnoreUndefined(filter1.severityList, filter2.severityList)) { + return false; + } + if (!isEqualIgnoreUndefined(filter1.assigneeId, filter2.assigneeId)) { + return false; + } + if (!isEqualIgnoreUndefined(filter1.searchPropagatedAlarms, filter2.searchPropagatedAlarms)) { + return false; + } + if (!isEqualIgnoreUndefined(filter1.assignedToCurrentUser, filter2.assignedToCurrentUser)) { + return false; + } + return true; + } + return false; +}; + export type AlarmCountQuery = EntityCountQuery & AlarmFilter; export type AlarmDataPageLink = EntityDataPageLink & AlarmFilter; diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index d4688546d7..2a7dedabec 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -26,6 +26,8 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { AbstractControl, UntypedFormGroup } from '@angular/forms'; import { RuleChainType } from '@shared/models/rule-chain.models'; +import { DebugRuleNodeEventBody } from '@shared/models/event.models'; +import { TranslateService } from '@ngx-translate/core'; export interface RuleNodeConfiguration { [key: string]: any; @@ -71,10 +73,14 @@ export interface RuleNodeConfigurationDescriptor { export interface IRuleNodeConfigurationComponent { ruleNodeId: string; ruleChainId: string; + hasScript: boolean; + testScriptLabel?: string; + changeScript?: EventEmitter; ruleChainType: RuleChainType; configuration: RuleNodeConfiguration; configurationChanged: Observable; validate(); + testScript? (debugEventBody?: DebugRuleNodeEventBody); [key: string]: any; } @@ -87,6 +93,8 @@ export abstract class RuleNodeConfigurationComponent extends PageComponent imple ruleChainId: string; + hasScript: boolean = false; + ruleChainType: RuleChainType; configurationValue: RuleNodeConfiguration; @@ -499,3 +507,4 @@ export function getRuleNodeHelpLink(component: RuleNodeComponentDescriptor): str } return 'ruleEngine'; } + diff --git a/ui-ngx/src/app/shared/models/time/time.models.ts b/ui-ngx/src/app/shared/models/time/time.models.ts index fd2b4f52fa..235df14bb0 100644 --- a/ui-ngx/src/app/shared/models/time/time.models.ts +++ b/ui-ngx/src/app/shared/models/time/time.models.ts @@ -452,6 +452,15 @@ export const calculateIntervalStartTime = (interval: QuickTimeInterval, currentD case QuickTimeInterval.PREVIOUS_MONTH: currentDate.subtract(1, 'months'); return currentDate.startOf('month'); + case QuickTimeInterval.PREVIOUS_QUARTER: + currentDate.subtract(1, 'quarter'); + return currentDate.startOf('quarter'); + case QuickTimeInterval.PREVIOUS_HALF_YEAR: + if (currentDate.get('quarter') < 3) { + return currentDate.startOf('year').subtract(2, 'quarters'); + } else { + return currentDate.startOf('year'); + } case QuickTimeInterval.PREVIOUS_YEAR: currentDate.subtract(1, 'years'); return currentDate.startOf('year'); diff --git a/ui-ngx/src/app/shared/models/unit.models.ts b/ui-ngx/src/app/shared/models/unit.models.ts new file mode 100644 index 0000000000..7d9f88a068 --- /dev/null +++ b/ui-ngx/src/app/shared/models/unit.models.ts @@ -0,0 +1,38 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ResourcesService } from '@core/services/resources.service'; +import { Observable } from 'rxjs'; + +export interface Unit { + name: string; + symbol: string; + tags: string[]; +} + +export const unitBySymbol = (_units: Array, symbol: string): Unit => _units.find(u => u.symbol === symbol); + +const searchUnitTags = (unit: Unit, searchText: string): boolean => + !!unit.tags.find(t => t.toUpperCase().includes(searchText.toUpperCase())); + +export const searchUnits = (_units: Array, searchText: string): Array => _units.filter( + u => u.symbol.toUpperCase().includes(searchText.toUpperCase()) || + u.name.toUpperCase().includes(searchText.toUpperCase()) || + searchUnitTags(u, searchText) +); + +export const getUnits = (resourcesService: ResourcesService): Observable> => + resourcesService.loadJsonResource('/assets/metadata/units.json'); diff --git a/ui-ngx/src/app/shared/models/user-settings.models.ts b/ui-ngx/src/app/shared/models/user-settings.models.ts index e39600f950..ac0bd95c29 100644 --- a/ui-ngx/src/app/shared/models/user-settings.models.ts +++ b/ui-ngx/src/app/shared/models/user-settings.models.ts @@ -16,6 +16,7 @@ export interface UserSettings { openedMenuSections?: string[]; + notDisplayConnectivityAfterAddDevice?: boolean; } export const initialUserSettings: UserSettings = { diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index bfe9021926..e0d9918540 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -19,7 +19,6 @@ import { TenantId } from '@shared/models/id/tenant-id'; import { WidgetTypeId } from '@shared/models/id/widget-type-id'; import { AggregationType, ComparisonDuration, Timewindow } from '@shared/models/time/time.models'; import { EntityType } from '@shared/models/entity-type.models'; -import { AlarmSearchStatus, AlarmSeverity } from '@shared/models/alarm.models'; import { DataKeyType } from './telemetry/telemetry.models'; import { EntityId } from '@shared/models/id/entity-id'; import * as moment_ from 'moment'; @@ -40,6 +39,7 @@ import { Observable } from 'rxjs'; import { Dashboard } from '@shared/models/dashboard.models'; import { IAliasController } from '@core/api/widget-api.models'; import { isEmptyStr } from '@core/utils'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; export enum widgetType { timeseries = 'timeseries', @@ -57,7 +57,6 @@ export interface WidgetTypeTemplate { export interface WidgetTypeData { name: string; icon: string; - isMdiIcon?: boolean; configHelpLinkId: string; template: WidgetTypeTemplate; } @@ -94,7 +93,6 @@ export const widgetTypesData = new Map( name: 'widget.rpc', icon: 'mdi:developer-board', configHelpLinkId: 'widgetsConfigRpc', - isMdiIcon: true, template: { bundleAlias: 'gpio_widgets', alias: 'basic_gpio_control' @@ -182,6 +180,9 @@ export interface WidgetTypeParameters { warnOnPageDataOverflow?: boolean; ignoreDataUpdateOnIntervalTick?: boolean; processNoDataByWidget?: boolean; + previewWidth?: string; + previewHeight?: string; + absoluteHeader?: boolean; } export interface WidgetControllerDescriptor { @@ -318,6 +319,11 @@ export interface DataKey extends KeyInfo { _hash?: number; } +export enum DataKeyConfigMode { + general = 'general', + advanced = 'advanced' +} + export enum DatasourceType { function = 'function', device = 'device', @@ -632,6 +638,7 @@ export interface WidgetConfig { backgroundColor?: string; padding?: string; margin?: string; + borderRadius?: string; widgetStyle?: {[klass: string]: any}; widgetCss?: string; titleStyle?: {[klass: string]: any}; @@ -700,6 +707,7 @@ export interface IWidgetSettingsComponent { aliasController: IAliasController; dashboard: Dashboard; widget: Widget; + widgetConfig: WidgetConfigComponentData; functionScopeVariables: string[]; settings: WidgetSettings; settingsChanged: Observable; @@ -731,6 +739,17 @@ export abstract class WidgetSettingsComponent extends PageComponent implements widget: Widget; + widgetConfigValue: WidgetConfigComponentData; + + set widgetConfig(value: WidgetConfigComponentData) { + this.widgetConfigValue = value; + this.onWidgetConfigSet(value); + } + + get widgetConfig(): WidgetConfigComponentData { + return this.widgetConfigValue; + } + functionScopeVariables: string[]; settingsValue: WidgetSettings; @@ -842,4 +861,7 @@ export abstract class WidgetSettingsComponent extends PageComponent implements return {}; } + protected onWidgetConfigSet(widgetConfig: WidgetConfigComponentData) { + } + } diff --git a/ui-ngx/src/app/shared/pipe/date-ago.pipe.ts b/ui-ngx/src/app/shared/pipe/date-ago.pipe.ts index 4fb964eae8..77482dfe4f 100644 --- a/ui-ngx/src/app/shared/pipe/date-ago.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/date-ago.pipe.ts @@ -37,19 +37,21 @@ export class DateAgoPipe implements PipeTransform { } - transform(value: number, args?: any): string { + transform(value: string| number | Date, args?: any): string { if (value) { const applyAgo = !!args?.applyAgo; + const short = !!args?.short; + const textPart = !!args?.textPart; const ms = Math.floor((+new Date() - +new Date(value))); if (ms < 29 * SECOND) { // less than 30 seconds ago will show as 'Just now' - return this.translate.instant('timewindow.just-now'); + return this.translate.instant(textPart ? 'timewindow.just-now-lower' : 'timewindow.just-now'); } let counter; // eslint-disable-next-line guard-for-in for (const i in intervals) { counter = Math.floor(ms / intervals[i]); if (counter > 0) { - let res = this.translate.instant(`timewindow.${i}`, {[i]: counter}); + let res = this.translate.instant(`timewindow.${i+(short ? '-short' : '')}`, {[i]: counter}); if (applyAgo) { res += ' ' + this.translate.instant('timewindow.ago'); } diff --git a/ui-ngx/src/app/shared/pipe/highlight.pipe.ts b/ui-ngx/src/app/shared/pipe/highlight.pipe.ts index 0f8595fc3b..5d712c5b93 100644 --- a/ui-ngx/src/app/shared/pipe/highlight.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/highlight.pipe.ts @@ -18,11 +18,10 @@ import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'highlight' }) export class HighlightPipe implements PipeTransform { - transform(text: string, search): string { + transform(text: string, search: string, includes = false, flags = 'i'): string { const pattern = search .replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); - const regex = new RegExp('^' + pattern, 'i'); - + const regex = new RegExp((!includes ? '^' : '') + pattern, flags); return search ? text.replace(regex, match => `${match}`) : text; } } diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 2a1bcfab87..88d21fd0c5 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -191,8 +191,13 @@ import { import { ColorPickerComponent } from '@shared/components/color-picker/color-picker.component'; import { ResourceAutocompleteComponent } from '@shared/components/resource/resource-autocomplete.component'; import { ShortNumberPipe } from '@shared/pipe/short-number.pipe'; -import { ToggleHeaderComponent } from '@shared/components/toggle-header.component'; +import { ToggleHeaderComponent, ToggleOption } from '@shared/components/toggle-header.component'; import { RuleChainSelectComponent } from '@shared/components/rule-chain/rule-chain-select.component'; +import { ToggleSelectComponent } from '@shared/components/toggle-select.component'; +import { UnitInputComponent } from '@shared/components/unit-input.component'; +import { MaterialIconsComponent } from '@shared/components/material-icons.component'; +import { ColorPickerPanelComponent } from '@shared/components/color-picker/color-picker-panel.component'; +import { TbIconComponent } from '@shared/components/icon.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -362,9 +367,15 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) GtMdLgLayoutGapDirective, GtMdLgShowHideDirective, ColorPickerComponent, + ColorPickerPanelComponent, ResourceAutocompleteComponent, ToggleHeaderComponent, - RuleChainSelectComponent + ToggleOption, + ToggleSelectComponent, + UnitInputComponent, + MaterialIconsComponent, + RuleChainSelectComponent, + TbIconComponent ], imports: [ CommonModule, @@ -590,9 +601,15 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) GtMdLgLayoutGapDirective, GtMdLgShowHideDirective, ColorPickerComponent, + ColorPickerPanelComponent, ResourceAutocompleteComponent, ToggleHeaderComponent, - RuleChainSelectComponent + ToggleOption, + ToggleSelectComponent, + UnitInputComponent, + MaterialIconsComponent, + RuleChainSelectComponent, + TbIconComponent ] }) export class SharedModule { } diff --git a/ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw b/ui-ngx/src/assets/dashboard/api_usage.json similarity index 100% rename from ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw rename to ui-ngx/src/assets/dashboard/api_usage.json diff --git a/ui-ngx/src/app/modules/home/pages/home-links/customer_user_home_page.raw b/ui-ngx/src/assets/dashboard/customer_user_home_page.json similarity index 100% rename from ui-ngx/src/app/modules/home/pages/home-links/customer_user_home_page.raw rename to ui-ngx/src/assets/dashboard/customer_user_home_page.json diff --git a/ui-ngx/src/app/modules/home/pages/home-links/sys_admin_home_page.raw b/ui-ngx/src/assets/dashboard/sys_admin_home_page.json similarity index 100% rename from ui-ngx/src/app/modules/home/pages/home-links/sys_admin_home_page.raw rename to ui-ngx/src/assets/dashboard/sys_admin_home_page.json diff --git a/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw b/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json similarity index 98% rename from ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw rename to ui-ngx/src/assets/dashboard/tenant_admin_home_page.json index 9205fddf71..6f9215b4f9 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw +++ b/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json @@ -48,7 +48,7 @@ "padding": "16px", "settings": { "useMarkdownTextFunction": false, - "markdownTextPattern": "
\n
\n
{{ 'widgets.activity.title' | translate }}
\n \n \n
\n \n \n \n \n \n \n \n \n
", + "markdownTextPattern": "
\n
\n
{{ 'widgets.activity.title' | translate }}
\n \n {{ 'device.devices' | translate }}\n {{ 'widgets.transport-messages.title' | translate }}\n \n
\n \n \n \n \n \n \n \n \n
", "applyDefaultMarkdownStyle": false, "markdownCss": ".tb-card-content {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n}\n" }, @@ -1101,4 +1101,4 @@ }, "externalId": null, "name": "Tenant Administrator Home Page" -} \ No newline at end of file +} diff --git a/ui-ngx/src/assets/docker.svg b/ui-ngx/src/assets/docker.svg new file mode 100644 index 0000000000..f152739de6 --- /dev/null +++ b/ui-ngx/src/assets/docker.svg @@ -0,0 +1 @@ + diff --git a/ui-ngx/src/assets/fonts/MaterialIcons-Regular.ttf b/ui-ngx/src/assets/fonts/MaterialIcons-Regular.ttf index be4be29c86..9d09b0feb8 100644 Binary files a/ui-ngx/src/assets/fonts/MaterialIcons-Regular.ttf and b/ui-ngx/src/assets/fonts/MaterialIcons-Regular.ttf differ diff --git a/ui-ngx/src/assets/help/en_US/date/date-format.md b/ui-ngx/src/assets/help/en_US/date/date-format.md new file mode 100644 index 0000000000..502ab7d4f7 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/date/date-format.md @@ -0,0 +1,88 @@ +#### Pre-defined format options + +| Option | Equivalent to | Examples (given in `en-US` locale) | +|------------|---------------------------------|-----------------------------------------------| +| short | M/d/yy, h:mm a | 6/15/15, 9:03 AM | +| medium | MMM d, y, h:mm:ss a | Jun 15, 2015, 9:03:01 AM | +| long | MMMM d, y, h:mm:ss a z | June 15, 2015 at 9:03:01 AM GMT+1 | +| full | EEEE, MMMM d, y, h:mm:ss a zzzz | Monday, June 15, 2015 at 9:03:01 AM GMT+01:00 | +| shortDate | M/d/yy | 6/15/15 | +| mediumDate | MMM d, y | Jun 15, 2015 | +| longDate | MMMM d, y | June 15, 2015 | +| fullDate | EEEE, MMMM d, y | Monday, June 15, 2015 | +| shortTime | h:mm a | 9:03 AM | +| mediumTime | h:mm:ss a | 9:03:01 AM | +| longTime | h:mm:ss a z | 9:03:01 AM GMT+1 | +| fullTime | h:mm:ss a zzzz | 9:03:01 AM GMT+01:00 | + +#### Custom format options + +You can construct a format string using symbols to specify the components +of a date-time value, as described in the following table. +Format details depend on the locale. +Fields marked with (*) are only available in the extra data set for the given locale. + +| Field type | Format | Description | Example Value | +|---------------------|-------------|--------------------------------------------------------------|------------------------------------------------------------| +| Era | G, GG & GGG | Abbreviated | AD | +| | GGGG | Wide | Anno Domini | +| | GGGGG | Narrow | A | +| Year | y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 | +| | yy | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | +| | yyy | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | +| | yyyy | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | +| Week-numbering year | Y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 | +| | YY | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | +| | YYY | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | +| | YYYY | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | +| Month | M | Numeric: 1 digit | 9, 12 | +| | MM | Numeric: 2 digits + zero padded | 09, 12 | +| | MMM | Abbreviated | Sep | +| | MMMM | Wide | September | +| | MMMMM | Narrow | S | +| Month standalone | L | Numeric: 1 digit | 9, 12 | +| | LL | Numeric: 2 digits + zero padded | 09, 12 | +| | LLL | Abbreviated | Sep | +| | LLLL | Wide | September | +| | LLLLL | Narrow | S | +| Week of year | w | Numeric: minimum digits | 1... 53 | +| | ww | Numeric: 2 digits + zero padded | 01... 53 | +| Week of month | W | Numeric: 1 digit | 1... 5 | +| Day of month | d | Numeric: minimum digits | 1 | +| | dd | Numeric: 2 digits + zero padded | 01 | +| Week day | E, EE & EEE | Abbreviated | Tue | +| | EEEE | Wide | Tuesday | +| | EEEEE | Narrow | T | +| | EEEEEE | Short | Tu | +| Week day standalone | c, cc | Numeric: 1 digit | 2 | +| | ccc | Abbreviated | Tue | +| | cccc | Wide | Tuesday | +| | ccccc | Narrow | T | +| | cccccc | Short | Tu | +| Period | a, aa & aaa | Abbreviated | am/pm or AM/PM | +| | aaaa | Wide (fallback to `a` when missing) | ante meridiem/post meridiem | +| | aaaaa | Narrow | a/p | +| Period* | B, BB & BBB | Abbreviated | mid. | +| | BBBB | Wide | am, pm, midnight, noon, morning, afternoon, evening, night | +| | BBBBB | Narrow | md | +| Period standalone* | b, bb & bbb | Abbreviated | mid. | +| | bbbb | Wide | am, pm, midnight, noon, morning, afternoon, evening, night | +| | bbbbb | Narrow | md | +| Hour 1-12 | h | Numeric: minimum digits | 1, 12 | +| | hh | Numeric: 2 digits + zero padded | 01, 12 | +| Hour 0-23 | H | Numeric: minimum digits | 0, 23 | +| | HH | Numeric: 2 digits + zero padded | 00, 23 | +| Minute | m | Numeric: minimum digits | 8, 59 | +| | mm | Numeric: 2 digits + zero padded | 08, 59 | +| Second | s | Numeric: minimum digits | 0... 59 | +| | ss | Numeric: 2 digits + zero padded | 00... 59 | +| Fractional seconds | S | Numeric: 1 digit | 0... 9 | +| | SS | Numeric: 2 digits + zero padded | 00... 99 | +| | SSS | Numeric: 3 digits + zero padded (= milliseconds) | 000... 999 | +| Zone | z, zz & zzz | Short specific non location format (fallback to O) | GMT-8 | +| | zzzz | Long specific non location format (fallback to OOOO) | GMT-08:00 | +| | Z, ZZ & ZZZ | ISO8601 basic format | -0800 | +| | ZZZZ | Long localized GMT format | GMT-8:00 | +| | ZZZZZ | ISO8601 extended format + Z indicator for offset 0 (= XXXXX) | -08:00 | +| | O, OO & OOO | Short localized GMT format | GMT-8 | +| | OOOO | Long localized GMT format | GMT-08:00 | diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/card/value_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/card/value_color_fn.md new file mode 100644 index 0000000000..639043bfbc --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/card/value_color_fn.md @@ -0,0 +1,40 @@ +#### Color function + +
+
+ +*function (value): string* + +A JavaScript function used to compute a color. + +**Parameters:** + +
    +
  • value: primitive (number/string/boolean) - A value of the current datapoint. +
  • +
+ +**Returns:** + +Should return string value presenting color. + +In case no data is returned, color value from **Color** settings field will be used. + +
+ +##### Examples + +* Calculate color depending on `temperature` telemetry value: + +```javascript +var temperature = value; +if (typeof temperature !== undefined) { + var percent = (temperature + 60)/120 * 100; + return tinycolor.mix('blue', 'red', percent).toHexString(); +} +return 'blue'; +{:copy-code} +``` + +
+
diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md index 64e994fc3e..ede068d68f 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md @@ -31,7 +31,7 @@ if (type == 'colorpin') { var temperature = data['temperature']; if (typeof temperature !== undefined) { var percent = (temperature + 60)/120 * 100; - return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + return tinycolor.mix('blue', 'red', percent).toHexString(); } return 'blue'; } diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md index 056e47d0eb..c4df0a99a9 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md @@ -31,7 +31,7 @@ if (type == 'colorpin') { var temperature = data['temperature']; if (typeof temperature !== undefined) { var percent = (temperature + 60)/120 * 100; - return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + return tinycolor.mix('blue', 'red', percent).toHexString(); } return 'blue'; } diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md index 30f5e0f4d5..de092704c3 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md @@ -31,7 +31,7 @@ if (type == 'colorpin') { var temperature = data['temperature']; if (typeof temperature !== undefined) { var percent = (temperature + 60)/120 * 100; - return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + return tinycolor.mix('blue', 'red', percent).toHexString(); } return 'blue'; } diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md index 736bd727f0..b4cc0c5223 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md @@ -31,7 +31,7 @@ if (type == 'thermostat') { var temperature = data['temperature']; if (typeof temperature !== undefined) { var percent = (temperature + 60)/120 * 100; - return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + return tinycolor.mix('blue', 'red', percent).toHexString(); } return 'blue'; } diff --git a/ui-ngx/src/assets/linux.svg b/ui-ngx/src/assets/linux.svg new file mode 100644 index 0000000000..66f505437f --- /dev/null +++ b/ui-ngx/src/assets/linux.svg @@ -0,0 +1 @@ + diff --git a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json index 8c07387adc..25ae92b297 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -1376,13 +1376,7 @@ "device-configuration": "Configuració del dispositiu", "transport-configuration": "Configuració del transport", "wizard": { - "device-wizard": "Assistent de dispositiu", - "device-details": "Detalls del dispositiu", - "new-device-profile": "Crear un nou perfil de dispositiu", - "existing-device-profile": "Seleccionar un perfil existent", - "specific-configuration": "Configuració específica", - "customer-to-assign-device": "Client al que assignar el dispositiu", - "add-credentials": "Afegir credencial" + "device-details": "Detalls del dispositiu" }, "unassign-devices-from-edge-title": "Està segur de que desitja desassignar {count, plural, =1 {1 dispositivo} other {# dispositivos} }?", "unassign-devices-from-edge-text": "Després de la confirmació, tots els dispositius seleccionats quedaran sense assignar i la vora no podrà accedir a ells." @@ -1404,8 +1398,6 @@ "delete": "Esborrar perfil de dispositiu", "copyId": "Copiar ID de perfil", "name-max-length": "El nom ha de ser inferior a 256", - "new-device-profile-name": "Nom del perfil", - "new-device-profile-name-required": "Cal nom de perfil.", "name": "Nom", "name-required": "Cal nom.", "type": "Tipus de perfil", @@ -4488,7 +4480,7 @@ "created": "{{created}} creades", "updated": "{{updated}} actualitzades", "deleted": "{{deleted}} esborrades", - "remove-other-entities-confirm-text": "Atenció! Aquesta acció esborrarà permanentment todas les entitats actuals
no presents a la versió a restaurar.

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

Escriu \"remove other entities\" per confirmar.", "auto-commit-to-branch": "autopublicar a la branca {{ branch }}", "default-create-entity-version-name": "{{entityName}} actualizació", "sync-strategy-merge-hint": "Crea o actualitza les entitats seleccionades al repositori. Les altres entitats no seran modificades.", diff --git a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json index 229a4d7eee..d89971cd0c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -1018,13 +1018,7 @@ "device-configuration": "Konfigurace zařízení", "transport-configuration": "Konfigurace přenosu", "wizard": { - "device-wizard": "Průvodce zařízením", - "device-details": "Detail zařízení", - "new-device-profile": "Vytvořit nový profil zařízení", - "existing-device-profile": "Vybrat existující profil zařízení", - "specific-configuration": "Specifická konfigurace", - "customer-to-assign-device": "Přiřadit zařízení zákazníkovi", - "add-credentials": "Přidat přístupový údaj" + "device-details": "Detail zařízení" }, "unassign-devices-from-edge-title": "Jste se jisti, že chcete odebrat { count, plural, =1 {1 zařízení} other {# zařízení} }?", "unassign-devices-from-edge-text": "Po potvrzení budou všechna vybraná zařízení odebrána a nebudou pro edge dostupná." @@ -1045,8 +1039,6 @@ "set-default": "Učinit profil zařízení defaultním", "delete": "Smazat profil zařízení", "copyId": "Kopírovat Id profilu zařízení", - "new-device-profile-name": "Název profilu zařízení", - "new-device-profile-name-required": "Název profilu zařízení je povinný.", "name": "Název", "name-required": "Název je povinný.", "type": "Typ profilu", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 0f1dd146b1..4e3b3ca779 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -1095,13 +1095,7 @@ "device-configuration": "Enhedskonfiguration", "transport-configuration": "Transportkonfiguration", "wizard": { - "device-wizard": "Enhedsguide", - "device-details": "Enhedsoplysninger", - "new-device-profile": "Opret ny enhedsprofil", - "existing-device-profile": "Vælg eksisterende enhedsprofil", - "specific-configuration": "Specifik konfiguration", - "customer-to-assign-device": "Kunden skal tildele enheden", - "add-credential": "Tilføj brugeroplysninger" + "device-details": "Enhedsoplysninger" } }, "device-profile": { @@ -1120,8 +1114,6 @@ "set-default": "Gør enhedsprofil standard", "delete": "Slet enhedsprofil", "copyId": "Kopiér enhedsprofil-id", - "new-device-profile-name": "Enhedsprofilnavn", - "new-device-profile-name-required": "Enhedsprofilnavn er påkrævet.", "name": "Navn", "name-required": "Navn er påkrævet.", "type": "Profiltype", diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 4f978abeb9..dadc52e670 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -10,6 +10,9 @@ "permission-denied": "Permission Denied", "permission-denied-text": "You don't have permission to perform this operation!" }, + "account": { + "account": "Account" + }, "action": { "activate": "Activate", "suspend": "Suspend", @@ -67,7 +70,11 @@ "more": "More", "less": "Less", "skip": "Skip", - "send": "Send" + "send": "Send", + "reset": "Reset", + "show-more": "Show more", + "dont-show-again": "Do not show again", + "see-documentation": "See documentation" }, "aggregation": { "aggregation": "Aggregation", @@ -689,6 +696,7 @@ "attribute": { "attributes": "Attributes", "latest-telemetry": "Latest telemetry", + "no-latest-telemetry": "No latest telemetry", "attributes-scope": "Entity attributes scope", "scope-latest-telemetry": "Latest telemetry", "scope-client": "Client attributes", @@ -875,7 +883,8 @@ "loading": "Loading...", "proceed": "Proceed", "open-details-page": "Open details page", - "not-found": "Not found" + "not-found": "Not found", + "documentation": "Documentation" }, "content-type": { "json": "Json", @@ -938,6 +947,13 @@ "edges": "Customer edge instances", "manage-edges": "Manage edges" }, + "date": { + "last-update-n-ago": "Last update N ago", + "last-update-n-ago-text": "Last update {{ agoText }}", + "custom-date": "Custom date", + "format": "Format", + "preview": "Preview" + }, "datetime": { "date-from": "Date from", "time-from": "Time from", @@ -1130,6 +1146,7 @@ }, "datakey": { "settings": "Settings", + "general": "General", "advanced": "Advanced", "key": "Key", "label": "Label", @@ -1187,7 +1204,9 @@ "delta-calculation-result": "Delta calculation result", "delta-calculation-result-previous-value": "Previous value", "delta-calculation-result-delta-absolute": "Delta (absolute)", - "delta-calculation-result-delta-percent": "Delta (percent)" + "delta-calculation-result-delta-percent": "Delta (percent)", + "source": "Source", + "latest": "Latest" }, "datasource": { "type": "Datasource type", @@ -1370,16 +1389,27 @@ "device-configuration": "Device configuration", "transport-configuration": "Transport configuration", "wizard": { - "device-wizard": "Device Wizard", - "device-details": "Device details", - "new-device-profile": "Create new device profile", - "existing-device-profile": "Select existing device profile", - "specific-configuration": "Specific configuration", - "customer-to-assign-device": "Customer to assign the device", - "add-credentials": "Add credentials" + "device-details": "Device details" }, "unassign-devices-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 device} other {# devices} }?", - "unassign-devices-from-edge-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the edge." + "unassign-devices-from-edge-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the edge.", + "time": "Time", + "connectivity": { + "check-connectivity": "Check connectivity", + "device-created-check-connectivity": "Device created. Let's check connectivity!", + "loading-check-connectivity-command": "Loading check connectivity commands...", + "use-following-instructions": "Use the following instructions for sending telemetry on behalf of the device using shell", + "execute-following-command": "Execute the following command", + "install-curl-windows": "Starting Windows 10 b17063, cURL is available by default", + "install-mqtt-windows": "Use the instructions to download, install, setup and run mosquitto_pub", + "install-coap-client": "Use the instructions to download, install, setup and run coap-client", + "install-necessary-client-tools": "Install necessary client tools", + "mqtts-x509-command": "Use the following documentation to connect the device via MQTT with authorization X509", + "coaps-x509-command": "Use the following documentation to connect the device via CoAP over DTLS with authorization X509", + "snmp-command": "Use the following documentation to connect the device through the SNMP.", + "sparkplug-command": "Use the following documentation to connect the device through the MQTT Sparkplug.", + "lwm2m-command": "Use the following documentation to connect the device through the LWM2M." + } }, "asset-profile": { "asset-profile": "Asset profile", @@ -1443,8 +1473,6 @@ "delete": "Delete device profile", "copyId": "Copy device profile Id", "name-max-length": "Name should be less than 256", - "new-device-profile-name": "Device profile name", - "new-device-profile-name-required": "Device profile name is required.", "name": "Name", "name-required": "Name is required.", "type": "Profile type", @@ -1463,6 +1491,7 @@ "transport-type-lwm2m-hint": "LWM2M transport type", "transport-type-snmp": "SNMP", "transport-type-snmp-hint": "Specify SNMP transport configuration", + "transport-type-http": "HTTP", "description": "Description", "default": "Default", "profile-configuration": "Profile configuration", @@ -2779,8 +2808,14 @@ "left-side": "Left side layout" }, "legend": { - "direction": "Legend direction", - "position": "Legend position", + "direction": "Direction", + "position": "Position", + "show-values": "Show values", + "min-option": "Min", + "max-option": "Max", + "average-option": "Average", + "total-option": "Total", + "latest-option": "Latest", "sort-legend": "Sort datakeys in legend", "show-max": "Show max value", "show-min": "Show min value", @@ -3478,7 +3513,8 @@ "output": "Output", "test": "Test", "help": "Help", - "reset-debug-mode": "Reset debug mode in all nodes" + "reset-debug-mode": "Reset debug mode in all nodes", + "test-with-this-message": "{{test}} with this message" }, "timezone": { "timezone": "Timezone", @@ -3843,15 +3879,22 @@ "timewindow": { "timewindow": "Timewindow", "years": "{ years, plural, =1 { year } other {# years } }", + "years-short": "{{ years }}y", "months": "{ months, plural, =1 { month } other {# months } }", + "months-short": "{{ months }}M", "weeks": "{ weeks, plural, =1 { week } other {# weeks } }", + "weeks-short": "{{ weeks }}w", "days": "{ days, plural, =1 { day } other {# days } }", + "days-short": "{{ days }}d", "hours": "{ hours, plural, =0 { hour } =1 {1 hour } other {# hours } }", "hr": "{{ hr }} hr", + "hr-short": "{{ hr }}h", "minutes": "{ minutes, plural, =0 { minute } =1 {1 minute } other {# minutes } }", "min": "{{ min }} min", + "min-short": "{{ min }}m", "seconds": "{ seconds, plural, =0 { second } =1 {1 second } other {# seconds } }", "sec": "{{ sec }} sec", + "sec-short": "{{ sec }}s", "short": { "days": "{ days, plural, =1 {1 day } other {# days } }", "hours": "{ hours, plural, =1 {1 hour } other {# hours } }", @@ -3870,8 +3913,428 @@ "hide": "Hide", "interval": "Interval", "just-now": "Just now", + "just-now-lower": "just now", "ago": "ago" }, + "unit": { + "millimeter": "Millimeter", + "centimeter": "Centimeter", + "angstrom": "Angstrom", + "nanometer": "Nanometer", + "micrometer": "Micrometer", + "meter": "Meter", + "kilometer": "Kilometer", + "inch": "Inch", + "foot": "Foot", + "yard": "Yard", + "mile": "Mile", + "nautical-mile": "Nautical Mile", + "astronomical-unit": "Astronomical Unit", + "reciprocal-metre": "Reciprocal Metre", + "meter-per-meter": "Meter per meter", + "steradian": "Steradian", + "thou": "Thou", + "barleycorn": "Barleycorn", + "hand": "Hand", + "chain": "Chain", + "furlong": "Furlong", + "league": "League", + "fathom": "Fathom", + "cable": "Cable", + "link": "Link", + "rod": "Rod", + "nanogram": "Nanogram", + "microgram": "Microgram", + "milligram": "Milligram", + "gram": "Gram", + "kilogram": "Kilogram", + "tonne": "Tonne", + "ounce": "Ounce", + "pound": "Pound", + "stone": "Stone", + "hundredweight-count": "Hundredweight count", + "short-tons": "Short tons", + "dalton": "Dalton", + "grain": "Grain", + "drachm": "Drachm", + "quarter": "Quarter", + "slug": "Slug", + "carat": "Carat", + "cubic-millimeter": "Cubic Millimeter", + "cubic-centimeter": "Cubic Centimeter", + "cubic-meter": "Cubic Meter/s", + "cubic-kilometer": "Cubic Kilometers", + "microliter": "Microliter", + "milliliter": "Milliliter", + "liter": "Liter", + "hectoliter": "Hectolitre", + "cubic-inch": "Cubic Inch", + "cubic-foot": "Cubic Foot", + "cubic-yard": "Cubic Yards", + "fluid-ounce": "Fluid Ounce", + "pint": "Pint", + "quart": "Quart", + "gallon": "Gallon", + "oil-barrels": "Oil Barrels", + "cubic-meter-per-kilogram": "Cubic Meter per Kilogram", + "gill": "Gill", + "hogshead": "Hogshead", + "teaspoon": "Teaspoon", + "tablespoon": "Tablespoon", + "cup": "Cup", + "celsius": "Celsius", + "kelvin": "Kelvin", + "rankine": "Rankine", + "fahrenheit": "Fahrenheit", + "percent": "Percent", + "meter-per-second": "Meter per Second", + "kilometer-per-hour": "Kilometer per Hour", + "foot-per-second": "Foot per Second", + "mile-per-hour": "Mile per Hour", + "knot": "Knot", + "millimeters-per-minute": "Millimeters per minute", + "kilometer-per-hour-squared": "Kilometer per hour squared", + "foot-per-second-squared": "Foot per second squared", + "pascal": "Pascal", + "kilopascal": "Kilopascal", + "megapascal": "Megapascal", + "gigapascal": "Gigapascal", + "millibar": "Millibar", + "bar": "Bar", + "kilobar": "Kilobar", + "newton": "Newton", + "newton-meter": "Newton meter", + "foot-pounds": "Foot-pounds", + "inch-pounds": "Inch-pounds", + "newton-per-meter": "Newton per meter", + "atmospheres": "Atmospheres", + "pounds-per-square-inch": "Pounds per Square Inch", + "torr": "Torr", + "inches-of-mercury": "Inches of Mercury", + "pascal-per-square-meter": "Pascal per Square Meter", + "pound-per-square-inch": "Pound per Square Inch", + "newton-per-square-meter": "Newton per Square Meter", + "kilogram-force-per-square-meter": "Kilogram-force per Square Meter", + "pascal-per-square-centimeter": "Pascal per Square Centimeter", + "ton-force-per-square-inch": "Ton-force per Square Inch", + "kilonewton-per-square-meter": "Kilonewton per Square Meter", + "newton-per-square-millimeter": "Newton per Square Millimeter", + + "microjoule": "Microjoule", + "millijoule": "Millijoule", + "joule": "Joule", + "kilojoule": "Kilojoule", + "megajoule": "Megajoule", + "gigajoule": "Gigajoule", + "watt-hour": "Watt-hour", + "kilowatt-hour": "Kilowatt-hour", + "electron-volts": "Electron volts", + "joules-per-coulomb": "Joules per Coulomb", + "british-thermal-unit": "British Thermal Units", + "foot-pound": "Foot-pound", + "calorie": "Calorie", + "small-calorie": "Small Calorie", + "kilocalorie": "Kilocalorie", + "joule-per-kelvin": "Joule per Kelvin", + "joule-per-kilogram-kelvin": "Joule per Kilogram-Kelvin", + "joule-per-kilogram": "Joule per Kilogram", + "watt-per-meter-kelvin": "Watt per Meter-Kelvin", + "joule-per-cubic-meter": "Joule per Cubic Meter", + "therm": "Therm", + "electric-dipole-moment": "Electric Dipole Moment", + "magnetic-dipole-moment": "Magnetic Dipole Moment", + "debye": "Debye", + "coulomb-per-square-meter-per-volt": "Coulomb per Square Meter per Volt", + "milliwatt": "Milliwatt", + "microwatt": "Microwatt", + "watt": "Watt", + "kilowatt": "Kilowatt", + "megawatt": "Megawatt", + "gigawatt": "Gigawatt", + "metric-horsepower": "Metric Horsepower", + "milliwatt-per-square-centimeter": "Milliwatts per square centimeter", + "watt-per-square-centimeter": "Watts per square centimeter", + "kilowatt-per-square-centimeter": "Kilowatts per square centimeter", + "milliwatt-per-square-meter": "Milliwatts per square meter", + "watt-per-square-meter": "Watts per square meter", + "kilowatt-per-square-meter": "Kilowatts per square meter", + "watt-per-square-inch": "Watts per square inch", + "kilowatt-per-square-inch": "Kilowatts per square inch", + "horsepower": "Horsepower", + "btu-per-hour": "British thermal units/hour", + "coulomb": "Coulomb", + "millicoulomb": "Millicoulombs", + "microcoulomb": "Microcoulomb", + "picocoulomb": "Picocoulomb", + "coulomb-per-meter": "Coulomb per meter", + "coulomb-per-cubic-meter": "Coulomb per Cubic Meter", + "coulomb-per-square-meter": "Coulomb per Square Meter", + "square-millimeter": "Square Millimeter", + "square-centimeter": "Square Centimeter", + "square-meter": "Square Meter", + "hectare": "Hectare", + "square-kilometer": "Square Kilometer", + "square-inch": "Square Inch", + "square-foot": "Square Foot", + "square-yard": "Square Yard", + "acre": "Acre", + "square-mile": "Square Mile", + "are": "Are", + "barn": "Barn", + "circular-inch": "Circular Inch", + "milliampere-hour": "Milliampere-hour", + "milliampere-hour-tags": "electric current, current flow, electric charge, current capacity, flow of electricity, electrical flow, milliampere-hour, milliampere-hours, mAh", + "ampere-hours": "Ampere-hours", + "ampere-hours-tags": "electric current, current flow, electric charge, current capacity, flow of electricity, electrical flow, ampere, ampere-hours, Ah", + "kiloampere-hours": "Kiloampere-hours", + "kiloampere-hours-tags": "electric current, current flow, electric charge, current capacity, flow of electricity, electrical flow, kiloampere-hours, kiloampere-hour, kAh", + "nanoampere": "Nanoampere", + "nanoampere-tags": "current, amperes, nanoampere, nA", + "picoampere": "Picoampere", + "picoampere-tags": "current, amperes, picoampere, pA", + "microampere": "Microampere", + "microampere-tags": "electric current, microampere, microamperes, μA", + "milliampere": "Milliampere", + "milliampere-tags": "electric current, milliampere, milliamperes, mA", + "ampere": "Ampere", + "ampere-tags": "electric current, current flow, flow of electricity, electrical flow, ampere, amperes, amperage, A", + "kiloamperes": "Kiloamperes", + "kiloamperes-tags": "electric current, current flow, kiloamperes, kA", + "microampere-per-square-centimeter": "Microampere per square centimeter", + "microampere-per-square-centimeter-tags": "Current density, microampere per square centimeter, µA/cm²", + "ampere-per-square-meter": "Ampere per Square Meter", + "ampere-per-square-meter-tags": "current density, current per unit area, ampere per square meter, A/m²", + "ampere-per-meter": "Ampere per Meter", + "ampere-per-meter-tags": "magnetic field strength, magnetic field intensity, ampere per meter, A/m", + "oersted": "Oersted", + "oersted-tags": "magnetic field, oersted, Oe", + "bohr-magneton": "Bohr Magneton", + "bohr-magneton-tags": "atomic physics, magnetic moment, bohr magneton, μB", + "ampere-meter-squared": "Ampere-Meter Squared", + "ampere-meter-squared-tags": "magnetic moment, dipole moment, ampere-meter squared, A·m²", + "ampere-meter": "Ampere-Meter", + "ampere-meter-tags": "magnetic field, current loop, ampere-meter, A·m", + "nanovolt": "Nanovolt", + "picovolt": "Picovolt", + "millivolts": "Millivolts", + "microvolts": "Microvolts", + "volt": "Volt", + "kilovolts": "Kilovolts", + "dbmV": "dBmV", + "volt-meter": "Volt-Meter", + "kilovolt-meter": "Kilovolt-Meter", + "megavolt-meter": "Megavolt-Meter", + "microvolt-meter": "Microvolt-Meter", + "millivolt-meter": "Millivolt-Meter", + "nanovolt-meter": "Nanovolt-Meter", + "ohm": "Ohm", + "microohm": "Microohm", + "milliohm": "Milliohm", + "kilohm": "Kilohm", + "megohm": "Megohm", + "gigohm": "Gigohm", + "hertz": "Hertz", + "kilohertz": "Kilohertz", + "megahertz": "Megahertz", + "gigahertz": "Gigahertz", + "rpm": "Revolutions Per Minute", + "candela-per-square-meter": "Candela per square meter", + "candela": "Candela", + "lumen": "Lumen", + "lux": "Lux", + "foot-candle": "Foot-candle", + "lumen-per-square-meter": "Lumen per square meter", + "lux-second": "Lux second", + "lumen-second": "Lumen second", + "lumens-per-watt": "Lumens per watt", + "absorbance": "Absorbance", + "mole": "Mole", + "nanomole": "Nanomole", + "micromole": "MicroMole", + "millimole": "Millimole", + "kilomole": "Kilomole", + "mole-per-cubic-meter": "Mole per Cubic Meter", + "rssi": "RSSI", + "ppm": "Parts Per Million", + "ppb": "Parts Per Billion", + "micrograms-per-cubic-meter": "Micrograms per Cubic Meter", + "aqi": "AQI", + "gram-per-cubic-meter": "Gram per cubic meter", + "gram-per-kilogram": "Specific Humidity", + "millimeters-per-second": "Millimeters per second", + "neper": "Neper", + "bel": "Bel", + "decibel": "Decibel", + "meters-per-second-squared": "Meters per second squared", + "becquerel": "Becquerel", + "curie": "Curie", + "gray": "Gray", + "sievert": "Sievert", + "roentgen": "Roentgen", + "cps": "Counts per Second", + "rad": "Rad", + "rem": "Rem", + "dps": "Disintegrations per second", + "rutherford": "Rutherford", + "coulombs-per-kilogram": "Coulombs per kilogram", + "becquerels-per-cubic-meter": "Becquerels per cubic meter", + "curies-per-liter": "Curies per liter", + "becquerels-per-second": "Becquerels per second", + "curies-per-second": "Curies per second", + "gy-per-second": "Gray per Second", + "watt-per-steradian": "Watt per Steradian", + "watt-per-square-metre-steradian": "Watt per Square Metre-Steradian", + "ph-level": "pH Level", + "turbidity": "Turbidity", + "mg-per-liter": "Milligrams per liter", + "microsiemens-per-centimeter": "Microsiemens per centimeter", + "millisiemens-per-meter": "Millisiemens per meter", + "siemens-per-meter": "Siemens per meter", + "kilogram-per-cubic-meter": "Kilogram per cubic meter", + "gram-per-cubic-centimeter": "Gram per cubic centimeter", + "kilogram-per-square-meter": "Kilogram per square metre", + "milligram-per-milliliter": "Milligram per milliliter", + "pound-per-cubic-foot": "Pound per cubic foot", + "ounces-per-cubic-inch": "Ounces per cubic inch", + "tons-per-cubic-yard": "Tons per cubic yard", + "particle-density": "Particle density", + "kilometers-per-liter": "Kilometers per liter", + "miles-per-gallon": "Miles per gallon", + "liters-per-100-km": "Liters per 100 km", + "gallons-per-mile": "Gallons per mile", + "liters-per-hour": "Liters per hour", + "gallons-per-hour": "Gallons per hour", + "beats-per-minute": "Beats per minute", + "millimeters-of-mercury": "Millimeters of mercury", + "milligrams-per-deciliter": "Milligrams per deciliter", + "g-force": "G-force", + "kilonewton": "Kilonewton", + "kilogram-force": "Kilogram-Force", + "pound-force": "Pound-Force", + "kilopound-force": "Kilopound-Force", + "dyne": "Dyne", + "poundal": "Poundal", + "kip": "Kip", + "gal": "Gal", + "gravity": "Gravity", + "hectopascal": "Hectopascal", + "atmosphere": "Atmosphere", + "millibars": "Millibars", + "inch-of-mercury": "One inch of mercury", + "richter-scale": "Richter Scale", + "second": "Second", + "minute": "Minute", + "hour": "Hour", + "day": "Day", + "week": "Week", + "month": "Month", + "year": "Year", + "cubic-foot-per-minute": "Cubic Foot Per Minute", + "cubic-meters-per-hour": "Cubic Meters Per Hour", + "cubic-meters-per-second": "Cubic Meters Per Second", + "liter-per-second": "Liter Per Second", + "liter-per-minute": "Liter Per Minute", + "gallons-per-minute": "Gallons Per Minute", + "cubic-foot-per-second": "Cubic foot per second", + "milliliters-per-minute": "Milliliters per minute", + "bit": "Bit", + "byte": "Byte", + "kilobyte": "Kilobyte", + "megabyte": "Megabyte", + "gigabyte": "Gigabyte", + "terabyte": "Terabyte", + "petabyte": "Petabyte", + "exabyte": "Exabyte", + "zettabyte": "Zettabyte", + "yottabyte": "Yottabyte", + "bit-per-second": "Bit per second", + "kilobit-per-second": "Kilobit per second", + "megabit-per-second": "Megabit per second", + "gigabit-per-second": "Gigabit per second", + "terabit-per-second": "Terabit per second", + "byte-per-second": "Byte per second", + "kilobyte-per-second": "Kilobyte per second", + "megabyte-per-second": "Megabyte per second", + "gigabyte-per-second": "Gigabyte per second", + "degree": "Degree", + "radian": "Radian", + "gradian": "Gradian", + "mil": "Mil", + "revolution": "Revolution", + "siemens": "Siemens", + "millisiemens": "Millisiemens", + "microsiemens": "Microsiemens", + "kilosiemens": "Kilosiemens", + "megasiemens": "Megasiemens", + "gigasiemens": "Gigasiemens", + "farad": "Farad", + "millifarad": "Millifarad", + "microfarad": "Microfarad", + "nanofarad": "Nanofarad", + "picofarad": "Picofarad", + "kilofarad": "Kilofarad", + "megafarad": "Megafarad", + "gigafarad": "Gigafarad", + "terfarad": "Terfarad", + "farad-per-meter": "Farad per Meter", + "tesla": "Tesla", + "gauss": "Gauss", + "kilogauss": "Kilogauss", + "millitesla": "Millitesla", + "microtesla": "Microtesla", + "nanotesla": "Nanotesla", + "kilotesla": "Kilotesla", + "megatesla": "Megatesla", + "millitesla-square-meters": "millitesla square meters", + "gamma": "Gamma", + "lambda": "Lambda", + "square-meter-per-second": "Square meter per second", + "square-centimeter-per-second": "Square centimeter per second", + "stoke": "Stoke", + "centistokes": "Centistokes", + "square-foot-per-second": "Square foot per second", + "square-inch-per-second": "Square inch per second", + "pascal-second": "Pascal-second", + "centipoise": "Centipoise", + "poise": "Poise", + "reynolds": "Reynolds", + "pound-per-foot-hour": "Pound per foot-hour", + "newton-second-per-square-meter": "Newton second per square meter", + "dyne-second-per-square-centimeter": "Dyne second per square centimeter", + "kilogram-per-meter-second": "Kilogram per meter-second", + "tesla-square-meters": "Tesla square meters", + "maxwell": "Maxwell", + "tesla-per-meter": "Tesla per Meter", + "gauss-per-centimeter": "Gauss per Centimeter", + "weber": "Weber", + "microweber": "Microweber", + "milliweber": "Milliweber", + "gauss-square-centimeter": "Gauss-Square Centimeter", + "kilogauss-square-centimeter": "Kilogauss-Square Centimeter", + "henry": "Henry", + "millihenry": "Millihenry", + "microhenry": "Microhenry", + "nanohenry": "Nanohenry", + "henry-per-meter": "Henry per Meter", + "tesla-meter-per-ampere": "Tesla Meter per Ampere", + "gauss-per-oersted": "Gauss per Oersted", + "kilogram-per-mole": "Kilogram per mole", + "gram-per-mole": "Gram per mole", + "milligram-per-mole": "Milligram per mole", + "joule-per-mole": "Joule per Mole", + "joule-per-mole-kelvin": "Joule per Mole-Kelvin", + "millivolts-per-meter": "Millivolts per meter", + "volts-per-meter": "Volts per meter", + "kilovolts-per-meter": "Kilovolts per meter", + "radian-per-second": "Radian per second", + "radian-per-second-squared": "Radian per second squared", + "revolutions-per-minute-per-second": "Angular acceleration", + "revolutions-per-minute-per-second-squared": "Angular Acceleration", + "deg-per-second": "deg/s", + "degrees-brix": "Degrees Brix", + "katal": "Katal", + "katal-per-cubic-metre": "Katal per Cubic Metre" + }, "user": { "user": "User", "users": "Users", @@ -4005,7 +4468,7 @@ "created": "{{created}} created", "updated": "{{updated}} updated", "deleted": "{{deleted}} deleted", - "remove-other-entities-confirm-text": "Be careful! This will permanently delete all current entities
not present in the version you want to restore.

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

Please type \"remove other entities\" to confirm.", "auto-commit-to-branch": "auto-commit to {{ branch }} branch", "default-create-entity-version-name": "{{entityName}} update", "sync-strategy-merge-hint": "Creates or updates selected entities in the repository. All other repository entities are not modified.", @@ -4195,6 +4658,7 @@ "enable-fullscreen": "Enable fullscreen", "background-color": "Background color", "text-color": "Text color", + "border-radius": "Border radius", "padding": "Padding", "margin": "Margin", "widget-style": "Widget style", @@ -4209,6 +4673,7 @@ "decimals": "Number of digits after floating point", "units-short": "Units", "decimals-short": "Decimals", + "decimals-suffix": "decimals", "timewindow": "Timewindow", "use-dashboard-timewindow": "Use dashboard timewindow", "use-widget-timewindow": "Use widget timewindow", @@ -4257,13 +4722,16 @@ "preview": "Preview", "set": "Set", "set-message": "Set message", - "card-title": "Card title", "advanced-title-style": "Advanced title style", "card-style": "Card style", "text": "Text", "background": "Background", "advanced-widget-style": "Advanced widget style", - "card-buttons": "Card buttons" + "card-buttons": "Card buttons", + "show-card-buttons": "Show card buttons", + "card-border-radius": "Card border radius", + "card-appearance": "Card appearance", + "color": "Color" }, "widget-type": { "import": "Import widget type", @@ -4274,9 +4742,23 @@ "invalid-widget-type-file-error": "Unable to import widget type: Invalid widget type data structure." }, "widgets": { + "background": { + "background": "Background", + "background-settings": "Background settings", + "background-type-image": "Upload image", + "background-type-image-url": "Image URL", + "background-type-color": "Solid color", + "image-url": "Image URL", + "overlay": "Overlay", + "enable-overlay": "Enable overlay", + "blur": "Blur", + "preview": "Preview" + }, "chart": { "common-settings": "Common settings", "enable-stacking-mode": "Enable stacking mode", + "selection": "Time range selection", + "enable-selection-mode": "Enable selection mode", "line-shadow-size": "Line shadow size", "display-smooth-lines": "Display smooth (curved) lines", "default-bar-width": "Default bar width for non-aggregated data (milliseconds)", @@ -4284,10 +4766,12 @@ "bar-alignment-left": "Left", "bar-alignment-right": "Right", "bar-alignment-center": "Center", + "default-font": "Default font", "default-font-size": "Default font size", "default-font-color": "Default font color", "thresholds-line-width": "Default line width for all thresholds", "tooltip-settings": "Tooltip settings", + "tooltip": "Tooltip", "show-tooltip": "Show tooltip", "hover-individual-points": "Hover individual points", "show-cumulative-values": "Show cumulative values in stacking mode", @@ -4362,9 +4846,10 @@ "axis-position-right": "Right", "thresholds": "Thresholds", "no-thresholds": "No thresholds configured", - "add-threshold": "Add new threshold", + "add-threshold": "Add threshold", "show-values-for-comparison": "Show historical values for comparison", "comparison-values-label": "Historical values label", + "comparison-line-color": "Comparison line color", "threshold-settings": "Threshold settings", "use-as-threshold": "Use key value as threshold", "threshold-line-width": "Threshold line width", @@ -4383,7 +4868,34 @@ "border-color": "Border color", "legend-settings": "Legend settings", "display-legend": "Display legend", - "labels-font-color": "Labels font color" + "labels-font-color": "Labels font color", + "series": "Series", + "add-series": "Add series", + "series-settings": "Series settings", + "remove-series": "Remove series", + "no-series": "No series configured", + "no-series-error": "At least one series should be specified", + "chart-appearance": "Chart appearance", + "vertical-grid-lines": "Vertical grid lines", + "horizontal-grid-lines": "Horizontal grid lines", + "chart-background": "Chart background", + "grid-lines-color": "Grid lines color", + "border": "Border", + "axis": "Axis", + "vertical-axis": "Vertical axis", + "ticks": "Ticks", + "horizontal-axis": "Horizontal axis" + }, + "color": { + "color-settings": "Color settings", + "color-type-constant": "Constant", + "color-type-range": "Range", + "color-type-function": "Function", + "color": "Color", + "value-range": "Value range", + "from": "From", + "to": "To", + "color-function": "Color function" }, "dashboard-state": { "dashboard-state-settings": "Dashboard state settings", @@ -4780,6 +5292,7 @@ "datakey-value-type-date": "Date", "datakey-value-type-time": "Time", "datakey-value-type-select": "Select", + "datakey-value-type-color": "Color", "value-is-required": "Value is required", "ability-to-edit-attribute": "Ability to edit attribute", "ability-to-edit-attribute-editable": "Editable (default)", @@ -5194,6 +5707,20 @@ "label-position-left": "Left", "label-position-top": "Top" }, + "value-card": { + "layout": "Layout", + "layout-square": "Square", + "layout-vertical": "Vertical", + "layout-centered": "Centered", + "layout-simplified": "Simplified", + "layout-horizontal": "Horizontal", + "layout-horizontal-reversed": "Horizontal reversed", + "label": "Label", + "icon": "Icon", + "value": "Value", + "date": "Date", + "value-card-style": "Value card style" + }, "table": { "common-table-settings": "Common Table Settings", "enable-search": "Enable search", @@ -5246,19 +5773,30 @@ "display-alarm-activity": "Display alarm activity", "allow-alarms-assign": "Allow alarms assignment", "columns": "Columns", + "column-settings": "Column settings", "remove-column": "Remove column", "add-column": "Add column", - "no-columns": "No columns configured" + "no-columns": "No columns configured", + "columns-to-display": "Columns to display", + "table-header": "Table header", + "header-buttons": "Header buttons", + "table-buttons": "Table buttons", + "pagination": "Pagination", + "rows": "Rows", + "timeseries-column-error": "At least one timeseries column should be specified", + "table-tabs": "Table tabs", + "show-cell-actions-menu-mobile": "Show cell actions dropdown menu in mobile mode" }, "value-source": { "value-source": "Value source", "predefined-value": "Predefined value", - "entity-attribute": "Value taken from entity attribute", + "entity-attribute": "Entity attribute", "value": "Value", "source-entity-alias": "Source entity alias", "source-entity-attribute": "Source entity attribute" }, "widget-font": { + "font-settings": "Font settings", "font-family": "Font family", "size": "Size", "relative-font-size": "Relative font size (percents)", @@ -5272,7 +5810,8 @@ "font-weight-bolder": "Bolder", "font-weight-lighter": "Lighter", "color": "Color", - "shadow-color": "Shadow color" + "shadow-color": "Shadow color", + "preview": "Preview" }, "home": { "no-data-available": "No data available" @@ -5469,11 +6008,17 @@ } } }, + "color": { + "color": "Color" + }, "icon": { "icon": "Icon", + "icons": "Icons", "select-icon": "Select icon", "material-icons": "Material icons", - "show-all": "Show all icons" + "show-all": "Show all icons", + "search-icon": "Search icon", + "no-icons-found": "No icons found for '{{iconSearch}}'" }, "phone-input": { "phone-input-label": "Phone number", diff --git a/ui-ngx/src/assets/locale/locale.constant-es_ES.json b/ui-ngx/src/assets/locale/locale.constant-es_ES.json index 4689c66bed..6a1516a56d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -1325,13 +1325,7 @@ "device-configuration": "Configuración del dispositivo", "transport-configuration": "Configuración del transporte", "wizard": { - "device-wizard": "Asistente de dispositivo", - "device-details": "Detalles del dispositivo", - "new-device-profile": "Crear un nuevo perfil de dispositivo", - "existing-device-profile": "Seleccionar un perfil existente", - "specific-configuration": "Configuración específica", - "customer-to-assign-device": "Cliente al que asignar el dispositivo", - "add-credentials": "Añadir credencial" + "device-details": "Detalles del dispositivo" }, "unassign-devices-from-edge-title": "¿Está seguro de que desea desasignar {count, plural, =1 {1 dispositivo} other {# dispositivos} }?", "unassign-devices-from-edge-text": "Después de la confirmación, todos los dispositivos seleccionados quedarán sin asignar y el Edge no podrá acceder a ellos." @@ -1398,8 +1392,6 @@ "delete": "Borrar perfil de dispositivo", "copyId": "Copiar ID de perfil", "name-max-length": "El nombre debe ser menor de 256", - "new-device-profile-name": "Nombre de perfil", - "new-device-profile-name-required": "Se requiere nombre de perfil.", "name": "Nombre", "name-required": "Se requiere nombre.", "type": "Tipo de perfil", @@ -3914,7 +3906,7 @@ "created": "{{created}} creadas", "updated": "{{updated}} actualizadas", "deleted": "{{deleted}} borradas", - "remove-other-entities-confirm-text": "Atención! Esta acción borrará permanentemente todas las entidades actuales
no presentes en la versión a restaurar.

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

Escribe \"remove other entities\" para confirmar.", "auto-commit-to-branch": "auto-publicar a la rama {{ branch }}", "default-create-entity-version-name": "{{entityName}} actualización", "sync-strategy-merge-hint": "Crea o actualiza las entidades seleccionadas en el repositorio. Las demás entidades no serán modificadas.", diff --git a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json index 8704210933..56712eeeb5 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -1053,13 +1053,7 @@ "device-configuration": "Configuration du dipositif", "transport-configuration": "Configuration du transport", "wizard": { - "device-wizard": "Wizard du dispositif", - "device-details": "Détails du dispositif", - "new-device-profile": "Créer un nouveau profil de dispositif", - "existing-device-profile": "Choisissez un profile de dispositif existant", - "specific-configuration": "Configuration spécifique", - "customer-to-assign-device": "Client auquel assigner le dispositif", - "add-credentials": "Ajouter identifiants" + "device-details": "Détails du dispositif" } }, "device-profile": { @@ -1079,8 +1073,6 @@ "delete": "Supprimer le profil de dispositif", "copyId": "Copier l'Identifiant du profil de dispositif", "name-max-length": "La longueur du nom devrait être moins de 256", - "new-device-profile-name": "Nom du profil de dispositif", - "new-device-profile-name-required": "Nom du profil de dispositif est requis.", "name": "Nom", "name-required": "Nom est requis.", "type": "Type de profile", diff --git a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json index 1462a4f3d1..0fd1ba039d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -913,13 +913,7 @@ "device-configuration": "장치 설정", "transport-configuration": "전송 설정", "wizard": { - "device-wizard": "장치 마법사", - "device-details": "장치 상세 정보", - "new-device-profile": "새로운 장치 프로파일 생성", - "existing-device-profile": "기존 장치 프로파일 선택", - "specific-configuration": "특수 설정", - "customer-to-assign-device": "장치에 할당할 커스터머", - "add-credentials": "크리덴셜 추가" + "device-details": "장치 상세 정보" } }, "device-profile": { @@ -938,8 +932,6 @@ "set-default": "Make device profile default", "delete": "Delete device profile", "copyId": "Copy device profile Id", - "new-device-profile-name": "장치 프로파일 이름", - "new-device-profile-name-required": "Device profile name is required.", "name": "이름", "name-required": "이름을 입력하세요.", "type": "프로파일 유형", diff --git a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json index 1200732365..fcc2f6f867 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -913,13 +913,7 @@ "device-configuration": "Device configuration", "transport-configuration": "Transport configuration", "wizard": { - "device-wizard": "Device Wizard", - "device-details": "Device details", - "new-device-profile": "Create new device profile", - "existing-device-profile": "Select existing device profile", - "specific-configuration": "Specific configuration", - "customer-to-assign-device": "Customer to assign the device", - "add-credentials": "Add credentials" + "device-details": "Device details" } }, "device-profile": { @@ -938,8 +932,6 @@ "set-default": "Make device profile default", "delete": "Delete device profile", "copyId": "Copy device profile Id", - "new-device-profile-name": "Device profile name", - "new-device-profile-name-required": "Device profile name is required.", "name": "Name", "name-required": "Name is required.", "type": "Profile type", diff --git a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json index 1aa6900be7..cd7e31e97f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -1021,13 +1021,7 @@ "device-configuration": "Cihaz yapılandırması", "transport-configuration": "Aktarım yapılandırması", "wizard": { - "device-wizard": "Cihaz Sihirbazı", - "device-details": "Cihaz ayrıntıları", - "new-device-profile": "Yeni cihaz profili oluştur", - "existing-device-profile": "Mevcut cihaz profilini seçin", - "specific-configuration": "Özel yapılandırma", - "customer-to-assign-device": "Cihazı atamak için kullanıcı grubu", - "add-credentials": "Kimlik bilgileri ekle" + "device-details": "Cihaz ayrıntıları" }, "unassign-devices-from-edge-title": "{ count, plural, =1 {1 cihazın} other {# cihazın} } atamasını kaldırmak istediğinizden emin misiniz?", "unassign-devices-from-edge-text": "Onaydan sonra, seçilen tüm cihazların ataması kaldırılacak ve uç tarafından erişilemeyecek." @@ -1048,8 +1042,6 @@ "set-default": "Cihaz profilini varsayılan yap", "delete": "Cihaz profilini sil", "copyId": "Cihaz profili kimliğini kopyala", - "new-device-profile-name": "Cihaz profili adı", - "new-device-profile-name-required": "Cihaz profili adı gerekli.", "name": "İsim", "name-required": "İsim gerekli.", "type": "Profil türü", diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index 58a214372a..78978b9896 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -1221,13 +1221,7 @@ "device-configuration": "设备配置", "transport-configuration": "传输配置", "wizard": { - "device-wizard": "设备向导", - "device-details": "设备详细信息", - "new-device-profile": "新建设备配置", - "existing-device-profile": "选择已有设备配置", - "specific-configuration": "指定配置", - "customer-to-assign-device": "客户分配设备", - "add-credentials": "添加凭据" + "device-details": "设备详细信息" }, "unassign-devices-from-edge-title": "确定要取消分配 { count, plural, =1 {1 个设备} other {# 个设备} } 吗?", "unassign-devices-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。" @@ -1292,8 +1286,6 @@ "delete": "删除设备配置", "copyId": "复制设备配置 ID", "name-max-length": "名称长度必须少于256个字符", - "new-device-profile-name": "设备配置名称", - "new-device-profile-name-required": "设备配置名称必填。", "name": "名称", "name-required": "名称是必需的。", "type": "配置类型", @@ -3495,7 +3487,7 @@ "created": "{{created}} 创建", "updated": "{{updated}} 更新", "deleted": "{{deleted}} 删除", - "remove-other-entities-confirm-text": "请注意!在还原版本中不存在的当前实体
将被永久 删除

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

请输入 \"remove other entities\" 进行确认。", "auto-commit-to-branch": "自动提交到 {{ branch }} 分支", "default-create-entity-version-name": "{{entityName}} 更新", "sync-strategy-merge-hint": "创建或更新选定的实体,仓库其他实体均不修改。", diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json index 2d493961aa..d8712eed6e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -1134,13 +1134,7 @@ "device-configuration": "設備配置", "transport-configuration": "傳輸配置", "wizard": { - "device-wizard": "設備嚮導", - "device-details": "設備詳情", - "new-device-profile": "建立設備協議", - "existing-device-profile": "選擇現有的設備協議", - "specific-configuration": "具體配置", - "customer-to-assign-device": "客戶指定設備", - "add-credentials": "新增驗證資訊" + "device-details": "設備詳情" }, "unassign-devices-from-edge-title": "您確定要解除邊緣設備 { count, plural, =1 {1 device} other {# devices} }的指定嗎?", "unassign-devices-from-edge-text": "確認後邊緣指定設備將解除指定及其所有相關資料將無法恢復。" @@ -1205,8 +1199,6 @@ "delete": "刪除設備協議", "copyId": "複製設備協議Id", "name-max-length": "名稱應小於256", - "new-device-profile-name": "設備協議名稱", - "new-device-profile-name-required": "需要設備協議名稱。", "name": "名稱", "name-required": "需要名稱", "type": "協議類型", @@ -3345,7 +3337,7 @@ "created": "{{created}}已創建", "updated": "{{updated}}已更新", "deleted": "{{deleted}} 已刪除", - "remove-other-entities-confirm-text": "小心!這將永久刪除您要恢復的版本中不存在的所有當前實體。請鍵入刪除其他實體進行確認。", + "remove-other-entities-confirm-text": "小心!這將永久刪除所有在您要恢復的版本中不存在的當前實體。請輸入 \"remove other entities\" 進行確認。", "auto-commit-to-branch": "自動提交到{{ branch }}分支", "default-create-entity-version-name": "{{entityName}} 更新", "sync-strategy-merge-hint": "在存儲庫中創建或更新選定實體。所有其他存儲實體都不會被修改。", diff --git a/ui-ngx/src/assets/macos.svg b/ui-ngx/src/assets/macos.svg new file mode 100644 index 0000000000..c3bac982fb --- /dev/null +++ b/ui-ngx/src/assets/macos.svg @@ -0,0 +1 @@ + diff --git a/ui-ngx/src/assets/metadata/material-icons.json b/ui-ngx/src/assets/metadata/material-icons.json new file mode 100644 index 0000000000..2da54c48c2 --- /dev/null +++ b/ui-ngx/src/assets/metadata/material-icons.json @@ -0,0 +1 @@ +[{"name":"more_horiz","tags":["3","DISABLE_IOS","app","application","components","disable_ios","dots","etc","horiz","horizontal","interface","ios","more","screen","site","three","ui","ux","web","website"]},{"name":"more_vert","tags":["3","DISABLE_IOS","android","app","application","components","disable_ios","dots","etc","interface","more","screen","site","three","ui","ux","vert","vertical","web","website"]},{"name":"open_in_new","tags":["app","application","arrow","box","components","in","interface","new","open","right","screen","site","ui","up","ux","web","website","window"]},{"name":"visibility","tags":["eye","on","reveal","see","show","view","visibility"]},{"name":"play_arrow","tags":["arrow","control","controls","media","music","play","video"]},{"name":"arrow_back","tags":["DISABLE_IOS","app","application","arrow","back","components","direction","disable_ios","interface","left","navigation","previous","screen","site","ui","ux","web","website"]},{"name":"arrow_downward","tags":["app","application","arrow","components","direction","down","downward","interface","navigation","screen","site","ui","ux","web","website"]},{"name":"arrow_forward","tags":["app","application","arrow","arrows","components","direction","forward","interface","navigation","right","screen","site","ui","ux","web","website"]},{"name":"arrow_upward","tags":["app","application","arrow","components","direction","interface","navigation","screen","site","ui","up","upward","ux","web","website"]},{"name":"close","tags":["cancel","close","exit","stop","x"]},{"name":"refresh","tags":["around","arrow","arrows","direction","inprogress","load","loading refresh","navigation","refresh","renew","right","rotate","turn"]},{"name":"menu","tags":["app","application","components","hamburger","interface","line","lines","menu","screen","site","ui","ux","web","website"]},{"name":"show_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","line","measure","metrics","presentation","show chart","statistics","tracking"]},{"name":"multiline_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","line","measure","metrics","multiple","statistics","tracking"]},{"name":"pie_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","pie","statistics","tracking"]},{"name":"insert_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","insert","measure","metrics","statistics","tracking"]},{"name":"people","tags":["accounts","committee","face","family","friends","humans","network","people","persons","profiles","social","team","users"]},{"name":"person","tags":["account","face","human","people","person","profile","user"]},{"name":"domain","tags":["apartment","architecture","building","business","domain","estate","home","place","real","residence","residential","shelter","web","www"]},{"name":"devices_other","tags":["Android","OS","ar","cell","chrome","desktop","device","gadget","hardware","iOS","ipad","mac","mobile","monitor","other","phone","tablet","vr","watch","wearables","window"]},{"name":"widgets","tags":["app","box","menu","setting","squares","ui","widgets"]},{"name":"dashboard","tags":["cards","dashboard","format","layout","rectangle","shapes","square","web","website"]},{"name":"map","tags":["destination","direction","location","map","maps","pin","place","route","stop","travel"]},{"name":"pin_drop","tags":["destination","direction","drop","location","maps","navigation","pin","place","stop"]},{"name":"gps_fixed","tags":["destination","direction","fixed","gps","location","maps","pin","place","pointer","stop","tracking"]},{"name":"extension","tags":["app","extended","extension","game","jigsaw","plugin add","puzzle","shape"]},{"name":"search","tags":["filter","find","glass","look","magnify","magnifying","search","see"]},{"name":"settings","tags":["application","change","details","gear","info","information","options","personal","service","settings"]},{"name":"notifications","tags":["active","alarm","alert","bell","chime","notifications","notify","reminder","ring","sound"]},{"name":"notifications_active","tags":["active","alarm","alert","bell","chime","notifications","notify","reminder","ring","ringing","sound"]},{"name":"info","tags":["alert","announcement","assistance","details","help","i","info","information","service","support"]},{"name":"error_outline","tags":["!","alert","attention","caution","circle","danger","error","exclamation","important","mark","notification","outline","symbol","warning"]},{"name":"warning","tags":["!","alert","attention","caution","danger","error","exclamation","important","mark","notification","symbol","triangle","warning"]},{"name":"list","tags":["file","format","index","list","menu","options"]},{"name":"download","tags":["arrow","down","download","downloads","drive","install","upload"]},{"name":"import_export","tags":["arrow","arrows","direction","down","explort","import","up"]},{"name":"share","tags":["DISABLE_IOS","android","connect","contect","disable_ios","link","media","multimedia","multiple","network","options","share","shared","sharing","social"]},{"name":"add","tags":["+","add","new symbol","plus","symbol"]},{"name":"edit","tags":["compose","create","edit","editing","input","new","pen","pencil","write","writing"]},{"name":"check","tags":["DISABLE_IOS","check","confirm","correct","disable_ios","done","enter","mark","ok","okay","select","tick","yes"]},{"name":"delete","tags":["bin","can","delete","garbage","remove","trash"]},{"name":"thermostat","tags":["climate","forecast","temperature","thermostat","weather"]},{"name":"air","tags":["air","blowing","breeze","flow","wave","weather","wind"]},{"name":"lightbulb","tags":["alert","announcement","idea","info","information","light","lightbulb"]},{"name":"home","tags":["address","app","application--house","architecture","building","components","design","estate","home","interface","layout","place","real","residence","residential","screen","shelter","site","structure","ui","unit","ux","web","website","window"]},{"name":"account_circle","tags":["account","avatar","circle","face","human","people","person","profile","thumbnail","user"]},{"name":"done","tags":["DISABLE_IOS","approve","check","complete","disable_ios","done","mark","ok","select","tick","validate","verified","yes"]},{"name":"check_circle","tags":["approve","check","circle","complete","done","mark","ok","select","tick","validate","verified","yes"]},{"name":"expand_more","tags":["arrow","arrows","chevron","collapse","direction","down","expand","expandable","list","more"]},{"name":"shopping_cart","tags":["add","bill","buy","card","cart","cash","checkout","coin","commerce","credit","currency","dollars","money","online","pay","payment","shopping"]},{"name":"email","tags":["email","envelop","letter","mail","message","send"]},{"name":"favorite","tags":["appreciate","favorite","heart","like","love","remember","save","shape"]},{"name":"description","tags":["article","data","description","doc","document","drive","file","folder","folders","notes","page","paper","sheet","slide","text","writing"]},{"name":"logout","tags":["app","application","arrow","components","design","exit","interface","leave","log","login","logout","right","screen","site","ui","ux","web","website"]},{"name":"favorite_border","tags":["border","favorite","heart","like","love","outline","remember","save","shape"]},{"name":"chevron_right","tags":["arrow","arrows","chevron","direction","right"]},{"name":"lock","tags":["lock","locked","password","privacy","private","protection","safety","secure","security"]},{"name":"location_on","tags":["destination","direction","location","maps","on","pin","place","room","stop"]},{"name":"schedule","tags":["clock","date","schedule","time"]},{"name":"local_shipping","tags":["automobile","car","cars","delivery","letter","local","mail","maps","office","package","parcel","post","postal","send","shipping","shopping","stamp","transportation","truck","vehicle"]},{"name":"language","tags":["globe","internet","language","planet","website","world","www"]},{"name":"call","tags":["call","cell","contact","device","hardware","mobile","phone","telephone"]},{"name":"file_download","tags":["arrow","arrows","down","download","downloads","drive","export","file","install","upload"]},{"name":"arrow_forward_ios","tags":["app","application","arrow","chevron","components","direction","forward","interface","ios","navigation","next","right","screen","site","ui","ux","web","website"]},{"name":"arrow_back_ios","tags":["DISABLE_IOS","app","application","arrow","back","chevron","components","direction","disable_ios","interface","ios","left","navigation","previous","screen","site","ui","ux","web","website"]},{"name":"groups","tags":["body","club","collaboration","crowd","gathering","groups","human","meeting","people","person","social","teams"]},{"name":"cancel","tags":["cancel","circle","close","exit","stop","x"]},{"name":"help_outline","tags":["?","assistance","circle","help","info","information","outline","punctuation","question mark","recent","restore","shape","support","symbol"]},{"name":"arrow_drop_down","tags":["app","application","arrow","components","direction","down","drop","interface","navigation","screen","site","ui","ux","web","website"]},{"name":"face","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"manage_accounts","tags":["accounts","change","details service-human","face","gear","manage","options","people","person","profile","settings","user"]},{"name":"place","tags":["destination","direction","location","maps","navigation","pin","place","point","stop"]},{"name":"verified","tags":["approve","badge","burst","check","complete","done","mark","ok","select","star","tick","validate","verified","yes"]},{"name":"add_circle_outline","tags":["+","add","circle","create","new","outline","plus"]},{"name":"filter_alt","tags":["alt","edit","filter","funnel","options","refine","sift"]},{"name":"thumb_up","tags":["favorite","fingers","gesture","hand","hands","like","rank","ranking","rate","rating","thumb","up"]},{"name":"event","tags":["calendar","date","day","event","mark","month","range","remember","reminder","today","week"]},{"name":"star","tags":["best","bookmark","favorite","highlight","ranking","rate","rating","save","star","toggle"]},{"name":"fingerprint","tags":["finger","fingerprint","id","identification","identity","print","reader","thumbprint","verification"]},{"name":"content_copy","tags":["content","copy","cut","doc","document","duplicate","file","multiple","past"]},{"name":"login","tags":["access","app","application","arrow","components","design","enter","in","interface","left","log","login","screen","sign","site","ui","ux","web","website"]},{"name":"add_circle","tags":["+","add","circle","create","new","plus"]},{"name":"visibility_off","tags":["disabled","enabled","eye","off","on","reveal","see","show","slash","view","visibility"]},{"name":"check_circle_outline","tags":["approve","check","circle","complete","done","finished","mark","ok","outline","select","tick","validate","verified","yes"]},{"name":"chevron_left","tags":["DISABLE_IOS","arrow","arrows","chevron","direction","disable_ios","left"]},{"name":"calendar_today","tags":["calendar","date","day","event","month","schedule","today"]},{"name":"send","tags":["email","mail","message","paper","plane","reply","right","send","share"]},{"name":"check_box","tags":["approved","box","button","check","component","control","form","mark","ok","select","selected","selection","tick","toggle","ui","yes"]},{"name":"highlight_off","tags":["cancel","close","exit","highlight","no","off","quit","remove","stop","x"]},{"name":"navigate_next","tags":["arrow","arrows","direction","navigate","next","right"]},{"name":"help","tags":["?","assistance","circle","help","info","information","punctuation","question mark","recent","restore","shape","support","symbol"]},{"name":"phone","tags":["call","cell","contact","device","hardware","mobile","phone","telephone"]},{"name":"paid","tags":["circle","currency","money","paid","payment","transaction"]},{"name":"task_alt","tags":["approve","check","circle","complete","done","mark","ok","select","task","tick","validate","verified","yes"]},{"name":"question_answer","tags":["answer","bubble","chat","comment","communicate","conversation","feedback","message","question","speech","talk"]},{"name":"expand_less","tags":["arrow","arrows","chevron","collapse","direction","expand","expandable","less","list","up"]},{"name":"clear","tags":["back","cancel","clear","correct","delete","erase","exit","x"]},{"name":"date_range","tags":["calendar","date","day","event","month","range","remember","reminder","schedule","time","today","week"]},{"name":"article","tags":["article","doc","document","file","page","paper","text","writing"]},{"name":"error","tags":["!","alert","attention","caution","circle","danger","error","exclamation","important","mark","notification","symbol","warning"]},{"name":"photo_camera","tags":["camera","image","photo","photography","picture"]},{"name":"check_box_outline_blank","tags":["blank","box","button","check","component","control","deselected","empty","form","outline","select","selection","square","tick","toggle","ui"]},{"name":"image","tags":["disabled","enabled","hide","image","landscape","mountain","mountains","off","on","photo","photography","picture","slash"]},{"name":"shopping_bag","tags":["bag","bill","business","buy","card","cart","cash","coin","commerce","credit","currency","dollars","money","online","pay","payment","shop","shopping","store","storefront"]},{"name":"person_outline","tags":["account","face","human","outline","people","person","profile","user"]},{"name":"school","tags":["academy","achievement","cap","class","college","education","graduation","hat","knowledge","learning","school","university"]},{"name":"file_upload","tags":["arrow","arrows","download","drive","export","file","up","upload"]},{"name":"perm_identity","tags":["account","avatar","face","human","identity","people","perm","person","profile","thumbnail","user"]},{"name":"credit_card","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","shopping","symbol"]},{"name":"history","tags":["arrow","back","backwards","clock","date","history","refresh","renew","reverse","rotate","schedule","time","turn"]},{"name":"trending_up","tags":["analytics","arrow","data","diagram","graph","infographic","measure","metrics","movement","rate","rating","statistics","tracking","trending","up"]},{"name":"support_agent","tags":["agent","care","customer","face","headphone","person","representative","service","support"]},{"name":"account_balance","tags":["account","balance","bank","bill","card","cash","coin","commerce","credit","currency","dollars","finance","money","online","pay","payment"]},{"name":"delete_outline","tags":["bin","can","delete","garbage","outline","remove","trash"]},{"name":"attach_money","tags":["attach","attachment","bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","symbol"]},{"name":"person_add","tags":["+","account","add","avatar","face","human","new","people","person","plus","profile","symbol","user"]},{"name":"public","tags":["earth","global","globe","map","network","planet","public","social","space","web","world"]},{"name":"save","tags":["data","disk","document","drive","file","floppy","multimedia","save","storage"]},{"name":"mail","tags":["email","envelop","letter","mail","message","send"]},{"name":"report_problem","tags":["!","alert","attention","caution","danger","error","exclamation","feedback","important","mark","notification","problem","report","symbol","triangle","warning"]},{"name":"fact_check","tags":["approve","check","complete","done","fact","list","mark","ok","select","tick","validate","verified","yes"]},{"name":"radio_button_unchecked","tags":["bullet","button","circle","deselected","form","off","on","point","radio","record","select","toggle","unchecked"]},{"name":"verified_user","tags":["approve","certified","check","complete","done","mark","ok","privacy","private","protect","protection","security","select","shield","tick","user","validate","verified","yes"]},{"name":"assignment","tags":["assignment","clipboard","doc","document","text","writing"]},{"name":"link","tags":["chain","clip","connection","link","linked","links","multimedia","url"]},{"name":"play_circle_filled","tags":["arrow","circle","control","controls","media","music","play","video"]},{"name":"emoji_events","tags":["achievement","award","chalice","champion","cup","emoji","events","first","prize","reward","sport","trophy","winner"]},{"name":"remove","tags":["can","delete","minus","negative","remove","substract","trash"]},{"name":"star_rate","tags":["achievement","bookmark","favorite","highlight","important","marked","ranking","rate","rating rank","reward","save","saved","shape","special","star"]},{"name":"apps","tags":["all","applications","apps","circles","collection","components","dots","grid","interface","squares","ui","ux"]},{"name":"business","tags":["apartment","architecture","building","business","company","estate","home","place","real","residence","residential","shelter"]},{"name":"filter_list","tags":["filter","lines","list","organize","sort"]},{"name":"arrow_right_alt","tags":["alt","arrow","arrows","direction","east","navigation","pointing","right"]},{"name":"chat","tags":["bubble","chat","comment","communicate","feedback","message","speech"]},{"name":"account_balance_wallet","tags":["account","balance","bank","bill","card","cash","coin","commerce","credit","currency","dollars","finance","money","online","pay","payment","wallet"]},{"name":"payments","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","layer","money","multiple","online","pay","payment","payments","price","shopping","symbol"]},{"name":"menu_book","tags":["book","dining","food","meal","menu","restaurant"]},{"name":"folder","tags":["data","doc","document","drive","file","folder","folders","sheet","slide","storage"]},{"name":"keyboard_arrow_down","tags":["arrow","arrows","down","keyboard"]},{"name":"autorenew","tags":["around","arrow","arrows","autorenew","cache","cached","direction","inprogress","load","loading refresh","navigation","renew","rotate","turn"]},{"name":"build","tags":["adjust","build","fix","home","nest","repair","tool","tools","wrench"]},{"name":"videocam","tags":["cam","camera","conference","film","filming","hardware","image","motion","picture","video","videography"]},{"name":"view_list","tags":["design","format","grid","layout","lines","list","stacked","view","website"]},{"name":"print","tags":["draft","fax","ink","machine","office","paper","print","printer","send"]},{"name":"work","tags":["bag","baggage","briefcase","business","case","job","suitcase","work"]},{"name":"store","tags":["bill","building","business","card","cash","coin","commerce","company","credit","currency","dollars","market","money","online","pay","payment","shop","shopping","store","storefront"]},{"name":"analytics","tags":["analytics","assessment","bar","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"radio_button_checked","tags":["app","application","bullet","button","checked","circle","components","design","form","interface","off","on","point","radio","record","screen","select","selected","site","toggle","ui","ux","web","website"]},{"name":"phone_iphone","tags":["Android","OS","cell","device","hardware","iOS","iphone","mobile","phone","tablet"]},{"name":"play_circle","tags":["arrow","circle","control","controls","media","music","play","video"]},{"name":"tune","tags":["adjust","audio","controls","custom","customize","edit","editing","filter","filters","instant","mix","music","options","setting","settings","slider","sliders","switches","tune"]},{"name":"delete_forever","tags":["bin","can","cancel","delete","exit","forever","garbage","remove","trash","x"]},{"name":"today","tags":["calendar","date","day","event","mark","month","remember","reminder","schedule","time","today"]},{"name":"grid_view","tags":["app","application square","blocks","components","dashboard","design","grid","interface","layout","screen","site","tiles","ui","ux","view","web","website","window"]},{"name":"east","tags":["arrow","directional","east","maps","navigation","right"]},{"name":"inventory_2","tags":["archive","box","file","inventory","organize","packages","product","stock","storage","supply"]},{"name":"mail_outline","tags":["email","envelop","letter","mail","message","outline","send"]},{"name":"admin_panel_settings","tags":["account","admin","avatar","certified","face","human","panel","people","person","privacy","private","profile","protect","protection","security","settings","shield","user","verified"]},{"name":"mic","tags":["hear","hearing","mic","microphone","noise","record","sound","voice"]},{"name":"calendar_month","tags":["calendar","date","day","event","month","schedule","today"]},{"name":"group","tags":["accounts","committee","face","family","friends","group","humans","network","people","persons","profiles","social","team","users"]},{"name":"picture_as_pdf","tags":["alphabet","as","character","document","file","font","image","letter","multiple","pdf","photo","photography","picture","symbol","text","type"]},{"name":"lock_open","tags":["lock","open","password","privacy","private","protection","safety","secure","security","unlocked"]},{"name":"volume_up","tags":["audio","control","music","sound","speaker","tv","up","volume"]},{"name":"watch_later","tags":["clock","date","later","schedule","time","watch"]},{"name":"grade","tags":["'favorite_news' .","'star_outline'","Duplicate of 'star_boarder'","star_border_purple500'"]},{"name":"receipt_long","tags":["bill","check","document","list","long","paper","paperwork","receipt","record","store","transaction"]},{"name":"local_offer","tags":["deal","discount","offer","price","shop","shopping","store","tag"]},{"name":"room","tags":["destination","direction","location","maps","pin","place","room","stop"]},{"name":"update","tags":["arrow","back","backwards","clock","forward","history","load","refresh","reverse","schedule","time","update"]},{"name":"badge","tags":["account","avatar","badge","card","certified","employee","face","human","identification","name","people","person","profile","security","user","work"]},{"name":"savings","tags":["bank","bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","pig","piggy","savings","symbol"]},{"name":"code","tags":["brackets","code","css","develop","developer","engineer","engineering","html","platform"]},{"name":"light_mode","tags":["bright","brightness","day","device","light","lighting","mode","morning","sky","sun","sunny"]},{"name":"receipt","tags":[]},{"name":"circle","tags":["circle","full","geometry","moon"]},{"name":"inventory","tags":["archive","box","clipboard","doc","document","file","inventory","organize","packages","product","stock","supply"]},{"name":"add_shopping_cart","tags":["add","card","cart","cash","checkout","coin","commerce","credit","currency","dollars","money","online","pay","payment","plus","shopping"]},{"name":"contact_support","tags":["?","bubble","chat","comment","communicate","contact","help","info","information","mark","message","punctuation","question","question mark","speech","support","symbol"]},{"name":"category","tags":["categories","category","circle","collection","items","product","sort","square","triangle"]},{"name":"edit_note","tags":["compose","create","draft","edit","editing","input","lines","note","pen","pencil","text","write","writing"]},{"name":"insights","tags":["ai","analytics","artificial","automatic","automation","bar","bars","chart","custom","data","diagram","genai","graph","infographic","insights","intelligence","magic","measure","metrics","smart","spark","sparkle","star","stars","statistics","tracking"]},{"name":"power_settings_new","tags":["info","information","off","on","power","save","settings","shutdown"]},{"name":"campaign","tags":["alert","announcement","campaign","loud","megaphone","microphone","notification","speaker"]},{"name":"format_list_bulleted","tags":["align","alignment","bulleted","doc","edit","editing","editor","format","list","notes","sheet","spreadsheet","text","type","writing"]},{"name":"star_border","tags":["best","bookmark","border","favorite","highlight","outline","ranking","rate","rating","save","star","toggle"]},{"name":"pause","tags":["control","controls","media","music","pause","video"]},{"name":"remove_circle_outline","tags":["block","can","circle","delete","minus","negative","outline","remove","substract","trash"]},{"name":"warning_amber","tags":["!","alert","amber","attention","caution","danger","error","exclamation","important","mark","notification","symbol","triangle","warning"]},{"name":"wifi","tags":["connection","data","internet","network","scan","service","signal","wifi","wireless"]},{"name":"arrow_back_ios_new","tags":["DISABLE_IOS","app","application","arrow","back","chevron","components","direction","disable_ios","interface","ios","left","navigation","new","previous","screen","site","ui","ux","web","website"]},{"name":"restart_alt","tags":["alt","around","arrow","inprogress","load","loading refresh","reboot","renew","repeat","reset","restart"]},{"name":"done_all","tags":["all","approve","check","complete","done","layers","mark","multiple","ok","select","stack","tick","validate","verified","yes"]},{"name":"pets","tags":["animal","cat","dog","hand","paw","pet"]},{"name":"storefront","tags":["business","buy","cafe","commerce","front","market","places","restaurant","retail","sell","shop","shopping","store","storefront"]},{"name":"sort","tags":["filter","find","lines","list","organize","sort"]},{"name":"mode_edit","tags":["compose","create","draft","draw","edit","mode","pen","pencil","write"]},{"name":"list_alt","tags":["alt","box","contained","format","lines","list","order","reorder","stacked","title"]},{"name":"toggle_on","tags":["active","app","application","components","configuration","control","design","disable","inable","inactive","interface","off","on","selection","settings","site","slider","switch","toggle","ui","ux","web","website"]},{"name":"dark_mode","tags":["app","application","dark","device","interface","mode","moon","night","silent","theme","ui","ux","website"]},{"name":"engineering","tags":["body","cogs","cogwheel","construction","engineering","fixing","gears","hat","helmet","human","maintenance","people","person","setting","worker"]},{"name":"explore","tags":["compass","destination","direction","east","explore","location","maps","needle","north","south","travel","west"]},{"name":"bolt","tags":["bolt","electric","energy","fast","flash","lightning","power","thunderbolt"]},{"name":"construction","tags":["build","carpenter","construction","equipment","fix","hammer","improvement","industrial","industry","repair","tools","wrench"]},{"name":"qr_code_scanner","tags":["barcode","camera","code","media","product","qr","quick","response","scanner","smartphone","url","urls"]},{"name":"bookmark","tags":["archive","bookmark","favorite","label","library","read","reading","remember","ribbon","save","tag"]},{"name":"vpn_key","tags":["code","key","lock","network","passcode","password","unlock","vpn"]},{"name":"monetization_on","tags":["bill","card","cash","circle","coin","commerce","cost","credit","currency","dollars","finance","monetization","money","on","online","pay","payment","shopping","symbol"]},{"name":"attach_file","tags":["add","attach","attachment","clip","file","link","mail","media"]},{"name":"timer","tags":["alarm","alert","bell","clock","disabled","duration","enabled","notification","off","on","slash","stop","time","timer","watch"]},{"name":"account_box","tags":["account","avatar","box","face","human","people","person","profile","square","thumbnail","user"]},{"name":"note_add","tags":["+","-doc","add","data","document","drive","file","folder","folders","new","note","page","paper","plus","sheet","slide","symbol","writing"]},{"name":"reorder","tags":["format","lines","list","order","reorder","stacked"]},{"name":"bookmark_border","tags":["archive","bookmark","border","favorite","label","library","read","reading","remember","ribbon","save","tag"]},{"name":"arrow_right","tags":["app","application","arrow","components","direction","interface","navigation","right","screen","site","ui","ux","web","website"]},{"name":"pending_actions","tags":["actions","clipboard","clock","date","doc","document","pending","remember","schedule","time"]},{"name":"smartphone","tags":["Android","OS","call","cell","chat","device","hardware","iOS","mobile","phone","smartphone","tablet","text"]},{"name":"upload_file","tags":["arrow","data","doc","document","download","drive","file","folder","folders","page","paper","sheet","slide","up","upload","writing"]},{"name":"account_tree","tags":["account","analytics","chart","connect","data","diagram","flow","graph","infographic","measure","metrics","process","square","statistics","structure","tracking","tree"]},{"name":"shopping_basket","tags":["add","basket","bill","buy","card","cart","cash","checkout","coin","commerce","credit","currency","dollars","money","online","pay","payment","shopping"]},{"name":"flag","tags":["country","flag","goal","mark","nation","report","start"]},{"name":"apartment","tags":["accommodation","apartment","architecture","building","city","company","estate","flat","home","house","office","places","real","residence","residential","shelter","units","workplace"]},{"name":"restaurant","tags":["breakfast","dining","dinner","eat","food","fork","knife","local","lunch","meal","places","restaurant","spoon","utensils"]},{"name":"people_alt","tags":["accounts","committee","face","family","friends","humans","network","people","persons","profiles","social","team","users"]},{"name":"reply","tags":["arrow","backward","left","mail","message","reply","send","share"]},{"name":"play_circle_outline","tags":["arrow","circle","control","controls","media","music","outline","play","video"]},{"name":"payment","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","shopping","symbol"]},{"name":"sync","tags":["360","around","arrow","arrows","direction","inprogress","load","loading refresh","renew","rotate","sync","turn"]},{"name":"task","tags":["approve","check","complete","data","doc","document","done","drive","file","folder","folders","mark","ok","page","paper","select","sheet","slide","task","tick","validate","verified","writing","yes"]},{"name":"launch","tags":["app","application","arrow","box","components","interface","launch","new","open","screen","site","ui","ux","web","website","window"]},{"name":"menu_open","tags":["app","application","arrow","components","hamburger","interface","left","line","lines","menu","open","screen","site","ui","ux","web","website"]},{"name":"add_box","tags":["add","box","new square","plus","symbol"]},{"name":"drag_indicator","tags":["app","application","circles","components","design","dots","drag","drop","indicator","interface","layout","mobile","monitor","move","phone","screen","shape","shift","site","tablet","ui","ux","web","website","window"]},{"name":"supervisor_account","tags":["account","avatar","control","face","human","parental","parental control","parents","people","person","profile","supervised","supervisor","user"]},{"name":"touch_app","tags":["app","command","fingers","gesture","hand","press","tap","touch"]},{"name":"pending","tags":["circle","dots","loading","pending","progress","wait","waiting"]},{"name":"zoom_in","tags":["big","bigger","find","glass","grow","in","look","magnify","magnifying","plus","scale","search","see","size","zoom"]},{"name":"manage_search","tags":["glass","history","magnifying","manage","search","text"]},{"name":"remove_circle","tags":["block","can","circle","delete","minus","negative","remove","substract","trash"]},{"name":"group_add","tags":["accounts","add","committee","face","family","friends","group","humans","increase","more","network","people","persons","plus","profiles","social","team","users"]},{"name":"chat_bubble_outline","tags":["bubble","chat","comment","communicate","feedback","message","outline","speech"]},{"name":"assessment","tags":["analytics","assessment","bar","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"priority_high","tags":["!","alert","attention","caution","danger","error","exclamation","high","important","mark","notification","symbol","warning"]},{"name":"push_pin","tags":["location","marker","pin","place","push","remember","save"]},{"name":"feed","tags":["article","feed","headline","information","news","newspaper","paper","public","social","timeline"]},{"name":"leaderboard","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","leaderboard","measure","metrics","statistics","tracking"]},{"name":"summarize","tags":["doc","document","list","menu","note","report","summary"]},{"name":"block","tags":["avoid","block","cancel","close","entry","exit","no","prohibited","quit","remove","stop"]},{"name":"event_available","tags":["approve","available","calendar","check","complete","date","done","event","mark","ok","schedule","select","tick","time","validate","verified","yes"]},{"name":"thumb_up_off_alt","tags":["alt","disabled","enabled","favorite","fingers","gesture","hand","hands","like","off","offline","on","rank","ranking","rate","rating","slash","thumb","up"]},{"name":"directions_car","tags":["automobile","car","cars","direction","directions","maps","public","transportation","vehicle"]},{"name":"open_in_full","tags":["action","arrow","arrows","expand","full","grow","in","move","open"]},{"name":"auto_stories","tags":["auto","book","flipping","pages","stories"]},{"name":"post_add","tags":["+","add","data","doc","document","drive","file","folder","folders","page","paper","plus","post","sheet","slide","text","writing"]},{"name":"calculate","tags":["+","-","=","calculate","count","finance calculator","math"]},{"name":"alternate_email","tags":["@","address","alternate","contact","email","tag"]},{"name":"create","tags":["compose","create","edit","editing","input","new","pen","pencil","write","writing"]},{"name":"cloud_upload","tags":["app","application","arrow","backup","cloud","connection","download","drive","files","folders","internet","network","sky","storage","up","upload"]},{"name":"local_fire_department","tags":["911","climate","department","fire","firefighter","flame","heat","home","hot","nest","thermostat"]},{"name":"bar_chart","tags":["analytics","bar","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"password","tags":["key","login","password","pin","security","star","unlock"]},{"name":"collections","tags":["album","collections","gallery","image","landscape","library","mountain","mountains","photo","photography","picture","stack"]},{"name":"preview","tags":["design","eye","layout","preview","reveal","screen","see","show","site","view","web","website","window","www"]},{"name":"star_outline","tags":["bookmark","favorite","half","highlight","ranking","rate","rating","save","star","toggle"]},{"name":"exit_to_app","tags":["app","application","arrow","components","design","exit","export","interface","layout","leave","mobile","monitor","move","output","phone","screen","site","tablet","to","ui","ux","web","website","window"]},{"name":"done_outline","tags":["all","approve","check","complete","done","mark","ok","outline","select","tick","validate","verified","yes"]},{"name":"psychology","tags":["behavior","body","brain","cognitive","function","gear","head","human","intellectual","mental","mind","people","person","preferences","psychiatric","psychology","science","settings","social","therapy","thinking","thoughts"]},{"name":"assignment_ind","tags":["account","assignment","clipboard","doc","document","face","ind","people","person","profile","user"]},{"name":"volunteer_activism","tags":["activism","donation","fingers","gesture","giving","hand","hands","heart","love","sharing","volunteer"]},{"name":"navigate_before","tags":["arrow","arrows","before","direction","left","navigate"]},{"name":"published_with_changes","tags":["approve","arrow","arrows","changes","check","complete","done","inprogress","load","loading","mark","ok","published","refresh","renew","replace","rotate","select","tick","validate","verified","with","yes"]},{"name":"add_a_photo","tags":["+","a photo","add","camera","lens","new","photography","picture","plus","symbol"]},{"name":"auto_awesome","tags":["adjust","ai","artificial","automatic","automation","custom","edit","editing","enhance","genai","intelligence","magic","smart","spark","sparkle","star","stars"]},{"name":"card_giftcard","tags":["account","balance","bill","card","cart","cash","certificate","coin","commerce","credit","currency","dollars","gift","giftcard","money","online","pay","payment","present","shopping"]},{"name":"fullscreen","tags":["adjust","app","application","components","full","fullscreen","interface","screen","site","size","ui","ux","view","web","website"]},{"name":"sell","tags":["bill","card","cart","cash","coin","commerce","credit","currency","dollars","money","online","pay","payment","price","sell","shopping","tag"]},{"name":"checklist","tags":["align","alignment","approve","check","checklist","complete","doc","done","edit","editing","editor","format","list","mark","notes","ok","select","sheet","spreadsheet","text","tick","type","validate","verified","writing","yes"]},{"name":"view_in_ar","tags":["3d","ar","augmented","cube","daydream","headset","in","reality","square","view","vr"]},{"name":"undo","tags":["arrow","backward","mail","previous","redo","repeat","rotate","undo"]},{"name":"arrow_drop_up","tags":["app","application","arrow","components","direction","drop","interface","navigation","screen","site","ui","up","ux","web","website"]},{"name":"feedback","tags":["!","alert","announcement","attention","bubble","caution","chat","comment","communicate","danger","error","exclamation","feedback","important","mark","message","notification","speech","symbol","warning"]},{"name":"health_and_safety","tags":["+","add","and","certified","cross","health","home","nest","plus","privacy","private","protect","protection","safety","security","shield","symbol","verified"]},{"name":"work_outline","tags":["bag","baggage","briefcase","business","case","job","suitcase","work"]},{"name":"unfold_more","tags":["arrow","arrows","chevron","collapse","direction","down","expand","expandable","list","more","navigation","unfold"]},{"name":"travel_explore","tags":["earth","explore","find","glass","global","globe","look","magnify","magnifying","map","network","planet","search","see","social","space","travel","web","world"]},{"name":"palette","tags":["art","color","colors","filters","paint","palette"]},{"name":"keyboard_arrow_right","tags":["arrow","arrows","keyboard","right"]},{"name":"double_arrow","tags":["arrow","arrows","direction","double","multiple","navigation","right"]},{"name":"computer","tags":["Android","OS","chrome","computer","desktop","device","hardware","iOS","mac","monitor","web","window"]},{"name":"timeline","tags":["data","history","line","movement","point","points","timeline","tracking","trending","zigzag"]},{"name":"thumb_up_alt","tags":["agreed","approved","confirm","correct","favorite","feedback","good","happy","like","okay","positive","satisfaction","social","thumb","up","vote","yes"]},{"name":"signal_cellular_alt","tags":["alt","analytics","bar","cell","cellular","chart","data","diagram","graph","infographic","internet","measure","metrics","mobile","network","phone","signal","statistics","tracking","wifi","wireless"]},{"name":"replay","tags":["arrow","arrows","control","controls","music","refresh","renew","repeat","replay","video"]},{"name":"swap_horiz","tags":["arrow","arrows","back","forward","horizontal","swap"]},{"name":"volume_off","tags":["audio","control","disabled","enabled","low","music","off","on","slash","sound","speaker","tv","volume"]},{"name":"forum","tags":["bubble","chat","comment","communicate","community","conversation","feedback","forum","hub","message","speech"]},{"name":"skip_next","tags":["arrow","control","controls","music","next","play","previous","skip","video"]},{"name":"water_drop","tags":["drink","drop","droplet","eco","liquid","nature","ocean","rain","social","water"]},{"name":"assignment_turned_in","tags":["approve","assignment","check","clipboard","complete","doc","document","done","in","mark","ok","select","tick","turn","validate","verified","yes"]},{"name":"library_books","tags":["add","album","audio","book","books","collection","library","read","reading"]},{"name":"maps_home_work","tags":["building","home","house","maps","office","work"]},{"name":"dns","tags":["address","bars","dns","domain","information","ip","list","lookup","name","server","system"]},{"name":"sync_alt","tags":["alt","arrow","arrows","horizontal","internet","sync","technology","up","update","wifi"]},{"name":"how_to_reg","tags":["approve","ballot","check","complete","done","election","how","mark","ok","poll","register","registration","select","tick","to reg","validate","verified","vote","yes"]},{"name":"notifications_none","tags":["alarm","alert","bell","none","notifications","notify","reminder","sound"]},{"name":"stars","tags":["achievement","bookmark","circle","favorite","highlight","important","marked","ranking","rate","rating rank","reward","save","saved","shape","special","star"]},{"name":"flight_takeoff","tags":["airport","departed","departing","flight","fly","landing","plane","takeoff","transportation","travel"]},{"name":"label","tags":["favorite","indent","label","library","mail","remember","save","stamp","sticker","tag"]},{"name":"devices","tags":["Android","OS","computer","desktop","device","hardware","iOS","laptop","mobile","monitor","phone","tablet","watch","wearable","web"]},{"name":"chat_bubble","tags":["bubble","chat","comment","communicate","feedback","message","speech"]},{"name":"emoji_emotions","tags":["+","add","emoji","emotions","expressions","face","feelings","glad","happiness","happy","icon","icons","insert","like","mood","new","person","pleased","plus","smile","smiling","social","survey","symbol"]},{"name":"remove_red_eye","tags":["eye","iris","look","looking","preview","red","remove","see","sight","vision"]},{"name":"content_paste","tags":["clipboard","content","copy","cut","doc","document","file","multiple","past"]},{"name":"folder_open","tags":["data","doc","document","drive","file","folder","folders","open","sheet","slide","storage"]},{"name":"text_snippet","tags":["data","doc","document","file","note","notes","snippet","storage","text","writing"]},{"name":"tips_and_updates","tags":["ai","alert","and","announcement","artificial","automatic","automation","custom","electricity","genai","idea","info","information","intelligence","light","lightbulb","magic","smart","spark","sparkle","star","tips","updates"]},{"name":"my_location","tags":["destination","direction","location","maps","navigation","pin","place","point","stop"]},{"name":"textsms","tags":["bubble","chat","comment","communicate","dots","feedback","message","speech","textsms"]},{"name":"cloud","tags":["cloud","connection","internet","network","sky","upload"]},{"name":"sports_esports","tags":["controller","entertainment","esports","game","gamepad","gaming","hobby","online","social","sports","video"]},{"name":"security","tags":["certified","privacy","private","protect","protection","security","shield","verified"]},{"name":"request_quote","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","quote","request","shopping","symbol"]},{"name":"toggle_off","tags":["active","app","application","components","configuration","control","design","disable","inable","inactive","interface","off","on","selection","settings","site","slider","switch","toggle","ui","ux","web","website"]},{"name":"book","tags":["book","bookmark","favorite","label","library","read","reading","remember","ribbon","save","tag"]},{"name":"contact_page","tags":["account","avatar","contact","data","doc","document","drive","face","file","folder","folders","human","page","people","person","profile","sheet","slide","storage","user","writing"]},{"name":"speed","tags":["arrow","control","controls","fast","gauge","meter","motion","music","slow","speed","speedometer","velocity","video"]},{"name":"bug_report","tags":["animal","bug","fix","insect","issue","problem","report","testing","virus","warning"]},{"name":"space_dashboard","tags":["cards","dashboard","format","grid","layout","rectangle","shapes","space","squares","web","website"]},{"name":"fiber_manual_record","tags":["circle","dot","fiber","manual","play","record","watch"]},{"name":"report","tags":["!","alert","attention","caution","danger","error","exclamation","important","mark","notification","octagon","report","symbol","warning"]},{"name":"alarm","tags":["alarm","alert","bell","clock","countdown","date","notification","schedule","time"]},{"name":"cached","tags":["around","arrows","cache","cached","inprogress","load","loading refresh","renew","rotate"]},{"name":"translate","tags":["language","speaking","speech","translate","translator","words"]},{"name":"pan_tool","tags":["fingers","gesture","hand","hands","human","move","pan","scan","stop","tool"]},{"name":"gavel","tags":["agreement","contract","court","document","gavel","government","judge","law","mallet","official","police","rule","rules","terms"]},{"name":"settings_suggest","tags":["ai","artificial","automatic","automation","change","custom","details","gear","genai","intelligence","magic","options","recommendation","service","settings","smart","spark","sparkle","star","suggest","suggestion","system"]},{"name":"file_copy","tags":["content","copy","cut","doc","document","duplicate","file","multiple","past"]},{"name":"edit_calendar","tags":["calendar","compose","create","date","day","draft","edit","editing","event","month","pen","pencil","schedule","write","writing"]},{"name":"contact_mail","tags":["account","address","avatar","communicate","contact","email","face","human","info","information","mail","message","people","person","profile","user"]},{"name":"quiz","tags":["?","assistance","faq","help","info","information","punctuation","question mark","quiz","support","symbol","test"]},{"name":"supervised_user_circle","tags":["account","avatar","circle","control","face","human","parental","parents","people","person","profile","supervised","supervisor","user"]},{"name":"cloud_download","tags":["app","application","arrow","backup","cloud","connection","down","download","drive","files","folders","internet","network","sky","storage","upload"]},{"name":"stop","tags":["control","controls","music","pause","play","square","stop","video"]},{"name":"person_search","tags":["account","avatar","face","find","glass","human","look","magnify","magnifying","people","person","profile","search","user"]},{"name":"location_city","tags":["apartments","architecture","buildings","business","city","estate","home","landscape","location","place","real","residence","residential","shelter","town","urban"]},{"name":"sentiment_very_satisfied","tags":["emotions","expressions","face","feelings","glad","happiness","happy","like","mood","person","pleased","satisfied","sentiment","smile","smiling","survey","very"]},{"name":"ios_share","tags":["arrow","export","ios","send","share","up"]},{"name":"minimize","tags":["app","application","components","design","interface","line","minimize","screen","shape","site","ui","ux","web","website"]},{"name":"qr_code","tags":["barcode","camera","code","media","product","qr","quick","response","smartphone","url","urls"]},{"name":"sentiment_satisfied_alt","tags":["account","alt","emoji","face","happy","human","people","person","profile","satisfied","sentiment","smile","user"]},{"name":"local_mall","tags":["bag","bill","building","business","buy","card","cart","cash","coin","commerce","credit","currency","dollars","handbag","local","mall","money","online","pay","payment","shop","shopping","store","storefront"]},{"name":"qr_code_2","tags":["barcode","camera","code","media","product","qr","quick","response","smartphone","url","urls"]},{"name":"flight","tags":["air","airplane","airport","flight","plane","transportation","travel","trip"]},{"name":"desktop_windows","tags":["Android","OS","chrome","desktop","device","display","hardware","iOS","mac","monitor","screen","television","tv","web","window","windows"]},{"name":"music_note","tags":["audio","audiotrack","key","music","note","sound","track"]},{"name":"sentiment_satisfied","tags":["emotions","expressions","face","feelings","glad","happiness","happy","like","mood","person","pleased","satisfied","sentiment","smile","smiling","survey"]},{"name":"android","tags":["android","character","logo","mascot","toy"]},{"name":"accessibility","tags":["accessibility","accessible","body","handicap","help","human","people","person"]},{"name":"backspace","tags":["arrow","back","backspace","cancel","clear","correct","delete","erase","remove"]},{"name":"precision_manufacturing","tags":["arm","automatic","chain","conveyor","crane","factory","industry","machinery","manufacturing","mechanical","precision","production","repairing","robot","supply","warehouse"]},{"name":"drag_handle","tags":["app","application ui","components","design","drag","handle","interface","layout","menu","move","screen","site","ui","ux","web","website","window"]},{"name":"smart_display","tags":["airplay","cast","chrome","connect","device","display","play","screen","screencast","smart","stream","television","tv","video","wireless"]},{"name":"near_me","tags":["destination","direction","location","maps","me","navigation","near","pin","place","point","stop"]},{"name":"west","tags":["arrow","directional","left","maps","navigation","west"]},{"name":"get_app","tags":["app","arrow","arrows","down","download","downloads","export","get","install","play","upload"]},{"name":"person_add_alt","tags":["+","account","add","face","human","people","person","plus","profile","user"]},{"name":"fitness_center","tags":["athlete","center","dumbbell","exercise","fitness","gym","hobby","places","sport","weights","workout"]},{"name":"shield","tags":["certified","privacy","private","protect","protection","security","shield","verified"]},{"name":"message","tags":["bubble","chat","comment","communicate","feedback","message","speech"]},{"name":"rocket_launch","tags":["launch","rocket","space","spaceship","takeoff"]},{"name":"record_voice_over","tags":["account","face","human","over","people","person","profile","record","recording","speak","speaking","speech","transcript","user","voice"]},{"name":"add_task","tags":["+","add","approve","check","circle","completed","increase","mark","ok","plus","select","task","tick","yes"]},{"name":"drive_file_rename_outline","tags":["compose","create","draft","drive","edit","editing","file","input","marker","pen","pencil","rename","write","writing"]},{"name":"insert_drive_file","tags":["doc","drive","file","format","insert","sheet","slide"]},{"name":"question_mark","tags":["?","assistance","help","info","information","punctuation","question mark","support","symbol"]},{"name":"trending_flat","tags":["arrow","change","data","flat","metric","movement","rate","right","track","tracking","trending"]},{"name":"handyman","tags":["build","construction","fix","hammer","handyman","repair","screw","screwdriver","tools"]},{"name":"emoji_objects","tags":["bulb","creative","emoji","idea","light","objects","solution","thinking"]},{"name":"military_tech","tags":["army","award","badge","honor","medal","merit","military","order","privilege","prize","rank","reward","ribbon","soldier","star","status","tech","trophy","win","winner"]},{"name":"hourglass_empty","tags":["countdown","empty","hourglass","loading","minutes","time","wait","waiting"]},{"name":"help_center","tags":["?","assistance","center","help","info","information","punctuation","question mark","recent","restore","support","symbol"]},{"name":"science","tags":["beaker","chemical","chemistry","experiment","flask","glass","laboratory","research","science","tube"]},{"name":"storage","tags":["computer","data","drive","memory","storage"]},{"name":"movie","tags":["cinema","film","media","movie","slate","video"]},{"name":"accessibility_new","tags":["accessibility","accessible","body","handicap","help","human","new","people","person"]},{"name":"workspace_premium","tags":["certification","degree","ecommerce","guarantee","medal","permit","premium","ribbon","verification","workspace"]},{"name":"directions_run","tags":["body","directions","human","jogging","maps","people","person","route","run","running","walk"]},{"name":"rule","tags":["approve","check","complete","done","incomplete","line","mark","missing","no","ok","rule","select","tick","validate","verified","wrong","x","yes"]},{"name":"thumb_down","tags":["ate","dislike","down","favorite","fingers","gesture","hand","hands","like","rank","ranking","rating","thumb"]},{"name":"event_note","tags":["calendar","date","event","note","schedule","text","time","writing"]},{"name":"contacts","tags":["account","avatar","call","cell","contacts","face","human","info","information","mobile","people","person","phone","profile","user"]},{"name":"comment","tags":["bubble","chat","comment","communicate","feedback","message","outline","speech"]},{"name":"restaurant_menu","tags":["book","dining","eat","food","fork","knife","local","meal","menu","restaurant","spoon"]},{"name":"add_photo_alternate","tags":["+","add","alternate","image","landscape","mountain","mountains","new","photo","photography","picture","plus","symbol"]},{"name":"confirmation_number","tags":["admission","confirmation","entertainment","event","number","ticket"]},{"name":"sticky_note_2","tags":["2","bookmark","mark","message","note","paper","sticky","text","writing"]},{"name":"format_quote","tags":["doc","edit","editing","editor","format","quotation","quote","sheet","spreadsheet","text","type","writing"]},{"name":"history_edu","tags":["document","edu","education","feather","history","letter","paper","pen","quill","school","story","tools","write","writing"]},{"name":"business_center","tags":["bag","baggage","briefcase","business","case","center","places","purse","suitcase","work"]},{"name":"upload","tags":["arrow","arrows","download","drive","up","upload"]},{"name":"skip_previous","tags":["arrow","control","controls","music","next","play","previous","skip","video"]},{"name":"archive","tags":["archive","inbox","mail","store"]},{"name":"wb_sunny","tags":["balance","bright","light","lighting","sun","sunny","wb","white"]},{"name":"cake","tags":["add","baked","birthday","cake","candles","celebration","dessert","food","frosting","new","party","pastries","pastry","plus","social","sweet","symbol"]},{"name":"attachment","tags":["attach","attachment","clip","compose","file","image","link"]},{"name":"source","tags":["code","composer","content","creation","data","doc","document","file","folder","mode","source","storage","view"]},{"name":"settings_applications","tags":["application","change","details","gear","info","information","options","personal","service","settings"]},{"name":"dashboard_customize","tags":["cards","customize","dashboard","format","layout","rectangle","shapes","square","web","website"]},{"name":"find_in_page","tags":["data","doc","document","drive","file","find","folder","folders","glass","in","look","magnify","magnifying","page","paper","search","see","sheet","slide","writing"]},{"name":"support","tags":["assist","buoy","help","life","lifebuoy","rescue","safe","safety","support"]},{"name":"ads_click","tags":["ads","browser","click","clicks","cursor","internet","target","traffic","web"]},{"name":"new_releases","tags":["approve","award","check","checkmark","complete","done","new","notification","ok","release","releases","select","star","symbol","tick","verification","verified","warning","yes"]},{"name":"flutter_dash","tags":["bird","dash","flutter","mascot"]},{"name":"playlist_add","tags":["+","add","collection","list","music","new","playlist","plus","symbol"]},{"name":"save_alt","tags":["alt","arrow","disk","document","down","file","floppy","multimedia","save"]},{"name":"close_fullscreen","tags":["action","arrow","arrows","close","collapse","direction","full","fullscreen","minimize","screen"]},{"name":"credit_score","tags":["approve","bill","card","cash","check","coin","commerce","complete","cost","credit","currency","dollars","done","finance","loan","mark","money","ok","online","pay","payment","score","select","symbol","tick","validate","verified","yes"]},{"name":"layers","tags":["arrange","disabled","enabled","interaction","layers","maps","off","on","overlay","pages","slash"]},{"name":"redeem","tags":["bill","card","cart","cash","certificate","coin","commerce","credit","currency","dollars","gift","giftcard","money","online","pay","payment","present","redeem","shopping"]},{"name":"spa","tags":["aromatherapy","flower","healthcare","leaf","massage","meditation","nature","petals","places","relax","spa","wellbeing","wellness"]},{"name":"announcement","tags":["!","alert","announcement","attention","bubble","caution","chat","comment","communicate","danger","error","exclamation","feedback","important","mark","message","notification","speech","symbol","warning"]},{"name":"keyboard_backspace","tags":["arrow","back","backspace","keyboard","left"]},{"name":"loyalty","tags":["benefits","card","credit","heart","loyalty","membership","miles","points","program","subscription","tag","travel","trip"]},{"name":"swap_vert","tags":["arrow","arrows","direction","down","navigation","swap","up","vert","vertical"]},{"name":"sentiment_dissatisfied","tags":["angry","disappointed","dislike","dissatisfied","emotions","expressions","face","feelings","frown","mood","person","sad","sentiment","survey","unhappy","unsatisfied","upset"]},{"name":"medical_services","tags":["aid","bag","briefcase","emergency","first","kit","medical","medicine","services"]},{"name":"view_headline","tags":["design","format","grid","headline","layout","paragraph","text","view","website"]},{"name":"arrow_circle_right","tags":["arrow","circle","direction","navigation","right"]},{"name":"format_list_numbered","tags":["align","alignment","digit","doc","edit","editing","editor","format","list","notes","number","numbered","sheet","spreadsheet","symbol","text","type","writing"]},{"name":"phone_android","tags":["OS","android","cell","device","hardware","iOS","mobile","phone","tablet"]},{"name":"sms","tags":["3","bubble","chat","communication","conversation","dots","message","more","service","sms","speech","three"]},{"name":"restore","tags":["arrow","back","backwards","clock","date","history","refresh","renew","restore","reverse","rotate","schedule","time","turn"]},{"name":"policy","tags":["certified","find","glass","legal","look","magnify","magnifying","policy","privacy","private","protect","protection","search","security","see","shield","verified"]},{"name":"dangerous","tags":["broken","danger","dangerous","fix","no","sign","stop","update","warning","wrong","x"]},{"name":"battery_full","tags":["battery","cell","charge","full","mobile","power"]},{"name":"euro_symbol","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","euro","finance","money","online","pay","payment","symbol"]},{"name":"query_stats","tags":["analytics","chart","data","diagram","find","glass","graph","infographic","line","look","magnify","magnifying","measure","metrics","query","search","see","statistics","stats","tracking"]},{"name":"group_work","tags":["alliance","collaboration","group","partnership","team","teamwork","together","work"]},{"name":"expand_circle_down","tags":["arrow","arrows","chevron","circle","collapse","direction","down","expand","expandable","list","more"]},{"name":"sensors","tags":["connection","network","scan","sensors","signal","wireless"]},{"name":"keyboard_arrow_up","tags":["arrow","arrows","keyboard","up"]},{"name":"brush","tags":["art","brush","design","draw","edit","editing","paint","painting","tool"]},{"name":"meeting_room","tags":["building","door","doorway","entrance","home","house","interior","meeting","office","open","places","room"]},{"name":"key","tags":["key","lock","password","unlock"]},{"name":"house","tags":["architecture","building","estate","family","home","homepage","house","place","places","real","residence","residential","shelter"]},{"name":"lunch_dining","tags":["breakfast","dining","dinner","drink","fastfood","food","hamburger","lunch","meal"]},{"name":"table_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic grid","measure","metrics","statistics","table","tracking"]},{"name":"border_color","tags":["all","border","doc","edit","editing","editor","pen","pencil","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"compare_arrows","tags":["arrow","arrows","collide","compare","direction","left","pressure","push","right","together"]},{"name":"south","tags":["arrow","directional","down","maps","navigation","south"]},{"name":"directions_walk","tags":["body","direction","directions","human","jogging","maps","people","person","route","run","walk"]},{"name":"arrow_left","tags":["app","application","arrow","components","direction","interface","left","navigation","screen","site","ui","ux","web","website"]},{"name":"tag","tags":["hash","hashtag","key","media","number","pound","social","tag","trend"]},{"name":"change_circle","tags":["around","arrows","change","circle","direction","navigation","rotate"]},{"name":"subject","tags":["alignment","doc","document","email","full","justify","list","note","subject","text","writing"]},{"name":"sentiment_very_dissatisfied","tags":["angry","disappointed","dislike","dissatisfied","emotions","expressions","face","feelings","mood","person","sad","sentiment","sorrow","survey","unhappy","unsatisfied","upset","very"]},{"name":"local_hospital","tags":["911","aid","cross","emergency","first","hospital","local","medicine"]},{"name":"table_view","tags":["format","grid","group","layout","multiple","table","view"]},{"name":"disabled_by_default","tags":["box","by","cancel","close","default","disabled","exit","no","quit","remove","square","stop","x"]},{"name":"notification_important","tags":["!","active","alarm","alert","attention","bell","caution","chime","danger","error","exclamation","important","mark","notification","notifications","notify","reminder","ring","sound","symbol","warning"]},{"name":"celebration","tags":["activity","birthday","celebration","event","fun","party"]},{"name":"laptop","tags":["Android","OS","chrome","computer","desktop","device","hardware","iOS","laptop","mac","monitor","web","windows"]},{"name":"loop","tags":["around","arrow","arrows","direction","inprogress","load","loading refresh","loop","music","navigation","renew","rotate","turn"]},{"name":"nightlight_round","tags":["dark","half","light","mode","moon","night","nightlight","round"]},{"name":"privacy_tip","tags":["alert","announcement","assistance","certified","details","help","i","info","information","privacy","private","protect","protection","security","service","shield","support","tip","verified"]},{"name":"import_contacts","tags":["address","book","contacts","import","info","information","open"]},{"name":"equalizer","tags":["adjustment","analytics","chart","data","equalizer","graph","measure","metrics","music","noise","sound","static","statistics","tracking","volume"]},{"name":"app_registration","tags":["app","apps","edit","pencil","register","registration"]},{"name":"keyboard_double_arrow_right","tags":["arrow","arrows","direction","double","multiple","navigation","right"]},{"name":"handshake","tags":["agreement","hand","hands","partnership","shake"]},{"name":"corporate_fare","tags":["architecture","building","business","corporate","estate","fare","organization","place","real","residence","residential","shelter"]},{"name":"local_library","tags":["book","community learning","library","local","read"]},{"name":"https","tags":["https","lock","locked","password","privacy","private","protection","safety","secure","security"]},{"name":"euro","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","euro","euros","finance","money","online","pay","payment","price","shopping","symbol"]},{"name":"coronavirus","tags":["19","bacteria","coronavirus","covid","disease","germs","illness","sick","social"]},{"name":"price_check","tags":["approve","bill","card","cash","check","coin","commerce","complete","cost","credit","currency","dollars","done","finance","mark","money","ok","online","pay","payment","price","select","shopping","symbol","tick","validate","verified","yes"]},{"name":"live_tv","tags":["Android","OS","antennas hardware","chrome","desktop","device","iOS","live","mac","monitor","movie","play","stream","television","tv","web","window"]},{"name":"park","tags":["attraction","fresh","local","nature","outside","park","plant","tree"]},{"name":"toc","tags":["content","format","lines","list","order","reorder","stacked","table","title","titles","toc"]},{"name":"track_changes","tags":["bullseye","changes","circle","evolve","lines","movement","rotate","shift","target","track"]},{"name":"arrow_circle_up","tags":["arrow","circle","direction","navigation","up"]},{"name":"emoji_people","tags":["arm","body","emoji","greeting","human","people","person","social","waving"]},{"name":"flash_on","tags":["bolt","disabled","electric","enabled","fast","flash","lightning","off","on","slash","thunderbolt"]},{"name":"copyright","tags":["alphabet","c","character","copyright","emblem","font","legal","letter","owner","symbol","text"]},{"name":"bookmarks","tags":["bookmark","bookmarks","favorite","label","layers","library","multiple","read","reading","remember","ribbon","save","stack","tag"]},{"name":"ac_unit","tags":["ac","air","cold","conditioner","flake","snow","temperature","unit","weather","winter"]},{"name":"contact_phone","tags":["account","avatar","call","communicate","contact","face","human","info","information","message","mobile","people","person","phone","profile","user"]},{"name":"keyboard_arrow_left","tags":["arrow","arrows","keyboard","left"]},{"name":"medication","tags":["doctor","drug","emergency","hospital","medication","medicine","pharmacy","pills","prescription"]},{"name":"grading","tags":["'favorite'_new'. ' Remove this icon & keep 'star'.","'star_boarder'","'star_border_purple500'","'star_outline'","'star_purple500'","'star_rate'","Same as 'star'"]},{"name":"keyboard_return","tags":["arrow","back","keyboard","left","return"]},{"name":"api","tags":["api","developer","development","enterprise","software"]},{"name":"smart_toy","tags":["bot","droid","games","robot","smart","toy"]},{"name":"input","tags":["arrow","box","download","input","login","move","right"]},{"name":"self_improvement","tags":["body","calm","care","chi","human","improvement","meditate","meditation","people","person","relax","self","sitting","wellbeing","yoga","zen"]},{"name":"live_help","tags":["?","assistance","bubble","chat","comment","communicate","help","info","information","live","message","punctuation","question mark","recent","restore","speech","support","symbol"]},{"name":"query_builder","tags":["builder","clock","date","query","schedule","time"]},{"name":"perm_media","tags":["collection","data","doc","document","file","folder","folders","image","landscape","media","mountain","mountains","perm","photo","photography","picture","storage"]},{"name":"download_for_offline","tags":["arrow","circle","down","download","for offline","install","upload"]},{"name":"view_module","tags":["design","format","grid","layout","module","square","squares","stacked","view","website"]},{"name":"pin","tags":["1","2","3","digit","key","login","logout","number","password","pattern","pin","security","star","symbol","unlock"]},{"name":"fast_forward","tags":["control","fast","forward","media","music","play","speed","time","tv","video"]},{"name":"forward_to_inbox","tags":["arrow","arrows","directions","email","envelop","forward","inbox","letter","mail","message","navigation","outgoing","right","send","to"]},{"name":"person_remove","tags":["account","avatar","delete","face","human","minus","people","person","profile","remove","unfriend","user"]},{"name":"local_atm","tags":["atm","bill","card","cart","cash","coin","commerce","credit","currency","dollars","local","money","online","pay","payment","shopping","symbol"]},{"name":"star_half","tags":["achievement","bookmark","favorite","half","highlight","important","marked","ranking","rate","rating rank","reward","save","saved","shape","special","star","toggle"]},{"name":"build_circle","tags":["adjust","build","circle","fix","repair","tool","wrench"]},{"name":"redo","tags":["arrow","backward","forward","next","redo","repeat","rotate","undo"]},{"name":"web","tags":["browser","internet","page","screen","site","web","website","www"]},{"name":"north_east","tags":["arrow","east","maps","navigation","noth","right","up"]},{"name":"north","tags":["arrow","directional","maps","navigation","north","up"]},{"name":"cottage","tags":["architecture","beach","cottage","estate","home","house","lake","lodge","maps","place","real","residence","residential","stay","traveling"]},{"name":"local_activity","tags":["activity","event","event ticket","local","star","things","ticket"]},{"name":"currency_exchange","tags":["360","around","arrow","arrows","cash","coin","commerce","currency","direction","dollars","exchange","inprogress","money","pay","renew","rotate","sync","turn","universal"]},{"name":"video_library","tags":["arrow","collection","library","play","video"]},{"name":"hourglass_bottom","tags":["bottom","countdown","half","hourglass","loading","minute","minutes","time","wait","waiting"]},{"name":"headphones","tags":["accessory","audio","device","ear","earphone","headphones","headset","listen","music","sound"]},{"name":"zoom_out","tags":["find","glass","look","magnify","magnifying","minus","negative","out","scale","search","see","size","small","smaller","zoom"]},{"name":"poll","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","poll","statistics","survey","tracking","vote"]},{"name":"perm_contact_calendar","tags":["account","calendar","contact","date","face","human","information","people","perm","person","profile","schedule","time","user"]},{"name":"forward","tags":["arrow","forward","mail","message","playback","right","sent"]},{"name":"person_pin","tags":["account","avatar","destination","direction","face","human","location","maps","people","person","pin","place","profile","stop","user"]},{"name":"home_work","tags":["architecture","building","estate","home","place","real","residence","residential","shelter","work"]},{"name":"playlist_add_check","tags":["add","approve","check","collection","complete","done","list","mark","music","ok","playlist","select","tick","validate","verified","yes"]},{"name":"local_cafe","tags":["bottle","cafe","coffee","cup","drink","food","restaurant","tea"]},{"name":"ondemand_video","tags":["Android","OS","chrome","demand","desktop","device","hardware","iOS","mac","monitor","ondemand","play","television","tv","video","web","window"]},{"name":"design_services","tags":["compose","create","design","draft","edit","editing","input","pen","pencil","ruler","service","write","writing"]},{"name":"looks_one","tags":["1","digit","looks","numbers","square","symbol"]},{"name":"backup","tags":["arrow","backup","cloud","data","drive","files folders","storage","up","upload"]},{"name":"newspaper","tags":["article","data","doc","document","drive","file","folder","folders","magazine","media","news","newspaper","notes","page","paper","sheet","slide","text","writing"]},{"name":"memory","tags":["card","chip","digital","memory","micro","processor","sd","storage"]},{"name":"open_with","tags":["arrow","arrows","direction","expand","move","open","pan","with"]},{"name":"content_cut","tags":["content","copy","cut","doc","document","file","past","scissors","trim"]},{"name":"keyboard","tags":["computer","device","hardware","input","keyboard","keypad","letter","office","text","type"]},{"name":"hourglass_top","tags":["countdown","half","hourglass","loading","minute","minutes","time","top","wait","waiting"]},{"name":"settings_phone","tags":["call","cell","contact","device","hardware","mobile","phone","settings","telephone"]},{"name":"rss_feed","tags":["application","blog","connection","data","feed","internet","network","rss","service","signal","website","wifi","wireless"]},{"name":"first_page","tags":["arrow","back","chevron","first","left","page","rewind"]},{"name":"delivery_dining","tags":["delivery","dining","food","meal","restaurant","scooter","takeout","transportation","vehicle","vespa"]},{"name":"rate_review","tags":["comment","feedback","pen","pencil","rate","review","stars","write"]},{"name":"control_point","tags":["+","add","circle","control","plus","point"]},{"name":"gpp_good","tags":["certified","check","good","gpp","ok","pass","security","shield","sim","tick"]},{"name":"circle_notifications","tags":["active","alarm","alert","bell","chime","circle","notifications","notify","reminder","ring","sound"]},{"name":"auto_fix_high","tags":["adjust","ai","artificial","auto","automatic","automation","custom","edit","editing","enhance","erase","fix","genai","high","intelligence","magic","modify","pen","smart","spark","sparkle","star","tool","wand"]},{"name":"book_online","tags":["Android","OS","admission","appointment","book","cell","device","event","hardware","iOS","mobile","online","pass","phone","reservation","tablet","ticket"]},{"name":"notes","tags":["comment","doc","document","note","notes","text","write","writing"]},{"name":"point_of_sale","tags":["checkout","cost","machine","merchant","money","of","pay","payment","point","pos","retail","sale","system","transaction"]},{"name":"perm_phone_msg","tags":["bubble","call","cell","chat","comment","communicate","contact","device","message","msg","perm","phone","recording","speech","telephone","voice"]},{"name":"speaker_notes","tags":["bubble","chat","comment","communicate","format","list","message","notes","speaker","speech","text"]},{"name":"fullscreen_exit","tags":["adjust","app","application","components","exit","full","fullscreen","interface","screen","site","size","ui","ux","view","web","website"]},{"name":"headset_mic","tags":["accessory","audio","chat","device","ear","earphone","headphones","headset","listen","mic","music","sound","talk"]},{"name":"create_new_folder","tags":["+","add","create","data","doc","document","drive","file","folder","new","plus","sheet","slide","storage","symbol"]},{"name":"wysiwyg","tags":["composer","mode","screen","site","software","system","text","view","visibility","web","website","window","wysiwyg"]},{"name":"label_important","tags":["favorite","important","indent","label","library","mail","remember","save","stamp","sticker","tag","wing"]},{"name":"card_membership","tags":["bill","bookmark","card","cash","certificate","coin","commerce","cost","credit","currency","dollars","finance","loyalty","membership","money","online","pay","payment","shopping","subscription"]},{"name":"style","tags":["booklet","cards","filters","options","style","tags"]},{"name":"arrow_circle_down","tags":["arrow","circle","direction","down","navigation"]},{"name":"file_present","tags":["clip","data","doc","document","drive","file","folder","folders","note","paper","present","reminder","sheet","slide","storage","writing"]},{"name":"directions_bus","tags":["automobile","bus","car","cars","directions","maps","public","transportation","vehicle"]},{"name":"whatshot","tags":["arrow","circle","direction","fire","frames","hot","round","whatshot"]},{"name":"sports_soccer","tags":["athlete","athletic","ball","entertainment","exercise","football","game","hobby","soccer","social","sports"]},{"name":"indeterminate_check_box","tags":["app","application","box","button","check","components","control","design","form","indeterminate","interface","screen","select","selected","selection","site","square","toggle","ui","undetermined","ux","web","website"]},{"name":"outlined_flag","tags":["country","flag","goal","mark","nation","outlined","report","start"]},{"name":"price_change","tags":["arrows","bill","card","cash","change","coin","commerce","cost","credit","currency","dollars","down","finance","money","online","pay","payment","price","shopping","symbol","up"]},{"name":"mark_email_read","tags":["approve","check","complete","done","email","envelop","letter","mail","mark","message","note","ok","read","select","send","sent","tick","yes"]},{"name":"library_add","tags":["+","add","collection","layers","library","multiple","music","new","plus","stacked","symbol","video"]},{"name":"pageview","tags":["doc","document","find","glass","magnifying","page","paper","search","view"]},{"name":"tv","tags":["device","display","monitor","screen","screencast","stream","television","tv","video","wireless"]},{"name":"inbox","tags":["archive","email","inbox","incoming","mail","message"]},{"name":"adjust","tags":["adjust","alter","center","circle","circles","dot","fix","image","move","target"]},{"name":"3d_rotation","tags":["3","3d","D","alphabet","arrow","arrows","av","camera","character","digit","font","letter","number","rotation","symbol","text","type","vr"]},{"name":"battery_charging_full","tags":["battery","bolt","cell","charge","charging","full","lightening","mobile","power","thunderbolt"]},{"name":"chair","tags":["chair","comfort","couch","decoration","furniture","home","house","living","lounging","loveseat","room","seat","seating","sofa"]},{"name":"directions_bike","tags":["bicycle","bike","direction","directions","human","maps","person","public","route","transportation"]},{"name":"mic_off","tags":["audio","disabled","enabled","hear","hearing","mic","microphone","noise","off","on","record","recording","slash","sound","voice"]},{"name":"local_police","tags":["911","badge","law","local","officer","police","protect","protection","security","shield"]},{"name":"fastfood","tags":["drink","fastfood","food","hamburger","maps","meal","places"]},{"name":"tungsten","tags":["electricity","indoor","lamp","light","lightbulb","setting","tungsten"]},{"name":"mood","tags":["emoji","emotions","expressions","face","feelings","glad","happiness","happy","like","mood","person","pleased","smile","smiling","social","survey"]},{"name":"pause_circle","tags":["circle","control","controls","media","music","pause","video"]},{"name":"upgrade","tags":["arrow","export","instal","line","replace","up","update","upgrade"]},{"name":"recommend","tags":["approved","circle","confirm","favorite","gesture","hand","like","reaction","recommend","social","support","thumbs","up","well"]},{"name":"directions_car_filled","tags":["automobile","car","cars","direction","directions","filled","maps","public","transportation","vehicle"]},{"name":"fmd_good","tags":["destination","direction","fmd","good","location","maps","pin","place","stop"]},{"name":"integration_instructions","tags":["brackets","clipboard","code","css","develop","developer","doc","document","engineer","engineering clipboard","html","instructions","integration","platform"]},{"name":"format_bold","tags":["B","alphabet","bold","character","doc","edit","editing","editor","font","format","letter","sheet","spreadsheet","styles","symbol","text","type","writing"]},{"name":"people_outline","tags":["accounts","committee","face","family","friends","humans","network","outline","people","persons","profiles","social","team","users"]},{"name":"trending_down","tags":["analytics","arrow","data","diagram","down","graph","infographic","measure","metrics","movement","rate","rating","statistics","tracking","trending"]},{"name":"change_history","tags":["change","history","shape","triangle"]},{"name":"female","tags":["female","gender","girl","lady","social","symbol","woman","women"]},{"name":"link_off","tags":["attached","chain","clip","connection","disabled","enabled","link","linked","links","multimedia","off","on","slash","url"]},{"name":"text_fields","tags":["T","add","alphabet","character","field","fields","font","input","letter","symbol","text","type"]},{"name":"swipe","tags":["arrow","arrows","fingers","gesture","hand","hands","swipe","touch"]},{"name":"reviews","tags":["bubble","chat","comment","communicate","feedback","message","rate","rating","recommendation","reviews","speech"]},{"name":"home_repair_service","tags":["box","equipment","fix","home","kit","mechanic","repair","repairing","service","tool","toolbox","tools","workshop"]},{"name":"subscriptions","tags":["enroll","list","media","order","play","signup","subscribe","subscriptions"]},{"name":"video_call","tags":["+","add","call","camera","chat","conference","film","filming","hardware","image","motion","new","picture","plus","symbol","video","videography"]},{"name":"zoom_out_map","tags":["arrow","arrows","destination","location","maps","move","out","place","stop","zoom"]},{"name":"straighten","tags":["length","measure","measurement","ruler","size","straighten"]},{"name":"arrow_drop_down_circle","tags":["app","application","arrow","circle","components","direction","down","drop","interface","navigation","screen","site","ui","ux","web","website"]},{"name":"bed","tags":["bed","bedroom","double","full","furniture","home","hotel","house","king","night","pillows","queen","rest","room","size","sleep"]},{"name":"drive_eta","tags":["automobile","car","cars","destination","direction","drive","estimate","eta","maps","public","transportation","travel","trip","vehicle"]},{"name":"class","tags":["archive","book","bookmark","class","favorite","label","library","read","reading","remember","ribbon","save","tag"]},{"name":"drafts","tags":["document","draft","drafts","email","file","letter","mail","message","read"]},{"name":"ballot","tags":["ballot","bullet","election","list","point","poll","vote"]},{"name":"volume_mute","tags":["audio","control","music","mute","sound","speaker","tv","volume"]},{"name":"table_rows","tags":["grid","layout","lines","rows","stacked","table"]},{"name":"accessible","tags":["accessibility","accessible","body","handicap","help","human","people","person","wheelchair"]},{"name":"stop_circle","tags":["circle","control","controls","music","pause","play","square","stop","video"]},{"name":"family_restroom","tags":["bathroom","child","children","family","father","kids","mother","parents","restroom","wc"]},{"name":"title","tags":["T","alphabet","character","font","header","letter","subject","symbol","text","title","type"]},{"name":"biotech","tags":["biotech","chemistry","laboratory","microscope","research","science","technology"]},{"name":"insert_emoticon","tags":["account","emoji","emoticon","face","happy","human","insert","people","person","profile","sentiment","smile","user"]},{"name":"g_translate","tags":["emblem","g","google","language","logo","mark","speaking","speech","translate","translator","words"]},{"name":"last_page","tags":["app","application","arrow","chevron","components","end","forward","interface","last","page","right","screen","site","ui","ux","web","website"]},{"name":"publish","tags":["arrow","cloud","file","import","publish","up","upload"]},{"name":"repeat","tags":["arrow","arrows","control","controls","media","music","repeat","video"]},{"name":"checklist_rtl","tags":["align","alignment","approve","check","checklist","complete","doc","done","edit","editing","editor","format","list","mark","notes","ok","rtl","select","sheet","spreadsheet","text","tick","type","validate","verified","writing","yes"]},{"name":"wifi_off","tags":["connection","data","disabled","enabled","internet","network","off","offline","on","scan","service","signal","slash","wifi","wireless"]},{"name":"settings_accessibility","tags":["accessibility","body","details","human","information","people","person","personal","preferences","profile","settings","user"]},{"name":"percent","tags":["math","number","percent","symbol"]},{"name":"insert_photo","tags":["image","insert","landscape","mountain","mountains","photo","photography","picture"]},{"name":"hotel","tags":["body","hotel","human","people","person","sleep","stay","travel","trip"]},{"name":"cleaning_services","tags":["clean","cleaning","dust","services","sweep"]},{"name":"downloading","tags":["arrow","circle","down","download","downloading","downloads","install","pending","progress","upload"]},{"name":"expand","tags":["arrow","arrows","compress","enlarge","expand","grow","move","push","together"]},{"name":"local_phone","tags":["booth","call","communication","phone","telecommunication"]},{"name":"offline_bolt","tags":["bolt","circle","electric","fast","lightning","offline","thunderbolt"]},{"name":"auto_graph","tags":["analytics","auto","chart","data","diagram","graph","infographic","line","measure","metrics","stars","statistics","tracking"]},{"name":"local_grocery_store","tags":["grocery","market","shop","store"]},{"name":"photo_library","tags":["album","image","library","mountain","mountains","photo","photography","picture"]},{"name":"miscellaneous_services","tags":[]},{"name":"note_alt","tags":["alt","clipboard","document","file","memo","note","page","paper","writing"]},{"name":"settings_backup_restore","tags":["arrow","back","backup","backwards","refresh","restore","reverse","rotate","settings"]},{"name":"production_quantity_limits","tags":["!","alert","attention","bill","card","cart","cash","caution","coin","commerce","credit","currency","danger","dollars","error","exclamation","important","limits","mark","money","notification","online","pay","payment","production","quantity","shopping","symbol","warning"]},{"name":"person_off","tags":["account","avatar","disabled","enabled","face","human","off","on","people","person","profile","slash","user"]},{"name":"report_gmailerrorred","tags":["!","alert","attention","caution","danger","error","exclamation","gmail","gmailerrorred","important","mark","notification","octagon","report","symbol","warning"]},{"name":"camera","tags":["aperture","camera","lens","photo","photography","picture","shutter"]},{"name":"recycling","tags":["bio","eco","green","loop","recyclable","recycle","recycling","rotate","sustainability","sustainable","trash"]},{"name":"male","tags":["boy","gender","male","man","social","symbol"]},{"name":"not_interested","tags":["cancel","close","dislike","exit","interested","no","not","off","quit","remove","stop","x"]},{"name":"event_busy","tags":["busy","calendar","cancel","close","date","event","exit","no","remove","schedule","stop","time","unavailable","x"]},{"name":"arrow_circle_left","tags":["arrow","circle","direction","left","navigation"]},{"name":"shuffle","tags":["arrow","arrows","control","controls","music","random","shuffle","video"]},{"name":"aspect_ratio","tags":["aspect","expand","image","ratio","resize","scale","size","square"]},{"name":"other_houses","tags":["architecture","cottage","estate","home","house","houses","maps","other","place","real","residence","residential","stay","traveling"]},{"name":"model_training","tags":["arrow","bulb","idea","inprogress","light","load","loading","model","refresh","renew","restore","reverse","rotate","training"]},{"name":"unfold_less","tags":["arrow","arrows","chevron","collapse","direction","expand","expandable","inward","less","list","navigation","unfold","up"]},{"name":"insert_chart_outlined","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","insert","measure","metrics","outlined","statistics","tracking"]},{"name":"donut_large","tags":["analytics","chart","data","diagram","donut","graph","infographic","inprogress","large","measure","metrics","pie","statistics","tracking"]},{"name":"view_column","tags":["column","design","format","grid","layout","vertical","view","website"]},{"name":"segment","tags":["alignment","fonts","format","lines","list","paragraph","part","piece","rule","rules","segment","style","text"]},{"name":"checkroom","tags":["checkroom","closet","clothes","coat check","hanger"]},{"name":"mode","tags":["compose","create","draft","draw","edit","mode","pen","pencil","write"]},{"name":"portrait","tags":["account","face","human","people","person","photo","picture","portrait","profile","user"]},{"name":"camera_alt","tags":["alt","camera","image","photo","photography","picture"]},{"name":"keyboard_double_arrow_left","tags":["arrow","arrows","direction","double","left","multiple","navigation"]},{"name":"delete_sweep","tags":["bin","can","delete","garbage","remove","sweep","trash"]},{"name":"hub","tags":["center","connection","core","focal point","hub","network","nucleus","topology"]},{"name":"audiotrack","tags":["audio","audiotrack","key","music","note","sound","track"]},{"name":"calendar_view_month","tags":["calendar","date","day","event","format","grid","layout","month","schedule","today","view"]},{"name":"draw","tags":["compose","create","design","draft","draw","edit","editing","input","pen","pencil","write","writing"]},{"name":"navigation","tags":["destination","direction","location","maps","navigation","pin","place","point","stop"]},{"name":"folder_shared","tags":["account","collaboration","data","doc","document","drive","face","file","folder","human","people","person","profile","share","shared","sheet","slide","storage","team","user"]},{"name":"read_more","tags":["arrow","more","read","text"]},{"name":"stacked_bar_chart","tags":["analytics","bar","chart-chart","data","diagram","graph","infographic","measure","metrics","stacked","statistics","tracking"]},{"name":"mode_comment","tags":["bubble","chat","comment","communicate","feedback","message","mode comment","speech"]},{"name":"schedule_send","tags":["calendar","clock","date","email","letter","mail","remember","schedule","send","share","time"]},{"name":"bluetooth","tags":["bluetooth","cast","connect","connection","device","paring","streaming","symbol","wireless"]},{"name":"graphic_eq","tags":["audio","eq","equalizer","graphic","music","recording","sound","voice"]},{"name":"markunread","tags":["email","envelop","letter","mail","markunread","message","send","unread"]},{"name":"alarm_on","tags":["alarm","alert","bell","clock","disabled","duration","enabled","notification","off","on","slash","time","timer","watch"]},{"name":"local_gas_station","tags":["auto","car","gas","local","oil","station","vehicle"]},{"name":"person_add_alt_1","tags":[]},{"name":"maximize","tags":["app","application","components","design","interface","line","maximize","screen","shape","site","ui","ux","web","website"]},{"name":"bookmark_add","tags":["+","add","bookmark","favorite","plus","remember","ribbon","save","symbol"]},{"name":"dvr","tags":["Android","OS","audio","chrome","computer","desktop","device","display","dvr","electronic","hardware","iOS","list","mac","monitor","record","recorder","screen","tv","video","web","window"]},{"name":"do_not_disturb_on","tags":["cancel","close","denied","deny","disabled","disturb","do","enabled","off","on","remove","silence","slash","stop"]},{"name":"train","tags":["automobile","car","cars","direction","maps","public","rail","subway","train","transportation","vehicle"]},{"name":"person_pin_circle","tags":["account","circle","destination","direction","face","human","location","maps","people","person","pin","place","profile","stop","user"]},{"name":"square_foot","tags":["construction","feet","foot","inches","length","measurement","ruler","school","set","square","tools"]},{"name":"more_time","tags":["+","add","clock","date","more","new","plus","schedule","symbol","time"]},{"name":"document_scanner","tags":["article","data","doc","document","drive","file","folder","folders","notes","page","paper","scan","scanner","sheet","slide","text","writing"]},{"name":"thumbs_up_down","tags":["dislike","down","favorite","fingers","gesture","hands","like","rate","rating","thumbs","up"]},{"name":"settings_ethernet","tags":["arrows","computer","connect","connection","connectivity","dots","ethernet","internet","network","settings","wifi"]},{"name":"sort_by_alpha","tags":["alphabet","alphabetize","az","by alpha","character","font","letter","list","order","organize","sort","symbol","text","type"]},{"name":"theaters","tags":["film","movie","movies","show","showtimes","theater","theaters","watch"]},{"name":"cloud_done","tags":["app","application","approve","backup","check","cloud","complete","connection","done","drive","files","folders","internet","mark","network","ok","select","sky","storage","tick","upload","validate","verified","yes"]},{"name":"local_parking","tags":["alphabet","auto","car","character","font","garage","letter","local","park","parking","symbol","text","type","vehicle"]},{"name":"view_agenda","tags":["agenda","cards","design","format","grid","layout","stacked","view","website"]},{"name":"mark_email_unread","tags":["check","circle","email","envelop","letter","mail","mark","message","note","notification","send","unread"]},{"name":"local_florist","tags":["florist","flower","local","shop"]},{"name":"connect_without_contact","tags":["communicating","connect","contact","distance","people","signal","social","socialize","without"]},{"name":"thumb_down_off_alt","tags":["disabled","dislike","down","enabled","favorite","filled","fingers","gesture","hand","hands","like","off","offline","on","rank","ranking","rate","rating","slash","thumb"]},{"name":"sentiment_neutral","tags":["emotionless","emotions","expressions","face","feelings","fine","indifference","mood","neutral","okay","person","sentiment","survey"]},{"name":"call_end","tags":["call","cell","contact","device","end","hardware","mobile","phone","telephone"]},{"name":"subdirectory_arrow_right","tags":["arrow","directory","down","navigation","right","sub","subdirectory"]},{"name":"diamond","tags":["diamond","fashion","gems","jewelry","logo","retail","valuable","valuables"]},{"name":"podcasts","tags":["broadcast","casting","network","podcasts","signal","transmitting","wireless"]},{"name":"monitor_heart","tags":["baseline","device","ecc","ecg","fitness","health","heart","medical","monitor","track"]},{"name":"all_inclusive","tags":["all","endless","forever","inclusive","infinity","loop","mobius","neverending","strip","sustainability","sustainable"]},{"name":"wc","tags":["bathroom","closet","female","male","man","restroom","room","wash","water","wc","women"]},{"name":"grass","tags":["backyard","fodder","grass","ground","home","lawn","plant","turf","yard"]},{"name":"important_devices","tags":["Android","OS","desktop","devices","hardware","iOS","important","mobile","monitor","phone","star","tablet","web"]},{"name":"back_hand","tags":["back","fingers","gesture","hand","raised"]},{"name":"hiking","tags":["backpacking","bag","climbing","duffle","hiking","mountain","social","sports","stick","trail","travel","walking"]},{"name":"masks","tags":["air","cover","covid","face","hospital","masks","medical","pollution","protection","respirator","sick","social"]},{"name":"waving_hand","tags":["bye","fingers","gesture","goodbye","greetings","hand","hello","palm","wave","waving"]},{"name":"architecture","tags":["architecture","art","compass","design","draw","drawing","engineering","geometric","tool"]},{"name":"local_post_office","tags":["delivery","email","envelop","letter","local","mail","message","office","package","parcel","post","postal","send","stamp"]},{"name":"functions","tags":["average","calculate","count","custom","doc","edit","editing","editor","functions","math","sheet","spreadsheet","style","sum","text","type","writing"]},{"name":"directions","tags":["arrow","directions","maps","right","route","sign","traffic"]},{"name":"money","tags":["100","bill","card","cash","coin","commerce","cost","credit","currency","digit","dollars","finance","money","number","online","pay","payment","price","shopping","symbol"]},{"name":"unpublished","tags":["approve","check","circle","complete","disabled","done","enabled","mark","off","ok","on","select","slash","tick","unpublished","validate","verified","yes"]},{"name":"notifications_off","tags":["active","alarm","alert","bell","chime","disabled","enabled","notifications","notify","off","offline","on","reminder","ring","slash","sound"]},{"name":"airport_shuttle","tags":["airport","automobile","car","cars","commercial","delivery","direction","maps","mini","public","shuttle","transport","transportation","travel","truck","van","vehicle"]},{"name":"insert_link","tags":["add","attach","clip","file","insert","link","mail","media"]},{"name":"thumb_down_alt","tags":["bad","decline","disapprove","dislike","down","feedback","hate","negative","no","reject","social","thumb","veto","vote"]},{"name":"two_wheeler","tags":["automobile","bike","car","cars","direction","maps","motorcycle","public","scooter","sport","transportation","travel","two wheeler","vehicle"]},{"name":"nightlight","tags":["dark","disturb","mode","moon","night","nightlight","sleep"]},{"name":"mic_none","tags":["hear","hearing","mic","microphone","noise","none","record","sound","voice"]},{"name":"keyboard_double_arrow_down","tags":["arrow","arrows","direction","double","down","multiple","navigation"]},{"name":"invert_colors","tags":["colors","drop","droplet","edit","editing","hue","invert","inverted","palette","tone","water"]},{"name":"clear_all","tags":["all","clear","doc","document","format","lines","list"]},{"name":"mouse","tags":["click","computer","cursor","device","hardware","mouse","wireless"]},{"name":"mode_edit_outline","tags":["compose","create","draft","draw","edit","mode","outline","pen","pencil","write"]},{"name":"open_in_browser","tags":["arrow","browser","in","open","site","up","web","website","window"]},{"name":"insert_invitation","tags":["calendar","date","day","event","insert","invitation","mark","month","range","remember","reminder","today","week"]},{"name":"fast_rewind","tags":["back","control","fast","media","music","play","rewind","speed","time","tv","video"]},{"name":"opacity","tags":["color","drop","droplet","hue","invert","inverted","opacity","palette","tone","water"]},{"name":"video_camera_front","tags":["account","camera","face","front","human","image","people","person","photo","photography","picture","profile","user","video"]},{"name":"commute","tags":["automobile","car","commute","direction","maps","public","train","transportation","trip","vehicle"]},{"name":"addchart","tags":["+","addchart","analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","new","plus","statistics","symbol","tracking"]},{"name":"no_accounts","tags":["account","accounts","avatar","disabled","enabled","face","human","no","off","offline","on","people","person","profile","slash","thumbnail","unavailable","unidentifiable","unknown","user"]},{"name":"coffee","tags":["beverage","coffee","cup","drink","mug","plate","set","tea"]},{"name":"luggage","tags":["airport","bag","baggage","carry","flight","hotel","luggage","on","suitcase","travel","trip"]},{"name":"workspaces","tags":["circles","collaboration","dot","filled","group","outline","space","team","work","workspaces"]},{"name":"child_care","tags":["babies","baby","care","child","children","face","infant","kids","newborn","toddler","young"]},{"name":"sports_score","tags":["destination","flag","goal","score","sports"]},{"name":"library_music","tags":["add","album","collection","library","music","song","sounds"]},{"name":"history_toggle_off","tags":["clock","date","history","off","schedule","time","toggle"]},{"name":"system_update_alt","tags":["arrow","down","download","export","system","update"]},{"name":"access_time","tags":[]},{"name":"rotate_right","tags":["around","arrow","direction","inprogress","load","loading refresh","renew","right","rotate","turn"]},{"name":"color_lens","tags":["art","color","lens","paint","pallet"]},{"name":"grid_on","tags":["collage","disabled","enabled","grid","image","layout","off","on","slash","view"]},{"name":"crop_free","tags":["adjust","adjustments","crop","edit","editing","focus","frame","free","image","photo","photos","settings","size","zoom"]},{"name":"cloud_queue","tags":["cloud","connection","internet","network","queue","sky","upload"]},{"name":"keyboard_voice","tags":["keyboard","mic","microphone","noise","record","recorder","speaker","voice"]},{"name":"format_align_left","tags":["align","alignment","doc","edit","editing","editor","format","left","sheet","spreadsheet","text","type","writing"]},{"name":"view_week","tags":["bars","columns","design","format","grid","layout","view","website","week"]},{"name":"real_estate_agent","tags":["agent","architecture","broker","estate","hand","home","house","loan","mortgage","property","real","residence","residential","sales","social"]},{"name":"horizontal_rule","tags":["gmail","horizontal","line","novitas","rule"]},{"name":"topic","tags":["data","doc","document","drive","file","folder","sheet","slide","storage","topic"]},{"name":"shower","tags":["bath","bathroom","closet","home","house","place","plumbing","room","shower","sprinkler","wash","water","wc"]},{"name":"format_italic","tags":["alphabet","character","doc","edit","editing","editor","font","format","italic","letter","sheet","spreadsheet","style","symbol","text","type","writing"]},{"name":"traffic","tags":["direction","light","maps","signal","street","traffic"]},{"name":"add_business","tags":["+","add","bill","building","business","card","cash","coin","commerce","company","credit","currency","dollars","market","money","new","online","pay","payment","plus","shop","shopping","store","storefront","symbol"]},{"name":"electrical_services","tags":["charge","cord","electric","electrical","plug","power","services","wire"]},{"name":"timelapse","tags":["duration","motion","photo","time","timelapse","timer","video"]},{"name":"youtube_searched_for","tags":["arrow","back","backwards","find","glass","history","inprogress","load","loading","look","magnify","magnifying","refresh","renew","restore","reverse","rotate","search","see","youtube"]},{"name":"front_hand","tags":["fingers","front","gesture","hand","hello","palm","stop"]},{"name":"yard","tags":["backyard","flower","garden","home","house","nature","pettle","plants","yard"]},{"name":"tour","tags":["destination","flag","places","tour","travel","visit"]},{"name":"factory","tags":["factory","industry","manufacturing","warehouse"]},{"name":"developer_board","tags":["board","chip","computer","developer","development","hardware","microchip","processor"]},{"name":"more","tags":["3","archive","bookmark","dots","etc","favorite","indent","label","more","remember","save","stamp","sticker","tab","tag","three"]},{"name":"star_purple500","tags":["500","best","bookmark","favorite","highlight","purple","ranking","rate","rating","save","star","toggle"]},{"name":"format_color_fill","tags":["bucket","color","doc","edit","editing","editor","fill","format","paint","sheet","spreadsheet","style","text","type","writing"]},{"name":"beach_access","tags":["access","beach","places","summer","sunny","umbrella"]},{"name":"local_bar","tags":["alcohol","bar","bottle","club","cocktail","drink","food","liquor","local","wine"]},{"name":"add_link","tags":["add","attach","clip","link","new","plus","symbol"]},{"name":"landscape","tags":["image","landscape","mountain","mountains","nature","photo","photography","picture"]},{"name":"slideshow","tags":["movie","photos","play","slideshow","square","video","view"]},{"name":"stream","tags":["cast","connected","feed","live","network","signal","stream","wireless"]},{"name":"videocam_off","tags":["cam","camera","conference","disabled","enabled","film","filming","hardware","image","motion","off","offline","on","picture","slash","video","videography"]},{"name":"directions_boat","tags":["automobile","boat","car","cars","direction","directions","ferry","maps","public","transportation","vehicle"]},{"name":"download_done","tags":["arrow","arrows","check","done","down","download","downloads","drive","install","installed","ok","tick","upload"]},{"name":"volume_down","tags":["audio","control","down","music","sound","speaker","tv","volume"]},{"name":"alt_route","tags":["alt","alternate","alternative","arrows","direction","maps","navigation","options","other","route","routes","split","symbol"]},{"name":"mood_bad","tags":["bad","disappointment","dislike","emoji","emotions","expressions","face","feelings","mood","person","rating","social","survey","unhappiness","unhappy","unpleased","unsmile","unsmiling"]},{"name":"vaccines","tags":["aid","covid","doctor","drug","emergency","hospital","immunity","injection","medical","medication","medicine","needle","pharmacy","sick","syringe","vaccination","vaccines","vial"]},{"name":"dialpad","tags":["buttons","call","contact","device","dial","dialpad","dots","mobile","numbers","pad","phone"]},{"name":"route","tags":["directions","maps","path","route","sign","traffic"]},{"name":"hide_source","tags":["circle","disabled","enabled","hide","off","offline","on","shape","slash","source"]},{"name":"bookmark_added","tags":["added","approve","bookmark","check","complete","done","favorite","mark","ok","remember","save","select","tick","validate","verified","yes"]},{"name":"mark_as_unread","tags":["as","envelop","letter","mail","mark","post","postal","read","receive","send","unread"]},{"name":"plagiarism","tags":["doc","document","find","glass","look","magnifying","page","paper","plagiarism","search","see"]},{"name":"turned_in","tags":["archive","bookmark","favorite","in","label","library","read","reading","remember","ribbon","save","tag","turned"]},{"name":"settings_input_antenna","tags":["airplay","antenna","arrows","cast","computer","connect","connection","connectivity","dots","input","internet","network","screencast","settings","stream","wifi","wireless"]},{"name":"shop","tags":["bag","bill","buy","card","cart","cash","coin","commerce","credit","currency","dollars","google","money","online","pay","payment","play","shop","shopping","store"]},{"name":"pool","tags":["athlete","athletic","beach","body","entertainment","exercise","hobby","human","ocean","people","person","places","pool","sea","sports","swim","swimming","water"]},{"name":"search_off","tags":["cancel","close","disabled","enabled","find","glass","look","magnify","magnifying","off","on","search","see","slash","stop","x"]},{"name":"approval","tags":["apply","approval","approvals","approve","certificate","certification","disapproval","drive","file","impression","ink","mark","postage","stamp"]},{"name":"currency_rupee","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","rupee","shopping","symbol"]},{"name":"power","tags":["charge","cord","electric","electrical","outlet","plug","power"]},{"name":"collections_bookmark","tags":["album","archive","bookmark","collections","favorite","gallery","label","library","read","reading","remember","ribbon","save","stack","tag"]},{"name":"not_started","tags":["circle","media","not","pause","play","started","video"]},{"name":"pedal_bike","tags":["automobile","bicycle","bike","car","cars","direction","human","maps","pedal","public","route","scooter","transportation","vehicle","vespa"]},{"name":"water","tags":["aqua","beach","lake","ocean","river","water","waves","weather"]},{"name":"router","tags":["box","cable","connection","hardware","internet","network","router","signal","wifi"]},{"name":"flight_land","tags":["airport","arrival","arriving","flight","fly","land","landing","plane","transportation","travel"]},{"name":"shopping_cart_checkout","tags":["arrow","cart","cash","checkout","coin","commerce","currency","dollars","money","online","pay","payment","right","shopping"]},{"name":"agriculture","tags":["agriculture","automobile","car","cars","cultivation","farm","harvest","maps","tractor","transport","travel","truck","vehicle"]},{"name":"where_to_vote","tags":["approve","ballot","check","complete","destination","direction","done","location","maps","mark","ok","pin","place","poll","select","stop","tick","to","validate election","verified","vote","where","yes"]},{"name":"beenhere","tags":["approve","archive","beenhere","bookmark","check","complete","done","favorite","label","library","mark","ok","read","reading","remember","ribbon","save","select","tag","tick","validate","verified","yes"]},{"name":"add_comment","tags":["+","add","bubble","chat","comment","communicate","feedback","message","new","plus","speech","symbol"]},{"name":"copy_all","tags":["all","content","copy","cut","doc","document","file","multiple","page","paper","past"]},{"name":"dynamic_feed","tags":["'mail_outline'","'markunread'. Keep 'mail' and remove others.","Duplicate of 'email'"]},{"name":"videogame_asset","tags":["asset","console","controller","device","game","gamepad","gaming","playstation","video"]},{"name":"move_to_inbox","tags":["archive","arrow","down","email","envelop","inbox","incoming","letter","mail","message","move to","send"]},{"name":"crop_square","tags":["adjust","adjustments","app","application","area","components","crop","design","edit","editing","expand","frame","image","images","interface","open","photo","photos","rectangle","screen","settings","shape","shapes","site","size","square","ui","ux","web","website","window"]},{"name":"recent_actors","tags":["account","actors","avatar","card","cards","carousel","face","human","layers","list","people","person","profile","recent","thumbnail","user"]},{"name":"emoji_nature","tags":["animal","bee","bug","daisy","emoji","flower","insect","ladybug","nature","petals","spring","summer"]},{"name":"cloud_off","tags":["app","application","backup","cloud","connection","disabled","drive","enabled","files","folders","internet","network","off","offline","on","sky","slash","storage","upload"]},{"name":"panorama_fish_eye","tags":["angle","circle","eye","fish","image","panorama","photo","photography","picture","wide"]},{"name":"lens","tags":["circle","full","geometry","lens","moon"]},{"name":"360","tags":["360","arrow","av","camera","direction","rotate","rotation","vr"]},{"name":"share_location","tags":["destination","direction","gps","location","maps","pin","place","share","stop","tracking"]},{"name":"assignment_late","tags":["!","alert","assignment","attention","caution","clipboard","danger","doc","document","error","exclamation","important","late","mark","notification","symbol","warning"]},{"name":"switch_account","tags":["account","choices","face","human","multiple","options","people","person","profile","social","switch","user"]},{"name":"looks_two","tags":["2","digit","looks","numbers","square","symbol"]},{"name":"do_not_disturb","tags":["cancel","close","denied","deny","disturb","do","remove","silence","stop"]},{"name":"donut_small","tags":["analytics","chart","data","diagram","donut","graph","infographic","inprogress","measure","metrics","pie","small","statistics","tracking"]},{"name":"saved_search","tags":["find","glass","important","look","magnify","magnifying","marked","saved","search","see","star"]},{"name":"contactless","tags":["bluetooth","cash","connect","connection","connectivity","contact","contactless","credit","device","finance","pay","payment","signal","transaction","wifi","wireless"]},{"name":"highlight_alt","tags":["alt","arrow","box","click","cursor","draw","focus","highlight","pointer","select","selection","target"]},{"name":"assignment_return","tags":["arrow","assignment","back","clipboard","doc","document","left","retun"]},{"name":"kitchen","tags":["appliance","cold","food","fridge","home","house","ice","kitchen","places","refrigerator","storage"]},{"name":"warehouse","tags":["garage","industry","manufacturing","storage","warehouse"]},{"name":"liquor","tags":["alcohol","bar","bottle","club","cocktail","drink","food","liquor","party","store","wine"]},{"name":"gpp_maybe","tags":["!","alert","attention","caution","certified","danger","error","exclamation","gpp","important","mark","maybe","notification","privacy","private","protect","protection","security","shield","sim","symbol","verified","warning"]},{"name":"settings_input_component","tags":["audio","av","cable","cables","component","connect","connection","connectivity","input","internet","plug","points","settings","video","wifi"]},{"name":"waves","tags":["beach","lake","ocean","pool","river","sea","swim","water","wave","waves"]},{"name":"hotel_class","tags":["achievement","bookmark","class","favorite","highlight","hotel","important","marked","rank","ranking","rate","rating","reward","save","saved","shape","special","star"]},{"name":"web_asset","tags":["-website","app","application desktop","asset","browser","design","download","image","interface","internet","layout","screen","site","ui","ux","video","web","website","window","www"]},{"name":"view_carousel","tags":["cards","carousel","design","format","grid","layout","view","website"]},{"name":"anchor","tags":["anchor","google","logo"]},{"name":"filter_alt_off","tags":["alt","disabled","edit","filter","funnel","off","offline","options","refine","sift","slash"]},{"name":"balance","tags":["balance","equal","equity","impartiality","justice","parity","stability. equilibrium","steadiness","symmetry"]},{"name":"view_quilt","tags":["design","format","grid","layout","quilt","square","squares","stacked","view","website"]},{"name":"library_add_check","tags":["add","approve","check","collection","complete","done","layers","library","mark","multiple","music","ok","select","stacked","tick","validate","verified","video","yes"]},{"name":"queue_music","tags":["collection","list","music","playlist","queue"]},{"name":"casino","tags":["casino","dice","dots","entertainment","gamble","gambling","game","games","luck","places"]},{"name":"hearing","tags":["accessibility","accessible","aid","ear","handicap","hearing","help","impaired","listen","sound","volume"]},{"name":"phone_enabled","tags":["call","cell","contact","device","enabled","hardware","mobile","phone","telephone"]},{"name":"linear_scale","tags":["app","application","components","design","interface","layout","linear","measure","menu","scale","screen","site","slider","ui","ux","web","website","window"]},{"name":"holiday_village","tags":["architecture","beach","camping","cottage","estate","holiday","home","house","lake","lodge","maps","place","real","residence","residential","stay","traveling","vacation","village"]},{"name":"turned_in_not","tags":["archive","bookmark","favorite","in","label","library","not","read","reading","remember","ribbon","save","tag","turned"]},{"name":"sync_problem","tags":["!","360","alert","around","arrow","arrows","attention","caution","danger","direction","error","exclamation","important","inprogress","load","loading refresh","mark","notification","problem","renew","rotate","symbol","sync","turn","warning"]},{"name":"start","tags":["arrow","keyboard","next","right","start"]},{"name":"all_inbox","tags":["Inbox","all","delivered","delivery","email","mail","message","send"]},{"name":"mediation","tags":["arrow","arrows","direction","dots","mediation","right"]},{"name":"edit_off","tags":["compose","create","disabled","draft","edit","editing","enabled","input","new","off","offline","on","pen","pencil","slash","write","writing"]},{"name":"emergency","tags":["asterisk","clinic","emergency","health","hospital","maps","medical","symbol"]},{"name":"settings_remote","tags":["bluetooth","connection","connectivity","device","remote","settings","signal","wifi","wireless"]},{"name":"drive_file_move","tags":["arrow","data","doc","document","drive","file","folder","move","right","sheet","slide","storage"]},{"name":"fit_screen","tags":["enlarge","fit","format","layout","reduce","scale","screen","size"]},{"name":"hourglass_full","tags":["countdown","full","hourglass","loading","minutes","time","wait","waiting"]},{"name":"nights_stay","tags":["climate","cloud","crescent","dark","lunar","mode","moon","nights","phases","silence","silent","sky","stay","time","weather"]},{"name":"pause_circle_filled","tags":["circle","control","controls","filled","media","music","pause","video"]},{"name":"catching_pokemon","tags":["catching","go","pokemon","pokestop","travel"]},{"name":"king_bed","tags":["bed","bedroom","double","furniture","home","hotel","house","king","night","pillows","queen","rest","room","sleep"]},{"name":"flaky","tags":["approve","check","close","complete","contrast","done","exit","flaky","mark","no","ok","options","select","stop","tick","verified","x","yes"]},{"name":"format_size","tags":["alphabet","character","color","doc","edit","editing","editor","fill","font","format","letter","paint","sheet","size","spreadsheet","style","symbol","text","type","writing"]},{"name":"interests","tags":["circle","heart","interests","shapes","social","square","triangle"]},{"name":"stacked_line_chart","tags":["analytics","chart","data","diagram","graph","infographic","line","measure","metrics","stacked","statistics","tracking"]},{"name":"unarchive","tags":["archive","arrow","inbox","mail","store","unarchive","undo","up"]},{"name":"subtitles","tags":["accessible","caption","cc","character","closed","decoder","language","media","movies","subtitle","subtitles","tv"]},{"name":"toll","tags":["bill","booth","car","card","cash","coin","commerce","credit","currency","dollars","highway","money","online","pay","payment","ticket","toll"]},{"name":"keyboard_double_arrow_up","tags":["arrow","arrows","direction","double","multiple","navigation","up"]},{"name":"time_to_leave","tags":["automobile","car","cars","destination","direction","drive","estimate","eta","maps","public","transportation","travel","trip","vehicle"]},{"name":"location_searching","tags":["destination","direction","location","maps","pin","place","pointer","searching","stop","tracking"]},{"name":"cable","tags":["cable","connect","connection","device","electronics","usb","wire"]},{"name":"moving","tags":["arrow","direction","moving","navigation","travel","up"]},{"name":"remove_shopping_cart","tags":["card","cart","cash","checkout","coin","commerce","credit","currency","disabled","dollars","enabled","off","on","online","pay","payment","remove","shopping","slash","tick"]},{"name":"cast_for_education","tags":["Android","OS","airplay","cast","chrome","connect","desktop","device","display","education","for","hardware","iOS","learning","lessons teaching","mac","monitor","screen","screencast","streaming","television","tv","web","window","wireless"]},{"name":"fiber_new","tags":["alphabet","character","fiber","font","letter","network","new","symbol","text","type"]},{"name":"format_underlined","tags":["alphabet","character","doc","edit","editing","editor","font","format","letter","line","sheet","spreadsheet","style","symbol","text","type","under","underlined","writing"]},{"name":"pause_circle_outline","tags":["circle","control","controls","media","music","outline","pause","video"]},{"name":"mark_chat_unread","tags":["bubble","chat","circle","comment","communicate","mark","message","notification","speech","unread"]},{"name":"insert_comment","tags":["add","bubble","chat","comment","feedback","insert","message"]},{"name":"cameraswitch","tags":["arrows","camera","cameraswitch","flip","rotate","swap","switch","view"]},{"name":"rocket","tags":["rocket","space","spaceship"]},{"name":"local_airport","tags":["air","airplane","airport","flight","plane","transportation","travel","trip"]},{"name":"lock_clock","tags":["clock","date","lock","locked","password","privacy","private","protection","safety","schedule","secure","security","time"]},{"name":"device_hub","tags":["Android","OS","circle","computer","desktop","device","hardware","hub","iOS","laptop","mobile","monitor","phone","square","tablet","triangle","watch","wearable","web"]},{"name":"filter_vintage","tags":["edit","editing","effect","filter","flower","image","images","photography","picture","pictures","vintage"]},{"name":"sailing","tags":["boat","entertainment","fishing","hobby","ocean","sailboat","sailing","sea","social sports","travel","water"]},{"name":"roofing","tags":["architecture","building","chimney","construction","estate","home","house","real","residence","residential","roof","roofing","service","shelter"]},{"name":"settings_voice","tags":["mic","microphone","record","recorder","settings","speaker","voice"]},{"name":"swap_horizontal_circle","tags":["arrow","arrows","back","circle","forward","horizontal","swap"]},{"name":"add_location_alt","tags":["+","add","alt","destination","direction","location","maps","new","pin","place","plus","stop","symbol"]},{"name":"room_service","tags":["alert","bell","delivery","hotel","notify","room","service"]},{"name":"content_paste_search","tags":["clipboard","content","doc","document","file","find","paste","search","trace","track"]},{"name":"reply_all","tags":["all","arrow","backward","group","left","mail","message","multiple","reply","send","share"]},{"name":"compost","tags":["bio","compost","compostable","decomposable","decompose","eco","green","leaf","leafs","nature","organic","plant","recycle","sustainability","sustainable"]},{"name":"bubble_chart","tags":["analytics","bar","bars","bubble","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"compare","tags":["adjust","adjustment","compare","edit","editing","edits","enhance","fix","image","images","photo","photography","photos","scan","settings"]},{"name":"money_off","tags":["bill","card","cart","cash","coin","commerce","credit","currency","disabled","dollars","enabled","money","off","on","online","pay","payment","shopping","slash","symbol"]},{"name":"file_open","tags":["arrow","doc","document","drive","file","left","open","page","paper"]},{"name":"filter_drama","tags":["cloud","drama","edit","editing","effect","filter","image","photo","photography","picture","sky camera"]},{"name":"shortcut","tags":["arrow","direction","forward","right","shortcut"]},{"name":"view_sidebar","tags":["design","format","grid","layout","sidebar","view","web"]},{"name":"looks_3","tags":["3","digit","looks","numbers","square","symbol"]},{"name":"note","tags":["bookmark","message","note","paper"]},{"name":"vertical_align_bottom","tags":["align","alignment","arrow","bottom","doc","down","edit","editing","editor","sheet","spreadsheet","text","type","vertical","writing"]},{"name":"3p","tags":["3","3p","account","avatar","bubble","chat","comment","communicate","face","human","message","party","people","person","profile","speech","user"]},{"name":"online_prediction","tags":["bulb","connection","idea","light","network","online","prediction","signal","wireless"]},{"name":"cancel_presentation","tags":["cancel","close","device","exit","no","present","presentation","quit","remove","screen","slide","stop","website","window","x"]},{"name":"select_all","tags":["all","select","selection","square","tool"]},{"name":"event_seat","tags":["assign","assigned","chair","event","furniture","reservation","row","seat","section","sit"]},{"name":"window","tags":["close","glass","grid","home","house","interior","layout","outside","window"]},{"name":"av_timer","tags":["av","clock","countdown","duration","minutes","seconds","time","timer","watch"]},{"name":"album","tags":["album","artist","audio","bvb","cd","computer","data","disk","file","music","record","sound","storage","track"]},{"name":"local_dining","tags":["dining","eat","food","fork","knife","local","meal","restaurant","spoon"]},{"name":"headset","tags":["accessory","audio","device","ear","earphone","headphones","headset","listen","music","sound"]},{"name":"maps_ugc","tags":["+","add","bubble","comment","communicate","feedback","maps","message","new","plus","speech","symbol","ugc"]},{"name":"airplane_ticket","tags":["airplane","airport","boarding","flight","fly","maps","pass","ticket","transportation","travel"]},{"name":"vertical_split","tags":["design","format","grid","layout","paragraph","split","text","vertical","website","writing"]},{"name":"sports_basketball","tags":["athlete","athletic","ball","basketball","entertainment","exercise","game","hobby","social","sports"]},{"name":"next_plan","tags":["arrow","circle","next","plan","right"]},{"name":"drive_folder_upload","tags":["arrow","data","doc","document","drive","file","folder","sheet","slide","storage","up","upload"]},{"name":"pregnant_woman","tags":["baby","birth","body","female","human","lady","maternity","mom","mother","people","person","pregnant","women"]},{"name":"wallpaper","tags":["background","image","landscape","photo","photography","picture","wallpaper"]},{"name":"image_search","tags":["find","glass","image","landscape","look","magnify","magnifying","mountain","mountains","photo","photography","picture","search","see"]},{"name":"data_exploration","tags":["analytics","arrow","chart","data","diagram","exploration","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"device_thermostat","tags":["celsius","device","fahrenheit","meter","temp","temperature","thermometer","thermostat"]},{"name":"healing","tags":["bandage","edit","editing","emergency","fix","healing","hospital","image","medicine"]},{"name":"laptop_mac","tags":["Android","OS","chrome","device","display","hardware","iOS","laptop","mac","monitor","screen","web","window"]},{"name":"height","tags":["arrow","color","doc","down","edit","editing","editor","fill","format","height","paint","sheet","spreadsheet","style","text","type","up","writing"]},{"name":"restore_from_trash","tags":["arrow","back","backwards","clock","date","history","refresh","renew","restore","reverse","rotate","schedule","time","turn"]},{"name":"radar","tags":["detect","military","near","network","position","radar","scan"]},{"name":"auto_awesome_motion","tags":["adjust","auto","awesome","collage","edit","editing","enhance","image","motion","photo","video"]},{"name":"file_download_done","tags":["arrow","arrows","check","done","down","download","downloads","drive","file","install","installed","tick","upload"]},{"name":"notification_add","tags":["+","active","add","alarm","alert","bell","chime","notification","notifications","notify","plus","reminder","ring","sound","symbol"]},{"name":"call_made","tags":["arrow","call","device","made","mobile"]},{"name":"camera_enhance","tags":["ai","artificial","automatic","automation","camera","custom","enhance","genai","important","intelligence","lens","magic","photo","photography","picture","quality","smart","spark","sparkle","special","star"]},{"name":"rotate_left","tags":["around","arrow","direction","inprogress","left","load","loading refresh","renew","rotate","turn"]},{"name":"local_taxi","tags":["automobile","cab","call","car","cars","direction","local","lyft","maps","public","taxi","transportation","uber","vehicle","yellow"]},{"name":"star_border_purple500","tags":["500","best","bookmark","border","favorite","highlight","outline","purple","ranking","rate","rating","save","star","toggle"]},{"name":"gpp_bad","tags":["bad","cancel","certified","close","error","exit","gpp","no","privacy","private","protect","protection","remove","security","shield","sim","stop","verified","x"]},{"name":"playlist_play","tags":["arrow","collection","list","music","play","playlist"]},{"name":"cast","tags":["Android","OS","airplay","cast","chrome","connect","desktop","device","display","hardware","iOS","mac","monitor","screen","screencast","streaming","television","tv","web","window","wireless"]},{"name":"vertical_align_top","tags":["align","alignment","arrow","doc","edit","editing","editor","sheet","spreadsheet","text","top","type","up","vertical","writing"]},{"name":"ramen_dining","tags":["breakfast","dining","dinner","drink","fastfood","food","lunch","meal","noodles","ramen","restaurant"]},{"name":"data_usage","tags":["analytics","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking","usage"]},{"name":"markunread_mailbox","tags":["deliver","envelop","letter","mail","mailbox","markunread","post","postal","postbox","receive","send","unread"]},{"name":"terminal","tags":["application","code","emulator","program","software","terminal"]},{"name":"screen_share","tags":["Android","OS","arrow","cast","chrome","device","display","hardware","iOS","laptop","mac","mirror","monitor","screen","share","steam","streaming","web","window"]},{"name":"center_focus_strong","tags":["camera","center","focus","image","lens","photo","photography","strong","zoom"]},{"name":"queue","tags":["add","collection","layers","list","multiple","music","playlist","queue","stack","stream","video"]},{"name":"games","tags":["adjust","arrow","arrows","control","controller","direction","games","gaming","left","move","right"]},{"name":"low_priority","tags":["arrange","arrow","backward","bottom","list","low","move","order","priority"]},{"name":"dynamic_form","tags":["bolt","code","dynamic","electric","fast","form","lightning","lists","questionnaire","thunderbolt"]},{"name":"tab","tags":["browser","computer","document","documents","folder","internet","tab","tabs","web","website","window","windows"]},{"name":"lock_reset","tags":["around","inprogress","load","loading refresh","lock","locked","password","privacy","private","protection","renew","rotate","safety","secure","security","turn"]},{"name":"room_preferences","tags":["building","door","doorway","entrance","gear","home","house","interior","office","open","preferences","room","settings"]},{"name":"crop","tags":["adjust","adjustments","area","crop","edit","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"monitor_weight","tags":["body","device","diet","health","monitor","scale","smart","weight"]},{"name":"trip_origin","tags":["circle","departure","origin","trip"]},{"name":"calendar_view_week","tags":["calendar","date","day","event","format","grid","layout","month","schedule","today","view","week"]},{"name":"signal_wifi_4_bar","tags":["4","bar","cell","cellular","data","internet","mobile","network","phone","signal","wifi","wireless"]},{"name":"blur_on","tags":["blur","disabled","dots","edit","editing","effect","enabled","enhance","filter","off","on","slash"]},{"name":"view_stream","tags":["design","format","grid","layout","lines","list","stacked","stream","view","website"]},{"name":"radio","tags":["antenna","audio","device","frequency","hardware","listen","media","music","player","radio","signal","tune"]},{"name":"hail","tags":["body","hail","human","people","person","pick","public","stop","taxi","transportation"]},{"name":"do_disturb_on","tags":["cancel","close","denied","deny","disabled","disturb","do","enabled","off","on","remove","silence","slash","stop"]},{"name":"sensor_door","tags":["alarm","security","security system"]},{"name":"wb_incandescent","tags":["balance","bright","edit","editing","incandescent","light","lighting","setting","settings","white","wp"]},{"name":"local_drink","tags":["cup","drink","drop","droplet","liquid","local","park","water"]},{"name":"accessible_forward","tags":["accessibility","accessible","body","forward","handicap","help","human","people","person","wheelchair"]},{"name":"replay_circle_filled","tags":["arrow","arrows","circle","control","controls","filled","music","refresh","renew","repeat","replay","video"]},{"name":"local_printshop","tags":["draft","fax","ink","local","machine","office","paper","print","printer","printshop","send"]},{"name":"local_laundry_service","tags":["cleaning","clothing","dry","dryer","hotel","laundry","local","service","washer"]},{"name":"vpn_lock","tags":["earth","globe","lock","locked","network","password","privacy","private","protection","safety","secure","security","virtual","vpn","world"]},{"name":"schema","tags":["analytics","chart","data","diagram","flow","graph","infographic","measure","metrics","schema","statistics","tracking"]},{"name":"request_page","tags":["data","doc","document","drive","file","folder","folders","page","paper","request","sheet","slide","writing"]},{"name":"token","tags":["badge","hexagon","mark","shield","sign","symbol"]},{"name":"branding_watermark","tags":["branding","components","copyright","design","emblem","format","identity","interface","layout","logo","screen","site","stamp","ui","ux","watermark","web","website","window"]},{"name":"theater_comedy","tags":["broadway","comedy","event","movie","musical","places","show","standup","theater","tour","watch"]},{"name":"text_format","tags":["alphabet","character","font","format","letter","square A","style","symbol","text","type"]},{"name":"directions_bus_filled","tags":["automobile","bus","car","cars","direction","directions","filled","maps","public","transportation","vehicle"]},{"name":"remove_done","tags":["approve","check","complete","disabled","done","enabled","finished","mark","multiple","off","ok","on","remove","select","slash","tick","yes"]},{"name":"sports_bar","tags":["alcohol","bar","beer","drink","liquor","pint","places","pub","sports"]},{"name":"watch","tags":["Android","OS","ar","clock","gadget","iOS","time","vr","watch","wearables","web","wristwatch"]},{"name":"add_to_drive","tags":["add","app","application","backup","cloud","drive","files","folders","gdrive","google","recovery","shortcut","storage"]},{"name":"format_align_center","tags":["align","alignment","center","doc","edit","editing","editor","format","sheet","spreadsheet","text","type","writing"]},{"name":"settings_power","tags":["info","information","off","on","power","save","settings","shutdown"]},{"name":"local_pizza","tags":["drink","fastfood","food","local","meal","pizza"]},{"name":"add_alert","tags":["+","active","add","alarm","alert","bell","chime","new","notifications","notify","plus","reminder","ring","sound","symbol"]},{"name":"smart_button","tags":["action","ai","artificial","automatic","automation","button","components","composer","custom","function","genai","intelligence","interface","magic","site","smart","spark","sparkle","special","star","stars","ui","ux","web","website"]},{"name":"flare","tags":["bright","edit","editing","effect","flare","image","images","light","photography","picture","pictures","sun"]},{"name":"developer_mode","tags":["Android","OS","bracket","cell","code","developer","development","device","engineer","hardware","iOS","mobile","mode","phone","tablet"]},{"name":"call_split","tags":["arrow","call","device","mobile","split"]},{"name":"free_breakfast","tags":["beverage","breakfast","cafe","coffee","cup","drink","free","mug","tea"]},{"name":"auto_delete","tags":["auto","bin","can","clock","date","delete","garbage","remove","schedule","time","trash"]},{"name":"sports_kabaddi","tags":["athlete","athletic","body","combat","entertainment","exercise","fighting","game","hobby","human","kabaddi","people","person","social","sports","wrestle","wrestling"]},{"name":"face_retouching_natural","tags":["ai","artificial","automatic","automation","custom","edit","editing","effect","emoji","emotion","face","faces","genai","image","intelligence","magic","natural","photo","photography","retouch","retouching","settings","smart","spark","sparkle","star","tag"]},{"name":"not_listed_location","tags":["?","assistance","destination","direction","help","info","information","listed","location","maps","not","pin","place","punctuation","question mark","stop","support","symbol"]},{"name":"wb_cloudy","tags":["balance","cloud","cloudy","edit","editing","white","wp"]},{"name":"sports","tags":["athlete","athletic","blowing","coach","entertainment","exercise","game","hobby","instrument","referee","social","sound","sports","warning","whistle"]},{"name":"emoji_symbols","tags":["ampersand","character","emoji","hieroglyph","music","note","percent","sign","symbols"]},{"name":"bathtub","tags":["bath","bathing","bathroom","bathtub","home","hotel","human","person","shower","travel","tub"]},{"name":"forward_10","tags":["10","arrow","control","controls","digit","fast","forward","music","number","play","seconds","symbol","video"]},{"name":"tablet_mac","tags":["Android","OS","device","hardware","iOS","ipad","mobile","tablet mac","web"]},{"name":"mode_night","tags":["dark","disturb","lunar","mode","moon","night","sleep"]},{"name":"broken_image","tags":["broken","corrupt","error","image","landscape","mountain","mountains","photo","photography","picture","torn"]},{"name":"escalator_warning","tags":["body","child","escalator","human","kid","parent","people","person","warning"]},{"name":"assistant","tags":["ai","artificial","assistant","automatic","automation","bubble","chat","comment","communicate","custom","feedback","genai","intelligence","magic","message","recommendation","smart","spark","sparkle","speech","star","suggestion","twinkle"]},{"name":"cases","tags":["bag","baggage","briefcase","business","case","cases","purse","suitcase"]},{"name":"wifi_tethering","tags":["cell","cellular","connection","data","internet","mobile","network","phone","scan","service","signal","speed","tethering","wifi","wireless"]},{"name":"reduce_capacity","tags":["arrow","body","capacity","covid","decrease","down","human","people","person","reduce","social"]},{"name":"colorize","tags":["color","colorize","dropper","extract","eye","picker","tool"]},{"name":"save_as","tags":["compose","create","data","disk","document","draft","drive","edit","editing","file","floppy","input","multimedia","pen","pencil","save","storage","write","writing"]},{"name":"card_travel","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","membership","miles","money","online","pay","payment","travel","trip"]},{"name":"emoji_food_beverage","tags":["beverage","coffee","cup","drink","emoji","mug","plate","set","tea"]},{"name":"font_download","tags":["A","alphabet","character","download","font","letter","square","symbol","text","type"]},{"name":"outbox","tags":["box","mail","outbox","send","sent"]},{"name":"battery_std","tags":["battery","cell","charge","mobile","plus","power","standard","std"]},{"name":"sick","tags":["covid","discomfort","emotions","expressions","face","feelings","fever","flu","ill","mood","pain","person","sick","survey","upset"]},{"name":"add_location","tags":["+","add","destination","direction","location","maps","new","pin","place","plus","stop","symbol"]},{"name":"try","tags":["bookmark","bubble","chat","comment","communicate","favorite","feedback","highlight","important","marked","message","save","saved","shape","special","speech","star","try"]},{"name":"discount","tags":[]},{"name":"man","tags":["boy","gender","male","man","social","symbol"]},{"name":"running_with_errors","tags":["!","alert","attention","caution","danger","duration","error","errors","exclamation","important","mark","notification","process","processing","running","symbol","time","warning","with"]},{"name":"diversity_3","tags":["committee","diverse","diversity","family","friends","group","groups","humans","network","people","persons","social","team"]},{"name":"filter_none","tags":["filter","multiple","none","square","stack"]},{"name":"cloud_sync","tags":["app","application","around","backup","cloud","connection","drive","files","folders","inprogress","internet","load","loading refresh","network","renew","rotate","sky","storage","turn","upload"]},{"name":"bloodtype","tags":["blood","bloodtype","donate","droplet","emergency","hospital","medicine","negative","positive","type","water"]},{"name":"dinner_dining","tags":["breakfast","dining","dinner","food","fork","lunch","meal","restaurant","spaghetti","utensils"]},{"name":"transfer_within_a_station","tags":["a","arrow","arrows","body","direction","human","left","maps","people","person","public","right","route","station","stop","transfer","transportation","vehicle","walk","within"]},{"name":"weekend","tags":["chair","couch","furniture","home","living","lounge","relax","room","weekend"]},{"name":"child_friendly","tags":["baby","care","carriage","child","children","friendly","infant","kid","newborn","stroller","toddler","young"]},{"name":"offline_pin","tags":["approve","check","checkmark","circle","complete","done","mark","offline","ok","pin","select","tick","validate","verified","yes"]},{"name":"replay_10","tags":["10","arrow","arrows","control","controls","digit","music","number","refresh","renew","repeat","replay","symbol","ten","video"]},{"name":"brightness_4","tags":["4","brightness","circle","control","crescent","level","moon","screen","sun"]},{"name":"cruelty_free","tags":["animal","bunny","cruelty","eco","free","nature","rabbit","social","sustainability","sustainable","testing"]},{"name":"format_paint","tags":["brush","color","doc","edit","editing","editor","fill","format","paint","roller","sheet","spreadsheet","style","text","type","writing"]},{"name":"filter_center_focus","tags":["camera","center","dot","edit","filter","focus","image","photo","photography","picture"]},{"name":"area_chart","tags":["analytics","area","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"bakery_dining","tags":["bakery","bread","breakfast","brunch","croissant","dining","food"]},{"name":"emoji_transportation","tags":["architecture","automobile","building","car","cars","direction","emoji","estate","maps","place","public","real","residence","residential","shelter","transportation","travel","vehicle"]},{"name":"folder_special","tags":["bookmark","data","doc","document","drive","favorite","file","folder","highlight","important","marked","save","saved","shape","sheet","slide","special","star","storage"]},{"name":"door_front","tags":["closed","door","doorway","entrance","exit","front","home","house","way"]},{"name":"calendar_view_day","tags":["calendar","date","day","event","format","grid","layout","month","schedule","today","view","week"]},{"name":"legend_toggle","tags":["analytics","chart","data","diagram","graph","infographic","legend","measure","metrics","monitoring","stackdriver","statistics","toggle","tracking"]},{"name":"light","tags":["bulb","ceiling","hanging","inside","interior","lamp","light","lighting","pendent","room"]},{"name":"find_replace","tags":["around","arrows","find","glass","inprogress","load","loading refresh","look","magnify","magnifying","renew","replace","rotate","search","see"]},{"name":"crop_original","tags":["adjust","adjustments","area","crop","edit","editing","frame","image","images","original","photo","photos","picture","settings","size"]},{"name":"rowing","tags":["activity","boat","body","canoe","human","people","person","row","rowing","sport","water"]},{"name":"enhanced_encryption","tags":["+","add","encryption","enhanced","lock","locked","new","password","plus","privacy","private","protection","safety","secure","security","symbol"]},{"name":"how_to_vote","tags":["ballot","election","how","poll","to","vote"]},{"name":"chrome_reader_mode","tags":["chrome","mode","read","reader","text"]},{"name":"auto_fix_normal","tags":["ai","artificial","auto","automatic","automation","custom","edit","erase","fix","genai","intelligence","magic","modify","smart","spark","sparkle","star","wand"]},{"name":"compress","tags":["arrow","arrows","collide","compress","pressure","push","together"]},{"name":"dehaze","tags":["adjust","dehaze","edit","editing","enhance","haze","image","lines","photo","photography","remove"]},{"name":"outlet","tags":["connect","connecter","electricity","outlet","plug","power"]},{"name":"desktop_mac","tags":["Android","OS","chrome","desktop","device","display","hardware","iOS","mac","monitor","screen","web","window"]},{"name":"nature_people","tags":["activity","body","forest","human","nature","outdoor","outside","park","people","person","tree","wilderness"]},{"name":"sports_tennis","tags":["athlete","athletic","ball","bat","entertainment","exercise","game","hobby","racket","social","sports","tennis"]},{"name":"forest","tags":["forest","jungle","nature","plantation","plants","trees","woodland"]},{"name":"upcoming","tags":["alarm","calendar","mail","message","notification","upcoming"]},{"name":"assignment_returned","tags":["arrow","assignment","clipboard","doc","document","down","returned"]},{"name":"cookie","tags":["biscuit","cookies","data","dessert","wafer"]},{"name":"fax","tags":["fax","machine","office","phone","send"]},{"name":"square","tags":["draw","four","shape quadrangle","sides","square"]},{"name":"density_medium","tags":["density","horizontal","lines","medium","rule","rules"]},{"name":"terrain","tags":["geography","landscape","mountain","terrain"]},{"name":"settings_brightness","tags":["brightness","dark","filter","light","mode","setting","settings"]},{"name":"attach_email","tags":["attach","attachment","clip","compose","email","envelop","letter","link","mail","message","send"]},{"name":"photo","tags":["image","mountain","mountains","photo","photography","picture"]},{"name":"http","tags":["alphabet","character","font","http","letter","symbol","text","transfer","type","url","website"]},{"name":"garage","tags":["automobile","automotive","car","cars","direction","garage","maps","transportation","travel","vehicle"]},{"name":"wine_bar","tags":["alcohol","bar","cocktail","cup","drink","glass","liquor","wine"]},{"name":"multiple_stop","tags":["arrows","directions","dots","left","maps","multiple","navigation","right","stop"]},{"name":"format_color_text","tags":["color","doc","edit","editing","editor","fill","format","paint","sheet","spreadsheet","style","text","type","writing"]},{"name":"gesture","tags":["drawing","finger","gesture","gestures","hand","motion"]},{"name":"heart_broken","tags":["break","broken","core","crush","health","heart","nucleus","split"]},{"name":"format_align_right","tags":["align","alignment","doc","edit","editing","editor","format","right","sheet","spreadsheet","text","type","writing"]},{"name":"transgender","tags":["female","gender","lgbt","male","neutral","social","symbol","transgender"]},{"name":"alarm_add","tags":["+","add","alarm","alert","bell","clock","countdown","date","new","notification","plus","schedule","symbol","time"]},{"name":"new_label","tags":["+","add","archive","bookmark","favorite","label","library","new","plus","read","reading","remember","ribbon","save","symbol","tag"]},{"name":"south_east","tags":["arrow","directional","down","east","maps","navigation","right","south"]},{"name":"backup_table","tags":["backup","drive","files folders","format","layout","stack","storage","table"]},{"name":"unsubscribe","tags":["cancel","close","email","envelop","letter","mail","message","newsletter","off","remove","send","subscribe","unsubscribe"]},{"name":"flash_off","tags":["bolt","disabled","electric","enabled","fast","flash","lightning","off","on","slash","thunderbolt"]},{"name":"elderly","tags":["body","cane","elderly","human","old","people","person","senior"]},{"name":"generating_tokens","tags":["access","ai","api","artificial","automatic","automation","coin","custom","genai","generating","intelligence","magic","smart","spark","sparkle","star","tokens"]},{"name":"spellcheck","tags":["a","alphabet","approve","character","check","font","letter","mark","ok","processor","select","spell","spellcheck","symbol","text","tick","type","word","write","yes"]},{"name":"auto_awesome_mosaic","tags":["adjust","auto","awesome","collage","edit","editing","enhance","image","mosaic","photo"]},{"name":"outdoor_grill","tags":["barbecue","bbq","charcoal","cooking","grill","home","house","outdoor","outside"]},{"name":"restore_page","tags":["arrow","data","doc","file","page","paper","refresh","restore","rotate","sheet","storage"]},{"name":"foundation","tags":["architecture","base","basis","building","construction","estate","foundation","home","house","real","residential"]},{"name":"credit_card_off","tags":["card","charge","commerce","cost","credit","disabled","enabled","finance","money","off","online","pay","payment","slash"]},{"name":"scatter_plot","tags":["analytics","bar","bars","chart","circles","data","diagram","dot","graph","infographic","measure","metrics","plot","scatter","statistics","tracking"]},{"name":"signal_cellular_4_bar","tags":["4","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","wifi","wireless"]},{"name":"add_moderator","tags":["+","add","certified","moderator","new","plus","privacy","private","protect","protection","security","shield","symbol","verified"]},{"name":"play_for_work","tags":["arrow","circle","down","google","half","play","work"]},{"name":"add_card","tags":["+","add","bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","new","online","pay","payment","plus","price","shopping","symbol"]},{"name":"app_settings_alt","tags":["Android","OS","app","applications","cell","device","gear","hardware","iOS","mobile","phone","setting","settings","tablet"]},{"name":"keyboard_tab","tags":["arrow","keyboard","left","next","right","tab"]},{"name":"wifi_protected_setup","tags":["around","arrow","arrows","protected","rotate","setup","wifi"]},{"name":"deck","tags":["chairs","deck","home","house","outdoors","outside","patio","social","terrace","umbrella","yard"]},{"name":"takeout_dining","tags":["box","container","delivery","dining","food","meal","restaurant","takeout"]},{"name":"tag_faces","tags":["emoji","emotion","faces","happy","satisfied","smile","tag"]},{"name":"brightness_6","tags":["6","brightness","circle","control","crescent","level","moon","screen","sun"]},{"name":"woman","tags":["female","gender","girl","lady","social","symbol","woman","women"]},{"name":"assistant_direction","tags":["assistant","destination","direction","location","maps","navigate","navigation","pin","place","right","stop"]},{"name":"brightness_5","tags":["5","brightness","circle","control","crescent","level","moon","screen","sun"]},{"name":"social_distance","tags":["6","apart","body","distance","ft","human","people","person","social","space"]},{"name":"free_cancellation","tags":["approve","calendar","cancel","cancellation","check","complete","date","day","done","event","exit","free","mark","month","no","ok","remove","schedule","select","stop","tick","validate","verified","x","yes"]},{"name":"subdirectory_arrow_left","tags":["arrow","directory","down","left","navigation","sub","subdirectory"]},{"name":"laptop_chromebook","tags":["Android","OS","chrome","chromebook","device","display","hardware","iOS","laptop","mac chromebook","monitor","screen","web","window"]},{"name":"format_list_numbered_rtl","tags":["align","alignment","digit","doc","edit","editing","editor","format","list","notes","number","numbered","rtl","sheet","spreadsheet","symbol","text","type","writing"]},{"name":"store_mall_directory","tags":["directory","mall","store"]},{"name":"settings_overscan","tags":["arrows","expand","image","photo","picture","scan","settings"]},{"name":"icecream","tags":["cream","dessert","food","ice","icecream","snack"]},{"name":"details","tags":["details","edit","editing","enhance","image","photo","photography","sharpen","triangle"]},{"name":"add_reaction","tags":["+","add","emoji","emotions","expressions","face","feelings","glad","happiness","happy","icon","icons","insert","like","mood","new","person","pleased","plus","smile","smiling","social","survey","symbol"]},{"name":"follow_the_signs","tags":["arrow","body","directional","follow","human","people","person","right","signs","social","the"]},{"name":"attribution","tags":["attribute","attribution","body","copyright","copywriter","human","people","person"]},{"name":"food_bank","tags":["architecture","bank","building","charity","eat","estate","food","fork","house","knife","meal","place","real","residence","residential","shelter","utensils"]},{"name":"closed_caption","tags":["accessible","alphabet","caption","cc","character","closed","decoder","font","language","letter","media","movies","subtitle","subtitles","symbol","text","tv","type"]},{"name":"gif","tags":["alphabet","animated","animation","bitmap","character","font","format","gif","graphics","interchange","letter","symbol","text","type"]},{"name":"phonelink","tags":["Android","OS","chrome","computer","connect","desktop","device","hardware","iOS","link","mac","mobile","phone","phonelink","sync","tablet","web","windows"]},{"name":"grain","tags":["dots","edit","editing","effect","filter","grain","image","images","photography","picture","pictures"]},{"name":"personal_injury","tags":["accident","aid","arm","bandage","body","broke","cast","fracture","health","human","injury","medical","patient","people","person","personal","sling","social"]},{"name":"flip_camera_android","tags":["android","camera","center","edit","editing","flip","image","mobile","orientation","rotate","turn"]},{"name":"museum","tags":["architecture","attraction","building","estate","event","exhibition","explore","local","museum","places","real","see","shop","store","tour"]},{"name":"north_west","tags":["arrow","directional","left","maps","navigation","north","up","west"]},{"name":"gite","tags":["architecture","estate","gite","home","hostel","house","maps","place","real","residence","residential","stay","traveling"]},{"name":"highlight","tags":["color","doc","edit","editing","editor","emphasize","fill","flash","format","highlight","light","paint","sheet","spreadsheet","style","text","type","writing"]},{"name":"brightness_1","tags":["1","brightness","circle","control","crescent","level","moon","screen"]},{"name":"plus_one","tags":["1","add","digit","increase","number","one","plus","symbol"]},{"name":"villa","tags":["architecture","beach","estate","home","house","maps","place","real","residence","residential","traveling","vacation stay","villa"]},{"name":"fmd_bad","tags":["!","alert","attention","bad","caution","danger","destination","direction","error","exclamation","fmd","important","location","maps","mark","notification","pin","place","symbol","warning"]},{"name":"flashlight_on","tags":["disabled","enabled","flash","flashlight","light","off","on","slash"]},{"name":"flip","tags":["edit","editing","flip","image","orientation","scan scanning"]},{"name":"nightlife","tags":["alcohol","bar","bottle","club","cocktail","dance","drink","food","glass","liquor","music","nightlife","note","wine"]},{"name":"present_to_all","tags":["all","arrow","present","presentation","screen","share","site","slides","to","web","website"]},{"name":"do_disturb","tags":["cancel","close","denied","deny","disturb","do","remove","silence","stop"]},{"name":"outbound","tags":["arrow","circle","directional","outbound","right","up"]},{"name":"local_pharmacy","tags":["911","aid","cross","emergency","first","hospital","local","medicine","pharmacy","places"]},{"name":"splitscreen","tags":["column","grid","layout","multitasking","row","screen","split","splitscreen","two"]},{"name":"waterfall_chart","tags":["analytics","bar","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking","waterfall"]},{"name":"switch_left","tags":["arrows","directional","left","navigation","switch","toggle"]},{"name":"domain_verification","tags":["app","application desktop","approve","check","complete","design","domain","done","interface","internet","layout","mark","ok","screen","select","site","tick","ui","ux","validate","verification","verified","web","website","window","www","yes"]},{"name":"fireplace","tags":["chimney","fire","fireplace","flame","home","house","living","pit","place","room","warm","winter"]},{"name":"video_settings","tags":["change","details","gear","info","information","options","play","screen","service","setting","settings","video","window"]},{"name":"disabled_visible","tags":["cancel","close","disabled","exit","eye","no","on","quit","remove","reveal","see","show","stop","view","visibility","visible"]},{"name":"network_wifi","tags":["cell","cellular","data","internet","mobile","network","phone","speed","wifi","wireless"]},{"name":"quickreply","tags":["bolt","bubble","chat","comment","communicate","fast","lightning","message","quick","quickreply","reply","speech","thunderbolt"]},{"name":"swap_vertical_circle","tags":["arrow","arrows","circle","down","swap","up","vertical"]},{"name":"format_align_justify","tags":["align","alignment","density","doc","edit","editing","editor","extra","format","justify","sheet","small","spreadsheet","text","type","writing"]},{"name":"settings_input_composite","tags":["component","composite","connection","connectivity","input","plug","points","settings"]},{"name":"loupe","tags":["+","add","details","focus","glass","loupe","magnifying","new","plus","symbol"]},{"name":"123","tags":["1","2","3","digit","number","symbol"]},{"name":"network_check","tags":["check","connect","connection","internet","meter","network","signal","speed","tick","wifi","wireless"]},{"name":"sms_failed","tags":["!","alert","attention","bubbles","caution","chat","communication","conversation","danger","error","exclamation","failed","feedback","important","mark","message","notification","service","sms","speech","symbol","warning"]},{"name":"cancel_schedule_send","tags":["cancel","email","mail","no","quit","remove","schedule","send","share","stop","x"]},{"name":"work_history","tags":["back","backwards","bag","baggage","briefcase","business","case","clock","date","history","job","pending","recent","schedule","suitcase","time","updates","work"]},{"name":"electric_bolt","tags":["bolt","electric","energy","fast","lightning","nest","thunderbolt"]},{"name":"view_day","tags":["cards","carousel","day","design","format","grid","layout","view","website"]},{"name":"night_shelter","tags":["architecture","bed","building","estate","homeless","house","night","place","real","shelter","sleep"]},{"name":"monitor","tags":["Android","OS","chrome","device","display","hardware","iOS","mac","monitor","screen","web","window"]},{"name":"clean_hands","tags":["bacteria","clean","disinfect","germs","gesture","hand","hands","sanitize","sanitizer"]},{"name":"mark_chat_read","tags":["approve","bubble","chat","check","comment","communicate","complete","done","mark","message","ok","read","select","sent","speech","tick","verified","yes"]},{"name":"comment_bank","tags":["archive","bank","bookmark","bubble","cchat","comment","communicate","favorite","label","library","message","remember","ribbon","save","speech","tag"]},{"name":"sim_card_download","tags":["arrow","camera","card","chip","device","down","download","memory","phone","sim","storage"]},{"name":"lan","tags":["computer","connection","data","internet","lan","network","service"]},{"name":"piano","tags":["instrument","keyboard","keys","music","musical","piano","social"]},{"name":"add_road","tags":["+","add","destination","direction","highway","maps","new","plus","road","stop","street","symbol","traffic"]},{"name":"add_ic_call","tags":["+","add","call","cell","contact","device","hardware","mobile","new","phone","plus","symbol","telephone"]},{"name":"rule_folder","tags":["approve","cancel","check","close","complete","data","doc","document","done","drive","exit","file","folder","mark","no","ok","remove","rule","select","sheet","slide","storage","tick","validate","verified","x","yes"]},{"name":"switch_access_shortcut","tags":["access","arrow","arrows","direction","navigation","new","north","shortcut","switch","symbol","up"]},{"name":"hardware","tags":["break","construction","hammer","hardware","nail","repair","tool"]},{"name":"line_weight","tags":["height","line","size","spacing","style","thickness","weight"]},{"name":"image_not_supported","tags":["disabled","enabled","image","landscape","mountain","mountains","not","off","on","photo","photography","picture","slash","supported"]},{"name":"flip_camera_ios","tags":["DISABLE_IOS","android","camera","disable_ios","edit","editing","flip","image","ios","mobile","orientation","rotate","turn"]},{"name":"phone_callback","tags":["arrow","call","callback","cell","contact","device","down","hardware","mobile","phone","telephone"]},{"name":"access_time_filled","tags":[]},{"name":"dining","tags":["cafe","cafeteria","cutlery","diner","dining","eat","eating","fork","room","spoon"]},{"name":"scale","tags":["measure","monitor","scale","weight"]},{"name":"airplanemode_active","tags":["active","airplane","airplanemode","flight","mode","on","signal"]},{"name":"set_meal","tags":["chopsticks","dinner","fish","food","lunch","meal","restaurant","set","teishoku"]},{"name":"mobile_friendly","tags":["Android","OS","approve","cell","check","complete","device","done","friendly","hardware","iOS","mark","mobile","ok","phone","select","tablet","tick","validate","verified","yes"]},{"name":"assured_workload","tags":["assured","compliance","confidential","federal","government","secure","sensitive regulatory","workload"]},{"name":"wallet","tags":[]},{"name":"merge_type","tags":["arrow","combine","direction","format","merge","text","type"]},{"name":"view_timeline","tags":["grid","layout","pattern","squares","timeline","view"]},{"name":"departure_board","tags":["automobile","board","bus","car","cars","clock","departure","maps","public","schedule","time","transportation","travel","vehicle"]},{"name":"event_repeat","tags":["around","calendar","date","day","event","inprogress","load","loading refresh","month","renew","rotate","schedule","turn"]},{"name":"sanitizer","tags":["bacteria","bottle","clean","covid","disinfect","germs","pump","sanitizer"]},{"name":"surfing","tags":["athlete","athletic","beach","body","entertainment","exercise","hobby","human","people","person","sea","social sports","sports","summer","surfing","water"]},{"name":"pix","tags":["bill","brazil","card","cash","commerce","credit","currency","finance","money","payment"]},{"name":"phonelink_ring","tags":["Android","OS","cell","connection","data","device","hardware","iOS","mobile","network","phone","phonelink","ring","service","signal","tablet","wireless"]},{"name":"display_settings","tags":["Android","OS","application","change","chrome","desktop","details","device","display","gear","hardware","iOS","info","information","mac","monitor","options","personal","screen","service","settings","web","window"]},{"name":"sports_motorsports","tags":["athlete","athletic","automobile","bike","drive","driving","entertainment","helmet","hobby","motorcycle","motorsports","protect","social","sports","vehicle"]},{"name":"horizontal_split","tags":["bars","format","horizontal","layout","lines","split","stacked"]},{"name":"view_comfy","tags":["comfy","grid","layout","pattern","squares","view"]},{"name":"polymer","tags":["emblem","logo","mark","polymer"]},{"name":"golf_course","tags":["athlete","athletic","ball","club","course","entertainment","flag","golf","golfer","golfing","hobby","hole","places","putt","sports"]},{"name":"batch_prediction","tags":["batch","bulb","idea","light","prediction"]},{"name":"filter_1","tags":["1","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"stay_current_portrait","tags":["Android","OS","current","device","hardware","iOS","mobile","phone","portrait","stay","tablet"]},{"name":"usb","tags":["cable","connection","device","usb","wire"]},{"name":"featured_play_list","tags":["collection","featured","highlighted","list","music","play","playlist","recommended"]},{"name":"data_object","tags":["brackets","code","coder","data","object","parentheses"]},{"name":"co_present","tags":["arrow","co-present","presentation","screen","share","site","slides","togather","web","website"]},{"name":"ev_station","tags":["automobile","car","cars","charging","electric","electricity","ev","maps","places","station","transportation","vehicle"]},{"name":"send_and_archive","tags":["archive","arrow","down","download","email","letter","mail","save","send","share"]},{"name":"send_to_mobile","tags":["Android","OS","arrow","device","export","forward","hardware","iOS","mobile","phone","right","send","share","tablet","to"]},{"name":"local_see","tags":["camera","lens","local","photo","photography","picture","see"]},{"name":"satellite_alt","tags":["alternative","artificial","communication","satellite","space","space station","television"]},{"name":"flatware","tags":["cafe","cafeteria","cutlery","diner","dining","eat","eating","fork","room","spoon"]},{"name":"speaker","tags":["box","electronic","loud","music","sound","speaker","stereo","system","video"]},{"name":"adb","tags":["adb","android","bridge","debug"]},{"name":"movie_creation","tags":["cinema","clapperboard","creation","film","movie","movies","slate","video"]},{"name":"picture_in_picture","tags":["crop","cropped","overlap","photo","picture","position","shape"]},{"name":"call_received","tags":["arrow","call","device","mobile","received"]},{"name":"battery_alert","tags":["!","alert","attention","battery","caution","cell","charge","danger","error","exclamation","important","mark","mobile","notification","power","symbol","warning"]},{"name":"system_update","tags":["Android","OS","arrow","arrows","cell","device","direction","down","download","hardware","iOS","install","mobile","phone","system","tablet","update"]},{"name":"webhook","tags":["api","developer","development","enterprise","software","webhook"]},{"name":"add_chart","tags":["+","add","analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","new","plus","statistics","symbol","tracking"]},{"name":"pan_tool_alt","tags":["fingers","gesture","hand","hands","human","move","pan","scan","stop","tool"]},{"name":"sports_handball","tags":["athlete","athletic","ball","body","entertainment","exercise","game","handball","hobby","human","people","person","social","sports"]},{"name":"electric_car","tags":["automobile","car","cars","electric","electricity","maps","transportation","travel","vehicle"]},{"name":"phone_forwarded","tags":["arrow","call","cell","contact","device","direction","forwarded","hardware","mobile","phone","right","telephone"]},{"name":"add_to_photos","tags":["add","collection","image","landscape","mountain","mountains","photo","photography","photos","picture","plus","to"]},{"name":"power_off","tags":["charge","cord","disabled","electric","electrical","enabled","off","on","outlet","plug","power","slash"]},{"name":"noise_control_off","tags":["audio","aware","cancel","cancellation","control","disabled","enabled","music","noise","note","off","offline","on","slash","sound"]},{"name":"code_off","tags":["brackets","code","css","develop","developer","disabled","enabled","engineer","engineering","html","off","on","platform","slash"]},{"name":"bookmark_remove","tags":["bookmark","delete","favorite","minus","remember","remove","ribbon","save","subtract"]},{"name":"screen_search_desktop","tags":["Android","OS","arrow","desktop","device","hardware","iOS","lock","monitor","rotate","screen","web"]},{"name":"panorama","tags":["angle","image","mountain","mountains","panorama","photo","photography","picture","view","wide"]},{"name":"settings_bluetooth","tags":["bluetooth","connect","connection","connectivity","device","settings","signal","symbol"]},{"name":"sports_baseball","tags":["athlete","athletic","ball","baseball","entertainment","exercise","game","hobby","social","sports"]},{"name":"festival","tags":["circus","event","festival","local","maps","places","tent","tour","travel"]},{"name":"lens_blur","tags":["blur","camera","dim","dot","effect","foggy","fuzzy","image","lens","photo","soften"]},{"name":"plumbing","tags":["build","construction","fix","handyman","plumbing","repair","tools","wrench"]},{"name":"toys","tags":["car","games","kids","toy","toys","windmill"]},{"name":"coffee_maker","tags":["appliances","beverage","coffee","cup","drink","machine","maker","mug"]},{"name":"edit_notifications","tags":["active","alarm","alert","bell","chime","compose","create","draft","edit","editing","input","new","notifications","notify","pen","pencil","reminder","ring","sound","write","writing"]},{"name":"personal_video","tags":["Android","OS","cam","chrome","desktop","device","hardware","iOS","mac","monitor","personal","television","tv","video","web","window"]},{"name":"animation","tags":["animation","circles","film","motion","movement","sequence","video"]},{"name":"bedtime","tags":["bedtime","nightime","sleep"]},{"name":"gamepad","tags":["buttons","console","controller","device","game","gamepad","gaming","playstation","video"]},{"name":"diversity_1","tags":["committee","diverse","diversity","family","friends","group","groups","heart","humans","network","people","persons","social","team"]},{"name":"center_focus_weak","tags":["camera","center","focus","image","lens","photo","photography","weak","zoom"]},{"name":"signal_wifi_statusbar_4_bar","tags":["4","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","statusbar","wifi","wireless"]},{"name":"manage_history","tags":["application","arrow","back","backwards","change","clock","date","details","gear","history","options","refresh","renew","reverse","rotate","schedule","settings","time","turn"]},{"name":"folder_zip","tags":["compress","data","doc","document","drive","file","folder","folders","open","sheet","slide","storage","zip"]},{"name":"flag_circle","tags":["circle","country","flag","goal","mark","nation","report","round","start"]},{"name":"south_west","tags":["arrow","directional","down","left","maps","navigation","south","west"]},{"name":"looks_4","tags":["4","digit","looks","numbers","square","symbol"]},{"name":"cloud_circle","tags":["app","application","backup","circle","cloud","connection","drive","files","folders","internet","network","sky","storage","upload"]},{"name":"format_shapes","tags":["alphabet","character","color","doc","edit","editing","editor","fill","font","format","letter","paint","shapes","sheet","spreadsheet","style","symbol","text","type","writing"]},{"name":"car_rental","tags":["automobile","car","cars","key","maps","rental","transportation","vehicle"]},{"name":"movie_filter","tags":["ai","artificial","automatic","automation","clapperboard","creation","custom","film","filter","genai","intelligence","magic","movie","movies","slate","smart","spark","sparkle","star","stars","video"]},{"name":"layers_clear","tags":["arrange","clear","delete","disabled","enabled","interaction","layers","maps","off","on","overlay","pages","slash"]},{"name":"phonelink_lock","tags":["Android","OS","cell","connection","device","erase","hardware","iOS","lock","locked","mobile","password","phone","phonelink","privacy","private","protection","safety","secure","security","tablet"]},{"name":"attractions","tags":["amusement","attractions","entertainment","ferris","fun","maps","park","places","wheel"]},{"name":"playlist_add_check_circle","tags":["add","album","artist","audio","cd","check","circle","collection","list","mark","music","playlist","record","sound","track"]},{"name":"hive","tags":["bee","honey","honeycomb"]},{"name":"no_photography","tags":["camera","disabled","enabled","image","no","off","on","photo","photography","picture","slash"]},{"name":"content_paste_go","tags":["clipboard","content","disabled","doc","document","enabled","file","go","on","paste","slash"]},{"name":"shop_two","tags":["add","arrow","buy","cart","google","play","purchase","shop","shopping","two"]},{"name":"edit_location","tags":["destination","direction","edit","location","maps","pen","pencil","pin","place","stop"]},{"name":"screen_rotation","tags":["Android","OS","arrow","device","hardware","iOS","mobile","phone","rotate","rotation","screen","tablet","turn"]},{"name":"numbers","tags":["digit","number","numbers","symbol"]},{"name":"sim_card","tags":["camera","card","chip","device","memory","phone","sim","storage"]},{"name":"control_camera","tags":["adjust","arrow","arrows","camera","center","control","direction","left","move","right"]},{"name":"blender","tags":["appliance","blender","cooking","electric","juicer","kitchen","machine","vitamix"]},{"name":"flip_to_front","tags":["arrange","arrangement","back","flip","format","front","layout","move","order","sort","to"]},{"name":"sports_volleyball","tags":["athlete","athletic","ball","entertainment","exercise","game","hobby","social","sports","volleyball"]},{"name":"stairs","tags":["down","staircase","stairs","up"]},{"name":"keyboard_alt","tags":["alt","computer","device","hardware","input","keyboard","keypad","letter","office","text","type"]},{"name":"crop_din","tags":["adjust","adjustments","area","crop","din","edit","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"html","tags":["alphabet","brackets","character","code","css","develop","developer","engineer","engineering","font","html","letter","platform","symbol","text","type"]},{"name":"signal_wifi_statusbar_connected_no_internet_4","tags":["!","4","alert","attention","caution","cell","cellular","connected","danger","data","error","exclamation","important","internet","mark","mobile","network","no","notification","phone","signal","speed","statusbar","symbol","warning","wifi","wireless"]},{"name":"pivot_table_chart","tags":["analytics","arrow","arrows","bar","bars","chart","data","diagram","direction","drive","edit","editing","graph","grid","infographic","measure","metrics","pivot","rotate","sheet","statistics","table","tracking"]},{"name":"microwave","tags":["appliance","cooking","electric","heat","home","house","kitchen","machine","microwave"]},{"name":"folder_copy","tags":["content","copy","cut","data","doc","document","drive","duplicate","file","folder","folders","multiple","paste","sheet","slide","storage"]},{"name":"output","tags":[]},{"name":"gif_box","tags":["alphabet","animated","animation","bitmap","character","font","format","gif","graphics","interchange","letter","symbol","text","type"]},{"name":"voice_chat","tags":["bubble","cam","camera","chat","comment","communicate","facetime","feedback","message","speech","video","voice"]},{"name":"local_convenience_store","tags":["--","24","bill","building","business","card","cash","coin","commerce","company","convenience","credit","currency","dollars","local","maps","market","money","new","online","pay","payment","plus","shop","shopping","store","storefront","symbol"]},{"name":"gps_not_fixed","tags":["destination","direction","disabled","enabled","gps","location","maps","not fixed","off","on","online","place","pointer","slash","tracking"]},{"name":"high_quality","tags":["alphabet","character","definition","display","font","high","hq","letter","movie","movies","quality","resolution","screen","symbol","text","tv","type"]},{"name":"switch_right","tags":["arrows","directional","navigation","right","switch","toggle"]},{"name":"pages","tags":["article","gplus","pages","paper","post","star"]},{"name":"table_restaurant","tags":["bar","dining","table"]},{"name":"speaker_notes_off","tags":["bubble","chat","comment","communicate","disabled","enabled","format","list","message","notes","off","on","slash","speaker","speech","text"]},{"name":"phone_disabled","tags":["call","cell","contact","device","disabled","enabled","hardware","mobile","off","offline","on","phone","slash","telephone"]},{"name":"eject","tags":["disc","drive","dvd","eject","remove","triangle","usb"]},{"name":"control_point_duplicate","tags":["+","add","circle","control","duplicate","multiple","new","plus","point","symbol"]},{"name":"filter","tags":["edit","editing","effect","filter","image","landscape","mountain","mountains","photo","photography","picture","settings"]},{"name":"pest_control","tags":["bug","control","exterminator","insects","pest"]},{"name":"backpack","tags":["back","backpack","bag","book","bookbag","knapsack","pack","storage","travel"]},{"name":"leak_add","tags":["add","connection","data","leak","link","network","service","signals","synce","wireless"]},{"name":"zoom_in_map","tags":["arrow","arrows","destination","in","location","maps","move","place","stop","zoom"]},{"name":"brightness_7","tags":["7","brightness","circle","control","crescent","level","moon","screen","sun"]},{"name":"system_security_update_good","tags":["Android","OS","approve","cell","check","complete","device","done","good","hardware","iOS","mark","mobile","ok","phone","security","select","system","tablet","tick","update","validate","verified","yes"]},{"name":"ring_volume","tags":["call","calling","cell","contact","device","hardware","incoming","mobile","phone","ring","ringer","sound","telephone","volume"]},{"name":"money_off_csred","tags":["bill","card","cart","cash","coin","commerce","credit","csred","currency","disabled","dollars","enabled","money","off","on","online","pay","payment","shopping","slash","symbol"]},{"name":"sports_football","tags":["athlete","athletic","ball","entertainment","exercise","football","game","hobby","social","sports"]},{"name":"nature","tags":["forest","nature","outdoor","outside","park","tree","wilderness"]},{"name":"vibration","tags":["Android","OS","alert","cell","device","hardware","iOS","mobile","mode","motion","notification","phone","silence","silent","tablet","vibrate","vibration"]},{"name":"snippet_folder","tags":["data","doc","document","drive","file","folder","sheet","slide","snippet","storage"]},{"name":"edit_road","tags":["destination","direction","edit","highway","maps","pen","pencil","road","street","traffic"]},{"name":"run_circle","tags":["body","circle","exercise","human","people","person","run","running"]},{"name":"dry_cleaning","tags":["cleaning","dry","hanger","hotel","laundry","places","service","towel"]},{"name":"alarm_off","tags":["alarm","alert","bell","clock","disabled","duration","enabled","notification","off","on","slash","time","timer","watch"]},{"name":"perm_data_setting","tags":["data","gear","info","information","perm","settings"]},{"name":"bedroom_parent","tags":["bed","bedroom","double","full","furniture","home","hotel","house","king","night","parent","pillows","queen","rest","room","sizem master","sleep"]},{"name":"airline_seat_recline_normal","tags":["airline","body","extra","feet","human","leg","legroom","normal","people","person","recline","seat","sitting","space","travel"]},{"name":"currency_bitcoin","tags":["bill","blockchain","card","cash","coin","commerce","cost","credit","currency","digital","dollars","finance","franc","money","online","pay","payment","price","shopping","symbol"]},{"name":"do_disturb_alt","tags":["cancel","close","denied","deny","disturb","do","remove","silence","stop"]},{"name":"sensor_window","tags":["alarm","security","security system"]},{"name":"incomplete_circle","tags":["chart","circle","incomplete"]},{"name":"settings_input_hdmi","tags":["cable","connection","connectivity","definition","hdmi","high","input","plug","plugin","points","settings","video","wire"]},{"name":"camera_indoor","tags":["architecture","building","camera","estate","film","filming","home","house","image","indoor","inside","motion","nest","picture","place","real","residence","residential","shelter","video","videography"]},{"name":"edit_location_alt","tags":["alt","edit","location","pen","pencil","pin"]},{"name":"texture","tags":["diagonal","lines","pattern","stripes","texture"]},{"name":"location_off","tags":["destination","direction","location","maps","off","pin","place","room","stop"]},{"name":"edit_attributes","tags":["approve","attribution","check","complete","done","edit","mark","ok","select","tick","validate","verified","yes"]},{"name":"duo","tags":["call","chat","conference","device","duo","video"]},{"name":"slow_motion_video","tags":["arrow","control","controls","motion","music","play","slow","speed","video"]},{"name":"perm_scan_wifi","tags":["alert","announcement","connection","info","information","internet","network","perm","scan","service","signal","wifi","wireless"]},{"name":"phonelink_setup","tags":["Android","OS","call","chat","device","hardware","iOS","info","mobile","phone","phonelink","settings","setup","tablet","text"]},{"name":"hourglass_disabled","tags":["clock","countdown","disabled","empty","enabled","hourglass","loading","minute","minutes","off","on","slash","time","wait","waiting"]},{"name":"add_to_queue","tags":["+","Android","OS","add","chrome","desktop","device","display","hardware","iOS","mac","monitor","new","plus","queue","screen","symbol","to","web","window"]},{"name":"pie_chart_outline","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","outline","pie","statistics","tracking"]},{"name":"playlist_remove","tags":["-","collection","list","minus","music","playlist","remove"]},{"name":"next_week","tags":["arrow","bag","baggage","briefcase","business","case","next","suitcase","week"]},{"name":"church","tags":["christian","christianity","religion","spiritual","worship"]},{"name":"medical_information","tags":["badge","card","health","id","information","medical","services"]},{"name":"view_compact","tags":["compact","grid","layout","pattern","squares","view"]},{"name":"timer_off","tags":["alarm","alert","bell","clock","disabled","duration","enabled","notification","off","on","slash","stop","time","timer","watch"]},{"name":"bluetooth_connected","tags":["bluetooth","cast","connect","connection","device","paring","streaming","symbol","wireless"]},{"name":"photo_size_select_actual","tags":["actual","image","mountain","mountains","photo","photography","picture","select","size"]},{"name":"short_text","tags":["brief","comment","doc","document","note","short","text","write","writing"]},{"name":"bedroom_baby","tags":["babies","baby","bedroom","child","children","home","horse","house","infant","kid","newborn","rocking","room","toddler","young"]},{"name":"video_camera_back","tags":["back","camera","image","landscape","mountain","mountains","photo","photography","picture","rear","video"]},{"name":"bathroom","tags":["bath","bathroom","closet","home","house","place","plumbing","room","shower","sprinkler","wash","water","wc"]},{"name":"downhill_skiing","tags":["athlete","athletic","body","downhill","entertainment","exercise","hobby","human","people","person","ski social","skiing","snow","sports","travel","winter"]},{"name":"filter_list_off","tags":["alt","disabled","edit","filter","list","off","offline","options","refine","sift","slash"]},{"name":"connected_tv","tags":["Android","OS","airplay","chrome","connect","connected","desktop","device","display","hardware","iOS","mac","monitor","screen","screencast","streaming","television","tv","web","window","wireless"]},{"name":"format_indent_increase","tags":["align","alignment","doc","edit","editing","editor","format","increase","indent","indentation","paragraph","sheet","spreadsheet","text","type","writing"]},{"name":"settings_cell","tags":["Android","OS","cell","device","hardware","iOS","mobile","phone","settings","tablet"]},{"name":"remember_me","tags":["Android","OS","avatar","device","hardware","human","iOS","identity","me","mobile","people","person","phone","profile","remember","tablet","user"]},{"name":"kayaking","tags":["athlete","athletic","body","canoe","entertainment","exercise","hobby","human","kayak","kayaking","lake","paddle","paddling","people","person","rafting","river","row","social","sports","summer","travel","water"]},{"name":"switch_access_shortcut_add","tags":["+","access","add","arrow","arrows","direction","navigation","new","north","plus","shortcut","switch","symbol","up"]},{"name":"app_blocking","tags":["Android","OS","app","application","block","blocking","cancel","cell","device","hardware","iOS","mobile","phone","stop","stopped","tablet"]},{"name":"elevator","tags":["body","down","elevator","human","people","person","up"]},{"name":"work_off","tags":["bag","baggage","briefcase","business","case","disabled","enabled","job","off","on","slash","suitcase","work"]},{"name":"sensors_off","tags":["connection","disabled","enabled","network","off","on","scan","sensors","signal","slash","wireless"]},{"name":"stay_primary_portrait","tags":["Android","OS","current","device","hardware","iOS","mobile","phone","portrait","primary","stay","tablet"]},{"name":"cell_tower","tags":["broadcast","casting","cell","network","signal","tower","transmitting","wireless"]},{"name":"moped","tags":["automobile","bike","car","cars","maps","scooter","transportation","vehicle","vespa"]},{"name":"wrong_location","tags":["cancel","close","destination","direction","exit","location","maps","no","pin","place","quit","remove","stop","wrong","x"]},{"name":"groups_2","tags":["body","club","collaboration","crowd","gathering","groups","hair","human","meeting","people","person","social","teams"]},{"name":"public_off","tags":["disabled","earth","enabled","global","globe","map","network","off","on","planet","public","slash","social","space","web","world"]},{"name":"picture_in_picture_alt","tags":["crop","cropped","overlap","photo","picture","position","shape"]},{"name":"chair_alt","tags":["cahir","furniture","home","house","kitchen","lounging","seating","table"]},{"name":"car_repair","tags":["automobile","car","cars","maps","repair","transportation","vehicle"]},{"name":"airplay","tags":["airplay","arrow","connect","control","desktop","device","display","monitor","screen","signal"]},{"name":"nfc","tags":["communication","data","field","mobile","near","nfc","wireless"]},{"name":"line_style","tags":["dash","dotted","line","rule","spacing","style"]},{"name":"transform","tags":["adjust","crop","edit","editing","image","photo","picture","transform"]},{"name":"single_bed","tags":["bed","bedroom","double","furniture","home","hotel","house","king","night","pillows","queen","rest","room","single","sleep","twin"]},{"name":"pattern","tags":["key","login","password","pattern","pin","security","star","unlock"]},{"name":"local_movies","tags":[]},{"name":"repeat_one","tags":["1","arrow","arrows","control","controls","digit","media","music","number","one","repeat","symbol","video"]},{"name":"swap_calls","tags":["arrow","arrows","calls","device","direction","mobile","share","swap"]},{"name":"do_not_disturb_alt","tags":["cancel","close","denied","deny","disturb","do","remove","silence","stop"]},{"name":"smoking_rooms","tags":["allowed","cigarette","places","rooms","smoke","smoking","tobacco","zone"]},{"name":"remove_moderator","tags":["certified","disabled","enabled","moderator","off","on","privacy","private","protect","protection","remove","security","shield","slash","verified"]},{"name":"perm_device_information","tags":["Android","OS","alert","announcement","device","hardware","i","iOS","info","information","mobile","perm","phone","tablet"]},{"name":"wash","tags":["bathroom","clean","fingers","gesture","hand","wash","wc"]},{"name":"mode_standby","tags":["disturb","mode","power","sleep","standby","target"]},{"name":"door_sliding","tags":["auto","automatic","door","doorway","double","entrance","exit","glass","home","house","sliding","two"]},{"name":"skateboarding","tags":["athlete","athletic","body","entertainment","exercise","hobby","human","people","person","skate","skateboarder","skateboarding","social","sports"]},{"name":"difference","tags":["compare","content","copy","cut","diff","difference","doc","document","duplicate","file","multiple","past"]},{"name":"group_remove","tags":["accounts","committee","face","family","friends","group","humans","network","people","persons","profiles","remove","social","team","users"]},{"name":"brightness_high","tags":["auto","brightness","control","high","mobile","monitor","phone","sun"]},{"name":"cabin","tags":["architecture","cabin","camping","cottage","estate","home","house","log","maps","place","real","residence","residential","stay","traveling","wood"]},{"name":"camera_outdoor","tags":["architecture","building","camera","estate","film","filming","home","house","image","motion","nest","outdoor","outside","picture","place","real","residence","residential","shelter","video","videography"]},{"name":"troubleshoot","tags":["analytics","chart","data","diagram","find","glass","graph","infographic","line","look","magnify","magnifying","measure","metrics","search","see","statistics","tracking","troubleshoot"]},{"name":"tablet_android","tags":["OS","android","device","hardware","iOS","ipad","mobile","tablet","web"]},{"name":"house_siding","tags":["architecture","building","construction","estate","exterior","facade","home","house","real","residential","siding"]},{"name":"satellite","tags":["bluetooth","connect","connection","connectivity","data","device","image","internet","landscape","location","maps","mountain","mountains","network","photo","photography","picture","satellite","scan","service","signal","symbol","wireless-- wifi"]},{"name":"motion_photos_on","tags":["animation","circle","disabled","enabled","motion","off","on","photos","play","slash","video"]},{"name":"door_back","tags":["back","closed","door","doorway","entrance","exit","home","house","way"]},{"name":"strikethrough_s","tags":["alphabet","character","cross","doc","edit","editing","editor","font","letter","out","s","sheet","spreadsheet","strikethrough","styles","symbol","text","type","writing"]},{"name":"co2","tags":["carbon","chemical","co2","dioxide","gas"]},{"name":"notifications_paused","tags":["active","alarm","alert","bell","chime","ignore","notifications","notify","paused","quiet","reminder","ring --- pause","sleep","snooze","sound","z","zzz"]},{"name":"currency_yen","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","shopping","symbol","yen"]},{"name":"call_to_action","tags":["action","alert","bar","call","components","cta","design","info","information","interface","layout","message","notification","screen","site","to","ui","ux","web","website","window"]},{"name":"photo_camera_front","tags":["account","camera","face","front","human","image","people","person","photo","photography","picture","portrait","profile","user"]},{"name":"directions_boat_filled","tags":["automobile","boat","car","cars","direction","directions","ferry","filled","maps","public","transportation","vehicle"]},{"name":"subtitles_off","tags":["accessibility","accessible","caption","cc","closed","disabled","enabled","language","off","on","slash","subtitle","subtitles","translate","video"]},{"name":"rotate_90_degrees_ccw","tags":["90","arrow","arrows","ccw","degrees","direction","edit","editing","image","photo","rotate","turn"]},{"name":"vertical_align_center","tags":["align","alignment","arrow","center","doc","down","edit","editing","editor","sheet","spreadsheet","text","type","up","vertical","writing"]},{"name":"living","tags":["chair","comfort","couch","decoration","furniture","home","house","living","lounging","loveseat","room","seat","seating","sofa"]},{"name":"battery_saver","tags":["+","add","battery","charge","charging","new","plus","power","saver","symbol"]},{"name":"hot_tub","tags":["bath","bathing","bathroom","bathtub","hot","hotel","human","jacuzzi","person","shower","spa","steam","travel","tub","water"]},{"name":"play_lesson","tags":["audio","book","bookmark","digital","ebook","lesson","multimedia","play","play lesson","read","reading","ribbon"]},{"name":"update_disabled","tags":["arrow","back","backwards","clock","date","disabled","enabled","forward","history","load","off","on","refresh","reverse","rotate","schedule","slash","time","update"]},{"name":"psychology_alt","tags":["?","assistance","behavior","body","brain","cognitive","function","gear","head","help","human","info","information","intellectual","mental","mind","people","person","preferences","psychiatric","psychology","punctuation","question mark","science","settings","social","support","symbol","therapy","thinking","thoughts"]},{"name":"cast_connected","tags":["Android","OS","airplay","cast","chrome","connect","connected","desktop","device","display","hardware","iOS","mac","monitor","screen","screencast","streaming","television","tv","web","window","wireless"]},{"name":"format_color_reset","tags":["clear","color","disabled","doc","droplet","edit","editing","editor","enabled","fill","format","off","on","paint","reset","sheet","slash","spreadsheet","style","text","type","water","writing"]},{"name":"snooze","tags":["alarm","bell","clock","duration","notification","snooze","time","timer","watch","z"]},{"name":"person_remove_alt_1","tags":[]},{"name":"align_horizontal_left","tags":["align","alignment","format","horizontal","layout","left","lines","paragraph","rule","rules","style","text"]},{"name":"boy","tags":["body","boy","gender","human","male","man","people","person","social","symbol"]},{"name":"battery_5_bar","tags":["5","bar","battery","cell","charge","mobile","power"]},{"name":"mic_external_on","tags":["audio","disabled","enabled","external","mic","microphone","off","on","slash","sound","voice"]},{"name":"voicemail","tags":["call","device","message","missed","mobile","phone","recording","voice","voicemail"]},{"name":"join_full","tags":["circle","combine","command","full","join","left","outer","overlap","right","sql"]},{"name":"looks_5","tags":["5","digit","looks","numbers","square","symbol"]},{"name":"countertops","tags":["counter","countertops","home","house","kitchen","sink","table","tops"]},{"name":"energy_savings_leaf","tags":["eco","energy","leaf","leaves","nest","savings","usage"]},{"name":"safety_divider","tags":["apart","distance","divider","safety","separate","social","space"]},{"name":"move_up","tags":["arrow","direction","jump","move","navigation","transfer","up"]},{"name":"storm","tags":["forecast","hurricane","storm","temperature","twister","weather","wind"]},{"name":"sync_disabled","tags":["360","around","arrow","arrows","direction","disabled","enabled","inprogress","load","loading refresh","off","on","renew","rotate","slash","sync","turn"]},{"name":"javascript","tags":["alphabet","brackets","character","code","css","develop","developer","engineer","engineering","font","html","javascript","letter","platform","symbol","text","type"]},{"name":"tram","tags":["automobile","car","cars","direction","maps","public","rail","subway","train","tram","transportation","vehicle"]},{"name":"app_shortcut","tags":["app","bookmarked","favorite","highlight","important","marked","mobile","save","saved","shortcut","software","special","star"]},{"name":"data_saver_off","tags":["analytics","bar","bars","chart","data","diagram","donut","graph","infographic","measure","metrics","off","on","ring","saver","statistics","tracking"]},{"name":"laptop_windows","tags":["Android","OS","chrome","device","display","hardware","iOS","laptop","mac","monitor","screen","web","window","windows"]},{"name":"doorbell","tags":["alarm","bell","door","doorbell","home","house","ringing"]},{"name":"hd","tags":["alphabet","character","definition","display","font","hd","high","letter","movie","movies","resolution","screen","symbol","text","tv","type"]},{"name":"file_download_off","tags":["arrow","disabled","down","download","drive","enabled","export","file","install","off","on","save","slash","upload"]},{"name":"apps_outage","tags":["all","applications","apps","circles","collection","components","dots","grid","interface","outage","squares","ui","ux"]},{"name":"taxi_alert","tags":["!","alert","attention","automobile","cab","car","cars","caution","danger","direction","error","exclamation","important","lyft","maps","mark","notification","public","symbol","taxi","transportation","uber","vehicle","warning","yellow"]},{"name":"breakfast_dining","tags":["bakery","bread","breakfast","butter","dining","food","toast"]},{"name":"brightness_medium","tags":["auto","brightness","control","medium","mobile","monitor","phone","sun"]},{"name":"gradient","tags":["color","edit","editing","effect","filter","gradient","image","images","photography","picture","pictures"]},{"name":"swipe_left","tags":["arrow","arrows","finger","hand","hit","left","navigation","reject","strike","swing","swipe","take"]},{"name":"soup_kitchen","tags":["breakfast","brunch","dining","food","kitchen","lunch","meal","soup"]},{"name":"voice_over_off","tags":["account","disabled","enabled","face","human","off","on","over","people","person","profile","recording","slash","speak","speaking","speech","transcript","user","voice"]},{"name":"water_damage","tags":["architecture","building","damage","drop","droplet","estate","house","leak","plumbing","real","residence","residential","shelter","water"]},{"name":"abc","tags":["alphabet","character","font","letter","symbol","text","type"]},{"name":"data_saver_on","tags":["+","add","analytics","chart","data","diagram","graph","infographic","measure","metrics","new","on","plus","ring","saver","statistics","symbol","tracking"]},{"name":"signal_wifi_0_bar","tags":["0","bar","cell","cellular","data","internet","mobile","network","phone","signal","wifi","wireless"]},{"name":"brightness_low","tags":["auto","brightness","control","low","mobile","monitor","phone","sun"]},{"name":"device_unknown","tags":["?","Android","OS","assistance","cell","device","hardware","help","iOS","info","information","mobile","phone","punctuation","question mark","support","symbol","tablet","unknown"]},{"name":"fire_extinguisher","tags":["emergency","extinguisher","fire","water"]},{"name":"fitbit","tags":["athlete","athletic","exercise","fitbit","fitness","hobby","logo"]},{"name":"bedroom_child","tags":["bed","bedroom","child","children","furniture","home","hotel","house","kid","night","pillows","rest","room","size","sleep","twin","young"]},{"name":"closed_caption_off","tags":["accessible","alphabet","caption","cc","character","closed","decoder","font","language","letter","media","movies","off","outline","subtitle","subtitles","symbol","text","tv","type"]},{"name":"bluetooth_searching","tags":["bluetooth","connection","device","paring","search","searching","symbol"]},{"name":"content_paste_off","tags":["clipboard","content","disabled","doc","document","enabled","file","off","on","paste","slash"]},{"name":"hexagon","tags":["hexagon","shape","six sides"]},{"name":"tap_and_play","tags":["Android","OS wifi","cell","connection","device","hardware","iOS","internet","mobile","network","phone","play","signal","tablet","tap","to","wireless"]},{"name":"domain_add","tags":["+","add","apartment","architecture","building","business","domain","estate","home","new","place","plus","real","residence","residential","shelter","symbol","web","www"]},{"name":"signpost","tags":["arrow","direction","left","maps","right","signal","signs","street","traffic"]},{"name":"screenshot","tags":["Android","OS","cell","crop","device","hardware","iOS","mobile","phone","screen","screenshot","tablet"]},{"name":"network_cell","tags":["cell","cellular","data","internet","mobile","network","phone","speed","wifi","wireless"]},{"name":"repeat_on","tags":["arrow","arrows","control","controls","media","music","on","repeat","video"]},{"name":"charging_station","tags":["Android","OS","battery","bolt","cell","charging","device","electric","hardware","iOS","lightning","mobile","phone","station","tablet","thunderbolt"]},{"name":"grid_4x4","tags":["4","by","grid","layout","lines","space"]},{"name":"assistant_photo","tags":["assistant","flag","photo","recommendation","smart","star","suggestion"]},{"name":"carpenter","tags":["building","carpenter","construction","cutting","handyman","repair","saw","tool"]},{"name":"private_connectivity","tags":["connectivity","lock","locked","password","privacy","private","protection","safety","secure","security"]},{"name":"mobiledata_off","tags":["arrow","data","disabled","down","enabled","internet","mobile","network","off","on","slash","speed","up","wifi","wireless"]},{"name":"atm","tags":["alphabet","atm","automated","bill","card","cart","cash","character","coin","commerce","credit","currency","dollars","font","letter","machine","money","online","pay","payment","shopping","symbol","teller","text","type"]},{"name":"rv_hookup","tags":["arrow","attach","automobile","automotive","back","car","cars","connect","direction","hookup","left","maps","public","right","rv","trailer","transportation","travel","truck","van","vehicle"]},{"name":"replay_30","tags":["30","arrow","arrows","control","controls","digit","music","number","refresh","renew","repeat","replay","symbol","thirty","video"]},{"name":"offline_share","tags":["Android","OS","arrow","cell","connect","device","direction","hardware","iOS","link","mobile","multiple","offline","phone","right","share","tablet"]},{"name":"settings_input_svideo","tags":["cable","connection","connectivity","definition","input","plug","plugin","points","settings","standard","svideo","video"]},{"name":"soap","tags":["bathroom","clean","fingers","gesture","hand","soap","wash","wc"]},{"name":"baby_changing_station","tags":["babies","baby","bathroom","body","changing","child","children","father","human","infant","kids","mother","newborn","people","person","station","toddler","wc","young"]},{"name":"sports_cricket","tags":["athlete","athletic","ball","bat","cricket","entertainment","exercise","game","hobby","social","sports"]},{"name":"ad_units","tags":["Android","OS","ad","banner","cell","device","hardware","iOS","mobile","notification","notifications","phone","tablet","top","units"]},{"name":"wb_twilight","tags":["balance","light","lighting","noon","sun","sunset","twilight","wb","white"]},{"name":"no_encryption","tags":["disabled","enabled","encryption","lock","no","off","on","password","safety","security","slash"]},{"name":"table_bar","tags":["bar","cafe","round","table"]},{"name":"diversity_2","tags":["committee","diverse","diversity","family","friends","group","groups","heart","humans","network","people","persons","social","team"]},{"name":"subway","tags":["automobile","bike","car","cars","maps","rail","scooter","subway","train","transportation","travel","tunnel","underground","vehicle","vespa"]},{"name":"browser_updated","tags":["Android","OS","arrow","browser","chrome","desktop","device","display","download","hardware","iOS","mac","monitor","screen","updated","web","window"]},{"name":"currency_pound","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","pound","price","shopping","symbol"]},{"name":"transit_enterexit","tags":["arrow","direction","enterexit","maps","navigation","route","transit","transportation"]},{"name":"contrast","tags":["black","contrast","edit","editing","effect","filter","grayscale","image","images","photography","picture","pictures","settings","white"]},{"name":"lightbulb_circle","tags":["alert","announcement","idea","info","information","light","lightbulb"]},{"name":"rectangle","tags":["four sides","parallelograms","polygons","quadrilaterals","recangle","shape"]},{"name":"call_merge","tags":["arrow","call","device","merge","mobile"]},{"name":"hide_image","tags":["disabled","enabled","hide","image","landscape","mountain","mountains","off","on","photo","photography","picture","slash"]},{"name":"shield_moon","tags":["certified","do not disturb","moon","night","privacy","private","protect","protection","security","shield","verified"]},{"name":"group_off","tags":["body","club","collaboration","crowd","gathering","group","human","meeting","off","people","person","social","teams"]},{"name":"music_off","tags":["audio","audiotrack","disabled","enabled","key","music","note","off","on","slash","sound","track"]},{"name":"bluetooth_disabled","tags":["bluetooth","cast","connect","connection","device","disabled","enabled","off","offline","on","paring","slash","streaming","symbol","wireless"]},{"name":"flip_to_back","tags":["arrange","arrangement","back","flip","format","front","layout","move","order","sort","to"]},{"name":"sd_card","tags":["camera","card","digital","memory","photos","sd","secure","storage"]},{"name":"exposure_plus_1","tags":["1","add","brightness","contrast","digit","edit","editing","effect","exposure","image","number","photo","photography","plus","settings","symbol"]},{"name":"view_array","tags":["array","design","format","grid","layout","view","website"]},{"name":"sports_mma","tags":["arts","athlete","athletic","boxing","combat","entertainment","exercise","fighting","game","glove","hobby","martial","mixed","mma","social","sports"]},{"name":"straight","tags":["arrow","arrows","direction","directions","maps","navigation","path","route","sign","straight","traffic","up"]},{"name":"thermostat_auto","tags":["A","auto","celsius","fahrenheit","meter","temp","temperature","thermometer","thermostat"]},{"name":"mobile_screen_share","tags":["Android","OS","cast","cell","device","hardware","iOS","mirror","mobile","monitor","phone","screen","screencast","share","stream","streaming","tablet","tv","wireless"]},{"name":"phone_missed","tags":["arrow","call","cell","contact","device","hardware","missed","mobile","phone","telephone"]},{"name":"brunch_dining","tags":["breakfast","brunch","champagne","dining","drink","food","lunch","meal"]},{"name":"featured_video","tags":["advertised","advertisement","featured","highlighted","recommended","video","watch"]},{"name":"merge","tags":["arrow","arrows","direction","directions","maps","merge","navigation","path","route","sign","traffic"]},{"name":"open_in_new_off","tags":["arrow","box","disabled","enabled","export","in","new","off","on","open","slash","window"]},{"name":"hdr_auto","tags":["A","alphabet","auto","camera","character","circle","dynamic","font","hdr","high","letter","photo","range","symbol","text","type"]},{"name":"join_inner","tags":["circle","command","inner","join","matching","overlap","sql","values"]},{"name":"solar_power","tags":["eco","energy","heat","nest","power","solar","sun","sunny"]},{"name":"crop_16_9","tags":["16","9","adjust","adjustments","area","by","crop","edit","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"swipe_right","tags":["accept","arrows","direction","finger","hands","hit","navigation","right","strike","swing","swpie","take"]},{"name":"phonelink_erase","tags":["Android","OS","cancel","cell","close","connection","device","erase","exit","hardware","iOS","mobile","no","phone","phonelink","remove","stop","tablet","x"]},{"name":"smoke_free","tags":["cigarette","disabled","enabled","free","never","no","off","on","places","prohibited","slash","smoke","smoking","tobacco","warning","zone"]},{"name":"install_desktop","tags":["Android","OS","chrome","desktop","device","display","fix","hardware","iOS","install","mac","monitor","place","pwa","screen","web","window"]},{"name":"shutter_speed","tags":["aperture","camera","duration","image","lens","photo","photography","photos","picture","setting","shutter","speed","stop","time","timer","watch"]},{"name":"keyboard_hide","tags":["arrow","computer","device","down","hardware","hide","input","keyboard","keypad","text"]},{"name":"exposure","tags":["add","brightness","contrast","edit","editing","effect","exposure","image","minus","photo","photography","picture","plus","settings","subtract"]},{"name":"nordic_walking","tags":["athlete","athletic","body","entertainment","exercise","hiking","hobby","human","nordic","people","person","social","sports","travel","walker","walking"]},{"name":"umbrella","tags":["beach","protection","rain","sun","sunny","umbrella"]},{"name":"move_down","tags":["arrow","direction","down","jump","move","navigation","transfer"]},{"name":"filter_2","tags":["2","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"photo_album","tags":["album","archive","bookmark","image","label","library","mountain","mountains","photo","photography","picture","ribbon","save","tag"]},{"name":"security_update_good","tags":["Android","OS","checkmark","device","good","hardware","iOS","mobile","ok","phone","security","tablet","tick","update"]},{"name":"ssid_chart","tags":["chart","graph","lines","network","ssid","wifi"]},{"name":"score","tags":["2k","alphabet","analytics","bar","bars","character","chart","data","diagram","digit","font","graph","infographic","letter","measure","metrics","number","score","statistics","symbol","text","tracking","type"]},{"name":"swipe_up","tags":["arrows","direction","disable","enable","finger","hands","hit","navigation","strike","swing","swpie","take","up"]},{"name":"battery_4_bar","tags":["4","bar","battery","cell","charge","mobile","power"]},{"name":"all_out","tags":["all","circle","out","shape"]},{"name":"battery_unknown","tags":["?","assistance","battery","cell","charge","help","info","information","mobile","power","punctuation","question mark","support","symbol","unknown"]},{"name":"sports_golf","tags":["athlete","athletic","ball","club","entertainment","exercise","game","golf","golfer","golfing","hobby","social","sports"]},{"name":"sports_martial_arts","tags":["arts","athlete","athletic","entertainment","exercise","hobby","human","karate","martial","people","person","social","sports"]},{"name":"filter_tilt_shift","tags":["blur","center","edit","editing","effect","filter","focus","image","images","photography","picture","pictures","shift","tilt"]},{"name":"electric_bike","tags":["bike","electric","electricity","maps","scooter","transportation","travel","vespa"]},{"name":"border_all","tags":["all","border","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"auto_mode","tags":["ai","around","arrow","arrows","artificial","auto","automatic","automation","custom","direction","genai","inprogress","intelligence","load","loading refresh","magic","mode","navigation","nest","renew","rotate","smart","spark","sparkle","star","turn"]},{"name":"hvac","tags":["air","conditioning","heating","hvac","ventilation"]},{"name":"scanner","tags":["copy","device","hardware","machine","scan","scanner"]},{"name":"shuffle_on","tags":["arrow","arrows","control","controls","music","on","random","shuffle","video"]},{"name":"wifi_calling_3","tags":["3","calling","cell","cellular","data","internet","mobile","network","phone","speed","wifi","wireless"]},{"name":"signal_wifi_off","tags":["cell","cellular","data","disabled","enabled","internet","mobile","network","off","on","phone","signal","slash","speed","wifi","wireless"]},{"name":"girl","tags":["body","female","gender","girl","human","lady","people","person","social","symbol","woman","women"]},{"name":"shop_2","tags":["2","add","arrow","buy","cart","google","play","purchase","shop","shopping"]},{"name":"hdr_strong","tags":["circles","dots","dynamic","enhance","hdr","high","range","strong"]},{"name":"directions_transit","tags":["automobile","car","cars","direction","directions","maps","public","rail","subway","train","transit","transportation","vehicle"]},{"name":"label_off","tags":["disabled","enabled","favorite","indent","label","library","mail","off","on","remember","save","slash","stamp","sticker","tag","wing"]},{"name":"tablet","tags":["Android","OS","device","hardware","iOS","ipad","mobile","tablet","web"]},{"name":"5g","tags":["5g","alphabet","cellular","character","data","digit","font","letter","mobile","network","number","phone","signal","speed","symbol","text","type","wifi"]},{"name":"vrpano","tags":["angle","image","landscape","mountain","mountains","panorama","photo","photography","picture","view","vrpano","wide"]},{"name":"forward_30","tags":["30","arrow","control","controls","digit","fast","forward","music","number","seconds","symbol","video"]},{"name":"battery_0_bar","tags":["0","bar","battery","cell","charge","mobile","power"]},{"name":"airline_seat_recline_extra","tags":["airline","body","extra","feet","human","leg","legroom","people","person","seat","sitting","space","travel"]},{"name":"looks","tags":["circle","half","looks","rainbow"]},{"name":"linked_camera","tags":["camera","connect","connection","lens","linked","network","photo","photography","picture","signal","signals","sync","wireless"]},{"name":"paragliding","tags":["athlete","athletic","body","entertainment","exercise","fly","gliding","hobby","human","parachute","paragliding","people","person","sky","skydiving","social","sports","travel"]},{"name":"electric_scooter","tags":["bike","electric","maps","scooter","transportation","vehicle","vespa"]},{"name":"settings_system_daydream","tags":["backup","cloud","daydream","drive","settings","storage","system"]},{"name":"format_indent_decrease","tags":["align","alignment","decrease","doc","edit","editing","editor","format","indent","indentation","paragraph","sheet","spreadsheet","text","type","writing"]},{"name":"tapas","tags":["appetizer","brunch","dinner","food","lunch","restaurant","snack","tapas"]},{"name":"brightness_3","tags":["3","brightness","circle","control","crescent","level","moon","screen"]},{"name":"tab_unselected","tags":["browser","computer","document","documents","folder","internet","tab","tabs","unselected","web","website","window","windows"]},{"name":"density_small","tags":["density","horizontal","lines","rule","rules","small"]},{"name":"blur_circular","tags":["blur","circle","circular","dots","edit","editing","effect","enhance","filter"]},{"name":"rice_bowl","tags":["bowl","dinner","food","lunch","meal","restaurant","rice"]},{"name":"rounded_corner","tags":["adjust","corner","edit","rounded","shape","square","transform"]},{"name":"person_add_disabled","tags":["+","account","add","disabled","enabled","face","human","new","off","offline","on","people","person","plus","profile","slash","symbol","user"]},{"name":"music_video","tags":["band","music","recording","screen","tv","video","watch"]},{"name":"looks_6","tags":["6","digit","looks","numbers","square","symbol"]},{"name":"do_not_touch","tags":["disabled","do","enabled","fingers","gesture","hand","not","off","on","slash","touch"]},{"name":"playlist_add_circle","tags":["add","album","artist","audio","cd","check","circle","collection","list","mark","music","playlist","record","sound","track"]},{"name":"domain_disabled","tags":["apartment","architecture","building","business","company","disabled","domain","enabled","estate","home","internet","maps","off","office","offline","on","place","real","residence","residential","slash","web","website"]},{"name":"flash_auto","tags":["a","auto","bolt","electric","fast","flash","lightning","thunderbolt"]},{"name":"6_ft_apart","tags":["6","apart","body","covid","distance","feet","ft","human","people","person","social"]},{"name":"signal_wifi_bad","tags":["bad","bar","cancel","cell","cellular","close","data","exit","internet","mobile","network","no","phone","quit","remove","signal","stop","wifi","wireless","x"]},{"name":"crisis_alert","tags":["!","alert","attention","bullseye","caution","crisis","danger","error","exclamation","important","mark","notification","symbol","target","warning"]},{"name":"queue_play_next","tags":["+","add","arrow","desktop","device","display","hardware","monitor","new","next","play","plus","queue","screen","steam","symbol","tv"]},{"name":"format_clear","tags":["T","alphabet","character","clear","disabled","doc","edit","editing","editor","enabled","font","format","letter","off","on","sheet","slash","spreadsheet","style","symbol","text","type","writing"]},{"name":"bus_alert","tags":["!","alert","attention","automobile","bus","car","cars","caution","danger","error","exclamation","important","maps","mark","notification","symbol","transportation","vehicle","warning"]},{"name":"party_mode","tags":["camera","lens","mode","party","photo","photography","picture"]},{"name":"snowboarding","tags":["athlete","athletic","body","entertainment","exercise","hobby","human","people","person","snow","snowboarding","social","sports","travel","winter"]},{"name":"text_rotate_vertical","tags":["A","alphabet","arrow","character","down","field","font","letter","move","rotate","symbol","text","type","vertical"]},{"name":"motion_photos_auto","tags":["A","alphabet","animation","auto","automatic","character","circle","font","gif","letter","live","motion","photos","symbol","text","type","video"]},{"name":"crop_portrait","tags":["adjust","adjustments","area","crop","edit","editing","frame","image","images","photo","photos","portrait","rectangle","settings","size","square"]},{"name":"thunderstorm","tags":["bolt","climate","cloud","cloudy","lightning","rain","rainfall","rainstorm","storm","thunder","thunderstorm","weather"]},{"name":"battery_6_bar","tags":["6","bar","battery","cell","charge","mobile","power"]},{"name":"space_bar","tags":["bar","keyboard","line","space"]},{"name":"replay_5","tags":["5","arrow","arrows","control","controls","digit","five","music","number","refresh","renew","repeat","replay","symbol","video"]},{"name":"local_car_wash","tags":["automobile","car","cars","local","maps","transportation","travel","vehicle","wash"]},{"name":"folder_delete","tags":["bin","can","data","delete","doc","document","drive","file","folder","folders","garbage","remove","sheet","slide","storage","trash"]},{"name":"data_thresholding","tags":["data","hidden","privacy","thresholding","thresold"]},{"name":"connecting_airports","tags":["airplane","airplanes","airport","airports","connecting","flight","plane","transportation","travel","trip"]},{"name":"access_alarms","tags":[]},{"name":"tty","tags":["call","cell","contact","deaf","device","hardware","impaired","mobile","phone","speech","talk","telephone","text","tty"]},{"name":"audio_file","tags":["audio","doc","document","key","music","note","sound","track"]},{"name":"egg","tags":["breakfast","brunch","egg","food"]},{"name":"balcony","tags":["architecture","balcony","doors","estate","home","house","maps","out","outside","place","real","residence","residential","stay","terrace","window"]},{"name":"kitesurfing","tags":["athlete","athletic","beach","body","entertainment","exercise","hobby","human","kitesurfing","people","person","social","sports","surf","travel","water"]},{"name":"call_missed_outgoing","tags":["arrow","call","device","missed","mobile","outgoing"]},{"name":"local_hotel","tags":["body","hotel","human","local","people","person","sleep","stay","travel","trip"]},{"name":"text_increase","tags":["+","add","alphabet","character","font","increase","letter","new","plus","resize","symbol","text","type"]},{"name":"speaker_phone","tags":["Android","OS","cell","device","hardware","iOS","mobile","phone","sound","speaker","tablet","volume"]},{"name":"no_food","tags":["disabled","drink","enabled","fastfood","food","hamburger","meal","no","off","on","slash"]},{"name":"brightness_2","tags":["2","brightness","circle","control","crescent","level","moon","screen"]},{"name":"mode_of_travel","tags":["arrow","destination","direction","location","maps","mode","of","pin","place","stop","transportation","travel","trip"]},{"name":"format_line_spacing","tags":["align","alignment","doc","edit","editing","editor","format","line","sheet","spacing","spreadsheet","text","type","writing"]},{"name":"iso","tags":["add","edit","editing","effect","image","iso","minus","photography","picture","plus","sensor","shutter","speed","subtract"]},{"name":"explore_off","tags":["compass","destination","direction","disabled","east","enabled","explore","location","maps","needle","north","off","on","slash","south","travel","west"]},{"name":"drive_file_move_rtl","tags":["arrow","arrows","data","direction","doc","document","drive","file","folder","folders","left","move","rtl","sheet","side","slide","storage"]},{"name":"cell_wifi","tags":["cell","connection","data","internet","mobile","network","phone","service","signal","wifi","wireless"]},{"name":"tonality","tags":["circle","edit","editing","filter","image","photography","picture","tonality"]},{"name":"spoke","tags":["connection","network","radius","spoke"]},{"name":"photo_filter","tags":["ai","artificial","automatic","automation","custom","filter","filters","genai","image","intelligence","magic","photo","photography","picture","smart","spark","sparkle","star"]},{"name":"desktop_access_disabled","tags":["Android","OS","access","chrome","desktop","device","disabled","display","enabled","hardware","iOS","mac","monitor","off","offline","on","screen","slash","web","window"]},{"name":"sports_gymnastics","tags":["athlete","athletic","entertainment","exercise","gymnastics","hobby","social","sports"]},{"name":"houseboat","tags":["architecture","beach","boat","estate","floating","home","house","houseboat","maps","place","real","residence","residential","sea","stay","traveling","vacation"]},{"name":"fence","tags":["backyard","barrier","boundaries","boundary","fence","home","house","protection","yard"]},{"name":"commit","tags":["accomplish","bind","circle","commit","dedicate","execute","line","perform","pledge"]},{"name":"photo_size_select_small","tags":["adjust","album","edit","editing","image","large","library","mountain","mountains","photo","photography","picture","select","size","small"]},{"name":"signal_wifi_connected_no_internet_4","tags":["4","cell","cellular","connected","data","internet","mobile","network","no","offline","phone","signal","wifi","wireless","x"]},{"name":"horizontal_distribute","tags":["alignment","distribute","format","horizontal","layout","lines","paragraph","rule","rules","style","text"]},{"name":"report_off","tags":["!","alert","attention","caution","danger","disabled","enabled","error","exclamation","important","mark","notification","octagon","off","offline","on","report","slash","symbol","warning"]},{"name":"polyline","tags":["compose","create","design","draw","line","polyline","vector"]},{"name":"art_track","tags":["album","art","artist","audio","image","music","photo","photography","picture","sound","track","tracks"]},{"name":"crop_7_5","tags":["5","7","adjust","adjustments","area","by","crop","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"filter_hdr","tags":["camera","edit","editing","effect","filter","hdr","image","mountain","mountains","photo","photography","picture"]},{"name":"text_rotation_none","tags":["A","alphabet","arrow","character","field","font","letter","move","none","rotate","symbol","text","type"]},{"name":"battery_3_bar","tags":["3","bar","battery","cell","charge","mobile","power"]},{"name":"align_vertical_bottom","tags":["align","alignment","bottom","format","layout","lines","paragraph","rule","rules","style","text","vertical"]},{"name":"stop_screen_share","tags":["Android","OS","arrow","cast","chrome","device","disabled","display","enabled","hardware","iOS","laptop","mac","mirror","monitor","off","offline","on","screen","share","slash","steam","stop","streaming","web","window"]},{"name":"imagesearch_roller","tags":["art","image","imagesearch","paint","roller","search"]},{"name":"bento","tags":["bento","box","dinner","food","lunch","meal","restaurant","takeout"]},{"name":"rotate_90_degrees_cw","tags":["90","arrow","arrows","ccw","degrees","direction","edit","editing","image","photo","rotate","turn"]},{"name":"install_mobile","tags":["Android","OS","cell","device","hardware","iOS","install","mobile","phone","pwa","tablet"]},{"name":"hearing_disabled","tags":["accessibility","accessible","aid","disabled","ear","enabled","handicap","hearing","help","impaired","listen","off","on","slash","sound","volume"]},{"name":"video_file","tags":["camera","doc","document","film","filming","hardware","image","motion","picture","video","videography"]},{"name":"mms","tags":["bubble","chat","comment","communicate","feedback","image","landscape","message","mms","mountain","mountains","multimedia","photo","photography","picture","speech"]},{"name":"crop_rotate","tags":["adjust","adjustments","area","arrow","arrows","crop","edit","editing","frame","image","images","photo","photos","rotate","settings","size","turn"]},{"name":"wheelchair_pickup","tags":["accessibility","accessible","body","handicap","help","human","person","pickup","wheelchair"]},{"name":"aod","tags":["Android","OS","always","aod","device","display","hardware","homescreen","iOS","mobile","on","phone","tablet"]},{"name":"castle","tags":["castle","fort","fortress","mansion","palace"]},{"name":"interpreter_mode","tags":["interpreter","language","microphone","mode","person","speaking","symbol"]},{"name":"access_alarm","tags":[]},{"name":"forward_5","tags":["10","5","arrow","control","controls","digit","fast","forward","music","number","seconds","symbol","video"]},{"name":"add_to_home_screen","tags":["Android","OS","add to","arrow","cell","device","hardware","home","iOS","mobile","phone","screen","tablet","up"]},{"name":"not_accessible","tags":["accessibility","accessible","body","handicap","help","human","not","person","wheelchair"]},{"name":"signal_cellular_0_bar","tags":["0","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","wifi","wireless"]},{"name":"stadium","tags":["activity","amphitheater","arena","coliseum","event","local","stadium","star","things","ticket"]},{"name":"photo_size_select_large","tags":["adjust","album","edit","editing","image","large","library","mountain","mountains","photo","photography","picture","select","size"]},{"name":"groups_3","tags":["abstract","body","club","collaboration","crowd","gathering","groups","human","meeting","people","person","social","teams"]},{"name":"snowshoeing","tags":["body","human","people","person","snow","snowshoe","snowshoeing","sports","travel","walking","winter"]},{"name":"view_kanban","tags":["grid","kanban","layout","pattern","squares","view"]},{"name":"candlestick_chart","tags":["analytics","candlestick","chart","data","diagram","finance","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"filter_3","tags":["3","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"arrow_outward","tags":["app","application","arrow","arrows","components","direction","forward","interface","navigation","right","screen","site","ui","ux","web","website"]},{"name":"align_horizontal_center","tags":["align","alignment","center","format","horizontal","layout","lines","paragraph","rule","rules","style","text"]},{"name":"flashlight_off","tags":["disabled","enabled","flash","flashlight","light","off","on","slash"]},{"name":"security_update","tags":["Android","OS","arrow","device","down","download","hardware","iOS","mobile","phone","security","tablet","update"]},{"name":"iron","tags":["appliance","clothes","electric","iron","ironing","machine","object"]},{"name":"print_disabled","tags":["disabled","enabled","off","on","paper","print","printer","slash"]},{"name":"pin_invoke","tags":["action","arrow","dot","invoke","pin"]},{"name":"speaker_group","tags":["box","electronic","group","loud","multiple","music","sound","speaker","stereo","system","video"]},{"name":"exposure_zero","tags":["0","brightness","contrast","digit","edit","editing","effect","exposure","image","number","photo","photography","settings","symbol","zero"]},{"name":"bungalow","tags":["architecture","bungalow","cottage","estate","home","house","maps","place","real","residence","residential","stay","traveling"]},{"name":"streetview","tags":["maps","street","streetview","view"]},{"name":"swipe_down","tags":["arrows","direction","disable","down","enable","finger","hands","hit","navigation","strike","swing","swpie","take"]},{"name":"hdr_weak","tags":["circles","dots","dynamic","enhance","hdr","high","range","weak"]},{"name":"css","tags":["alphabet","brackets","character","code","css","develop","developer","engineer","engineering","font","html","letter","platform","symbol","text","type"]},{"name":"call_missed","tags":["arrow","call","device","missed","mobile"]},{"name":"gps_off","tags":["destination","direction","disabled","enabled","gps","location","maps","not fixed","off","offline","on","place","pointer","slash","tracking"]},{"name":"sports_hockey","tags":["athlete","athletic","entertainment","exercise","game","hobby","hockey","social","sports","sticks"]},{"name":"ice_skating","tags":["athlete","athletic","entertainment","exercise","hobby","ice","shoe","skates","skating","social","sports","travel"]},{"name":"keyboard_capslock","tags":["arrow","capslock","keyboard","up"]},{"name":"earbuds","tags":["accessory","audio","earbuds","earphone","headphone","listen","music","sound"]},{"name":"camera_front","tags":["body","camera","front","human","lens","mobile","person","phone","photography","portrait","selfie"]},{"name":"vertical_distribute","tags":["alignment","distribute","format","layout","lines","paragraph","rule","rules","style","text","vertical"]},{"name":"currency_ruble","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","ruble","shopping","symbol"]},{"name":"signal_wifi_statusbar_null","tags":["cell","cellular","data","internet","mobile","network","null","phone","signal","speed","statusbar","wifi","wireless"]},{"name":"align_horizontal_right","tags":["align","alignment","format","horizontal","layout","lines","paragraph","right","rule","rules","style","text"]},{"name":"crop_5_4","tags":["4","5","adjust","adjustments","area","by","crop","edit","editing settings","frame","image","images","photo","photos","rectangle","size","square"]},{"name":"format_strikethrough","tags":["alphabet","character","doc","edit","editing","editor","font","format","letter","sheet","spreadsheet","strikethrough","style","symbol","text","type","writing"]},{"name":"face_6","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"join_left","tags":["circle","command","join","left","matching","overlap","sql","values"]},{"name":"explicit","tags":["adult","alphabet","character","content","e","explicit","font","language","letter","media","movies","music","symbol","text","type"]},{"name":"extension_off","tags":["disabled","enabled","extended","extension","jigsaw","off","on","piece","puzzle","shape","slash"]},{"name":"perm_camera_mic","tags":["camera","image","microphone","min","perm","photo","photography","picture","speaker"]},{"name":"sports_rugby","tags":["athlete","athletic","ball","entertainment","exercise","game","hobby","rugby","social","sports"]},{"name":"pause_presentation","tags":["app","application desktop","device","pause","present","presentation","screen","share","site","slides","web","website","window","www"]},{"name":"south_america","tags":["continent","landscape","place","region","south america"]},{"name":"sd_storage","tags":["camera","card","data","digital","memory","sd","secure","storage"]},{"name":"superscript","tags":["2","doc","edit","editing","editor","gmail","novitas","sheet","spreadsheet","style","superscript","symbol","text","writing","x"]},{"name":"4g_mobiledata","tags":["4g","alphabet","cellular","character","digit","font","letter","mobile","mobiledata","network","number","phone","signal","speed","symbol","text","type","wifi"]},{"name":"pinch","tags":["arrow","arrows","compress","direction","finger","grasp","hand","navigation","nip","pinch","squeeze","tweak"]},{"name":"lock_person","tags":[]},{"name":"grid_3x3","tags":["3","grid","layout","line","space"]},{"name":"mark_unread_chat_alt","tags":["bubble","chat","circle","comment","communicate","mark","message","notification","speech","unread"]},{"name":"web_stories","tags":["google","images","logo","stories","web"]},{"name":"safety_check","tags":["certified","check","clock","privacy","private","protect","protection","safety","schedule","security","shield","time","verified"]},{"name":"filter_frames","tags":["boarders","border","camera","center","edit","editing","effect","filter","filters","focus","frame","frames","image","options","photo","photography","picture"]},{"name":"spatial_audio_off","tags":["audio","disabled","enabled","music","note","off","offline","on","slash","sound","spatial"]},{"name":"directions_subway","tags":["automobile","car","cars","direction","directions","maps","public","rail","subway","train","transportation","vehicle"]},{"name":"reset_tv","tags":["arrow","device","hardware","monitor","reset","television","tv"]},{"name":"4k","tags":["4000","4K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"burst_mode","tags":["burst","image","landscape","mode","mountain","mountains","multiple","photo","photography","picture"]},{"name":"chalet","tags":["architecture","chalet","cottage","estate","home","house","maps","place","real","residence","residential","stay","traveling"]},{"name":"battery_1_bar","tags":["1","bar","battery","cell","charge","mobile","power"]},{"name":"elderly_woman","tags":["body","cane","elderly","female","gender","girl","human","lady","old","people","person","senior","social","symbol","woman","women"]},{"name":"headset_off","tags":["accessory","audio","chat","device","disabled","ear","earphone","enabled","headphones","headset","listen","mic","music","off","on","slash","sound","talk"]},{"name":"swipe_vertical","tags":["arrows","direction","finger","hands","hit","navigation","strike","swing","swpie","take","verticle"]},{"name":"crib","tags":["babies","baby","bassinet","bed","child","children","cradle","crib","infant","kid","newborn","sleeping","toddler"]},{"name":"video_label","tags":["label","screen","video","window"]},{"name":"fiber_smart_record","tags":["circle","dot","fiber","play","record","smart","watch"]},{"name":"brightness_auto","tags":["A","auto","brightness","control","display","level","mobile","monitor","phone","screen","sun"]},{"name":"margin","tags":["design","layout","margin","padding","size","square"]},{"name":"punch_clock","tags":["clock","date","punch","schedule","time","timer","timesheet"]},{"name":"compass_calibration","tags":["calibration","compass","connection","internet","location","maps","network","refresh","service","signal","wifi","wireless"]},{"name":"mosque","tags":["islam","islamic","masjid","muslim","religion","spiritual","worship"]},{"name":"medication_liquid","tags":["+","bottle","doctor","drug","health","hospital","liquid","medications","medicine","pharmacy","spoon","vessel"]},{"name":"camera_roll","tags":["camera","film","image","library","photo","photography","roll"]},{"name":"pin_end","tags":["action","arrow","dot","end","pin"]},{"name":"dialer_sip","tags":["alphabet","call","cell","character","contact","device","dialer","font","hardware","initiation","internet","letter","mobile","over","phone","protocol","routing","session","sip","symbol","telephone","text","type","voice"]},{"name":"oil_barrel","tags":["barrel","droplet","gas","gasoline","nest","oil","water"]},{"name":"disc_full","tags":["!","alert","attention","caution","cd","danger","disc","error","exclamation","full","important","mark","music","notification","storage","symbol","warning"]},{"name":"signal_cellular_connected_no_internet_4_bar","tags":["!","4","alert","attention","bar","caution","cell","cellular","connected","danger","data","error","exclamation","important","internet","mark","mobile","network","no","notification","phone","signal","symbol","warning","wifi","wireless"]},{"name":"wind_power","tags":["eco","energy","nest","power","wind","windy"]},{"name":"logo_dev","tags":["dev","dev.to","logo"]},{"name":"sledding","tags":["athlete","athletic","body","entertainment","exercise","hobby","human","people","person","sled","sledding","sledge","snow","social","sports","travel","winter"]},{"name":"invert_colors_off","tags":["colors","disabled","drop","droplet","enabled","hue","invert","inverted","off","offline","on","opacity","palette","slash","tone","water"]},{"name":"wifi_lock","tags":["cellular","connection","data","internet","lock","locked","mobile","network","password","privacy","private","protection","safety","secure","security","service","signal","wifi","wireless"]},{"name":"noise_aware","tags":["audio","aware","cancellation","music","noise","note","sound"]},{"name":"face_3","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"car_crash","tags":["accident","automobile","car","cars","collision","crash","direction","maps","public","transportation","vehicle"]},{"name":"comments_disabled","tags":["bubble","chat","comment","comments","communicate","disabled","enabled","feedback","message","off","offline","on","slash","speech"]},{"name":"data_array","tags":["array","brackets","code","coder","data","parentheses"]},{"name":"do_not_disturb_on_total_silence","tags":["busy","disturb","do","mute","no","not","on total","quiet","silence"]},{"name":"filter_b_and_w","tags":["and","b","black","contrast","edit","editing","effect","filter","grayscale","image","images","photography","picture","pictures","settings","w","white"]},{"name":"no_encryption_gmailerrorred","tags":["disabled","enabled","encryption","error","gmail","lock","locked","no","off","on","slash"]},{"name":"blur_linear","tags":["blur","dots","edit","editing","effect","enhance","filter","linear"]},{"name":"view_cozy","tags":["comfy","cozy","design","format","layout","view","web"]},{"name":"wifi_calling","tags":["call","calling","cell","connect","connection","connectivity","contact","device","hardware","mobile","phone","signal","telephone","wifi","wireless"]},{"name":"electric_rickshaw","tags":["automobile","car","cars","electric","india","maps","rickshaw","transportation","truck","vehicle"]},{"name":"rtt","tags":["call","real","rrt","text","time"]},{"name":"join_right","tags":["circle","command","join","matching","overlap","right","sql","values"]},{"name":"crop_3_2","tags":["2","3","adjust","adjustments","area","by","crop","edit","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"crop_landscape","tags":["adjust","adjustments","area","crop","edit","editing","frame","image","images","landscape","photo","photos","settings","size"]},{"name":"nearby_error","tags":["!","alert","attention","caution","danger","error","exclamation","important","mark","nearby","notification","symbol","warning"]},{"name":"airplanemode_inactive","tags":["airplane","airplanemode","airport","disabled","enabled","flight","fly","inactive","maps","mode","off","offline","on","slash","transportation","travel"]},{"name":"airline_stops","tags":["airline","arrow","destination","direction","layover","location","maps","place","stops","transportation","travel","trip"]},{"name":"bluetooth_audio","tags":["audio","bluetooth","connect","connection","device","music","signal","sound","symbol"]},{"name":"portable_wifi_off","tags":["connection","data","disabled","enabled","internet","network","off","offline","on","portable","service","signal","slash","wifi","wireless"]},{"name":"turn_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sign","traffic","turn"]},{"name":"1x_mobiledata","tags":["1x","alphabet","cellular","character","digit","font","letter","mobile","mobiledata","network","number","phone","signal","speed","symbol","text","type","wifi"]},{"name":"do_not_step","tags":["boot","disabled","do","enabled","feet","foot","not","off","on","shoe","slash","sneaker","step","steps"]},{"name":"sensor_occupied","tags":["body","body response","connection","fitbit","human","network","people","person","scan","sensors","signal","smart body scan sensor","wireless"]},{"name":"directions_railway","tags":["automobile","car","cars","direction","directions","maps","public","railway","train","transportation","vehicle"]},{"name":"security_update_warning","tags":["!","Android","OS","alert","attention","caution","danger","device","download","error","exclamation","hardware","iOS","important","mark","mobile","notification","phone","security","symbol","tablet","update","warning"]},{"name":"pentagon","tags":["five sides","pentagon","shape"]},{"name":"wrap_text","tags":["arrow writing","doc","edit","editing","editor","sheet","spreadsheet","text","type","wrap","write","writing"]},{"name":"no_meeting_room","tags":["building","disabled","door","doorway","enabled","entrance","home","house","interior","meeting","no","off","office","on","open","places","room","slash"]},{"name":"sd_card_alert","tags":["!","alert","attention","camera","card","caution","danger","digital","error","exclamation","important","mark","memory","notification","photos","sd","secure","storage","symbol","warning"]},{"name":"deselect","tags":["all","disabled","enabled","off","on","selection","slash","square","tool"]},{"name":"switch_camera","tags":["arrow","arrows","camera","photo","photography","picture","switch"]},{"name":"text_rotate_up","tags":["A","alphabet","arrow","character","field","font","letter","move","rotate","symbol","text","type","up"]},{"name":"sync_lock","tags":["around","arrow","arrows","lock","locked","password","privacy","private","protection","renew","rotate","safety","secure","security","sync","turn"]},{"name":"switch_video","tags":["arrow","arrows","camera","photography","switch","video","videos"]},{"name":"border_clear","tags":["border","clear","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"repeat_one_on","tags":["arrow","arrows","control","controls","digit","media","music","number","on","one","repeat","symbol","video"]},{"name":"no_meals","tags":["dining","disabled","eat","enabled","food","fork","knife","meal","meals","no","off","on","restaurant","slash","spoon","utensils"]},{"name":"align_vertical_top","tags":["align","alignment","format","layout","lines","paragraph","rule","rules","style","text","top","vertical"]},{"name":"subscript","tags":["2","doc","edit","editing","editor","gmail","novitas","sheet","spreadsheet","style","subscript","symbol","text","writing","x"]},{"name":"font_download_off","tags":["alphabet","character","disabled","download","enabled","font","letter","off","on","slash","square","symbol","text","type"]},{"name":"scoreboard","tags":["board","points","score","scoreboard","sports"]},{"name":"swipe_right_alt","tags":["accept","alt","arrows","direction","finger","hands","hit","navigation","right","strike","swing","swpie","take"]},{"name":"align_vertical_center","tags":["align","alignment","center","format","layout","lines","paragraph","rule","rules","style","text","vertical"]},{"name":"electric_meter","tags":["bolt","electric","energy","fast","lightning","measure","meter","nest","thunderbolt","usage","voltage","volts"]},{"name":"contact_emergency","tags":["account","avatar","call","cell","contacts","face","human","info","information","mobile","people","person","phone","profile","user"]},{"name":"signal_cellular_connected_no_internet_0_bar","tags":["!","0","alert","attention","bar","caution","cell","cellular","connected","danger","data","error","exclamation","important","internet","mark","mobile","network","no","notification","phone","signal","symbol","warning","wifi","wireless"]},{"name":"sim_card_alert","tags":["!","alert","attention","camera","card","caution","danger","digital","error","exclamation","important","mark","memory","notification","photos","sd","secure","storage","symbol","warning"]},{"name":"battery_2_bar","tags":["2","bar","battery","cell","charge","mobile","power"]},{"name":"text_rotation_angleup","tags":["A","alphabet","angleup","arrow","character","field","font","letter","move","rotate","symbol","text","type"]},{"name":"text_rotation_down","tags":["A","alphabet","arrow","character","dow","field","font","letter","move","rotate","symbol","text","type"]},{"name":"railway_alert","tags":["!","alert","attention","automobile","bike","car","cars","caution","danger","direction","error","exclamation","important","maps","mark","notification","public","railway","scooter","subway","symbol","train","transportation","vehicle","vespa","warning"]},{"name":"escalator","tags":["down","escalator","staircase","up"]},{"name":"electric_moped","tags":["automobile","bike","car","cars","electric","maps","moped","scooter","transportation","travel","vehicle","vespa"]},{"name":"closed_caption_disabled","tags":["accessible","alphabet","caption","cc","character","closed","decoder","disabled","enabled","font","language","letter","media","movies","off","on","slash","subtitle","subtitles","symbol","text","tv","type"]},{"name":"filter_7","tags":["7","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"heat_pump","tags":["air conditioner","cool","energy","furnance","heat","nest","pump","usage"]},{"name":"dry","tags":["air","bathroom","dry","dryer","fingers","gesture","hand","wc"]},{"name":"fork_right","tags":["arrow","arrows","direction","directions","fork","maps","navigation","path","right","route","sign","traffic"]},{"name":"text_rotation_angledown","tags":["A","alphabet","angledown","arrow","character","field","font","letter","move","rotate","symbol","text","type"]},{"name":"do_not_disturb_off","tags":["cancel","close","denied","deny","disabled","disturb","do","enabled","off","on","remove","silence","slash","stop"]},{"name":"screen_lock_portrait","tags":["Android","OS","device","hardware","iOS","lock","mobile","phone","portrait","rotate","screen","tablet"]},{"name":"send_time_extension","tags":["deliver","dispatch","envelop","extension","mail","message","schedule","send","time"]},{"name":"keyboard_command_key","tags":["button","command key","control","keyboard"]},{"name":"remove_from_queue","tags":["desktop","device","display","from","hardware","monitor","queue","remove","screen","steam"]},{"name":"filter_4","tags":["4","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"filter_9_plus","tags":["+","9","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","plus","settings","stack","symbol"]},{"name":"exposure_plus_2","tags":["2","add","brightness","contrast","digit","edit","editing","effect","exposure","image","number","photo","photography","plus","settings","symbol"]},{"name":"surround_sound","tags":["circle","signal","sound","speaker","surround","system","volumn","wireless"]},{"name":"airline_seat_individual_suite","tags":["airline","body","business","class","first","human","individual","people","person","rest","seat","sleep","suite","travel"]},{"name":"home_max","tags":["device","gadget","hardware","home","internet","iot","max","nest","smart","things"]},{"name":"phone_paused","tags":["call","cell","contact","device","hardware","mobile","pause","paused","phone","telephone"]},{"name":"local_play","tags":[]},{"name":"stroller","tags":["baby","care","carriage","child","children","infant","kid","newborn","stroller","toddler","young"]},{"name":"wifi_password","tags":["(scan)","[cellular","connection","data","internet","lock","mobile]","network","password","secure","service","signal","wifi","wireless"]},{"name":"browse_gallery","tags":["clock","collection","gallery","library","stack","watch"]},{"name":"system_security_update","tags":["Android","OS","arrow","cell","device","down","hardware","iOS","mobile","phone","security","system","tablet","update"]},{"name":"person_2","tags":["account","face","human","people","person","profile","user"]},{"name":"screenshot_monitor","tags":["Android","OS","chrome","desktop","device","display","hardware","iOS","mac","monitor","screen","screengrab","screenshot","web","window"]},{"name":"wb_iridescent","tags":["balance","bright","edit","editing","iridescent","light","lighting","setting","settings","white","wp"]},{"name":"grid_off","tags":["collage","disabled","enabled","grid","image","layout","off","on","slash","view"]},{"name":"system_security_update_warning","tags":["!","Android","OS","alert","attention","caution","cell","danger","device","error","exclamation","hardware","iOS","important","mark","mobile","notification","phone","security","symbol","system","tablet","update","warning"]},{"name":"play_disabled","tags":["control","controls","disabled","enabled","media","music","off","on","play","slash","video"]},{"name":"php","tags":["alphabet","brackets","character","code","css","develop","developer","engineer","engineering","font","html","letter","php","platform","symbol","text","type"]},{"name":"phishing","tags":["fish","fishing","fraud","hook","phishing","scam"]},{"name":"border_style","tags":["border","color","doc","edit","editing","editor","sheet","spreadsheet","stroke","style","text","type","writing"]},{"name":"motion_photos_paused","tags":["animation","circle","motion","pause","paused","photos","video"]},{"name":"headphones_battery","tags":["accessory","audio","battery","charging","device","ear","earphone","headphones","headset","listen","music","sound"]},{"name":"monochrome_photos","tags":["black","camera","image","monochrome","photo","photography","photos","picture","white"]},{"name":"web_asset_off","tags":["asset","browser","disabled","enabled","internet","off","on","page","screen","slash","web","webpage","website","windows","www"]},{"name":"wifi_tethering_off","tags":["cell","cellular","connection","data","disabled","enabled","internet","mobile","network","off","offline","on","phone","scan","service","signal","slash","speed","tethering","wifi","wireless"]},{"name":"text_decrease","tags":["-","alphabet","character","decrease","font","letter","minus","remove","resize","subtract","symbol","text","type"]},{"name":"view_comfy_alt","tags":["alt","comfy","cozy","design","format","layout","view","web"]},{"name":"photo_camera_back","tags":["back","camera","image","landscape","mountain","mountains","photo","photography","picture","rear"]},{"name":"folder_off","tags":["data","disabled","doc","document","drive","enabled","file","folder","folders","off","on","online","sheet","slash","slide","storage"]},{"name":"gas_meter","tags":["droplet","energy","gas","measure","meter","nest","usage","water"]},{"name":"edgesensor_high","tags":["Android","OS","cell","device","edge","hardware","high","iOS","mobile","move","phone","sensitivity","sensor","tablet","vibrate"]},{"name":"filter_5","tags":["5","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"stay_current_landscape","tags":["Android","OS","current","device","hardware","iOS","landscape","mobile","phone","stay","tablet"]},{"name":"sip","tags":["alphabet","call","character","dialer","font","initiation","internet","letter","over","phone","protocol","routing","session","sip","symbol","text","type","voice"]},{"name":"power_input","tags":["input","lines","power","supply"]},{"name":"smart_screen","tags":["Android","OS","airplay","cast","cell","connect","device","hardware","iOS","mobile","phone","screen","screencast","smart","stream","tablet","video"]},{"name":"mail_lock","tags":["email","envelop","letter","lock","locked","mail","message","password","privacy","private","protection","safety","secure","security","send"]},{"name":"dataset","tags":[]},{"name":"nat","tags":["communication","nat"]},{"name":"do_disturb_off","tags":["cancel","close","denied","deny","disabled","disturb","do","enabled","off","on","remove","silence","slash","stop"]},{"name":"no_drinks","tags":["alcohol","beverage","bottle","cocktail","drink","drinks","food","liquor","no","wine"]},{"name":"bike_scooter","tags":["automobile","bike","car","cars","maps","scooter","transportation","vehicle","vespa"]},{"name":"dock","tags":["Android","OS","cell","charging","connector","device","dock","hardware","iOS","mobile","phone","power","station","tablet"]},{"name":"face_2","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"face_retouching_off","tags":["disabled","edit","editing","effect","emoji","emotion","enabled","face","faces","image","natural","off","on","photo","photography","retouch","retouching","settings","slash","tag"]},{"name":"auto_fix_off","tags":["ai","artificial","auto","automatic","automation","custom","disabled","edit","enabled","erase","fix","genai","intelligence","magic","modify","off","on","slash","smart","spark","sparkle","star","wand"]},{"name":"airline_seat_flat","tags":["airline","body","business","class","first","flat","human","people","person","rest","seat","sleep","travel"]},{"name":"phone_locked","tags":["call","cell","contact","device","hardware","lock","locked","mobile","password","phone","privacy","private","protection","safety","secure","security","telephone"]},{"name":"network_locked","tags":["alert","available","cellular","connection","data","error","internet","lock","locked","mobile","network","not","privacy","private","protection","restricted","safety","secure","security","service","signal","warning","wifi","wireless"]},{"name":"padding","tags":["design","layout","margin","padding","size","square"]},{"name":"browser_not_supported","tags":["browser","disabled","enabled","internet","not","off","on","page","screen","site","slash","supported","web","website","www"]},{"name":"border_outer","tags":["border","doc","edit","editing","editor","outer","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"exposure_neg_1","tags":["1","brightness","contrast","digit","edit","editing","effect","exposure","image","neg","negative","number","photo","photography","settings","symbol"]},{"name":"view_compact_alt","tags":["alt","compact","design","format","layout dense","view","web"]},{"name":"pest_control_rodent","tags":["control","exterminator","mice","pest","rodent"]},{"name":"swipe_down_alt","tags":["alt","arrows","direction","disable","down","enable","finger","hands","hit","navigation","strike","swing","swpie","take"]},{"name":"airlines","tags":["airlines","airplane","airport","flight","plane","transportation","travel","trip"]},{"name":"turn_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","route","sign","traffic","turn"]},{"name":"sd","tags":["alphabet","camera","card","character","data","device","digital","drive","flash","font","image","letter","memory","photo","sd","secure","symbol","text","type"]},{"name":"near_me_disabled","tags":["destination","direction","disabled","enabled","location","maps","me","navigation","near","off","on","pin","place","point","slash"]},{"name":"face_4","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"stay_primary_landscape","tags":["Android","OS","current","device","hardware","iOS","landscape","mobile","phone","primary","stay","tablet"]},{"name":"4g_plus_mobiledata","tags":["4g","alphabet","cellular","character","digit","font","letter","mobile","mobiledata","network","number","phone","plus","signal","speed","symbol","text","type","wifi"]},{"name":"snowmobile","tags":["automobile","car","direction","skimobile","snow","snowmobile","social","sports","transportation","travel","vehicle","winter"]},{"name":"sign_language","tags":["communication","deaf","fingers","gesture","hand","language","sign"]},{"name":"network_ping","tags":["alert","available","cellular","connection","data","internet","ip","mobile","network","ping","service","signal","wifi","wireless"]},{"name":"signal_cellular_off","tags":["cell","cellular","data","disabled","enabled","internet","mobile","network","off","offline","on","phone","signal","slash","wifi","wireless"]},{"name":"signal_cellular_nodata","tags":["cell","cellular","data","internet","mobile","network","no","nodata","offline","phone","quit","signal","wifi","wireless","x"]},{"name":"no_sim","tags":["camera","card","device","eject","insert","memory","no","phone","sim","storage"]},{"name":"signal_wifi_4_bar_lock","tags":["4","bar","cell","cellular","data","internet","lock","locked","mobile","network","password","phone","privacy","private","protection","safety","secure","security","signal","wifi","wireless"]},{"name":"missed_video_call","tags":["arrow","call","camera","film","filming","hardware","image","missed","motion","picture","record","video","videography"]},{"name":"lte_mobiledata","tags":["alphabet","character","data","font","internet","letter","lte","mobile","network","speed","symbol","text","type","wifi","wireless"]},{"name":"earbuds_battery","tags":["accessory","audio","battery","charging","earbuds","earphone","headphone","listen","music","sound"]},{"name":"panorama_photosphere","tags":["angle","horizontal","image","panorama","photo","photography","photosphere","picture","wide"]},{"name":"no_crash","tags":["accident","auto","automobile","car","cars","check","collision","confirm","correct","crash","direction","done","enter","maps","mark","no","ok","okay","select","tick","transportation","vehicle","yes"]},{"name":"add_alarm","tags":[]},{"name":"directions_transit_filled","tags":["automobile","car","cars","direction","directions","filled","maps","public","rail","subway","train","transit","transportation","vehicle"]},{"name":"u_turn_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","route","sign","traffic","u-turn"]},{"name":"line_axis","tags":["axis","dash","horizontal","line","stroke","vertical"]},{"name":"density_large","tags":["density","horizontal","large","lines","rule","rules"]},{"name":"location_disabled","tags":["destination","direction","disabled","enabled","location","maps","off","on","pin","place","pointer","slash","stop","tracking"]},{"name":"bluetooth_drive","tags":["automobile","bluetooth","car","cars","cast","connect","connection","device","drive","maps","paring","streaming","symbol","transportation","travel","vehicle","wireless"]},{"name":"30fps","tags":["30fps","alphabet","camera","character","digit","font","fps","frames","letter","number","symbol","text","type","video"]},{"name":"no_luggage","tags":["bag","baggage","carry","disabled","enabled","luggage","no","off","on","slash","suitcase","travel"]},{"name":"leak_remove","tags":["connection","data","disabled","enabled","leak","link","network","off","offline","on","remove","service","signals","slash","synce","wireless"]},{"name":"filter_8","tags":["8","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"mobile_off","tags":["Android","OS","cell","device","disabled","enabled","hardware","iOS","mobile","off","on","phone","silence","slash","tablet"]},{"name":"key_off","tags":["disabled","enabled","key","lock","off","offline","on","password","slash","unlock"]},{"name":"signal_cellular_null","tags":["cell","cellular","data","internet","mobile","network","null","phone","signal","wifi","wireless"]},{"name":"phonelink_off","tags":["Android","OS","chrome","computer","connect","desktop","device","disabled","enabled","hardware","iOS","link","mac","mobile","off","on","phone","phonelink","slash","sync","tablet","web","windows"]},{"name":"filter_9","tags":["9","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"home_mini","tags":["Internet","device","gadget","hardware","home","iot","mini","nest","smart","things"]},{"name":"on_device_training","tags":["arrow","bulb","call","cell","contact","device","hardware","idea","inprogress","light","load","loading","mobile","model","phone","refresh","renew","restore","reverse","rotate","telephone","training"]},{"name":"egg_alt","tags":["breakfast","brunch","egg","food"]},{"name":"media_bluetooth_on","tags":["bluetooth","connect","connection","connectivity","device","disabled","enabled","media","music","note","off","on","online","paring","signal","slash","symbol","wireless"]},{"name":"10k","tags":["10000","10K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"video_stable","tags":["film","filming","recording","setting","stability","stable","taping","video"]},{"name":"add_home","tags":[]},{"name":"no_transfer","tags":["automobile","bus","car","cars","direction","disabled","enabled","maps","no","off","on","public","slash","transfer","transportation","vehicle"]},{"name":"timer_10","tags":["10","digits","duration","number","numbers","seconds","time","timer"]},{"name":"directions_subway_filled","tags":["automobile","car","cars","direction","directions","filled","maps","public","rail","subway","train","transportation","vehicle"]},{"name":"wb_shade","tags":["balance","house","light","lighting","shade","wb","white"]},{"name":"swipe_left_alt","tags":["alt","arrow","arrows","finger","hand","hit","left","navigation","reject","strike","swing","swipe","take"]},{"name":"filter_6","tags":["6","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"cyclone","tags":["crisis","disaster","natural","rain","storm","weather","wind","winds"]},{"name":"network_wifi_1_bar","tags":[]},{"name":"directions_railway_filled","tags":["automobile","car","cars","direction","directions","filled","maps","public","railway","train","transportation","vehicle"]},{"name":"wifi_find","tags":["(scan)","[cellular","connection","data","detect","discover","find","internet","look","magnifying glass","mobile]","network","notice","search","service","signal","wifi","wireless"]},{"name":"blur_off","tags":["blur","disabled","dots","edit","editing","effect","enabled","enhance","off","on","slash"]},{"name":"motion_photos_off","tags":["animation","circle","disabled","enabled","motion","off","on","photos","slash","video"]},{"name":"lyrics","tags":["audio","bubble","chat","comment","communicate","feedback","key","lyrics","message","music","note","song","sound","speech","track"]},{"name":"raw_on","tags":["alphabet","character","disabled","enabled","font","image","letter","off","on","original","photo","photography","raw","slash","symbol","text","type"]},{"name":"flight_class","tags":["airplane","business","class","first","flight","plane","seat","transportation","travel","trip","window"]},{"name":"insert_page_break","tags":["break","doc","document","file","page","paper"]},{"name":"rsvp","tags":["alphabet","character","font","invitation","invite","letter","plaît","respond","rsvp","répondez","sil","symbol","text","type","vous"]},{"name":"tire_repair","tags":["auto","automobile","car","cars","gauge","mechanic","pressure","repair","tire","vehicle"]},{"name":"swipe_up_alt","tags":["alt","arrows","direction","disable","enable","finger","hands","hit","navigation","strike","swing","swpie","take","up"]},{"name":"3g_mobiledata","tags":["3g","alphabet","cellular","character","digit","font","letter","mobile","mobiledata","network","number","phone","signal","speed","symbol","text","type","wifi"]},{"name":"tv_off","tags":["Android","OS","chrome","desktop","device","disabled","enabled","hardware","iOS","mac","monitor","off","on","slash","television","tv","web","window"]},{"name":"hdr_on","tags":["add","alphabet","character","dynamic","enhance","font","hdr","high","letter","on","plus","range","select","symbol","text","type"]},{"name":"add_home_work","tags":[]},{"name":"motion_photos_pause","tags":["animation","circle","motion","pause","paused","photos","video"]},{"name":"edgesensor_low","tags":["Android","cell","device","edge","hardware","iOS","low","mobile","move","phone","sensitivity","sensor","tablet","vibrate"]},{"name":"grid_goldenratio","tags":["golden","goldenratio","grid","layout","lines","ratio","space"]},{"name":"network_wifi_3_bar","tags":[]},{"name":"temple_buddhist","tags":["buddha","buddhism","buddhist","monastery","religion","spiritual","temple","worship"]},{"name":"airline_seat_flat_angled","tags":["airline","angled","body","business","class","first","flat","human","people","person","rest","seat","sleep","travel"]},{"name":"fort","tags":["castle","fort","fortress","mansion","palace"]},{"name":"spatial_tracking","tags":["audio","disabled","enabled","music","note","off","offline","on","slash","sound","spatial","tracking"]},{"name":"screen_lock_rotation","tags":["Android","OS","arrow","device","hardware","iOS","lock","mobile","phone","rotate","rotation","screen","tablet","turn"]},{"name":"fiber_pin","tags":["alphabet","character","fiber","font","letter","network","pin","symbol","text","type"]},{"name":"phone_bluetooth_speaker","tags":["bluetooth","call","cell","connect","connection","connectivity","contact","device","hardware","mobile","phone","signal","speaker","symbol","telephone","wireless"]},{"name":"vignette","tags":["border","edit","editing","filter","gradient","image","photo","photography","setting","vignette"]},{"name":"panorama_horizontal","tags":["angle","horizontal","image","panorama","photo","photography","picture","wide"]},{"name":"propane_tank","tags":["bbq","gas","grill","nest","propane","tank"]},{"name":"kebab_dining","tags":["dining","dinner","food","kebab","meal","meat","skewer"]},{"name":"developer_board_off","tags":["board","chip","computer","developer","development","disabled","enabled","hardware","microchip","off","on","processor","slash"]},{"name":"adf_scanner","tags":["adf","document","feeder","machine","office","scan","scanner"]},{"name":"no_cell","tags":["Android","OS","cell","device","disabled","enabled","hardware","iOS","mobile","no","off","on","phone","slash","tablet"]},{"name":"dirty_lens","tags":["camera","dirty","lens","photo","photography","picture","splat"]},{"name":"usb_off","tags":["cable","connection","device","off","usb","wire"]},{"name":"image_aspect_ratio","tags":["aspect","image","photo","photography","picture","ratio","rectangle","square"]},{"name":"30fps_select","tags":["30","camera","digits","fps","frame","frequency","image","numbers","per","rate","second","seconds","select","video"]},{"name":"60fps","tags":["60fps","camera","digit","fps","frames","number","symbol","video"]},{"name":"screen_lock_landscape","tags":["Android","OS","device","hardware","iOS","landscape","lock","mobile","phone","rotate","screen","tablet"]},{"name":"lte_plus_mobiledata","tags":["+","alphabet","character","data","font","internet","letter","lte","mobile","network","plus","speed","symbol","text","type","wifi","wireless"]},{"name":"piano_off","tags":["disabled","enabled","instrument","keyboard","keys","music","musical","off","on","piano","slash","social"]},{"name":"unfold_more_double","tags":["arrow","arrows","chevron","collapse","direction","double","down","expand","expandable","list","more","navigation","unfold"]},{"name":"deblur","tags":["adjust","deblur","edit","editing","enhance","face","image","lines","photo","photography","sharpen"]},{"name":"person_4","tags":["account","face","human","people","person","profile","user"]},{"name":"spatial_audio","tags":["audio","music","note","sound","spatial"]},{"name":"camera_rear","tags":["camera","front","lens","mobile","phone","photo","photography","picture","portrait","rear","selfie"]},{"name":"timer_10_select","tags":["10","alphabet","camera","character","digit","font","letter","number","seconds","select","symbol","text","timer","type"]},{"name":"face_5","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"minor_crash","tags":["accident","auto","automobile","car","cars","collision","directions","maps","public","transportation","vehicle"]},{"name":"sos","tags":["font","help","letters","save","sos","text","type"]},{"name":"videogame_asset_off","tags":["asset","console","controller","device","disabled","enabled","game","gamepad","gaming","off","on","playstation","slash","video","videogame"]},{"name":"flood","tags":["crisis","disaster","natural","rain","storm","weather"]},{"name":"60fps_select","tags":["60","camera","digits","fps","frame","frequency","numbers","per","rate","second","seconds","select","video"]},{"name":"timer_3","tags":["3","digits","duration","number","numbers","seconds","time","timer"]},{"name":"vpn_key_off","tags":["code","disabled","enabled","key","lock","network","off","offline","on","passcode","password","slash","unlock","vpn"]},{"name":"directions_off","tags":["arrow","directions","disabled","enabled","maps","off","on","right","route","sign","slash","traffic"]},{"name":"emergency_share","tags":["alert","attention","caution","danger","emergency","important","notification","share","warning"]},{"name":"panorama_wide_angle_select","tags":["angle","image","panorama","photo","photography","picture","select","wide"]},{"name":"airline_seat_legroom_normal","tags":["airline","body","feet","human","leg","legroom","normal","people","person","seat","sitting","space","travel"]},{"name":"fiber_dvr","tags":["alphabet","character","digital","dvr","electronics","fiber","font","letter","network","record","recorder","symbol","text","tv","type","video"]},{"name":"person_3","tags":["account","face","human","people","person","profile","user"]},{"name":"scuba_diving","tags":["diving","entertainment","exercise","hobby","scuba","social","swim","swimming"]},{"name":"signal_cellular_no_sim","tags":["camera","card","cellular","chip","device","disabled","enabled","memory","no","off","offline","on","phone","signal","sim","slash","storage"]},{"name":"24mp","tags":["24","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"exposure_neg_2","tags":["2","brightness","contrast","digit","edit","editing","effect","exposure","image","neg","negative","number","photo","photography","settings","symbol"]},{"name":"network_wifi_2_bar","tags":[]},{"name":"wifi_2_bar","tags":["2","bar","cell","cellular","connection","data","internet","mobile","network","phone","scan","service","signal","wifi","wireless"]},{"name":"u_turn_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sign","traffic","u-turn"]},{"name":"currency_yuan","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","shopping","symbol","yuan"]},{"name":"currency_lira","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","lira","money","online","pay","payment","price","shopping","symbol"]},{"name":"no_flash","tags":["bolt","camera","disabled","enabled","flash","image","lightning","no","off","on","photo","photography","picture","slash","thunderbolt"]},{"name":"temple_hindu","tags":["hindu","hinduism","hindus","mandir","religion","spiritual","temple","worship"]},{"name":"mode_fan_off","tags":["air conditioner","cool","disabled","enabled","fan","nest","off","on","slash"]},{"name":"airline_seat_legroom_extra","tags":["airline","body","extra","feet","human","leg","legroom","people","person","seat","sitting","space","travel"]},{"name":"4k_plus","tags":["+","4000","4K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"border_inner","tags":["border","doc","edit","editing","editor","inner","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"wifi_tethering_error","tags":["!","alert","attention","caution","cell","cellular","connection","danger","data","error","exclamation","important","internet","mark","mobile","network","notification","phone","rounded","scan","service","signal","speed","symbol","tethering","warning","wifi","wireless"]},{"name":"airline_seat_legroom_reduced","tags":["airline","body","feet","human","leg","legroom","people","person","reduced","seat","sitting","space","travel"]},{"name":"synagogue","tags":["jew","jewish","religion","shul","spiritual","temple","worship"]},{"name":"border_left","tags":["border","doc","edit","editing","editor","left","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"autofps_select","tags":["A","alphabet","auto","character","font","fps","frame","frequency","letter","per","rate","second","seconds","select","symbol","text","type"]},{"name":"signal_cellular_alt_2_bar","tags":["2","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","wifi","wireless"]},{"name":"g_mobiledata","tags":["alphabet","character","data","font","g","letter","mobile","network","service","symbol","text","type"]},{"name":"1k","tags":["1000","1K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"format_textdirection_l_to_r","tags":["align","alignment","doc","edit","editing","editor","format","ltr","sheet","spreadsheet","text","textdirection","type","writing"]},{"name":"border_bottom","tags":["border","bottom","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"fork_left","tags":["arrow","arrows","direction","directions","fork","left","maps","navigation","path","route","sign","traffic"]},{"name":"severe_cold","tags":["!","alert","attention","caution","climate","cold","crisis","danger","disaster","error","exclamation","important","notification","severe","snow","snowflake","warning","weather","winter"]},{"name":"tsunami","tags":["crisis","disaster","flood","rain","storm","tsunami","weather"]},{"name":"signal_cellular_alt_1_bar","tags":["1","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","wifi","wireless"]},{"name":"border_vertical","tags":["border","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","type","vertical","writing"]},{"name":"turn_sharp_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sharp","sign","traffic","turn"]},{"name":"no_backpack","tags":["accessory","backpack","bag","bookbag","knapsack","no","pack","travel"]},{"name":"remove_road","tags":["-","cancel","close","destination","direction","exit","highway","maps","minus","new","no","remove","road","stop","street","symbol","traffic","x"]},{"name":"timer_3_select","tags":["3","alphabet","camera","character","digit","font","letter","number","seconds","select","symbol","text","timer","type"]},{"name":"roller_skating","tags":["athlete","athletic","entertainment","exercise","hobby","roller","shoe","skate","skates","skating","social","sports","travel"]},{"name":"panorama_horizontal_select","tags":["angle","horizontal","image","panorama","photo","photography","picture","select","wide"]},{"name":"border_horizontal","tags":["border","doc","edit","editing","editor","horizontal","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"2k","tags":["2000","2K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"wifi_1_bar","tags":["1","bar","cell","cellular","connection","data","internet","mobile","network","phone","scan","service","signal","wifi","wireless"]},{"name":"format_textdirection_r_to_l","tags":["align","alignment","doc","edit","editing","editor","format","rtl","sheet","spreadsheet","text","textdirection","type","writing"]},{"name":"wifi_channel","tags":["(scan)","[cellular","channel","connection","data","internet","mobile]","network","service","signal","wifi","wireless"]},{"name":"roundabout_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","roundabout","route","sign","traffic"]},{"name":"wb_auto","tags":["A","W","alphabet","auto","automatic","balance","character","edit","editing","font","image","letter","photo","photography","symbol","text","type","white","wp"]},{"name":"panorama_photosphere_select","tags":["angle","horizontal","image","panorama","photo","photography","photosphere","picture","select","wide"]},{"name":"panorama_wide_angle","tags":["angle","image","panorama","photo","photography","picture","wide"]},{"name":"hdr_plus","tags":["+","add","alphabet","character","circle","dynamic","enhance","font","hdr","high","letter","plus","range","select","symbol","text","type"]},{"name":"panorama_vertical_select","tags":["angle","image","panorama","photo","photography","picture","select","vertical","wide"]},{"name":"border_top","tags":["border","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","top","type","writing"]},{"name":"mic_external_off","tags":["audio","disabled","enabled","external","mic","microphone","off","on","slash","sound","voice"]},{"name":"width_full","tags":[]},{"name":"h_mobiledata","tags":["alphabet","character","data","font","h","letter","mobile","network","service","symbol","text","type"]},{"name":"roller_shades","tags":["blinds","cover","curtains","nest","open","roller","shade","shutter","sunshade"]},{"name":"no_stroller","tags":["baby","care","carriage","child","children","disabled","enabled","infant","kid","newborn","no","off","on","parents","slash","stroller","toddler","young"]},{"name":"tornado","tags":["crisis","disaster","natural","rain","storm","tornado","weather","wind"]},{"name":"keyboard_control_key","tags":["control key","keyboard"]},{"name":"turn_slight_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sharp","sign","slight","traffic","turn"]},{"name":"border_right","tags":["border","doc","edit","editing","editor","right","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"1k_plus","tags":["+","1000","1K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"turn_slight_left","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sign","slight","traffic","turn"]},{"name":"screen_rotation_alt","tags":["Android","OS","arrow","device","hardware","iOS","mobile","phone","rotate","rotation","screen","tablet","turn"]},{"name":"dataset_linked","tags":[]},{"name":"unfold_less_double","tags":["arrow","arrows","chevron","collapse","direction","double","expand","expandable","inward","less","list","navigation","unfold","up"]},{"name":"8k","tags":["8000","8K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"landslide","tags":["crisis","disaster","natural","rain","storm","weather"]},{"name":"media_bluetooth_off","tags":["bluetooth","connect","connection","connectivity","device","disabled","enabled","media","music","note","off","offline","on","paring","signal","slash","symbol","wireless"]},{"name":"fire_truck","tags":[]},{"name":"e_mobiledata","tags":["alphabet","data","e","font","letter","mobile","mobiledata","text","type"]},{"name":"panorama_vertical","tags":["angle","image","panorama","photo","photography","picture","vertical","wide"]},{"name":"r_mobiledata","tags":["alphabet","character","data","font","letter","mobile","r","symbol","text","type"]},{"name":"12mp","tags":["12","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"repartition","tags":["arrow","arrows","data","partition","refresh","renew","repartition","restore","table"]},{"name":"width_normal","tags":[]},{"name":"h_plus_mobiledata","tags":["+","alphabet","character","data","font","h","letter","mobile","network","plus","service","symbol","text","type"]},{"name":"hdr_enhanced_select","tags":["add","alphabet","character","dynamic","enhance","font","hdr","high","letter","plus","range","select","symbol","text","type"]},{"name":"mp","tags":["alphabet","character","font","image","letter","megapixel","mp","photo","photography","pixels","quality","resolution","symbol","text","type"]},{"name":"shape_line","tags":["circle","draw","edit","editing","line","shape","square"]},{"name":"9k_plus","tags":["+","9000","9K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"5k","tags":["5000","5K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"hevc","tags":["alphabet","character","coding","efficiency","font","hevc","high","letter","symbol","text","type","video"]},{"name":"currency_franc","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","franc","money","online","pay","payment","price","shopping","symbol"]},{"name":"8k_plus","tags":["+","7000","8K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"hdr_on_select","tags":["+","alphabet","camera","character","circle","dynamic","font","hdr","high","letter","on","photo","range","select","symbol","text","type"]},{"name":"3k","tags":["3000","3K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"transcribe","tags":[]},{"name":"width_wide","tags":[]},{"name":"hdr_auto_select","tags":["+","A","alphabet","auto","camera","character","circle","dynamic","font","hdr","high","letter","photo","range","select","symbol","text","type"]},{"name":"hls","tags":["alphabet","character","develop","developer","engineer","engineering","font","hls","letter","platform","symbol","text","type"]},{"name":"5k_plus","tags":["+","5000","5K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"assist_walker","tags":["accessibility","accessible","assist","body","disability","handicap","help","human","injured","injury","mobility","person","walk","walker"]},{"name":"hls_off","tags":["alphabet","character","develop","developer","disabled","enabled","engineer","engineering","font","hls","letter","off","offline","on","platform","slash","symbol","text","type"]},{"name":"18mp","tags":["18","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"format_overline","tags":["alphabet","character","doc","edit","editing","editor","font","format","letter","line","overline","sheet","spreadsheet","style","symbol","text","type","under","writing"]},{"name":"volcano","tags":["crisis","disaster","eruption","lava","magma","natural","volcano"]},{"name":"vaping_rooms","tags":["allowed","e-cigarette","never","no","places","prohibited","smoke","smoking","tobacco","vape","vaping","vapor","warning","zone"]},{"name":"watch_off","tags":["Android","OS","ar","clock","close","gadget","iOS","off","shut","time","vr","watch","wearables","web","wristwatch"]},{"name":"9k","tags":["9000","9K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"23mp","tags":["23","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"propane","tags":["gas","nest","propane"]},{"name":"raw_off","tags":["alphabet","character","disabled","enabled","font","image","letter","off","on","original","photo","photography","raw","slash","symbol","text","type"]},{"name":"keyboard_option_key","tags":["alt key","key","keyboard","modifier key","option"]},{"name":"woman_2","tags":["female","gender","girl","lady","social","symbol","woman","women"]},{"name":"2k_plus","tags":["+","2k","alphabet","character","digit","font","letter","number","plus","symbol","text","type"]},{"name":"6k_plus","tags":["+","6000","6K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"broadcast_on_personal","tags":[]},{"name":"10mp","tags":["10","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"man_2","tags":["boy","gender","male","man","social","symbol"]},{"name":"7k","tags":["7000","7K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"7k_plus","tags":["+","7000","7K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"nearby_off","tags":["disabled","enabled","nearby","off","on","slash"]},{"name":"3k_plus","tags":["+","3000","3K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"6k","tags":["6000","6K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"hdr_off","tags":["alphabet","character","disabled","dynamic","enabled","enhance","font","hdr","high","letter","off","on","range","select","slash","symbol","text","type"]},{"name":"roundabout_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","roundabout","route","sign","traffic"]},{"name":"hdr_off_select","tags":["alphabet","camera","character","circle","disabled","dynamic","enabled","font","hdr","high","letter","off","on","photo","range","select","slash","symbol","text","type"]},{"name":"bedtime_off","tags":["bedtime","disabled","lunar","moon","night","nightime","off","offline","slash","sleep"]},{"name":"18_up_rating","tags":[]},{"name":"turn_sharp_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","route","sharp","sign","traffic","turn"]},{"name":"11mp","tags":["11","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"roller_shades_closed","tags":["blinds","closed","cover","curtains","nest","roller","shade","shutter","sunshade"]},{"name":"20mp","tags":["20","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"blinds","tags":["blinds","cover","curtains","nest","open","shade","shutter","sunshade"]},{"name":"3mp","tags":["3","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"blind","tags":["accessibility","accessible","assist","blind","body","cane","disability","handicap","help","human","mobility","person","walk","walker"]},{"name":"emergency_recording","tags":["alert","attention","camera","caution","danger","emergency","film","filming","hardware","image","important","motion","notification","picture","record","video","videography","warning"]},{"name":"curtains","tags":["blinds","cover","curtains","nest","open","shade","shutter","sunshade"]},{"name":"13mp","tags":["13","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"5mp","tags":["5","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"21mp","tags":["21","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"blinds_closed","tags":["blinds","closed","cover","curtains","nest","shade","shutter","sunshade"]},{"name":"16mp","tags":["16","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"17mp","tags":["17","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"2mp","tags":["2","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"15mp","tags":["15","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"desk","tags":[]},{"name":"no_adult_content","tags":[]},{"name":"14mp","tags":["14","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"22mp","tags":["22","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"vertical_shades","tags":["blinds","cover","curtains","nest","open","shade","shutter","sunshade","vertical"]},{"name":"vertical_shades_closed","tags":["blinds","closed","cover","curtains","nest","roller","shade","shutter","sunshade"]},{"name":"curtains_closed","tags":["blinds","closed","cover","curtains","nest","shade","shutter","sunshade"]},{"name":"broadcast_on_home","tags":[]},{"name":"4mp","tags":["4","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"19mp","tags":["19","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"nest_cam_wired_stand","tags":["camera","film","filming","hardware","image","motion","nest","picture","stand","video","videography","wired"]},{"name":"9mp","tags":["9","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"7mp","tags":["7","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"8mp","tags":["8","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"6mp","tags":["6","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"devices_fold","tags":["Android","OS","cell","device","fold","foldable","hardware","iOS","mobile","phone","tablet"]},{"name":"vape_free","tags":["disabled","e-cigarette","enabled","free","never","no","off","on","places","prohibited","slash","smoke","smoking","tobacco","vape","vaping","vapor","warning","zone"]},{"name":"ramp_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","ramp","route","sign","traffic"]},{"name":"ramp_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","ramp","right","route","sign","traffic"]},{"name":"video_chat","tags":["bubble","cam","camera","chat","comment","communicate","facetime","feedback","message","speech","video","voice"]},{"name":"type_specimen","tags":[]},{"name":"man_4","tags":["abstract","boy","gender","male","man","social","symbol"]},{"name":"fluorescent","tags":["bright","fluorescent","lamp","light","lightbulb"]},{"name":"man_3","tags":["abstract","boy","gender","male","man","social","symbol"]},{"name":"fire_hydrant_alt","tags":[]},{"name":"macro_off","tags":["camera","disabled","enabled","flower","garden","image","macro","off","offline","on","slash"]},{"name":"mdi:ab-testing","tags":["developer / languages"]},{"name":"mdi:abacus","tags":["math"]},{"name":"mdi:abjad-arabic","tags":["alpha / numeric","writing system arabic"]},{"name":"mdi:abjad-hebrew","tags":["alpha / numeric","writing system hebrew"]},{"name":"mdi:abugida-devanagari","tags":["alpha / numeric","writing system devanagari"]},{"name":"mdi:abugida-thai","tags":["alpha / numeric","writing system thai"]},{"name":"mdi:access-point","tags":["wireless"]},{"name":"mdi:access-point-check","tags":["access point success","access point tick"]},{"name":"mdi:access-point-minus","tags":[]},{"name":"mdi:access-point-network","tags":[]},{"name":"mdi:access-point-network-off","tags":[]},{"name":"mdi:access-point-off","tags":[]},{"name":"mdi:access-point-plus","tags":[]},{"name":"mdi:access-point-remove","tags":[]},{"name":"mdi:account-alert","tags":["account / user","alert / error","user alert","account warning","user warning","person alert","person warning"]},{"name":"mdi:account-alert-outline","tags":["account / user","alert / error","user alert outline","account warning outline","user warning outline","person warning outline","person alert outline"]},{"name":"mdi:account-arrow-down","tags":["account / user","account download"]},{"name":"mdi:account-arrow-down-outline","tags":["account / user","account download outline"]},{"name":"mdi:account-arrow-left","tags":["account / user","user arrow left","person arrow left"]},{"name":"mdi:account-arrow-left-outline","tags":["account / user","user arrow left outline","person arrow left outline"]},{"name":"mdi:account-arrow-right","tags":["account / user","user arrow right","person arrow right"]},{"name":"mdi:account-arrow-right-outline","tags":["account / user","user arrow right outline","person arrow right outline"]},{"name":"mdi:account-arrow-up","tags":["account / user","account upload"]},{"name":"mdi:account-arrow-up-outline","tags":["account / user","account upload outline"]},{"name":"mdi:account-badge","tags":["account / user","account online","user online"]},{"name":"mdi:account-badge-outline","tags":["account / user","user online outline","account online outline"]},{"name":"mdi:account-box-multiple-outline","tags":["account / user"]},{"name":"mdi:account-cancel","tags":["account / user","user cancel","user block","person cancel","person block"]},{"name":"mdi:account-cancel-outline","tags":["account / user","user cancel outline","user block outline","person cancel outline","person block outline"]},{"name":"mdi:account-card","tags":["account / user"]},{"name":"mdi:account-card-outline","tags":["account / user"]},{"name":"mdi:account-cash","tags":["account / user","banking","currency"]},{"name":"mdi:account-cash-outline","tags":["account / user","banking","currency"]},{"name":"mdi:account-child-outline","tags":["account / user"]},{"name":"mdi:account-clock","tags":["account / user","date / time","user clock","account pending","person clock"]},{"name":"mdi:account-clock-outline","tags":["account / user","date / time","user clock outline","account pending outline","person clock outline"]},{"name":"mdi:account-cog","tags":["account / user","settings","account settings"]},{"name":"mdi:account-cog-outline","tags":["account / user","settings","account settings outline"]},{"name":"mdi:account-convert","tags":["account / user","user convert","person convert"]},{"name":"mdi:account-convert-outline","tags":["account / user"]},{"name":"mdi:account-cowboy-hat","tags":["account / user","agriculture","rancher"]},{"name":"mdi:account-cowboy-hat-outline","tags":["account / user","agriculture","rancher outline"]},{"name":"mdi:account-credit-card","tags":["account / user","banking","account payment","cardholder"]},{"name":"mdi:account-credit-card-outline","tags":["account / user","banking","account payment outline","cardholder outline"]},{"name":"mdi:account-details-outline","tags":["account / user","settings","person details outline","user details outline"]},{"name":"mdi:account-edit","tags":["account / user","edit / modify","user edit","person edit"]},{"name":"mdi:account-edit-outline","tags":["account / user","edit / modify"]},{"name":"mdi:account-eye","tags":["account / user","account view"]},{"name":"mdi:account-eye-outline","tags":["account / user","account view outline"]},{"name":"mdi:account-filter","tags":["account / user","account funnel","leads"]},{"name":"mdi:account-filter-outline","tags":["account / user","account funnel outline","leads outline"]},{"name":"mdi:account-group","tags":["account / user","home automation","user group","users group","person group","people group","accounts group"]},{"name":"mdi:account-group-outline","tags":["account / user","user group outline","users group outline","person group outline","people group outline","accounts group outline"]},{"name":"mdi:account-hard-hat","tags":["account / user","worker","construction"]},{"name":"mdi:account-hard-hat-outline","tags":["account / user","worker outline","construction outline"]},{"name":"mdi:account-heart","tags":["account / user","medical / hospital","user heart","person heart"]},{"name":"mdi:account-heart-outline","tags":["account / user","medical / hospital","user heart outline","person heart outline"]},{"name":"mdi:account-key","tags":["account / user","user key","person key"]},{"name":"mdi:account-key-outline","tags":["account / user","user key outline","person key outline"]},{"name":"mdi:account-lock","tags":["account / user","lock","account security","account secure","user lock","person lock"]},{"name":"mdi:account-lock-open","tags":["account / user","lock","account unlocked","user unlocked","user lock open"]},{"name":"mdi:account-lock-open-outline","tags":["account / user","lock","user lock open outline","user unlocked outline","account unlocked outline"]},{"name":"mdi:account-lock-outline","tags":["account / user","lock","account security outline","account secure outline","person lock outline","user lock outline"]},{"name":"mdi:account-minus","tags":["account / user","user minus","person minus"]},{"name":"mdi:account-minus-outline","tags":["account / user","user minus outline","person minus outline"]},{"name":"mdi:account-multiple-check","tags":["account / user","user multiple check","account multiple tick","accounts check","accounts tick","users check","users tick","user multiple tick","person multiple check","person multiple tick","people check","people tick","account multiple success"]},{"name":"mdi:account-multiple-check-outline","tags":["account / user","user multiple check outline","account multiple tick outline","accounts check outline","accounts tick outline","users check outline","users tick outline","user multiple tick outline","person multiple check outline","person multiple tick outline","people check outline","people tick outline","account multiple success outline"]},{"name":"mdi:account-multiple-remove","tags":["account / user","user multiple remove","person multiple remove"]},{"name":"mdi:account-multiple-remove-outline","tags":["account / user","user multiple remove outline","person multiple remove outline"]},{"name":"mdi:account-music-outline","tags":["account / user","artist outline"]},{"name":"mdi:account-network","tags":["account / user","user network","person network"]},{"name":"mdi:account-network-off","tags":["account / user"]},{"name":"mdi:account-network-off-outline","tags":["account / user"]},{"name":"mdi:account-network-outline","tags":["account / user","user network outline","person network outline"]},{"name":"mdi:account-off","tags":["account / user","user off","person off"]},{"name":"mdi:account-off-outline","tags":["account / user","user off outline","person off outline"]},{"name":"mdi:account-plus-outline","tags":["account / user","person add outline","register outline","user plus outline","account add outline","person plus outline","user add outline","invite"]},{"name":"mdi:account-question","tags":["account / user","user help","account question mark","account help","user question","person question","person help"]},{"name":"mdi:account-question-outline","tags":["account / user","account question mark outline","user help outline","account help outline","user question outline","person question outline","person help outline"]},{"name":"mdi:account-reactivate","tags":["account / user"]},{"name":"mdi:account-reactivate-outline","tags":["account / user"]},{"name":"mdi:account-remove","tags":["account / user","user remove","person remove"]},{"name":"mdi:account-remove-outline","tags":["account / user","user remove outline","person remove outline"]},{"name":"mdi:account-school","tags":["account / user","account student","account graduation"]},{"name":"mdi:account-school-outline","tags":["account / user","account student outline","account graduation outline"]},{"name":"mdi:account-search","tags":["account / user","user search","person search"]},{"name":"mdi:account-search-outline","tags":["account / user","user search outline","person search outline"]},{"name":"mdi:account-settings","tags":["account / user","settings","user settings","person settings"]},{"name":"mdi:account-settings-outline","tags":["account / user","settings"]},{"name":"mdi:account-star","tags":["account / user","user star","person star","account favorite"]},{"name":"mdi:account-star-outline","tags":["account / user","user star outline","person star outline"]},{"name":"mdi:account-supervisor-outline","tags":["account / user"]},{"name":"mdi:account-switch","tags":["account / user","user switch","accounts switch","users switch","person switch","people switch"]},{"name":"mdi:account-switch-outline","tags":["account / user"]},{"name":"mdi:account-sync","tags":["account / user","account cache"]},{"name":"mdi:account-sync-outline","tags":["account / user","account cache outline"]},{"name":"mdi:account-tag","tags":["account / user"]},{"name":"mdi:account-tag-outline","tags":["account / user"]},{"name":"mdi:account-tie","tags":["account / user","people / family","person tie","user tie"]},{"name":"mdi:account-tie-hat","tags":["account / user","transportation + flying","account pilot"]},{"name":"mdi:account-tie-hat-outline","tags":["account / user","transportation + flying","account pilot outline"]},{"name":"mdi:account-tie-outline","tags":["account / user"]},{"name":"mdi:account-tie-voice","tags":["account / user"]},{"name":"mdi:account-tie-voice-off","tags":["account / user"]},{"name":"mdi:account-tie-voice-off-outline","tags":["account / user"]},{"name":"mdi:account-tie-voice-outline","tags":["account / user"]},{"name":"mdi:account-tie-woman","tags":["account / user","people / family","business woman"]},{"name":"mdi:account-wrench","tags":["account / user","account service"]},{"name":"mdi:account-wrench-outline","tags":["account / user","account service outline"]},{"name":"mdi:advertisements","tags":["ads"]},{"name":"mdi:advertisements-off","tags":["ads off"]},{"name":"mdi:air-conditioner","tags":["home automation","automotive","ac unit"]},{"name":"mdi:air-filter","tags":["home automation","water filter","filter"]},{"name":"mdi:air-horn","tags":[]},{"name":"mdi:air-humidifier","tags":["home automation"]},{"name":"mdi:air-humidifier-off","tags":["home automation","air dehumidifier"]},{"name":"mdi:air-purifier-off","tags":["home automation"]},{"name":"mdi:airbag","tags":["automotive"]},{"name":"mdi:airballoon","tags":["transportation + other","transportation + flying","hot air balloon"]},{"name":"mdi:airballoon-outline","tags":["transportation + flying","hot air balloon outline"]},{"name":"mdi:airplane","tags":["transportation + flying","navigation","aeroplane","airplanemode active","flight","local airport","flight mode","plane"]},{"name":"mdi:airplane-alert","tags":["transportation + flying","alert / error"]},{"name":"mdi:airplane-check","tags":["transportation + flying","airplace success","airplane tick"]},{"name":"mdi:airplane-clock","tags":["transportation + flying","date / time","airplane schedule","airplane time","airplane date"]},{"name":"mdi:airplane-cog","tags":["transportation + flying","settings","airplane settings"]},{"name":"mdi:airplane-edit","tags":["transportation + flying","edit / modify"]},{"name":"mdi:airplane-marker","tags":["transportation + flying","navigation","airplane location","airplane gps"]},{"name":"mdi:airplane-minus","tags":["transportation + flying"]},{"name":"mdi:airplane-off","tags":["transportation + flying","aeroplane off","airplanemode inactive","flight mode off","plane off"]},{"name":"mdi:airplane-plus","tags":["transportation + flying"]},{"name":"mdi:airplane-remove","tags":["transportation + flying"]},{"name":"mdi:airplane-search","tags":["transportation + flying","airplane find"]},{"name":"mdi:airplane-settings","tags":["transportation + flying","settings"]},{"name":"mdi:airport","tags":["places","transportation + flying"]},{"name":"mdi:alarm-bell","tags":["notification"]},{"name":"mdi:alarm-light","tags":["home automation"]},{"name":"mdi:alarm-light-off","tags":["home automation"]},{"name":"mdi:alarm-light-off-outline","tags":["home automation"]},{"name":"mdi:alarm-light-outline","tags":["home automation"]},{"name":"mdi:alarm-multiple","tags":["date / time","alarms","alarm clock multiple","alarm clocks"]},{"name":"mdi:alarm-note","tags":[]},{"name":"mdi:alarm-note-off","tags":[]},{"name":"mdi:alarm-panel","tags":["home automation"]},{"name":"mdi:alarm-panel-outline","tags":["home automation"]},{"name":"mdi:alert-box","tags":["alert / error","warning box"]},{"name":"mdi:alert-box-outline","tags":["alert / error","warning box outline"]},{"name":"mdi:alert-circle-check","tags":["alert / error","alert circle success"]},{"name":"mdi:alert-circle-check-outline","tags":["alert / error","alert circle success outline"]},{"name":"mdi:alert-decagram-outline","tags":["alert / error","warning decagram outline"]},{"name":"mdi:alert-minus","tags":["alert / error"]},{"name":"mdi:alert-minus-outline","tags":["alert / error"]},{"name":"mdi:alert-octagon-outline","tags":["alert / error","warning octagon outline","stop alert outline"]},{"name":"mdi:alert-octagram","tags":["alert / error","warning octagram"]},{"name":"mdi:alert-octagram-outline","tags":["alert / error","warning octagram outline"]},{"name":"mdi:alert-outline","tags":["alert / error","warning outline"]},{"name":"mdi:alert-plus","tags":["alert / error"]},{"name":"mdi:alert-plus-outline","tags":["alert / error"]},{"name":"mdi:alert-remove","tags":["alert / error"]},{"name":"mdi:alert-remove-outline","tags":["alert / error"]},{"name":"mdi:alert-rhombus","tags":["alert / error"]},{"name":"mdi:alert-rhombus-outline","tags":["alert / error"]},{"name":"mdi:alien","tags":[]},{"name":"mdi:alien-outline","tags":[]},{"name":"mdi:all-inclusive-box","tags":["infinity box","forever box"]},{"name":"mdi:all-inclusive-box-outline","tags":["forever box outline","infinity box outline"]},{"name":"mdi:allergy","tags":["medical / hospital","hand","rash","germ"]},{"name":"mdi:alpha","tags":["alpha / numeric"]},{"name":"mdi:alpha-a","tags":["alpha / numeric","alphabet a","letter a"]},{"name":"mdi:alpha-a-box","tags":["alpha / numeric","alphabet a box","letter a box"]},{"name":"mdi:alpha-a-box-outline","tags":["alpha / numeric","alphabet a box outline","letter a box outline"]},{"name":"mdi:alpha-a-circle","tags":["alpha / numeric","alphabet a circle","letter a circle"]},{"name":"mdi:alpha-a-circle-outline","tags":["alpha / numeric","alphabet a circle outline","letter a circle outline"]},{"name":"mdi:alpha-b","tags":["alpha / numeric","alphabet b","letter b"]},{"name":"mdi:alpha-b-box","tags":["alpha / numeric","alphabet b box","letter b box"]},{"name":"mdi:alpha-b-box-outline","tags":["alpha / numeric","alphabet b box outline","letter b box outline"]},{"name":"mdi:alpha-b-circle","tags":["alpha / numeric","alphabet b circle","letter b circle"]},{"name":"mdi:alpha-b-circle-outline","tags":["alpha / numeric","alphabet b circle outline","letter b circle outline"]},{"name":"mdi:alpha-c","tags":["alpha / numeric","alphabet c","letter c"]},{"name":"mdi:alpha-c-box","tags":["alpha / numeric","alphabet c box","letter c box"]},{"name":"mdi:alpha-c-box-outline","tags":["alpha / numeric","alphabet c box outline","letter c box outline"]},{"name":"mdi:alpha-c-circle","tags":["alpha / numeric","alphabet c circle","letter c circle"]},{"name":"mdi:alpha-c-circle-outline","tags":["alpha / numeric","alphabet c circle outline","letter c circle outline"]},{"name":"mdi:alpha-d","tags":["automotive","alpha / numeric","alphabet d","letter d","drive"]},{"name":"mdi:alpha-d-box","tags":["alpha / numeric","alphabet d box","letter d box"]},{"name":"mdi:alpha-d-box-outline","tags":["alpha / numeric","alphabet d box outline","letter d box outline"]},{"name":"mdi:alpha-d-circle","tags":["alpha / numeric","alphabet d circle","letter d circle"]},{"name":"mdi:alpha-d-circle-outline","tags":["alpha / numeric","alphabet d circle outline","letter d circle outline"]},{"name":"mdi:alpha-e","tags":["alpha / numeric","alphabet e","letter e"]},{"name":"mdi:alpha-e-box","tags":["alpha / numeric","alphabet e box","letter e box"]},{"name":"mdi:alpha-e-box-outline","tags":["alpha / numeric","alphabet e box outline","letter e box outline"]},{"name":"mdi:alpha-e-circle","tags":["alpha / numeric","alphabet e circle","letter e circle"]},{"name":"mdi:alpha-e-circle-outline","tags":["alpha / numeric","alphabet e circle outline","letter e circle outline"]},{"name":"mdi:alpha-f","tags":["alpha / numeric","alphabet f","letter f"]},{"name":"mdi:alpha-f-box","tags":["alpha / numeric","alphabet f box","letter f box"]},{"name":"mdi:alpha-f-box-outline","tags":["alpha / numeric","alphabet f box outline","letter f box outline"]},{"name":"mdi:alpha-f-circle","tags":["alpha / numeric","alphabet f circle","letter f circle"]},{"name":"mdi:alpha-f-circle-outline","tags":["alpha / numeric","alphabet f circle outline","letter f circle outline"]},{"name":"mdi:alpha-g","tags":["alpha / numeric","alphabet g","letter g"]},{"name":"mdi:alpha-g-box","tags":["alpha / numeric","alphabet g box","letter g box"]},{"name":"mdi:alpha-g-box-outline","tags":["alpha / numeric","alphabet g box outline","letter g box outline"]},{"name":"mdi:alpha-g-circle","tags":["alpha / numeric","alphabet g circle","letter g circle"]},{"name":"mdi:alpha-g-circle-outline","tags":["alpha / numeric","alphabet g circle outline","letter g circle outline"]},{"name":"mdi:alpha-h","tags":["alpha / numeric","alphabet h","letter h"]},{"name":"mdi:alpha-h-box","tags":["alpha / numeric","alphabet h box","letter h box"]},{"name":"mdi:alpha-h-box-outline","tags":["alpha / numeric","alphabet h box outline","letter h box outline"]},{"name":"mdi:alpha-h-circle","tags":["alpha / numeric","alphabet h circle","letter h circle"]},{"name":"mdi:alpha-h-circle-outline","tags":["alpha / numeric","alphabet h circle outline","letter h circle outline","helipad"]},{"name":"mdi:alpha-i","tags":["alpha / numeric","alphabet i","letter i","roman numeral 1"]},{"name":"mdi:alpha-i-box","tags":["alpha / numeric","alphabet i box","letter i box"]},{"name":"mdi:alpha-i-box-outline","tags":["alpha / numeric","alphabet i box outline","letter i box outline"]},{"name":"mdi:alpha-i-circle","tags":["alpha / numeric","alphabet i circle","letter i circle"]},{"name":"mdi:alpha-i-circle-outline","tags":["alpha / numeric","alphabet i circle outline","letter i circle outline"]},{"name":"mdi:alpha-j","tags":["alpha / numeric","alphabet j","letter j"]},{"name":"mdi:alpha-j-box","tags":["alpha / numeric","alphabet j box","letter j box"]},{"name":"mdi:alpha-j-box-outline","tags":["alpha / numeric","alphabet j box outline","letter j box outline"]},{"name":"mdi:alpha-j-circle","tags":["alpha / numeric","alphabet j circle","letter j circle"]},{"name":"mdi:alpha-j-circle-outline","tags":["alpha / numeric","alphabet j circle outline","letter j circle outline"]},{"name":"mdi:alpha-k","tags":["alpha / numeric","alphabet k","letter k"]},{"name":"mdi:alpha-k-box","tags":["alpha / numeric","alphabet k box","letter k box"]},{"name":"mdi:alpha-k-box-outline","tags":["alpha / numeric","alphabet k box outline","letter k box outline"]},{"name":"mdi:alpha-k-circle","tags":["alpha / numeric","alphabet k circle","letter k circle"]},{"name":"mdi:alpha-k-circle-outline","tags":["alpha / numeric","alphabet k circle outline","letter k circle outline"]},{"name":"mdi:alpha-l","tags":["alpha / numeric","alphabet l","letter l"]},{"name":"mdi:alpha-l-box","tags":["alpha / numeric","alphabet l box","letter l box"]},{"name":"mdi:alpha-l-box-outline","tags":["alpha / numeric","alphabet l box outline","letter l box outline"]},{"name":"mdi:alpha-l-circle","tags":["alpha / numeric","alphabet l circle","letter l circle"]},{"name":"mdi:alpha-l-circle-outline","tags":["alpha / numeric","alphabet l circle outline","letter l circle outline"]},{"name":"mdi:alpha-m","tags":["alpha / numeric","alphabet m","letter m"]},{"name":"mdi:alpha-m-box","tags":["alpha / numeric","alphabet m box","letter m box"]},{"name":"mdi:alpha-m-box-outline","tags":["alpha / numeric","alphabet m box outline","letter m box outline"]},{"name":"mdi:alpha-m-circle","tags":["alpha / numeric","alphabet m circle","letter m circle"]},{"name":"mdi:alpha-m-circle-outline","tags":["alpha / numeric","alphabet m circle outline","letter m circle outline"]},{"name":"mdi:alpha-n","tags":["automotive","alpha / numeric","alphabet n","letter n","neutral"]},{"name":"mdi:alpha-n-box","tags":["alpha / numeric","alphabet n box","letter n box"]},{"name":"mdi:alpha-n-box-outline","tags":["alpha / numeric","alphabet n box outline","letter n box outline"]},{"name":"mdi:alpha-n-circle","tags":["alpha / numeric","alphabet n circle","letter n circle"]},{"name":"mdi:alpha-n-circle-outline","tags":["alpha / numeric","alphabet n circle outline","letter n circle outline"]},{"name":"mdi:alpha-o","tags":["alpha / numeric","alphabet o","letter o"]},{"name":"mdi:alpha-o-box","tags":["alpha / numeric","alphabet o box","letter o box"]},{"name":"mdi:alpha-o-box-outline","tags":["alpha / numeric","alphabet o box outline","letter o box outline"]},{"name":"mdi:alpha-o-circle","tags":["alpha / numeric","alphabet o circle","letter o circle"]},{"name":"mdi:alpha-o-circle-outline","tags":["alpha / numeric","alphabet o circle outline","letter o circle outline"]},{"name":"mdi:alpha-p","tags":["automotive","alpha / numeric","alphabet p","letter p","park"]},{"name":"mdi:alpha-p-box","tags":["alpha / numeric","alphabet p box","letter p box"]},{"name":"mdi:alpha-p-box-outline","tags":["alpha / numeric","alphabet p box outline","letter p box outline"]},{"name":"mdi:alpha-p-circle","tags":["alpha / numeric","alphabet p circle","letter p circle"]},{"name":"mdi:alpha-p-circle-outline","tags":["alpha / numeric","alphabet p circle outline","letter p circle outline"]},{"name":"mdi:alpha-q","tags":["alpha / numeric","alphabet q","letter q"]},{"name":"mdi:alpha-q-box","tags":["alpha / numeric","alphabet q box","letter q box"]},{"name":"mdi:alpha-q-box-outline","tags":["alpha / numeric","alphabet q box outline","letter q box outline"]},{"name":"mdi:alpha-q-circle","tags":["alpha / numeric","alphabet q circle","letter q circle"]},{"name":"mdi:alpha-q-circle-outline","tags":["alpha / numeric","alphabet q circle outline","letter q circle outline"]},{"name":"mdi:alpha-r","tags":["automotive","alpha / numeric","alphabet r","letter r","reverse"]},{"name":"mdi:alpha-r-box","tags":["alpha / numeric","alphabet r box","letter r box"]},{"name":"mdi:alpha-r-box-outline","tags":["alpha / numeric","alphabet r box outline","letter r box outline"]},{"name":"mdi:alpha-r-circle","tags":["alpha / numeric","alphabet r circle","letter r circle"]},{"name":"mdi:alpha-r-circle-outline","tags":["alpha / numeric","alphabet r circle outline","letter r circle outline"]},{"name":"mdi:alpha-s","tags":["alpha / numeric","alphabet s","letter s"]},{"name":"mdi:alpha-s-box","tags":["alpha / numeric","alphabet s box","letter s box"]},{"name":"mdi:alpha-s-box-outline","tags":["alpha / numeric","alphabet s box outline","letter s box outline"]},{"name":"mdi:alpha-s-circle","tags":["alpha / numeric","alphabet s circle","letter s circle"]},{"name":"mdi:alpha-s-circle-outline","tags":["alpha / numeric","alphabet s circle outline","letter s circle outline"]},{"name":"mdi:alpha-t","tags":["alpha / numeric","alphabet t","letter t"]},{"name":"mdi:alpha-t-box","tags":["alpha / numeric","alphabet t box","letter t box"]},{"name":"mdi:alpha-t-box-outline","tags":["alpha / numeric","alphabet t box outline","letter t box outline"]},{"name":"mdi:alpha-t-circle","tags":["alpha / numeric","alphabet t circle","letter t circle"]},{"name":"mdi:alpha-t-circle-outline","tags":["alpha / numeric","alphabet t circle outline","letter t circle outline"]},{"name":"mdi:alpha-u","tags":["alpha / numeric","alphabet u","letter u"]},{"name":"mdi:alpha-u-box","tags":["alpha / numeric","alphabet u box","letter u box"]},{"name":"mdi:alpha-u-box-outline","tags":["alpha / numeric","alphabet u box outline","letter u box outline"]},{"name":"mdi:alpha-u-circle","tags":["alpha / numeric","alphabet u circle","letter u circle"]},{"name":"mdi:alpha-u-circle-outline","tags":["alpha / numeric","alphabet u circle outline","letter u circle outline"]},{"name":"mdi:alpha-v","tags":["alpha / numeric","alphabet v","letter v","roman numeral 5"]},{"name":"mdi:alpha-v-box","tags":["alpha / numeric","alphabet v box","letter v box"]},{"name":"mdi:alpha-v-box-outline","tags":["alpha / numeric","alphabet v box outline","letter v box outline"]},{"name":"mdi:alpha-v-circle","tags":["alpha / numeric","alphabet v circle","letter v circle"]},{"name":"mdi:alpha-v-circle-outline","tags":["alpha / numeric","alphabet v circle outline","letter v circle outline"]},{"name":"mdi:alpha-w","tags":["alpha / numeric","alphabet w","letter w"]},{"name":"mdi:alpha-w-box","tags":["alpha / numeric","alphabet w box","letter w box"]},{"name":"mdi:alpha-w-box-outline","tags":["alpha / numeric","alphabet w box outline","letter w box outline"]},{"name":"mdi:alpha-w-circle","tags":["alpha / numeric","alphabet w circle","letter w circle"]},{"name":"mdi:alpha-w-circle-outline","tags":["alpha / numeric","alphabet w circle outline","letter w circle outline"]},{"name":"mdi:alpha-x","tags":["alpha / numeric","alphabet x","letter x","roman numeral 10"]},{"name":"mdi:alpha-x-box","tags":["alpha / numeric","alphabet x box","letter x box"]},{"name":"mdi:alpha-x-box-outline","tags":["alpha / numeric","alphabet x box outline","letter x box outline"]},{"name":"mdi:alpha-x-circle","tags":["alpha / numeric","alphabet x circle","letter x circle"]},{"name":"mdi:alpha-x-circle-outline","tags":["alpha / numeric","alphabet x circle outline","letter x circle outline"]},{"name":"mdi:alpha-y","tags":["alpha / numeric","alphabet y","letter y"]},{"name":"mdi:alpha-y-box","tags":["alpha / numeric","alphabet y box","letter y box"]},{"name":"mdi:alpha-y-box-outline","tags":["alpha / numeric","alphabet y box outline","letter y box outline"]},{"name":"mdi:alpha-y-circle","tags":["alpha / numeric","alphabet y circle","letter y circle"]},{"name":"mdi:alpha-y-circle-outline","tags":["alpha / numeric","alphabet y circle outline","letter y circle outline"]},{"name":"mdi:alpha-z","tags":["alpha / numeric","alphabet z","letter z"]},{"name":"mdi:alpha-z-box","tags":["alpha / numeric","alphabet z box","letter z box"]},{"name":"mdi:alpha-z-box-outline","tags":["alpha / numeric","alphabet z box outline","letter z box outline"]},{"name":"mdi:alpha-z-circle","tags":["alpha / numeric","alphabet z circle","letter z circle"]},{"name":"mdi:alpha-z-circle-outline","tags":["alpha / numeric","alphabet z circle outline","letter z circle outline"]},{"name":"mdi:alphabet-aurebesh","tags":["alpha / numeric","writing system aurebesh"]},{"name":"mdi:alphabet-cyrillic","tags":["alpha / numeric","writing system cyrillic"]},{"name":"mdi:alphabet-greek","tags":["alpha / numeric","writing system greek"]},{"name":"mdi:alphabet-latin","tags":["alpha / numeric","writing system latin"]},{"name":"mdi:alphabet-piqad","tags":["alpha / numeric","writing system piqad"]},{"name":"mdi:alphabet-tengwar","tags":["alpha / numeric","writing system tengwar"]},{"name":"mdi:alphabetical","tags":["alpha / numeric","letters","a b c","abc"]},{"name":"mdi:alphabetical-off","tags":["alpha / numeric","letters off","abc off","a b c off"]},{"name":"mdi:alphabetical-variant","tags":["alpha / numeric","letters","abc","a b c"]},{"name":"mdi:alphabetical-variant-off","tags":["alpha / numeric","letters off","abc off","a b c off"]},{"name":"mdi:altimeter","tags":[]},{"name":"mdi:ambulance","tags":["transportation + road","medical / hospital"]},{"name":"mdi:ammunition","tags":["bullets"]},{"name":"mdi:ampersand","tags":["and"]},{"name":"mdi:amplifier","tags":["home automation","music"]},{"name":"mdi:amplifier-off","tags":[]},{"name":"mdi:angle-acute","tags":["math"]},{"name":"mdi:angle-obtuse","tags":["math"]},{"name":"mdi:angle-right","tags":["math"]},{"name":"mdi:animation-outline","tags":[]},{"name":"mdi:animation-play-outline","tags":[]},{"name":"mdi:anvil","tags":[]},{"name":"mdi:api-off","tags":["developer / languages"]},{"name":"mdi:apple-keyboard-caps","tags":[]},{"name":"mdi:apple-keyboard-command","tags":[]},{"name":"mdi:apple-keyboard-control","tags":[]},{"name":"mdi:apple-keyboard-option","tags":[]},{"name":"mdi:apple-keyboard-shift","tags":[]},{"name":"mdi:application","tags":["iframe"]},{"name":"mdi:application-array","tags":["developer / languages","iframe array"]},{"name":"mdi:application-array-outline","tags":["developer / languages","iframe array outline"]},{"name":"mdi:application-braces","tags":["developer / languages","iframe braces"]},{"name":"mdi:application-braces-outline","tags":["developer / languages","iframe braces outline"]},{"name":"mdi:application-brackets","tags":["developer / languages","iframe brackets"]},{"name":"mdi:application-brackets-outline","tags":["developer / languages","iframe brackets outline"]},{"name":"mdi:application-cog","tags":["settings","iframe cog"]},{"name":"mdi:application-cog-outline","tags":["settings","application settings","iframe cog outline"]},{"name":"mdi:application-edit","tags":["edit / modify","iframe edit"]},{"name":"mdi:application-edit-outline","tags":["edit / modify","iframe edit outline"]},{"name":"mdi:application-export","tags":["iframe export outline"]},{"name":"mdi:application-import","tags":["iframe import outline"]},{"name":"mdi:application-outline","tags":["web asset","iframe outline"]},{"name":"mdi:application-parentheses","tags":["developer / languages","iframe parentheses"]},{"name":"mdi:application-parentheses-outline","tags":["developer / languages","iframe parentheses outline"]},{"name":"mdi:application-settings","tags":["settings","iframe settings"]},{"name":"mdi:application-settings-outline","tags":["settings","iframe settings outline"]},{"name":"mdi:application-variable","tags":["developer / languages","iframe variable"]},{"name":"mdi:application-variable-outline","tags":["developer / languages","iframe variable outline"]},{"name":"mdi:approximately-equal","tags":["math"]},{"name":"mdi:approximately-equal-box","tags":["math"]},{"name":"mdi:archive","tags":["box"]},{"name":"mdi:archive-alert","tags":["alert / error","box alert"]},{"name":"mdi:archive-alert-outline","tags":["alert / error","box alert outline"]},{"name":"mdi:archive-arrow-down","tags":["box arrow down","this side down"]},{"name":"mdi:archive-arrow-down-outline","tags":["box arrow down","this side down outline"]},{"name":"mdi:archive-arrow-up","tags":["box arrow up","this side up"]},{"name":"mdi:archive-arrow-up-outline","tags":["box arrow up outline","this side up outline"]},{"name":"mdi:archive-cancel","tags":["box cancel"]},{"name":"mdi:archive-cancel-outline","tags":["box cancel outline"]},{"name":"mdi:archive-check","tags":["box check","archive success","box success"]},{"name":"mdi:archive-check-outline","tags":["box check outline","archive success outline","box success outline"]},{"name":"mdi:archive-clock","tags":["date / time","box clock","box time","archive time"]},{"name":"mdi:archive-clock-outline","tags":["date / time","box clock outline","box time outline","archive time outline"]},{"name":"mdi:archive-cog","tags":["settings","box cog"]},{"name":"mdi:archive-cog-outline","tags":["settings","box cog outline"]},{"name":"mdi:archive-edit","tags":["edit / modify","box edit"]},{"name":"mdi:archive-edit-outline","tags":["edit / modify","box edit outline"]},{"name":"mdi:archive-eye","tags":["archive view","box eye","box view"]},{"name":"mdi:archive-eye-outline","tags":["archive view outline","box eye outline","box view outline"]},{"name":"mdi:archive-lock","tags":["lock","box lock"]},{"name":"mdi:archive-lock-open","tags":["lock","box lock open"]},{"name":"mdi:archive-lock-open-outline","tags":["lock","box lock open outline"]},{"name":"mdi:archive-lock-outline","tags":["lock","box lock outline"]},{"name":"mdi:archive-marker","tags":["navigation","archive location","box marker","box location"]},{"name":"mdi:archive-marker-outline","tags":["navigation","archive location outline","box marker outline","box location outline"]},{"name":"mdi:archive-minus","tags":["box minus"]},{"name":"mdi:archive-minus-outline","tags":["box minus outline"]},{"name":"mdi:archive-music","tags":["music","box music"]},{"name":"mdi:archive-music-outline","tags":["music","box music outline"]},{"name":"mdi:archive-off","tags":["box off"]},{"name":"mdi:archive-off-outline","tags":["box off outline"]},{"name":"mdi:archive-outline","tags":["box outline"]},{"name":"mdi:archive-plus","tags":["archive add","box plus","box add"]},{"name":"mdi:archive-plus-outline","tags":["archive add outline","box plus outline","box add outline"]},{"name":"mdi:archive-refresh","tags":["box refresh"]},{"name":"mdi:archive-refresh-outline","tags":["box refresh outline"]},{"name":"mdi:archive-remove","tags":["box remove"]},{"name":"mdi:archive-remove-outline","tags":["box remove outline"]},{"name":"mdi:archive-search","tags":["box search"]},{"name":"mdi:archive-search-outline","tags":["box search outline"]},{"name":"mdi:archive-settings","tags":["settings","box settings"]},{"name":"mdi:archive-settings-outline","tags":["settings","box settings outline"]},{"name":"mdi:archive-star","tags":["archive favorite","box star","box favorite"]},{"name":"mdi:archive-star-outline","tags":["archive favorite outline","box star outline","box favorite outline"]},{"name":"mdi:archive-sync","tags":["box sync"]},{"name":"mdi:archive-sync-outline","tags":["box sync outline"]},{"name":"mdi:arm-flex","tags":[]},{"name":"mdi:arm-flex-outline","tags":[]},{"name":"mdi:arrange-bring-forward","tags":["arrange","geographic information system"]},{"name":"mdi:arrange-bring-to-front","tags":["arrange","geographic information system"]},{"name":"mdi:arrange-send-backward","tags":["arrange","geographic information system"]},{"name":"mdi:arrange-send-to-back","tags":["arrange","geographic information system"]},{"name":"mdi:arrow-all","tags":["arrow"]},{"name":"mdi:arrow-bottom-left","tags":["arrow","arrow down left"]},{"name":"mdi:arrow-bottom-left-bold-box","tags":["arrow"]},{"name":"mdi:arrow-bottom-left-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-bottom-left-bold-outline","tags":["arrow","arrow down left bold outline"]},{"name":"mdi:arrow-bottom-left-thick","tags":["arrow","arrow down left thick","arrow bottom left bold","arrow down left bold"]},{"name":"mdi:arrow-bottom-left-thin","tags":["arrow"]},{"name":"mdi:arrow-bottom-right","tags":["arrow","arrow down right"]},{"name":"mdi:arrow-bottom-right-bold-box","tags":["arrow"]},{"name":"mdi:arrow-bottom-right-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-bottom-right-bold-outline","tags":["arrow","arrow down right bold outline"]},{"name":"mdi:arrow-bottom-right-thick","tags":["arrow","arrow down right thick","arrow bottom right bold","arrow down right bold"]},{"name":"mdi:arrow-bottom-right-thin","tags":["arrow"]},{"name":"mdi:arrow-collapse","tags":["arrow","arrow compress"]},{"name":"mdi:arrow-collapse-all","tags":["arrow","arrow compress all"]},{"name":"mdi:arrow-collapse-down","tags":["arrow","arrow compress down"]},{"name":"mdi:arrow-collapse-left","tags":["arrow","arrow compress left"]},{"name":"mdi:arrow-collapse-right","tags":["arrow","arrow compress right"]},{"name":"mdi:arrow-collapse-up","tags":["arrow","arrow compress up"]},{"name":"mdi:arrow-decision","tags":["arrow","proxy"]},{"name":"mdi:arrow-decision-auto","tags":["proxy auto"]},{"name":"mdi:arrow-decision-auto-outline","tags":["proxy auto outline"]},{"name":"mdi:arrow-decision-outline","tags":["arrow","proxy outline"]},{"name":"mdi:arrow-down","tags":["arrow","arrow downward","arrow bottom"]},{"name":"mdi:arrow-down-bold","tags":["arrow","arrow bottom bold"]},{"name":"mdi:arrow-down-bold-box","tags":["arrow","arrow bottom bold box"]},{"name":"mdi:arrow-down-bold-box-outline","tags":["arrow","arrow bottom bold box outline"]},{"name":"mdi:arrow-down-bold-circle","tags":["arrow","arrow bottom bold circle"]},{"name":"mdi:arrow-down-bold-circle-outline","tags":["arrow","arrow bottom bold circle outline"]},{"name":"mdi:arrow-down-bold-hexagon-outline","tags":["arrow","arrow bottom bold hexagon outline"]},{"name":"mdi:arrow-down-bold-outline","tags":["arrow","arrow bottom bold outline"]},{"name":"mdi:arrow-down-box","tags":["arrow","arrow bottom box"]},{"name":"mdi:arrow-down-circle","tags":["arrow","arrow bottom circle"]},{"name":"mdi:arrow-down-circle-outline","tags":["arrow","arrow bottom circle outline"]},{"name":"mdi:arrow-down-drop-circle-outline","tags":["arrow","arrow bottom drop circle outline"]},{"name":"mdi:arrow-down-left","tags":["arrow"]},{"name":"mdi:arrow-down-left-bold","tags":["arrow"]},{"name":"mdi:arrow-down-right","tags":["arrow"]},{"name":"mdi:arrow-down-right-bold","tags":["arrow"]},{"name":"mdi:arrow-down-thick","tags":["arrow","arrow bottom thick","arrow down bold","arrow bottom bold"]},{"name":"mdi:arrow-down-thin","tags":["arrow"]},{"name":"mdi:arrow-expand","tags":["arrow"]},{"name":"mdi:arrow-expand-all","tags":["arrow","geographic information system"]},{"name":"mdi:arrow-expand-down","tags":["arrow"]},{"name":"mdi:arrow-expand-left","tags":["arrow"]},{"name":"mdi:arrow-expand-right","tags":["arrow"]},{"name":"mdi:arrow-expand-up","tags":["arrow"]},{"name":"mdi:arrow-horizontal-lock","tags":["lock","arrow","scroll horizontal lock"]},{"name":"mdi:arrow-left-bold","tags":["arrow","automotive"]},{"name":"mdi:arrow-left-bold-box","tags":["arrow"]},{"name":"mdi:arrow-left-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-left-bold-circle","tags":["arrow"]},{"name":"mdi:arrow-left-bold-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-left-bold-hexagon-outline","tags":["arrow"]},{"name":"mdi:arrow-left-bold-outline","tags":["arrow","automotive"]},{"name":"mdi:arrow-left-bottom","tags":[]},{"name":"mdi:arrow-left-bottom-bold","tags":[]},{"name":"mdi:arrow-left-box","tags":["arrow"]},{"name":"mdi:arrow-left-circle","tags":["arrow","arrow back circle"]},{"name":"mdi:arrow-left-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-left-drop-circle","tags":["arrow"]},{"name":"mdi:arrow-left-drop-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-left-right","tags":["arrow"]},{"name":"mdi:arrow-left-right-bold","tags":["arrow"]},{"name":"mdi:arrow-left-right-bold-outline","tags":["arrow"]},{"name":"mdi:arrow-left-thick","tags":["arrow","arrow left bold"]},{"name":"mdi:arrow-left-thin","tags":["arrow"]},{"name":"mdi:arrow-left-top","tags":["turn left"]},{"name":"mdi:arrow-left-top-bold","tags":["turn left bold"]},{"name":"mdi:arrow-projectile","tags":["gaming / rpg","sport"]},{"name":"mdi:arrow-projectile-multiple","tags":["gaming / rpg","sport"]},{"name":"mdi:arrow-right-bold","tags":["arrow","automotive"]},{"name":"mdi:arrow-right-bold-box","tags":["arrow"]},{"name":"mdi:arrow-right-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-right-bold-circle","tags":["arrow"]},{"name":"mdi:arrow-right-bold-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-right-bold-hexagon-outline","tags":["arrow"]},{"name":"mdi:arrow-right-bold-outline","tags":["arrow","automotive"]},{"name":"mdi:arrow-right-bottom","tags":[]},{"name":"mdi:arrow-right-bottom-bold","tags":[]},{"name":"mdi:arrow-right-box","tags":["arrow"]},{"name":"mdi:arrow-right-circle","tags":["arrow","arrow forward circle"]},{"name":"mdi:arrow-right-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-right-drop-circle","tags":["arrow"]},{"name":"mdi:arrow-right-drop-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-right-thick","tags":["arrow","arrow right bold"]},{"name":"mdi:arrow-right-thin","tags":["arrow"]},{"name":"mdi:arrow-right-top","tags":["turn right"]},{"name":"mdi:arrow-right-top-bold","tags":["turn right bold"]},{"name":"mdi:arrow-split-horizontal","tags":["arrow","resize vertical","resize"]},{"name":"mdi:arrow-split-vertical","tags":["arrow","resize horizontal","resize"]},{"name":"mdi:arrow-top-left","tags":["arrow","arrow up left"]},{"name":"mdi:arrow-top-left-bold-box","tags":["arrow"]},{"name":"mdi:arrow-top-left-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-top-left-bold-outline","tags":["arrow","arrow up left bold outline"]},{"name":"mdi:arrow-top-left-bottom-right","tags":["arrow"]},{"name":"mdi:arrow-top-left-bottom-right-bold","tags":["arrow"]},{"name":"mdi:arrow-top-left-thick","tags":["arrow","arrow up left thick","arrow top left bold","arrow up left bold"]},{"name":"mdi:arrow-top-left-thin","tags":["arrow"]},{"name":"mdi:arrow-top-right","tags":["arrow","arrow up right"]},{"name":"mdi:arrow-top-right-bold-box","tags":["arrow"]},{"name":"mdi:arrow-top-right-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-top-right-bold-outline","tags":["arrow","arrow up right bold outline"]},{"name":"mdi:arrow-top-right-bottom-left","tags":["arrow"]},{"name":"mdi:arrow-top-right-bottom-left-bold","tags":["arrow"]},{"name":"mdi:arrow-top-right-thick","tags":["arrow","arrow up right thick","arrow top right bold","arrow up right bold"]},{"name":"mdi:arrow-top-right-thin","tags":["arrow"]},{"name":"mdi:arrow-u-down-left","tags":["u turn left"]},{"name":"mdi:arrow-u-down-left-bold","tags":["u turn left bold"]},{"name":"mdi:arrow-u-down-right","tags":["u turn right"]},{"name":"mdi:arrow-u-down-right-bold","tags":["u turn right bold"]},{"name":"mdi:arrow-u-left-bottom","tags":["undo"]},{"name":"mdi:arrow-u-left-bottom-bold","tags":["undo"]},{"name":"mdi:arrow-u-left-top","tags":["undo"]},{"name":"mdi:arrow-u-left-top-bold","tags":["undo"]},{"name":"mdi:arrow-u-right-bottom","tags":["redo"]},{"name":"mdi:arrow-u-right-bottom-bold","tags":["redo"]},{"name":"mdi:arrow-u-right-top","tags":["redo"]},{"name":"mdi:arrow-u-right-top-bold","tags":["redo"]},{"name":"mdi:arrow-u-up-left","tags":[]},{"name":"mdi:arrow-u-up-left-bold","tags":[]},{"name":"mdi:arrow-u-up-right","tags":[]},{"name":"mdi:arrow-u-up-right-bold","tags":[]},{"name":"mdi:arrow-up","tags":["arrow","arrow upward","arrow top"]},{"name":"mdi:arrow-up-bold","tags":["arrow","arrow top bold"]},{"name":"mdi:arrow-up-bold-box","tags":["arrow","arrow top bold box"]},{"name":"mdi:arrow-up-bold-box-outline","tags":["arrow","arrow top bold box outline"]},{"name":"mdi:arrow-up-bold-circle","tags":["arrow","arrow top bold circle"]},{"name":"mdi:arrow-up-bold-circle-outline","tags":["arrow","arrow top bold circle outline"]},{"name":"mdi:arrow-up-bold-hexagon-outline","tags":["arrow","arrow top bold hexagon outline"]},{"name":"mdi:arrow-up-bold-outline","tags":["arrow","arrow top bold outline"]},{"name":"mdi:arrow-up-box","tags":["arrow"]},{"name":"mdi:arrow-up-circle","tags":["arrow","arrow top circle"]},{"name":"mdi:arrow-up-circle-outline","tags":["arrow","arrow top circle outline"]},{"name":"mdi:arrow-up-down","tags":["arrow"]},{"name":"mdi:arrow-up-down-bold","tags":["arrow"]},{"name":"mdi:arrow-up-down-bold-outline","tags":["arrow"]},{"name":"mdi:arrow-up-drop-circle","tags":["arrow","arrow top drop circle"]},{"name":"mdi:arrow-up-drop-circle-outline","tags":["arrow","arrow top drop circle outline"]},{"name":"mdi:arrow-up-left","tags":[]},{"name":"mdi:arrow-up-left-bold","tags":[]},{"name":"mdi:arrow-up-right","tags":[]},{"name":"mdi:arrow-up-right-bold","tags":[]},{"name":"mdi:arrow-up-thick","tags":["arrow","arrow top thick","arrow up bold","arrow top bold"]},{"name":"mdi:arrow-up-thin","tags":["arrow"]},{"name":"mdi:arrow-vertical-lock","tags":["lock","arrow","scroll vertical lock"]},{"name":"mdi:artboard","tags":["drawing / art","canvas","frame"]},{"name":"mdi:asterisk","tags":["required"]},{"name":"mdi:asterisk-circle-outline","tags":["required circle"]},{"name":"mdi:atom","tags":["science"]},{"name":"mdi:atom-variant","tags":["science","orbit"]},{"name":"mdi:attachment-check","tags":["attachment tick","paperclip check","paperclip tick"]},{"name":"mdi:attachment-lock","tags":["lock","paperclip lock"]},{"name":"mdi:attachment-minus","tags":["paperclip minus","paperclip subtract","attachment subtract"]},{"name":"mdi:attachment-off","tags":["paperclip off"]},{"name":"mdi:attachment-plus","tags":["paperclip plus","paperclip add","attachment add"]},{"name":"mdi:attachment-remove","tags":["paperclip remove"]},{"name":"mdi:audio-input-rca","tags":["audio"]},{"name":"mdi:audio-input-stereo-minijack","tags":["audio"]},{"name":"mdi:audio-input-xlr","tags":["audio"]},{"name":"mdi:audio-video","tags":["home automation","audio","av receiver"]},{"name":"mdi:audio-video-off","tags":["home automation","audio","av receiver off"]},{"name":"mdi:augmented-reality","tags":[]},{"name":"mdi:aurora","tags":["science","weather","aurora borealis","aurora australis","northern lights","southern lights","polar lights"]},{"name":"mdi:auto-download","tags":[]},{"name":"mdi:auto-mode","tags":[]},{"name":"mdi:autorenew-off","tags":["arrow","clockwise arrows off","circular arrows off","circle arrows off","sync off"]},{"name":"mdi:awning","tags":["home automation","marquise","sun shade"]},{"name":"mdi:awning-outline","tags":["home automation","marquise outline","sun shade outline"]},{"name":"mdi:axe","tags":["hardware / tools"]},{"name":"mdi:axe-battle","tags":["gaming / rpg"]},{"name":"mdi:axis","tags":[]},{"name":"mdi:axis-arrow","tags":["arrow","accelerometer","gyro"]},{"name":"mdi:axis-arrow-info","tags":["arrow"]},{"name":"mdi:axis-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-lock","tags":["lock"]},{"name":"mdi:axis-x-arrow","tags":["arrow"]},{"name":"mdi:axis-x-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-x-rotate-clockwise","tags":[]},{"name":"mdi:axis-x-rotate-counterclockwise","tags":[]},{"name":"mdi:axis-x-y-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-y-arrow","tags":["arrow"]},{"name":"mdi:axis-y-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-y-rotate-clockwise","tags":[]},{"name":"mdi:axis-y-rotate-counterclockwise","tags":[]},{"name":"mdi:axis-z-arrow","tags":["arrow"]},{"name":"mdi:axis-z-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-z-rotate-clockwise","tags":["vertical rotate clockwise"]},{"name":"mdi:axis-z-rotate-counterclockwise","tags":["vertical rotate counterclockwise"]},{"name":"mdi:baby-bottle","tags":["people / family"]},{"name":"mdi:baby-bottle-outline","tags":["people / family"]},{"name":"mdi:baby-buggy","tags":["people / family","stroller","pram","carriage"]},{"name":"mdi:baby-buggy-off","tags":["people / family"]},{"name":"mdi:baby-carriage-off","tags":["people / family","child friendly off","stroller off","pram off","buggy off"]},{"name":"mdi:backburger","tags":["hamburger menu back"]},{"name":"mdi:backspace-reverse","tags":["clear reverse","erase reverse"]},{"name":"mdi:backspace-reverse-outline","tags":["clear reverse outline","erase reverse outline"]},{"name":"mdi:bacteria","tags":["science","medical / hospital"]},{"name":"mdi:bacteria-outline","tags":["science","medical / hospital"]},{"name":"mdi:badge-account","tags":["account / user","user badge","person badge"]},{"name":"mdi:badge-account-alert","tags":["account / user","alert / error","user badge alert","person badge alert","account badge warning","user badge warning","person badge warning"]},{"name":"mdi:badge-account-alert-outline","tags":["account / user","alert / error","user badge alert outline","person badge alert outline","account badge warning outline","user badge warning outline","person badge warning outline"]},{"name":"mdi:badge-account-outline","tags":["account / user","user badge outline","person badge outline"]},{"name":"mdi:badminton","tags":["sport","shuttlecock"]},{"name":"mdi:bag-personal","tags":["transportation + flying","backpack"]},{"name":"mdi:bag-personal-off","tags":["transportation + flying","backpack off"]},{"name":"mdi:bag-personal-off-outline","tags":["transportation + flying","backpack off outline"]},{"name":"mdi:bag-personal-outline","tags":["transportation + flying","backpack outline"]},{"name":"mdi:bag-personal-tag","tags":["property tag"]},{"name":"mdi:bag-personal-tag-outline","tags":["property tag outline"]},{"name":"mdi:baguette","tags":["food / drink","bread","bakery","french baguette","loaf"]},{"name":"mdi:balloon","tags":["holiday","party balloon"]},{"name":"mdi:ballot-recount","tags":["vote recount"]},{"name":"mdi:ballot-recount-outline","tags":["vote recount outline"]},{"name":"mdi:bank-check","tags":["banking"]},{"name":"mdi:bank-circle","tags":["banking"]},{"name":"mdi:bank-circle-outline","tags":["banking"]},{"name":"mdi:bank-minus","tags":["banking"]},{"name":"mdi:bank-off","tags":["banking"]},{"name":"mdi:bank-off-outline","tags":["banking"]},{"name":"mdi:bank-plus","tags":["banking","bank add"]},{"name":"mdi:bank-remove","tags":["banking"]},{"name":"mdi:bank-transfer","tags":["banking"]},{"name":"mdi:bank-transfer-in","tags":["banking"]},{"name":"mdi:bank-transfer-out","tags":["banking"]},{"name":"mdi:barcode","tags":[]},{"name":"mdi:barcode-off","tags":[]},{"name":"mdi:barcode-scan","tags":["barcode scanner"]},{"name":"mdi:barley","tags":["agriculture","food / drink","grain","wheat","gluten"]},{"name":"mdi:barley-off","tags":["agriculture","gluten free","grain off","wheat off"]},{"name":"mdi:barn","tags":["agriculture","farm"]},{"name":"mdi:baseball","tags":["sport"]},{"name":"mdi:baseball-bat","tags":["sport"]},{"name":"mdi:baseball-diamond","tags":["sport"]},{"name":"mdi:baseball-diamond-outline","tags":["sport"]},{"name":"mdi:baseball-outline","tags":["sport"]},{"name":"mdi:bash","tags":["developer / languages"]},{"name":"mdi:basket-check","tags":["shopping"]},{"name":"mdi:basket-check-outline","tags":["shopping"]},{"name":"mdi:basket-fill","tags":["shopping","skip fill"]},{"name":"mdi:basket-minus","tags":["shopping","shopping basket minus","skip minus"]},{"name":"mdi:basket-minus-outline","tags":["shopping","shopping basket minus outline","skip minus outline"]},{"name":"mdi:basket-off","tags":["shopping","shopping basket off","skip off"]},{"name":"mdi:basket-off-outline","tags":["shopping","shopping basket off outline","skip off outline"]},{"name":"mdi:basket-plus","tags":["shopping","shopping basket plus","skip plus"]},{"name":"mdi:basket-plus-outline","tags":["shopping","shopping basket plus outline","skip plus outline"]},{"name":"mdi:basket-remove","tags":["shopping","shopping basket remove","skip remove"]},{"name":"mdi:basket-remove-outline","tags":["shopping","shopping basket remove outline","skip remove outline"]},{"name":"mdi:basket-unfill","tags":["shopping"]},{"name":"mdi:basketball-hoop","tags":["sport"]},{"name":"mdi:basketball-hoop-outline","tags":["sport"]},{"name":"mdi:bat","tags":["holiday","animal"]},{"name":"mdi:battery-10-bluetooth","tags":["battery"]},{"name":"mdi:battery-20-bluetooth","tags":["battery"]},{"name":"mdi:battery-30-bluetooth","tags":["battery"]},{"name":"mdi:battery-40-bluetooth","tags":["battery"]},{"name":"mdi:battery-50-bluetooth","tags":["battery"]},{"name":"mdi:battery-60-bluetooth","tags":["battery"]},{"name":"mdi:battery-70-bluetooth","tags":["battery"]},{"name":"mdi:battery-80-bluetooth","tags":["battery"]},{"name":"mdi:battery-90-bluetooth","tags":["battery"]},{"name":"mdi:battery-alert-bluetooth","tags":["alert / error","battery","battery warning bluetooth"]},{"name":"mdi:battery-alert-variant","tags":["battery","alert / error"]},{"name":"mdi:battery-alert-variant-outline","tags":["battery","alert / error"]},{"name":"mdi:battery-arrow-down","tags":["battery"]},{"name":"mdi:battery-arrow-down-outline","tags":["battery"]},{"name":"mdi:battery-arrow-up","tags":["battery"]},{"name":"mdi:battery-arrow-up-outline","tags":["battery"]},{"name":"mdi:battery-bluetooth","tags":["battery","battery bluetooth 100","battery bluetooth full"]},{"name":"mdi:battery-bluetooth-variant","tags":["battery"]},{"name":"mdi:battery-charging-high","tags":["battery"]},{"name":"mdi:battery-charging-low","tags":["battery"]},{"name":"mdi:battery-charging-medium","tags":["battery"]},{"name":"mdi:battery-charging-wireless","tags":["battery","home automation","battery charging wireless full","battery charging wireless 100"]},{"name":"mdi:battery-charging-wireless-10","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-20","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-30","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-40","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-50","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-60","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-70","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-80","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-90","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-alert","tags":["battery","home automation","alert / error","battery charging wireless warning"]},{"name":"mdi:battery-charging-wireless-outline","tags":["battery","home automation","battery charging wireless empty","battery charging wireless 0"]},{"name":"mdi:battery-check","tags":["battery"]},{"name":"mdi:battery-check-outline","tags":["battery"]},{"name":"mdi:battery-clock","tags":["battery","home automation","date / time","battery full clock","battery 100 clock"]},{"name":"mdi:battery-clock-outline","tags":["battery","home automation","date / time","batter 0 clock","battery empty clock"]},{"name":"mdi:battery-heart","tags":["battery"]},{"name":"mdi:battery-heart-outline","tags":["battery"]},{"name":"mdi:battery-heart-variant","tags":["battery"]},{"name":"mdi:battery-high","tags":["battery"]},{"name":"mdi:battery-lock","tags":["battery","lock"]},{"name":"mdi:battery-lock-open","tags":["battery","lock"]},{"name":"mdi:battery-low","tags":["battery"]},{"name":"mdi:battery-medium","tags":["battery"]},{"name":"mdi:battery-minus","tags":["battery"]},{"name":"mdi:battery-minus-outline","tags":["battery"]},{"name":"mdi:battery-minus-variant","tags":["battery","home automation"]},{"name":"mdi:battery-negative","tags":["battery","home automation"]},{"name":"mdi:battery-off","tags":["battery"]},{"name":"mdi:battery-off-outline","tags":["battery"]},{"name":"mdi:battery-plus","tags":["battery"]},{"name":"mdi:battery-plus-outline","tags":["battery"]},{"name":"mdi:battery-plus-variant","tags":["battery","home automation","battery saver","battery add"]},{"name":"mdi:battery-positive","tags":["battery","home automation"]},{"name":"mdi:battery-remove","tags":["battery"]},{"name":"mdi:battery-remove-outline","tags":["battery"]},{"name":"mdi:battery-sync","tags":["battery","battery saver","battery recycle","battery eco"]},{"name":"mdi:battery-sync-outline","tags":["battery","battery saver outline","battery eco outline","battery recycle outline"]},{"name":"mdi:battery-unknown-bluetooth","tags":["battery"]},{"name":"mdi:beach","tags":["places","parasol"]},{"name":"mdi:beaker","tags":["science"]},{"name":"mdi:beaker-alert","tags":["alert / error","science"]},{"name":"mdi:beaker-alert-outline","tags":["alert / error","science"]},{"name":"mdi:beaker-check","tags":["science"]},{"name":"mdi:beaker-check-outline","tags":["science"]},{"name":"mdi:beaker-minus","tags":["science"]},{"name":"mdi:beaker-minus-outline","tags":["science"]},{"name":"mdi:beaker-outline","tags":["science"]},{"name":"mdi:beaker-plus","tags":["science"]},{"name":"mdi:beaker-plus-outline","tags":["science"]},{"name":"mdi:beaker-question","tags":["science"]},{"name":"mdi:beaker-question-outline","tags":["science"]},{"name":"mdi:beaker-remove","tags":["science"]},{"name":"mdi:beaker-remove-outline","tags":["science"]},{"name":"mdi:bed-clock","tags":["date / time","bed schedule","bed time","sleep schedule","sleep time"]},{"name":"mdi:bed-double","tags":["home automation","holiday","bedroom"]},{"name":"mdi:bed-empty","tags":["home automation","holiday"]},{"name":"mdi:bed-king-outline","tags":["home automation","holiday","bedroom outline"]},{"name":"mdi:bed-queen","tags":["home automation","holiday","bedroom"]},{"name":"mdi:bed-queen-outline","tags":["home automation","holiday","bedroom outline"]},{"name":"mdi:bed-single","tags":["home automation","holiday","bedroom"]},{"name":"mdi:bed-single-outline","tags":["home automation","holiday","bedroom outline"]},{"name":"mdi:beehive-off-outline","tags":["nature","agriculture"]},{"name":"mdi:beehive-outline","tags":["nature","agriculture","honey outline"]},{"name":"mdi:beekeeper","tags":["nature","agriculture","apiarists","apiculturists","honey farmer"]},{"name":"mdi:beer","tags":["food / drink","pint","pub","bar","drink","cup full"]},{"name":"mdi:beer-outline","tags":["food / drink","drink outline","cup full outline","pint outline","pub outline","bar outline"]},{"name":"mdi:bell-alert","tags":["alert / error","notification","bell warning"]},{"name":"mdi:bell-alert-outline","tags":["alert / error","notification"]},{"name":"mdi:bell-badge","tags":["notification","bell notification"]},{"name":"mdi:bell-badge-outline","tags":["notification","bell notification outline"]},{"name":"mdi:bell-cancel","tags":["notification"]},{"name":"mdi:bell-cancel-outline","tags":["notification"]},{"name":"mdi:bell-check","tags":["notification"]},{"name":"mdi:bell-check-outline","tags":["notification"]},{"name":"mdi:bell-cog","tags":["notification","settings","bell settings","notification settings"]},{"name":"mdi:bell-cog-outline","tags":["notification","settings","bell settings outline","notification settings outline"]},{"name":"mdi:bell-minus","tags":["notification"]},{"name":"mdi:bell-minus-outline","tags":["notification"]},{"name":"mdi:bell-plus","tags":["notification","add alert","bell add"]},{"name":"mdi:bell-plus-outline","tags":["notification","bell add outline","add alert outline"]},{"name":"mdi:bell-remove","tags":["notification"]},{"name":"mdi:bell-remove-outline","tags":["notification"]},{"name":"mdi:bench","tags":[]},{"name":"mdi:bench-back","tags":[]},{"name":"mdi:beta","tags":["alpha / numeric"]},{"name":"mdi:betamax","tags":[]},{"name":"mdi:bicycle","tags":["transportation + other","sport","bike","cycling"]},{"name":"mdi:bicycle-basket","tags":["transportation + other","sport","bike basket"]},{"name":"mdi:bicycle-cargo","tags":["transportation + other","sport","bike cargo"]},{"name":"mdi:bicycle-electric","tags":["transportation + other","bike electric"]},{"name":"mdi:bicycle-penny-farthing","tags":["transportation + other","sport","bicycle high wheel","bicycle antique"]},{"name":"mdi:bike-fast","tags":["transportation + other","sport","velocity"]},{"name":"mdi:bike-pedal","tags":["transportation + other","sport","bike pedal flat"]},{"name":"mdi:bike-pedal-clipless","tags":["transportation + other","sport"]},{"name":"mdi:bike-pedal-mountain","tags":["transportation + other","sport"]},{"name":"mdi:billboard","tags":[]},{"name":"mdi:billiards","tags":["sport","pool","eight ball"]},{"name":"mdi:billiards-rack","tags":["sport","pool table","pool rack","snooker rack","pool triangle","billiards triangle","snooker triangle"]},{"name":"mdi:binoculars","tags":[]},{"name":"mdi:bio","tags":[]},{"name":"mdi:biohazard","tags":["science"]},{"name":"mdi:bird","tags":["animal"]},{"name":"mdi:blinds","tags":["home automation","roller shade closed","window closed"]},{"name":"mdi:blinds-open","tags":["home automation","roller shade open","window open"]},{"name":"mdi:block-helper","tags":[]},{"name":"mdi:blood-bag","tags":["medical / hospital"]},{"name":"mdi:bluetooth","tags":[]},{"name":"mdi:bolt","tags":["hardware / tools"]},{"name":"mdi:bomb","tags":["gaming / rpg"]},{"name":"mdi:bomb-off","tags":["gaming / rpg"]},{"name":"mdi:bone","tags":["animal","holiday"]},{"name":"mdi:bone-off","tags":["animal","holiday"]},{"name":"mdi:book-account","tags":["account / user"]},{"name":"mdi:book-account-outline","tags":["account / user"]},{"name":"mdi:book-alert","tags":["alert / error"]},{"name":"mdi:book-alert-outline","tags":["alert / error"]},{"name":"mdi:book-alphabet","tags":["dictionary"]},{"name":"mdi:book-arrow-down","tags":[]},{"name":"mdi:book-arrow-down-outline","tags":[]},{"name":"mdi:book-arrow-left","tags":[]},{"name":"mdi:book-arrow-left-outline","tags":[]},{"name":"mdi:book-arrow-right","tags":[]},{"name":"mdi:book-arrow-right-outline","tags":[]},{"name":"mdi:book-arrow-up","tags":[]},{"name":"mdi:book-arrow-up-outline","tags":[]},{"name":"mdi:book-cancel","tags":[]},{"name":"mdi:book-cancel-outline","tags":[]},{"name":"mdi:book-check","tags":[]},{"name":"mdi:book-check-outline","tags":[]},{"name":"mdi:book-clock","tags":["date / time","book schedule","book time"]},{"name":"mdi:book-clock-outline","tags":["date / time","book schedule","book time"]},{"name":"mdi:book-cog","tags":["settings","book settings"]},{"name":"mdi:book-cog-outline","tags":["settings","book settings outline"]},{"name":"mdi:book-cross","tags":["religion","bible"]},{"name":"mdi:book-edit","tags":["edit / modify"]},{"name":"mdi:book-edit-outline","tags":["edit / modify"]},{"name":"mdi:book-education","tags":[]},{"name":"mdi:book-education-outline","tags":[]},{"name":"mdi:book-heart","tags":["book favorite","book love"]},{"name":"mdi:book-heart-outline","tags":["book favorite outline","book love outline"]},{"name":"mdi:book-information-variant","tags":["encyclopedia"]},{"name":"mdi:book-lock","tags":["lock","book secure"]},{"name":"mdi:book-lock-open","tags":["lock","book unsecure"]},{"name":"mdi:book-lock-open-outline","tags":["lock"]},{"name":"mdi:book-lock-outline","tags":["lock","book secure outline"]},{"name":"mdi:book-marker","tags":["navigation","book location"]},{"name":"mdi:book-marker-outline","tags":["navigation","book location outline"]},{"name":"mdi:book-minus","tags":[]},{"name":"mdi:book-minus-multiple","tags":["books minus"]},{"name":"mdi:book-minus-multiple-outline","tags":[]},{"name":"mdi:book-minus-outline","tags":[]},{"name":"mdi:book-multiple","tags":["books"]},{"name":"mdi:book-multiple-outline","tags":[]},{"name":"mdi:book-music","tags":["audio","music","audio book"]},{"name":"mdi:book-music-outline","tags":["music"]},{"name":"mdi:book-off","tags":[]},{"name":"mdi:book-off-outline","tags":[]},{"name":"mdi:book-play","tags":[]},{"name":"mdi:book-play-outline","tags":[]},{"name":"mdi:book-plus","tags":["book add"]},{"name":"mdi:book-plus-multiple","tags":["books plus","book multiple add","books add"]},{"name":"mdi:book-plus-multiple-outline","tags":[]},{"name":"mdi:book-plus-outline","tags":[]},{"name":"mdi:book-refresh","tags":[]},{"name":"mdi:book-refresh-outline","tags":[]},{"name":"mdi:book-remove","tags":[]},{"name":"mdi:book-remove-multiple","tags":["books remove"]},{"name":"mdi:book-remove-multiple-outline","tags":[]},{"name":"mdi:book-remove-outline","tags":[]},{"name":"mdi:book-search","tags":[]},{"name":"mdi:book-search-outline","tags":[]},{"name":"mdi:book-settings","tags":["settings"]},{"name":"mdi:book-settings-outline","tags":["settings"]},{"name":"mdi:book-sync","tags":[]},{"name":"mdi:book-sync-outline","tags":[]},{"name":"mdi:bookmark-box","tags":[]},{"name":"mdi:bookmark-box-multiple-outline","tags":["collections bookmark outline","library bookmark outline"]},{"name":"mdi:bookmark-box-outline","tags":[]},{"name":"mdi:bookmark-check-outline","tags":["bookmark success outline"]},{"name":"mdi:bookmark-minus","tags":[]},{"name":"mdi:bookmark-minus-outline","tags":[]},{"name":"mdi:bookmark-music","tags":["music"]},{"name":"mdi:bookmark-music-outline","tags":["music"]},{"name":"mdi:bookmark-off","tags":[]},{"name":"mdi:bookmark-off-outline","tags":[]},{"name":"mdi:bookmark-plus","tags":["bookmark add"]},{"name":"mdi:bookmark-remove","tags":[]},{"name":"mdi:bookmark-remove-outline","tags":[]},{"name":"mdi:bookshelf","tags":[]},{"name":"mdi:boom-gate","tags":["transportation + road","home automation","boom arm","boom barrier","arm barrier","barrier","automatic gate"]},{"name":"mdi:boom-gate-alert","tags":["alert / error","transportation + road","boom arm alert","boom barrier alert","arm barrier alert","barrier alert","automatic gate alert"]},{"name":"mdi:boom-gate-alert-outline","tags":["alert / error","transportation + road","boom arm alert outline","boom barrier alert outline","arm barrier alert outline","barrier alert outline","automatic gate alert outline"]},{"name":"mdi:boom-gate-arrow-down","tags":["transportation + road","boom arm down","boom barrier down","arm barrier down","barrier down","automatic gate down"]},{"name":"mdi:boom-gate-arrow-down-outline","tags":["transportation + road","boom arm down outline","boom barrier down outline","arm barrier down outline","barrier down outline","automatic gate down outline"]},{"name":"mdi:boom-gate-arrow-up","tags":["transportation + road","boom arm up","boom barrier up","arm barrier up","barrier up","automatic gate up"]},{"name":"mdi:boom-gate-arrow-up-outline","tags":["transportation + road","boom arm up outline","boom barrier up outline","arm barrier up outline","barrier up outline","automatic gate up outline"]},{"name":"mdi:boom-gate-outline","tags":["transportation + road","home automation","boom arm outline","boom barrier outline","arm barrier outline","barrier outline","automatic gate outline"]},{"name":"mdi:boom-gate-up","tags":["transportation + road","home automation","boom arm up","boom barrier up","arm barrier up","barrier up","automatic gate up"]},{"name":"mdi:boom-gate-up-outline","tags":["transportation + road","home automation","boom arm up outline","boom barrier up outline","arm barrier up outline","barrier up outline","automatic gate up outline"]},{"name":"mdi:boomerang","tags":["gaming / rpg"]},{"name":"mdi:border-all-variant","tags":["text / content / format"]},{"name":"mdi:border-bottom-variant","tags":["text / content / format"]},{"name":"mdi:border-left-variant","tags":["text / content / format"]},{"name":"mdi:border-none-variant","tags":["text / content / format"]},{"name":"mdi:border-radius","tags":["text / content / format","border round corners"]},{"name":"mdi:border-right-variant","tags":["text / content / format"]},{"name":"mdi:border-top-variant","tags":["text / content / format"]},{"name":"mdi:bottle-soda","tags":["food / drink","bottle coke","bottle pop"]},{"name":"mdi:bottle-soda-classic","tags":["food / drink","bottle coke classic","bottle pop classic"]},{"name":"mdi:bottle-soda-classic-outline","tags":[]},{"name":"mdi:bottle-soda-outline","tags":["food / drink","bottle coke outline","bottle pop outline"]},{"name":"mdi:bottle-tonic","tags":["science","flask"]},{"name":"mdi:bottle-tonic-outline","tags":["science","flask outline"]},{"name":"mdi:bottle-tonic-plus","tags":["gaming / rpg","health potion"]},{"name":"mdi:bottle-tonic-plus-outline","tags":["gaming / rpg","health potion outline"]},{"name":"mdi:bottle-tonic-skull","tags":["gaming / rpg","holiday","poison","moonshine"]},{"name":"mdi:bottle-tonic-skull-outline","tags":["gaming / rpg","holiday","poison outline","moonshine outline"]},{"name":"mdi:bottle-wine","tags":["food / drink"]},{"name":"mdi:bottle-wine-outline","tags":["food / drink"]},{"name":"mdi:bow-arrow","tags":["gaming / rpg","sport"]},{"name":"mdi:bow-tie","tags":["clothing"]},{"name":"mdi:bowl","tags":["food / drink"]},{"name":"mdi:bowl-mix","tags":["food / drink","mixing bowl"]},{"name":"mdi:bowl-mix-outline","tags":["food / drink","mixing bowl outline"]},{"name":"mdi:bowl-outline","tags":["food / drink"]},{"name":"mdi:bowling","tags":["sport"]},{"name":"mdi:box-cutter","tags":["hardware / tools","stanley knife"]},{"name":"mdi:box-cutter-off","tags":[]},{"name":"mdi:box-shadow","tags":[]},{"name":"mdi:boxing-glove","tags":["sport"]},{"name":"mdi:braille","tags":["touch reading","hand reading"]},{"name":"mdi:brain","tags":["medical / hospital"]},{"name":"mdi:bread-slice","tags":["food / drink"]},{"name":"mdi:bread-slice-outline","tags":["food / drink"]},{"name":"mdi:bridge","tags":["places"]},{"name":"mdi:briefcase-account","tags":["account / user","briefcase person","briefcase user"]},{"name":"mdi:briefcase-account-outline","tags":["account / user","briefcase person outline","briefcase user outline"]},{"name":"mdi:briefcase-arrow-left-right","tags":["briefcase transfer","briefcase exchange","briefcase swap"]},{"name":"mdi:briefcase-arrow-left-right-outline","tags":["briefcase exchange outline","briefcase transfer outline","briefcase swap outline"]},{"name":"mdi:briefcase-arrow-up-down","tags":["briefcase exchange","briefcase transfer","briefcase swap"]},{"name":"mdi:briefcase-arrow-up-down-outline","tags":["briefcase exchange outline","briefcase transfer outline","briefcase swap outline"]},{"name":"mdi:briefcase-check-outline","tags":[]},{"name":"mdi:briefcase-clock","tags":["date / time"]},{"name":"mdi:briefcase-clock-outline","tags":["date / time"]},{"name":"mdi:briefcase-download-outline","tags":[]},{"name":"mdi:briefcase-edit","tags":["edit / modify"]},{"name":"mdi:briefcase-edit-outline","tags":["edit / modify"]},{"name":"mdi:briefcase-eye","tags":["briefcase view"]},{"name":"mdi:briefcase-eye-outline","tags":["briefcase view outline"]},{"name":"mdi:briefcase-minus","tags":[]},{"name":"mdi:briefcase-minus-outline","tags":[]},{"name":"mdi:briefcase-off","tags":[]},{"name":"mdi:briefcase-off-outline","tags":[]},{"name":"mdi:briefcase-plus","tags":["briefcase add"]},{"name":"mdi:briefcase-plus-outline","tags":["briefcase add outline"]},{"name":"mdi:briefcase-remove","tags":[]},{"name":"mdi:briefcase-remove-outline","tags":[]},{"name":"mdi:briefcase-search","tags":[]},{"name":"mdi:briefcase-search-outline","tags":[]},{"name":"mdi:briefcase-upload","tags":[]},{"name":"mdi:briefcase-upload-outline","tags":[]},{"name":"mdi:briefcase-variant-off","tags":[]},{"name":"mdi:briefcase-variant-off-outline","tags":[]},{"name":"mdi:brightness-percent","tags":["shopping","discount","sale"]},{"name":"mdi:broom","tags":[]},{"name":"mdi:brush-off","tags":[]},{"name":"mdi:bucket","tags":[]},{"name":"mdi:bucket-outline","tags":[]},{"name":"mdi:buffet","tags":["home automation","sideboard"]},{"name":"mdi:bug-check","tags":["animal","bug tick"]},{"name":"mdi:bug-check-outline","tags":["animal","bug tick outline"]},{"name":"mdi:bug-pause","tags":[]},{"name":"mdi:bug-pause-outline","tags":[]},{"name":"mdi:bug-play","tags":["bug start"]},{"name":"mdi:bug-play-outline","tags":[]},{"name":"mdi:bug-stop","tags":[]},{"name":"mdi:bug-stop-outline","tags":[]},{"name":"mdi:bugle","tags":["automotive","music","car horn"]},{"name":"mdi:bulkhead-light","tags":["home automation"]},{"name":"mdi:bulldozer","tags":["hardware / tools"]},{"name":"mdi:bullet","tags":[]},{"name":"mdi:bulletin-board","tags":["notice board"]},{"name":"mdi:bullhorn-variant","tags":["announcement","megaphone","loudspeaker"]},{"name":"mdi:bullhorn-variant-outline","tags":["announcement outline","megaphone outline","loudspeaker outline"]},{"name":"mdi:bullseye","tags":["sport","target"]},{"name":"mdi:bullseye-arrow","tags":["sport","target arrow"]},{"name":"mdi:bunk-bed","tags":["home automation"]},{"name":"mdi:bunk-bed-outline","tags":["home automation"]},{"name":"mdi:bus-articulated-end","tags":["transportation + road"]},{"name":"mdi:bus-articulated-front","tags":["transportation + road"]},{"name":"mdi:bus-double-decker","tags":["transportation + road"]},{"name":"mdi:bus-electric","tags":["transportation + road"]},{"name":"mdi:bus-marker","tags":["navigation","bus location","bus stop"]},{"name":"mdi:bus-multiple","tags":["transportation + road","fleet"]},{"name":"mdi:bus-school","tags":["transportation + road","education"]},{"name":"mdi:bus-side","tags":["transportation + road"]},{"name":"mdi:bus-stop","tags":["transportation + road","navigation"]},{"name":"mdi:bus-stop-covered","tags":["transportation + road","navigation"]},{"name":"mdi:bus-stop-uncovered","tags":["transportation + road","navigation"]},{"name":"mdi:butterfly","tags":["nature","animal"]},{"name":"mdi:butterfly-outline","tags":["nature","animal"]},{"name":"mdi:button-cursor","tags":["form"]},{"name":"mdi:button-pointer","tags":["form"]},{"name":"mdi:cabin-a-frame","tags":["home automation"]},{"name":"mdi:cable-data","tags":[]},{"name":"mdi:cactus","tags":["nature"]},{"name":"mdi:calculator","tags":["math"]},{"name":"mdi:calendar-account","tags":["date / time","account / user","calendar user"]},{"name":"mdi:calendar-account-outline","tags":["date / time","account / user","calendar user outline"]},{"name":"mdi:calendar-alert","tags":["date / time","alert / error","event alert","calendar warning"]},{"name":"mdi:calendar-alert-outline","tags":["date / time","alert / error"]},{"name":"mdi:calendar-arrow-left","tags":["date / time","reschedule"]},{"name":"mdi:calendar-arrow-right","tags":["date / time","reschedule"]},{"name":"mdi:calendar-badge","tags":["date / time"]},{"name":"mdi:calendar-badge-outline","tags":["date / time"]},{"name":"mdi:calendar-blank","tags":["date / time","calendar today"]},{"name":"mdi:calendar-blank-multiple","tags":["date / time"]},{"name":"mdi:calendar-clock","tags":["date / time","event clock","event time","calendar time"]},{"name":"mdi:calendar-clock-outline","tags":["date / time"]},{"name":"mdi:calendar-collapse-horizontal","tags":["date / time"]},{"name":"mdi:calendar-collapse-horizontal-outline","tags":["date / time"]},{"name":"mdi:calendar-cursor","tags":["date / time"]},{"name":"mdi:calendar-cursor-outline","tags":["date / time"]},{"name":"mdi:calendar-edit","tags":["date / time","edit / modify","event edit"]},{"name":"mdi:calendar-edit-outline","tags":["date / time","edit / modify"]},{"name":"mdi:calendar-end","tags":["date / time"]},{"name":"mdi:calendar-end-outline","tags":["date / time"]},{"name":"mdi:calendar-expand-horizontal","tags":["date / time"]},{"name":"mdi:calendar-expand-horizontal-outline","tags":["date / time"]},{"name":"mdi:calendar-export","tags":["date / time"]},{"name":"mdi:calendar-export-outline","tags":["date / time"]},{"name":"mdi:calendar-filter","tags":["date / time"]},{"name":"mdi:calendar-filter-outline","tags":["date / time","event week end outline"]},{"name":"mdi:calendar-heart","tags":["date / time","event heart"]},{"name":"mdi:calendar-heart-outline","tags":["date / time"]},{"name":"mdi:calendar-import","tags":["date / time"]},{"name":"mdi:calendar-import-outline","tags":["date / time"]},{"name":"mdi:calendar-lock","tags":["date / time","lock"]},{"name":"mdi:calendar-lock-open","tags":["lock","date / time"]},{"name":"mdi:calendar-lock-open-outline","tags":["lock","date / time"]},{"name":"mdi:calendar-lock-outline","tags":["date / time","lock"]},{"name":"mdi:calendar-minus","tags":["date / time","event minus"]},{"name":"mdi:calendar-minus-outline","tags":["date / time"]},{"name":"mdi:calendar-month","tags":["date / time"]},{"name":"mdi:calendar-month-outline","tags":["date / time"]},{"name":"mdi:calendar-multiple","tags":["date / time","event multiple","calendars","events"]},{"name":"mdi:calendar-multiple-check","tags":["date / time","event multiple check","calendar multiple tick","calendars check","calendars tick","event multiple tick","events check","events tick"]},{"name":"mdi:calendar-multiselect","tags":["date / time"]},{"name":"mdi:calendar-multiselect-outline","tags":["date / time"]},{"name":"mdi:calendar-plus","tags":["date / time","event plus","calendar add","event add"]},{"name":"mdi:calendar-plus-outline","tags":["date / time"]},{"name":"mdi:calendar-question","tags":["date / time","calendar rsvp","event question","calendar help"]},{"name":"mdi:calendar-question-outline","tags":["date / time","calendar help outline"]},{"name":"mdi:calendar-refresh","tags":["date / time","calendar repeat"]},{"name":"mdi:calendar-refresh-outline","tags":["date / time","calendar repeat outline"]},{"name":"mdi:calendar-search","tags":["date / time","event search"]},{"name":"mdi:calendar-search-outline","tags":["date / time"]},{"name":"mdi:calendar-star","tags":["date / time","event star","calendar favorite"]},{"name":"mdi:calendar-star-four-points","tags":["date / time","calendar auto","event star four points","event auto"]},{"name":"mdi:calendar-star-outline","tags":["date / time"]},{"name":"mdi:calendar-start","tags":["date / time"]},{"name":"mdi:calendar-start-outline","tags":["date / time"]},{"name":"mdi:calendar-sync","tags":["date / time","calendar repeat"]},{"name":"mdi:calendar-sync-outline","tags":["date / time","calendar repeat outline"]},{"name":"mdi:calendar-today-outline","tags":["date / time","calendar day outline"]},{"name":"mdi:calendar-week","tags":["date / time","event week"]},{"name":"mdi:calendar-week-begin","tags":["date / time","event week begin"]},{"name":"mdi:calendar-week-begin-outline","tags":["date / time","event week begin outline"]},{"name":"mdi:calendar-week-outline","tags":["date / time","event week outline"]},{"name":"mdi:calendar-weekend","tags":["date / time"]},{"name":"mdi:calendar-weekend-outline","tags":["date / time"]},{"name":"mdi:camcorder","tags":["video / movie"]},{"name":"mdi:camcorder-off","tags":["video / movie"]},{"name":"mdi:camera-document","tags":["photography","overhead projector"]},{"name":"mdi:camera-document-off","tags":["photography","overhead projector off"]},{"name":"mdi:camera-flip","tags":["photography","camera sync","camera refresh"]},{"name":"mdi:camera-flip-outline","tags":["photography","camera sync outline","camera refresh outline"]},{"name":"mdi:camera-gopro","tags":["photography","device / tech"]},{"name":"mdi:camera-lock","tags":["photography","lock"]},{"name":"mdi:camera-lock-open","tags":["photography"]},{"name":"mdi:camera-lock-open-outline","tags":["photography"]},{"name":"mdi:camera-lock-outline","tags":["photography","lock"]},{"name":"mdi:camera-marker","tags":["photography","navigation","camera location"]},{"name":"mdi:camera-marker-outline","tags":["photography","navigation","camera location outline"]},{"name":"mdi:camera-metering-center","tags":["photography","camera metering centre"]},{"name":"mdi:camera-metering-matrix","tags":["photography"]},{"name":"mdi:camera-metering-partial","tags":["photography"]},{"name":"mdi:camera-metering-spot","tags":["photography"]},{"name":"mdi:camera-off","tags":["photography"]},{"name":"mdi:camera-off-outline","tags":["photography"]},{"name":"mdi:camera-retake","tags":["photography"]},{"name":"mdi:camera-retake-outline","tags":["photography"]},{"name":"mdi:camera-timer","tags":["date / time","photography"]},{"name":"mdi:campfire","tags":[]},{"name":"mdi:candelabra","tags":["home automation","holiday","candle","candelabrum"]},{"name":"mdi:candelabra-fire","tags":["home automation","holiday","candelabrum fire","candelabrum flame","candelabra flame","candle fire","candle flame"]},{"name":"mdi:candy","tags":["food / drink","treat","chocolate"]},{"name":"mdi:candy-off","tags":["food / drink","chocolate off","treat off"]},{"name":"mdi:candy-off-outline","tags":["food / drink","gaming / rpg","chocolate off outline","treat off outline","navi off"]},{"name":"mdi:candy-outline","tags":["food / drink","gaming / rpg","chocolate outline","treat outline","navi","hey listen","fairy"]},{"name":"mdi:candycane","tags":["holiday","food / drink"]},{"name":"mdi:cannabis","tags":["nature","medical / hospital","weed","pot","marijuana"]},{"name":"mdi:cannabis-off","tags":[]},{"name":"mdi:caps-lock","tags":["text / content / format"]},{"name":"mdi:car-2-plus","tags":["transportation + road","automotive","hov lane","high occupancy vehicle lane","carpool lane"]},{"name":"mdi:car-3-plus","tags":["transportation + road","automotive","hov lane","high occupancy vehicle lane","carpool lane"]},{"name":"mdi:car-arrow-left","tags":["automotive","transportation + road"]},{"name":"mdi:car-arrow-right","tags":["automotive","transportation + road"]},{"name":"mdi:car-back","tags":["automotive","transportation + road"]},{"name":"mdi:car-battery","tags":["battery","automotive"]},{"name":"mdi:car-brake-abs","tags":["automotive","anti lock brake system","anti lock braking system"]},{"name":"mdi:car-brake-alert","tags":["automotive","alert / error","car parking brake","car handbrake","car hand brake","car emergency brake","car brake warning"]},{"name":"mdi:car-brake-fluid-level","tags":["automotive"]},{"name":"mdi:car-brake-hold","tags":["automotive"]},{"name":"mdi:car-brake-low-pressure","tags":["automotive"]},{"name":"mdi:car-brake-parking","tags":["automotive"]},{"name":"mdi:car-brake-retarder","tags":["automotive"]},{"name":"mdi:car-brake-temperature","tags":["automotive"]},{"name":"mdi:car-brake-worn-linings","tags":["automotive"]},{"name":"mdi:car-child-seat","tags":["automotive","people / family"]},{"name":"mdi:car-clock","tags":["date / time","automotive"]},{"name":"mdi:car-clutch","tags":["automotive"]},{"name":"mdi:car-cog","tags":["automotive","settings","transportation + road","car settings"]},{"name":"mdi:car-connected","tags":["transportation + road","automotive"]},{"name":"mdi:car-convertible","tags":["transportation + road","automotive"]},{"name":"mdi:car-coolant-level","tags":["automotive"]},{"name":"mdi:car-cruise-control","tags":["automotive"]},{"name":"mdi:car-defrost-front","tags":["automotive"]},{"name":"mdi:car-defrost-rear","tags":["automotive"]},{"name":"mdi:car-door","tags":["automotive"]},{"name":"mdi:car-door-lock","tags":["automotive","lock"]},{"name":"mdi:car-emergency","tags":["transportation + road","automotive","car police"]},{"name":"mdi:car-esp","tags":["automotive","electronic stability program"]},{"name":"mdi:car-estate","tags":["transportation + road","automotive","car suv","car sports utility vehicle"]},{"name":"mdi:car-hatchback","tags":["transportation + road","automotive"]},{"name":"mdi:car-info","tags":["automotive"]},{"name":"mdi:car-key","tags":["transportation + road","automotive","car rental","rent a car"]},{"name":"mdi:car-lifted-pickup","tags":["automotive","agriculture"]},{"name":"mdi:car-light-alert","tags":["alert / error","automotive"]},{"name":"mdi:car-light-dimmed","tags":["automotive","head light dimmed","low beam"]},{"name":"mdi:car-light-fog","tags":["automotive","head light fog"]},{"name":"mdi:car-light-high","tags":["automotive","head light high","high beam"]},{"name":"mdi:car-limousine","tags":["transportation + road","automotive"]},{"name":"mdi:car-multiple","tags":["transportation + road","automotive"]},{"name":"mdi:car-off","tags":["automotive"]},{"name":"mdi:car-parking-lights","tags":["automotive"]},{"name":"mdi:car-pickup","tags":["transportation + road","automotive","agriculture"]},{"name":"mdi:car-search","tags":["automotive","car find"]},{"name":"mdi:car-search-outline","tags":["automotive","car find outline"]},{"name":"mdi:car-seat","tags":["automotive"]},{"name":"mdi:car-seat-cooler","tags":["automotive"]},{"name":"mdi:car-seat-heater","tags":["automotive"]},{"name":"mdi:car-select","tags":["automotive","car location"]},{"name":"mdi:car-settings","tags":["automotive","settings"]},{"name":"mdi:car-shift-pattern","tags":["automotive","car transmission","car manual transmission"]},{"name":"mdi:car-side","tags":["transportation + road","automotive","car saloon"]},{"name":"mdi:car-speed-limiter","tags":["automotive"]},{"name":"mdi:car-sports","tags":["transportation + road","sport","automotive"]},{"name":"mdi:car-tire-alert","tags":["automotive","alert / error","car tyre alert","car tyre warning","car tire warning"]},{"name":"mdi:car-traction-control","tags":["automotive"]},{"name":"mdi:car-turbocharger","tags":["automotive"]},{"name":"mdi:car-windshield","tags":["automotive","car front glass"]},{"name":"mdi:car-windshield-outline","tags":["automotive","car front glass outline"]},{"name":"mdi:car-wireless","tags":["automotive","car autonomous","car self driving","car smart"]},{"name":"mdi:car-wrench","tags":["automotive","hardware / tools","car repair","mechanic"]},{"name":"mdi:caravan","tags":["transportation + road","home automation","automotive"]},{"name":"mdi:card","tags":["form","button"]},{"name":"mdi:card-account-details","tags":["account / user","identification card","user card details","id card","person card details","drivers license","business card"]},{"name":"mdi:card-account-details-outline","tags":["account / user","identification card outline","user card details outline","id card outline","person card details outline","drivers license outline","business card outline"]},{"name":"mdi:card-account-details-star","tags":["account / user","card account details favorite"]},{"name":"mdi:card-account-details-star-outline","tags":["account / user","card account details favorite outline"]},{"name":"mdi:card-bulleted","tags":[]},{"name":"mdi:card-bulleted-off","tags":[]},{"name":"mdi:card-bulleted-off-outline","tags":[]},{"name":"mdi:card-bulleted-outline","tags":[]},{"name":"mdi:card-bulleted-settings","tags":["settings"]},{"name":"mdi:card-bulleted-settings-outline","tags":["settings"]},{"name":"mdi:card-minus","tags":[]},{"name":"mdi:card-minus-outline","tags":[]},{"name":"mdi:card-multiple","tags":[]},{"name":"mdi:card-multiple-outline","tags":[]},{"name":"mdi:card-off","tags":[]},{"name":"mdi:card-off-outline","tags":[]},{"name":"mdi:card-outline","tags":["form","button outline"]},{"name":"mdi:card-plus","tags":[]},{"name":"mdi:card-plus-outline","tags":[]},{"name":"mdi:card-remove","tags":[]},{"name":"mdi:card-remove-outline","tags":[]},{"name":"mdi:card-text","tags":[]},{"name":"mdi:card-text-outline","tags":[]},{"name":"mdi:cards","tags":["gaming / rpg"]},{"name":"mdi:cards-club","tags":["gaming / rpg","suit clubs","poker club"]},{"name":"mdi:cards-club-outline","tags":[]},{"name":"mdi:cards-diamond","tags":["gaming / rpg","transportation + road","suit diamonds","hov lane","high occupancy vehicle lane","carpool lane","poker diamond"]},{"name":"mdi:cards-diamond-outline","tags":["transportation + road","hov lane outline","high occupancy vehicle lane outline","carpool lane outline","poker diamond outline"]},{"name":"mdi:cards-heart","tags":["gaming / rpg","suit hearts","poker heart"]},{"name":"mdi:cards-heart-outline","tags":[]},{"name":"mdi:cards-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-club","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-club-multiple","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-club-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-club-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-diamond","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-diamond-multiple","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-diamond-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-diamond-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-heart","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-heart-multiple","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-heart-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-heart-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-spade","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-spade-multiple","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-spade-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-spade-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-spade","tags":["gaming / rpg","suit spades","poker spade"]},{"name":"mdi:cards-spade-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-variant","tags":["gaming / rpg"]},{"name":"mdi:carrot","tags":["agriculture","food / drink"]},{"name":"mdi:cart-arrow-down","tags":["shopping","shopping cart arrow down","trolley arrow down"]},{"name":"mdi:cart-arrow-right","tags":["shopping","trolley arrow right","shopping cart arrow right"]},{"name":"mdi:cart-arrow-up","tags":["shopping","shopping cart arrow up","trolley arrow up"]},{"name":"mdi:cart-check","tags":["shopping"]},{"name":"mdi:cart-heart","tags":["shopping","cart favorite","shopping favorite"]},{"name":"mdi:cart-minus","tags":["shopping","shopping cart minus","trolley minus"]},{"name":"mdi:cart-percent","tags":["shopping","cart discount","cart sale","trolley percent"]},{"name":"mdi:cart-remove","tags":["shopping","trolley remove","shopping cart remove"]},{"name":"mdi:cart-variant","tags":["shopping"]},{"name":"mdi:case-sensitive-alt","tags":[]},{"name":"mdi:cash","tags":["currency","banking","shopping","money"]},{"name":"mdi:cash-check","tags":["currency","banking"]},{"name":"mdi:cash-clock","tags":["banking","currency","date / time","cash schedule","payment schedule","payment clock","auto pay"]},{"name":"mdi:cash-fast","tags":["currency","banking","instant deposit","instant transfer","instant cash"]},{"name":"mdi:cash-lock","tags":["lock","currency","banking"]},{"name":"mdi:cash-lock-open","tags":["lock","currency","banking"]},{"name":"mdi:cash-marker","tags":["banking","currency","navigation","cod","cash on delivery","cash location"]},{"name":"mdi:cash-minus","tags":["currency","banking"]},{"name":"mdi:cash-multiple","tags":["currency","banking","money"]},{"name":"mdi:cash-off","tags":["currency","banking"]},{"name":"mdi:cash-plus","tags":["currency","banking"]},{"name":"mdi:cash-refund","tags":["banking","currency","cash return","cash chargeback"]},{"name":"mdi:cash-register","tags":["shopping","banking","till"]},{"name":"mdi:cash-remove","tags":["currency","banking"]},{"name":"mdi:cash-sync","tags":["banking","currency","auto pay","recurring payment","scheduled payment","cash cycle"]},{"name":"mdi:cassette","tags":["music","tape"]},{"name":"mdi:cast-audio","tags":["audio","cast speaker"]},{"name":"mdi:cast-audio-variant","tags":["apple airplay"]},{"name":"mdi:cast-off","tags":["home automation"]},{"name":"mdi:castle","tags":["places"]},{"name":"mdi:cat","tags":["animal","holiday","emoji cat","emoticon cat"]},{"name":"mdi:cctv","tags":["home automation","closed circuit television","security camera"]},{"name":"mdi:cctv-off","tags":["home automation","closed circuit television off","security camera off"]},{"name":"mdi:ceiling-fan","tags":["home automation"]},{"name":"mdi:ceiling-fan-light","tags":["home automation","ceiling fan on"]},{"name":"mdi:ceiling-light","tags":["home automation","ceiling lamp"]},{"name":"mdi:ceiling-light-multiple","tags":["home automation","ceiling lamp multiple"]},{"name":"mdi:ceiling-light-multiple-outline","tags":["home automation","ceiling lamp multiple outline"]},{"name":"mdi:ceiling-light-outline","tags":["home automation"]},{"name":"mdi:cellphone-arrow-down-variant","tags":["cellphone / phone","cellphone download"]},{"name":"mdi:cellphone-basic","tags":["cellphone / phone","device / tech","mobile phone basic"]},{"name":"mdi:cellphone-charging","tags":["cellphone / phone"]},{"name":"mdi:cellphone-check","tags":["cellphone / phone"]},{"name":"mdi:cellphone-key","tags":["cellphone / phone","device / tech","mobile phone key","smartphone key"]},{"name":"mdi:cellphone-marker","tags":["cellphone / phone","navigation","cellphone location","cellphone map","find my phone","cellphone gps"]},{"name":"mdi:cellphone-message","tags":["cellphone / phone","device / tech","mobile phone message","smartphone message"]},{"name":"mdi:cellphone-message-off","tags":["cellphone / phone"]},{"name":"mdi:cellphone-nfc-off","tags":["cellphone / phone"]},{"name":"mdi:cellphone-remove","tags":["cellphone / phone","device / tech","phonelink erase","mobile phone erase","smartphone erase","cellphone erase"]},{"name":"mdi:cellphone-text","tags":["cellphone / phone","device / tech","mobile phone text","smartphone text"]},{"name":"mdi:cellphone-wireless","tags":["cellphone / phone","device / tech","mobile phone wireless","smartphone wireless"]},{"name":"mdi:certificate","tags":["diploma","seal"]},{"name":"mdi:certificate-outline","tags":["diploma outline","seal outline"]},{"name":"mdi:chair-rolling","tags":["home automation","office chair","study chair"]},{"name":"mdi:chair-school","tags":["desk","education","learn"]},{"name":"mdi:chandelier","tags":["home automation","ceiling light","girandole","candelabra lamp","suspended light"]},{"name":"mdi:chart-arc","tags":["math","report arc","widget arc"]},{"name":"mdi:chart-areaspline","tags":["math","report areaspline","widget areaspline","graph areaspline"]},{"name":"mdi:chart-areaspline-variant","tags":["math","report areaspline variant","widget areaspline variant","graph areaspline variant"]},{"name":"mdi:chart-bar","tags":["math","report bar","widget bar","graph bar"]},{"name":"mdi:chart-bar-stacked","tags":["math","report bar stacked","widget bar stacked","graph bar stacked"]},{"name":"mdi:chart-bell-curve","tags":["math","report bell curve","widget bell curve","graph bell curve"]},{"name":"mdi:chart-bell-curve-cumulative","tags":["math","report bell curve cumulative","widget bell curve cumulative","graph bell curve cumulative"]},{"name":"mdi:chart-donut-variant","tags":["math","chart doughnut variant","report donut variant","widget donut variant"]},{"name":"mdi:chart-gantt","tags":["math","report gantt","timeline","widget gantt","roadmap"]},{"name":"mdi:chart-histogram","tags":["math","report histogram","widget histogram","graph histogram"]},{"name":"mdi:chart-line","tags":["math","report line","widget line","graph line"]},{"name":"mdi:chart-line-stacked","tags":["math","report line stacked","widget line stacked","graph line stacked"]},{"name":"mdi:chart-multiple","tags":["math","report multiple","widget multiple","graph multiple"]},{"name":"mdi:chart-ppf","tags":["math","chart production possibility frontier","report ppf","widget ppf","graph ppf"]},{"name":"mdi:chart-sankey","tags":["math","chart snakey","report sankey","widget sankey","graph sankey"]},{"name":"mdi:chart-sankey-variant","tags":["math","chart snakey variant","report sankey variant","widget sankey variant","graph sankey variant"]},{"name":"mdi:chart-scatter-plot","tags":["math","report scatter plot","widget scatter plot","graph scatter plot"]},{"name":"mdi:chart-scatter-plot-hexbin","tags":["math","chart scatterplot hexbin","report scatter plot hexbin","widget scatter plot hexbin","graph scatter plot hexbin"]},{"name":"mdi:chart-timeline","tags":["math","report timeline","widget timeline","graph timeline","roadmap"]},{"name":"mdi:chart-waterfall","tags":["math"]},{"name":"mdi:chat","tags":[]},{"name":"mdi:chat-alert","tags":["alert / error","chat warning"]},{"name":"mdi:chat-alert-outline","tags":["alert / error"]},{"name":"mdi:chat-minus","tags":[]},{"name":"mdi:chat-minus-outline","tags":[]},{"name":"mdi:chat-outline","tags":[]},{"name":"mdi:chat-plus","tags":[]},{"name":"mdi:chat-plus-outline","tags":[]},{"name":"mdi:chat-processing","tags":["chat typing"]},{"name":"mdi:chat-processing-outline","tags":["chat typing outline"]},{"name":"mdi:chat-question","tags":["chat help"]},{"name":"mdi:chat-question-outline","tags":["chat help outline"]},{"name":"mdi:chat-remove","tags":[]},{"name":"mdi:chat-remove-outline","tags":[]},{"name":"mdi:chat-sleep","tags":[]},{"name":"mdi:chat-sleep-outline","tags":[]},{"name":"mdi:check-bold","tags":["check thick","success thick","success bold"]},{"name":"mdi:check-decagram","tags":["verified","decagram check","approve","approval","tick decagram"]},{"name":"mdi:check-decagram-outline","tags":["approve","approval","verified"]},{"name":"mdi:check-network","tags":["tick network"]},{"name":"mdi:check-network-outline","tags":["tick network outline"]},{"name":"mdi:check-underline","tags":[]},{"name":"mdi:check-underline-circle","tags":[]},{"name":"mdi:check-underline-circle-outline","tags":[]},{"name":"mdi:checkbook-arrow-left","tags":["banking","chequebook arrow left"]},{"name":"mdi:checkbook-arrow-right","tags":["banking","chequebook arrow right"]},{"name":"mdi:checkbox-blank-badge","tags":["notification","form","checkbox blank notification","app notification","app badge"]},{"name":"mdi:checkbox-blank-badge-outline","tags":["notification","form","checkbox blank notification outline","app notification outline","app badge outline"]},{"name":"mdi:checkbox-blank-off","tags":["form"]},{"name":"mdi:checkbox-blank-off-outline","tags":["form"]},{"name":"mdi:checkbox-intermediate","tags":["form","checkbox indeterminate"]},{"name":"mdi:checkbox-intermediate-variant","tags":["form","checkbox indeterminate variant"]},{"name":"mdi:checkbox-marked-circle-auto-outline","tags":["form","task auto","todo auto"]},{"name":"mdi:checkbox-marked-circle-minus-outline","tags":["form","todo minus","task minus"]},{"name":"mdi:checkbox-marked-circle-plus-outline","tags":["form","task plus","task add","todo plus","todo add"]},{"name":"mdi:checkbox-multiple-blank","tags":["form","checkboxes blank"]},{"name":"mdi:checkbox-multiple-blank-circle","tags":["form","checkboxes blank circle"]},{"name":"mdi:checkbox-multiple-blank-circle-outline","tags":["form","checkboxes blank circle outline"]},{"name":"mdi:checkbox-multiple-blank-outline","tags":["form","checkboxes blank outline"]},{"name":"mdi:checkbox-multiple-marked","tags":["form","checkboxes marked"]},{"name":"mdi:checkbox-multiple-marked-circle","tags":["form","checkboxes marked circle"]},{"name":"mdi:checkbox-multiple-marked-circle-outline","tags":["form","checkboxes marked circle outline"]},{"name":"mdi:checkbox-multiple-marked-outline","tags":["form","checkboxes marked outline"]},{"name":"mdi:checkbox-multiple-outline","tags":["form","check boxes outline","tick box multiple outline"]},{"name":"mdi:checkbox-outline","tags":["form"]},{"name":"mdi:checkerboard","tags":["gaming / rpg","geographic information system","raster"]},{"name":"mdi:checkerboard-minus","tags":["geographic information system","raster minus"]},{"name":"mdi:checkerboard-plus","tags":["geographic information system","raster plus"]},{"name":"mdi:checkerboard-remove","tags":["geographic information system","raster remove"]},{"name":"mdi:cheese","tags":["food / drink","swiss cheese"]},{"name":"mdi:cheese-off","tags":["food / drink"]},{"name":"mdi:chef-hat","tags":["clothing","toque","cook"]},{"name":"mdi:chemical-weapon","tags":[]},{"name":"mdi:chess-bishop","tags":["gaming / rpg"]},{"name":"mdi:chess-king","tags":["gaming / rpg","crown","royalty"]},{"name":"mdi:chess-knight","tags":["gaming / rpg","chess horse"]},{"name":"mdi:chess-pawn","tags":["gaming / rpg"]},{"name":"mdi:chess-queen","tags":["gaming / rpg","crown","royalty"]},{"name":"mdi:chess-rook","tags":["gaming / rpg","chess castle","chess tower"]},{"name":"mdi:chevron-double-down","tags":["arrow"]},{"name":"mdi:chevron-double-left","tags":["arrow"]},{"name":"mdi:chevron-double-right","tags":["arrow"]},{"name":"mdi:chevron-double-up","tags":["arrow"]},{"name":"mdi:chevron-down-box","tags":["form","arrow"]},{"name":"mdi:chevron-down-box-outline","tags":["form","arrow"]},{"name":"mdi:chevron-down-circle","tags":["arrow"]},{"name":"mdi:chevron-down-circle-outline","tags":["arrow"]},{"name":"mdi:chevron-left-box","tags":["arrow"]},{"name":"mdi:chevron-left-box-outline","tags":["arrow"]},{"name":"mdi:chevron-left-circle","tags":["arrow"]},{"name":"mdi:chevron-left-circle-outline","tags":["arrow"]},{"name":"mdi:chevron-right-box","tags":["arrow"]},{"name":"mdi:chevron-right-box-outline","tags":["arrow"]},{"name":"mdi:chevron-right-circle","tags":["arrow"]},{"name":"mdi:chevron-right-circle-outline","tags":["arrow"]},{"name":"mdi:chevron-up-box","tags":["arrow"]},{"name":"mdi:chevron-up-box-outline","tags":["arrow"]},{"name":"mdi:chevron-up-circle","tags":["arrow"]},{"name":"mdi:chevron-up-circle-outline","tags":["arrow"]},{"name":"mdi:chili-alert","tags":["alert / error"]},{"name":"mdi:chili-alert-outline","tags":["alert / error"]},{"name":"mdi:chili-hot","tags":["food / drink","chilli hot","pepper","spicy"]},{"name":"mdi:chili-hot-outline","tags":[]},{"name":"mdi:chili-medium","tags":["food / drink","chilli medium","pepper","spicy"]},{"name":"mdi:chili-medium-outline","tags":[]},{"name":"mdi:chili-mild","tags":["food / drink","agriculture","chilli mild","pepper","spicy"]},{"name":"mdi:chili-mild-outline","tags":[]},{"name":"mdi:chili-off","tags":["food / drink","chilli off","pepper off","spicy off"]},{"name":"mdi:chili-off-outline","tags":[]},{"name":"mdi:chip","tags":["integrated circuit"]},{"name":"mdi:cigar","tags":[]},{"name":"mdi:cigar-off","tags":[]},{"name":"mdi:circle","tags":["shape","lens"]},{"name":"mdi:circle-box","tags":[]},{"name":"mdi:circle-box-outline","tags":[]},{"name":"mdi:circle-double","tags":["shape"]},{"name":"mdi:circle-half","tags":["shape","brightness half"]},{"name":"mdi:circle-half-full","tags":["shape"]},{"name":"mdi:circle-medium","tags":[]},{"name":"mdi:circle-multiple","tags":["currency","banking","coins"]},{"name":"mdi:circle-off-outline","tags":["null off"]},{"name":"mdi:circle-opacity","tags":["shape","drawing / art","circle transparent"]},{"name":"mdi:circle-outline","tags":["shape","null"]},{"name":"mdi:circle-slice-1","tags":[]},{"name":"mdi:circle-slice-2","tags":[]},{"name":"mdi:circle-slice-3","tags":[]},{"name":"mdi:circle-slice-4","tags":[]},{"name":"mdi:circle-slice-5","tags":[]},{"name":"mdi:circle-slice-6","tags":[]},{"name":"mdi:circle-slice-7","tags":[]},{"name":"mdi:circle-slice-8","tags":[]},{"name":"mdi:circle-small","tags":["math","bullet","multiplication","dot"]},{"name":"mdi:circular-saw","tags":["hardware / tools"]},{"name":"mdi:city-switch","tags":["places","city swap"]},{"name":"mdi:city-variant","tags":["places"]},{"name":"mdi:city-variant-outline","tags":["places"]},{"name":"mdi:clipboard","tags":[]},{"name":"mdi:clipboard-account-outline","tags":["account / user","clipboard user outline","clipboard person outline","assignment ind outline"]},{"name":"mdi:clipboard-alert-outline","tags":["alert / error","clipboard warning outline"]},{"name":"mdi:clipboard-arrow-left-outline","tags":[]},{"name":"mdi:clipboard-arrow-right","tags":[]},{"name":"mdi:clipboard-arrow-right-outline","tags":[]},{"name":"mdi:clipboard-arrow-up","tags":["clipboard arrow top"]},{"name":"mdi:clipboard-arrow-up-outline","tags":["clipboard arrow top outline"]},{"name":"mdi:clipboard-check-multiple","tags":[]},{"name":"mdi:clipboard-check-multiple-outline","tags":[]},{"name":"mdi:clipboard-check-outline","tags":["clipboard tick outline"]},{"name":"mdi:clipboard-clock","tags":["date / time"]},{"name":"mdi:clipboard-clock-outline","tags":["date / time"]},{"name":"mdi:clipboard-edit","tags":["edit / modify"]},{"name":"mdi:clipboard-edit-outline","tags":["edit / modify"]},{"name":"mdi:clipboard-file","tags":["files / folders"]},{"name":"mdi:clipboard-file-outline","tags":["files / folders"]},{"name":"mdi:clipboard-flow","tags":[]},{"name":"mdi:clipboard-flow-outline","tags":[]},{"name":"mdi:clipboard-list","tags":[]},{"name":"mdi:clipboard-list-outline","tags":[]},{"name":"mdi:clipboard-minus","tags":[]},{"name":"mdi:clipboard-minus-outline","tags":[]},{"name":"mdi:clipboard-multiple","tags":[]},{"name":"mdi:clipboard-multiple-outline","tags":[]},{"name":"mdi:clipboard-off","tags":[]},{"name":"mdi:clipboard-off-outline","tags":[]},{"name":"mdi:clipboard-outline","tags":[]},{"name":"mdi:clipboard-play","tags":[]},{"name":"mdi:clipboard-play-multiple","tags":[]},{"name":"mdi:clipboard-play-multiple-outline","tags":[]},{"name":"mdi:clipboard-play-outline","tags":[]},{"name":"mdi:clipboard-plus","tags":["clipboard add"]},{"name":"mdi:clipboard-plus-outline","tags":[]},{"name":"mdi:clipboard-pulse","tags":["medical / hospital","clipboard vitals"]},{"name":"mdi:clipboard-pulse-outline","tags":["medical / hospital","clipboard vitals outline"]},{"name":"mdi:clipboard-remove","tags":[]},{"name":"mdi:clipboard-remove-outline","tags":[]},{"name":"mdi:clipboard-search","tags":[]},{"name":"mdi:clipboard-search-outline","tags":[]},{"name":"mdi:clipboard-text-clock","tags":["date / time","clipboard text date","clipboard text time","clipboard text history"]},{"name":"mdi:clipboard-text-clock-outline","tags":["date / time","clipboard text date outline","clipboard text time outline","clipboard text history outline"]},{"name":"mdi:clipboard-text-multiple","tags":[]},{"name":"mdi:clipboard-text-multiple-outline","tags":[]},{"name":"mdi:clipboard-text-off","tags":[]},{"name":"mdi:clipboard-text-off-outline","tags":[]},{"name":"mdi:clipboard-text-outline","tags":[]},{"name":"mdi:clipboard-text-play","tags":[]},{"name":"mdi:clipboard-text-play-outline","tags":[]},{"name":"mdi:clipboard-text-search","tags":[]},{"name":"mdi:clipboard-text-search-outline","tags":[]},{"name":"mdi:clippy","tags":[]},{"name":"mdi:clock-alert","tags":["date / time","alert / error","clock warning"]},{"name":"mdi:clock-alert-outline","tags":["date / time","alert / error","clock warning"]},{"name":"mdi:clock-check","tags":["date / time"]},{"name":"mdi:clock-check-outline","tags":["date / time"]},{"name":"mdi:clock-digital","tags":["date / time","home automation"]},{"name":"mdi:clock-edit","tags":["date / time","edit / modify"]},{"name":"mdi:clock-edit-outline","tags":["date / time","edit / modify"]},{"name":"mdi:clock-end","tags":["date / time"]},{"name":"mdi:clock-fast","tags":["date / time","velocity"]},{"name":"mdi:clock-in","tags":["date / time"]},{"name":"mdi:clock-minus","tags":["date / time"]},{"name":"mdi:clock-minus-outline","tags":["date / time"]},{"name":"mdi:clock-out","tags":["date / time"]},{"name":"mdi:clock-plus","tags":["date / time"]},{"name":"mdi:clock-plus-outline","tags":["date / time"]},{"name":"mdi:clock-remove","tags":["date / time"]},{"name":"mdi:clock-remove-outline","tags":["date / time"]},{"name":"mdi:clock-star-four-points","tags":["date / time","clock auto"]},{"name":"mdi:clock-star-four-points-outline","tags":["date / time","clock auto outline"]},{"name":"mdi:clock-start","tags":["date / time"]},{"name":"mdi:clock-time-eight","tags":["date / time"]},{"name":"mdi:clock-time-eight-outline","tags":["date / time"]},{"name":"mdi:clock-time-eleven","tags":["date / time"]},{"name":"mdi:clock-time-eleven-outline","tags":["date / time"]},{"name":"mdi:clock-time-five","tags":["date / time"]},{"name":"mdi:clock-time-five-outline","tags":["date / time"]},{"name":"mdi:clock-time-four","tags":["date / time"]},{"name":"mdi:clock-time-four-outline","tags":["date / time"]},{"name":"mdi:clock-time-nine","tags":["date / time"]},{"name":"mdi:clock-time-nine-outline","tags":["date / time"]},{"name":"mdi:clock-time-one","tags":["date / time"]},{"name":"mdi:clock-time-one-outline","tags":["date / time"]},{"name":"mdi:clock-time-seven","tags":["date / time"]},{"name":"mdi:clock-time-seven-outline","tags":["date / time"]},{"name":"mdi:clock-time-six","tags":["date / time"]},{"name":"mdi:clock-time-six-outline","tags":["date / time"]},{"name":"mdi:clock-time-ten","tags":["date / time"]},{"name":"mdi:clock-time-ten-outline","tags":["date / time"]},{"name":"mdi:clock-time-three","tags":["date / time"]},{"name":"mdi:clock-time-three-outline","tags":["date / time"]},{"name":"mdi:clock-time-twelve","tags":["date / time"]},{"name":"mdi:clock-time-twelve-outline","tags":["date / time"]},{"name":"mdi:clock-time-two","tags":["date / time"]},{"name":"mdi:clock-time-two-outline","tags":["date / time"]},{"name":"mdi:close-box","tags":["math","form","multiply box","clear box","cancel box","remove box"]},{"name":"mdi:close-box-multiple","tags":["form","close boxes","library remove","library close","multiply boxes","multiply box multiple","cancel box multiple","remove box multiple"]},{"name":"mdi:close-box-multiple-outline","tags":["form","close boxes outline","library remove outline","library close outline","multiply boxes outline","multiply box multiple outline","remove box multiple","cancel box multiple"]},{"name":"mdi:close-box-outline","tags":["math","form","multiply box outline","clear box outline","remove box outline","cancel box outline"]},{"name":"mdi:close-circle","tags":["form","remove circle","cancel circle","multiply circle","clear circle"]},{"name":"mdi:close-circle-multiple","tags":["form","remove circle multiple","coins close","coins remove","clear circle multiple","multiply circle multiple"]},{"name":"mdi:close-circle-multiple-outline","tags":["form","remove circle multiple outline","coins close outline","coins remove outline","cancel circle multiple outline","multiply circle multiple outline","clear circle multiple outline"]},{"name":"mdi:close-network","tags":["remove network","cancel network","multiply network","clear network"]},{"name":"mdi:close-network-outline","tags":["remove network outline","cancel network outline","multiply network outline","clear network outline"]},{"name":"mdi:close-octagon","tags":["dangerous","multiply octagon","remove octagon","cancel octagon","clear octagon","stop remove"]},{"name":"mdi:close-octagon-outline","tags":["remove octagon outline","multiply octagon outline","clear octagon outline","cancel octagon outline","stop remove outline"]},{"name":"mdi:close-outline","tags":["remove outline","cancel outline","multiply outline","clear outline"]},{"name":"mdi:close-thick","tags":["close bold","remove thick","remove bold","multiply thick","multiply bold","clear thick","clear bold","cancel thick","cancel bold"]},{"name":"mdi:cloud-alert","tags":["alert / error","cloud","weather","cloud warning"]},{"name":"mdi:cloud-alert-outline","tags":["alert / error","weather","cloud"]},{"name":"mdi:cloud-arrow-down","tags":["cloud","weather"]},{"name":"mdi:cloud-arrow-down-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-arrow-left","tags":["weather","cloud"]},{"name":"mdi:cloud-arrow-left-outline","tags":["weather","cloud"]},{"name":"mdi:cloud-arrow-right","tags":["weather","cloud"]},{"name":"mdi:cloud-arrow-right-outline","tags":["weather","cloud"]},{"name":"mdi:cloud-arrow-up","tags":["cloud","weather"]},{"name":"mdi:cloud-arrow-up-outline","tags":["weather","cloud"]},{"name":"mdi:cloud-braces","tags":["cloud","developer / languages","cloud json"]},{"name":"mdi:cloud-cancel","tags":["cloud","weather"]},{"name":"mdi:cloud-cancel-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-check","tags":["cloud","weather"]},{"name":"mdi:cloud-check-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-check-variant-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-clock","tags":["weather","cloud"]},{"name":"mdi:cloud-clock-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-cog","tags":["cloud","weather"]},{"name":"mdi:cloud-cog-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-lock","tags":["cloud","lock"]},{"name":"mdi:cloud-lock-open","tags":["cloud"]},{"name":"mdi:cloud-lock-open-outline","tags":["cloud"]},{"name":"mdi:cloud-lock-outline","tags":["cloud","lock"]},{"name":"mdi:cloud-minus","tags":["cloud"]},{"name":"mdi:cloud-minus-outline","tags":["cloud"]},{"name":"mdi:cloud-percent","tags":["weather","cloud","nature","humidity","rain chance","cloud discount"]},{"name":"mdi:cloud-percent-outline","tags":["weather","cloud","nature","cloud discount outline","humidity outline","rain chance outline"]},{"name":"mdi:cloud-plus","tags":["cloud"]},{"name":"mdi:cloud-plus-outline","tags":["cloud"]},{"name":"mdi:cloud-print","tags":["cloud","printer","home automation"]},{"name":"mdi:cloud-print-outline","tags":["cloud","printer","home automation"]},{"name":"mdi:cloud-question","tags":["cloud","weather"]},{"name":"mdi:cloud-question-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-refresh","tags":["cloud","weather"]},{"name":"mdi:cloud-refresh-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-refresh-variant","tags":["cloud","weather"]},{"name":"mdi:cloud-refresh-variant-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-remove","tags":["cloud"]},{"name":"mdi:cloud-remove-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-search","tags":["cloud","weather"]},{"name":"mdi:cloud-search-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-sync","tags":["cloud","weather"]},{"name":"mdi:cloud-sync-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-tags","tags":["cloud","cloud xml"]},{"name":"mdi:clouds","tags":["weather","cloud"]},{"name":"mdi:clover","tags":["nature","luck"]},{"name":"mdi:clover-outline","tags":["nature","luck outline"]},{"name":"mdi:coach-lamp","tags":["home automation","coach light","carriage lamp","carriage light"]},{"name":"mdi:coach-lamp-variant","tags":["home automation","coach light","carriage light","carriage lamp"]},{"name":"mdi:coat-rack","tags":["home automation","clothing","foyer","hallway","entry room"]},{"name":"mdi:code-array","tags":["developer / languages"]},{"name":"mdi:code-braces","tags":["developer / languages","math","set"]},{"name":"mdi:code-braces-box","tags":["developer / languages"]},{"name":"mdi:code-brackets","tags":["developer / languages","math","square brackets"]},{"name":"mdi:code-equal","tags":["developer / languages"]},{"name":"mdi:code-greater-than","tags":["developer / languages","math"]},{"name":"mdi:code-greater-than-or-equal","tags":["developer / languages","math"]},{"name":"mdi:code-json","tags":["developer / languages"]},{"name":"mdi:code-less-than","tags":["developer / languages","math"]},{"name":"mdi:code-less-than-or-equal","tags":["developer / languages","math"]},{"name":"mdi:code-not-equal","tags":["developer / languages"]},{"name":"mdi:code-not-equal-variant","tags":["developer / languages"]},{"name":"mdi:code-parentheses","tags":["developer / languages"]},{"name":"mdi:code-parentheses-box","tags":["developer / languages"]},{"name":"mdi:code-string","tags":["developer / languages"]},{"name":"mdi:code-tags-check","tags":["developer / languages","code tags tick"]},{"name":"mdi:coffee-maker-check","tags":["home automation","food / drink","coffee maker done","coffee maker complete"]},{"name":"mdi:coffee-maker-check-outline","tags":["home automation","food / drink","coffee maker complete outline","coffee maker done outline"]},{"name":"mdi:coffee-off","tags":["food / drink","drink off","tea off","cup off","free breakfast off","local cafe off"]},{"name":"mdi:coffee-off-outline","tags":["food / drink","drink off outline","cup off outline","tea off outline","free breakfast off outline","local cafe off outline"]},{"name":"mdi:coffee-to-go","tags":["food / drink","tea to go","drink to go","cup to go","free breakfast to go","local cafe to go"]},{"name":"mdi:coffee-to-go-outline","tags":["food / drink","tea to go outline","cup to go outline","drink to go outline","free breakfast to go outline","local cafe to go outline"]},{"name":"mdi:coffin","tags":["holiday","death","dead"]},{"name":"mdi:cog-clockwise","tags":["settings"]},{"name":"mdi:cog-counterclockwise","tags":["settings"]},{"name":"mdi:cog-off","tags":["settings","settings off"]},{"name":"mdi:cog-off-outline","tags":["settings","settings off outline"]},{"name":"mdi:cog-pause","tags":["settings","settings pause","gear pause"]},{"name":"mdi:cog-pause-outline","tags":["settings","settings pause outline","gear pause outline"]},{"name":"mdi:cog-play","tags":["settings","settings play","gear play"]},{"name":"mdi:cog-play-outline","tags":["settings","settings play outline","gear play outline"]},{"name":"mdi:cog-refresh","tags":["settings","settings refresh"]},{"name":"mdi:cog-refresh-outline","tags":["settings","settings refresh outline"]},{"name":"mdi:cog-stop","tags":["settings","settings stop","gear stop"]},{"name":"mdi:cog-stop-outline","tags":["settings","settings stop outline","gear stop outline"]},{"name":"mdi:cog-sync","tags":["settings","settings sync"]},{"name":"mdi:cog-sync-outline","tags":["settings","settings sync outline"]},{"name":"mdi:cog-transfer","tags":["settings","settings transfer"]},{"name":"mdi:cog-transfer-outline","tags":["settings","settings transfer outline"]},{"name":"mdi:collapse-all","tags":["animation minus"]},{"name":"mdi:collapse-all-outline","tags":["animation minus outline"]},{"name":"mdi:comma","tags":[]},{"name":"mdi:comma-box","tags":[]},{"name":"mdi:comma-box-outline","tags":[]},{"name":"mdi:comma-circle","tags":[]},{"name":"mdi:comma-circle-outline","tags":[]},{"name":"mdi:comment","tags":[]},{"name":"mdi:comment-account","tags":["account / user","comment user","comment person"]},{"name":"mdi:comment-account-outline","tags":["account / user","comment user outline","comment person outline"]},{"name":"mdi:comment-alert","tags":["alert / error","comment warning"]},{"name":"mdi:comment-alert-outline","tags":["alert / error","comment warning outline"]},{"name":"mdi:comment-arrow-left","tags":["comment previous"]},{"name":"mdi:comment-arrow-left-outline","tags":["comment previous outline"]},{"name":"mdi:comment-arrow-right","tags":["comment next"]},{"name":"mdi:comment-arrow-right-outline","tags":["comment next outline"]},{"name":"mdi:comment-bookmark","tags":[]},{"name":"mdi:comment-bookmark-outline","tags":[]},{"name":"mdi:comment-check","tags":["comment tick"]},{"name":"mdi:comment-check-outline","tags":["comment tick outline"]},{"name":"mdi:comment-edit","tags":["edit / modify"]},{"name":"mdi:comment-edit-outline","tags":["edit / modify"]},{"name":"mdi:comment-eye","tags":[]},{"name":"mdi:comment-eye-outline","tags":[]},{"name":"mdi:comment-flash","tags":["comment quick"]},{"name":"mdi:comment-flash-outline","tags":["comment quick outline"]},{"name":"mdi:comment-minus","tags":[]},{"name":"mdi:comment-minus-outline","tags":[]},{"name":"mdi:comment-multiple","tags":["comments"]},{"name":"mdi:comment-multiple-outline","tags":["comments outline"]},{"name":"mdi:comment-off","tags":[]},{"name":"mdi:comment-off-outline","tags":[]},{"name":"mdi:comment-outline","tags":[]},{"name":"mdi:comment-plus","tags":["comment add"]},{"name":"mdi:comment-plus-outline","tags":["comment add outline"]},{"name":"mdi:comment-processing","tags":[]},{"name":"mdi:comment-processing-outline","tags":[]},{"name":"mdi:comment-question","tags":["comment help"]},{"name":"mdi:comment-question-outline","tags":["comment help outline"]},{"name":"mdi:comment-quote","tags":["feedback"]},{"name":"mdi:comment-quote-outline","tags":["feedback outline"]},{"name":"mdi:comment-remove","tags":[]},{"name":"mdi:comment-remove-outline","tags":[]},{"name":"mdi:comment-search","tags":[]},{"name":"mdi:comment-search-outline","tags":[]},{"name":"mdi:comment-text","tags":[]},{"name":"mdi:comment-text-multiple","tags":["comments text"]},{"name":"mdi:comment-text-multiple-outline","tags":["comments text outline"]},{"name":"mdi:comment-text-outline","tags":[]},{"name":"mdi:compare-remove","tags":[]},{"name":"mdi:compass-outline","tags":["navigation","geographic information system"]},{"name":"mdi:compass-rose","tags":["navigation"]},{"name":"mdi:cone","tags":["shape"]},{"name":"mdi:cone-off","tags":["shape"]},{"name":"mdi:connection","tags":["home automation","plug"]},{"name":"mdi:console","tags":["terminal"]},{"name":"mdi:console-line","tags":["terminal line"]},{"name":"mdi:console-network","tags":["terminal network"]},{"name":"mdi:console-network-outline","tags":["terminal network outline"]},{"name":"mdi:consolidate","tags":[]},{"name":"mdi:contactless-payment","tags":["currency"]},{"name":"mdi:contactless-payment-circle-outline","tags":["currency"]},{"name":"mdi:contain","tags":[]},{"name":"mdi:contain-end","tags":[]},{"name":"mdi:contain-start","tags":[]},{"name":"mdi:content-duplicate","tags":[]},{"name":"mdi:content-save-alert","tags":["alert / error","floppy disc alert"]},{"name":"mdi:content-save-alert-outline","tags":["alert / error","floppy disc alert outline"]},{"name":"mdi:content-save-all","tags":["floppy disc multiple"]},{"name":"mdi:content-save-all-outline","tags":["floppy disc multiple outline"]},{"name":"mdi:content-save-check","tags":[]},{"name":"mdi:content-save-check-outline","tags":[]},{"name":"mdi:content-save-cog","tags":["settings","floppy disc cog"]},{"name":"mdi:content-save-cog-outline","tags":["settings","floppy disc cog outline"]},{"name":"mdi:content-save-edit","tags":["edit / modify","floppy disc edit"]},{"name":"mdi:content-save-edit-outline","tags":["edit / modify","floppy disc edit outline"]},{"name":"mdi:content-save-minus","tags":[]},{"name":"mdi:content-save-minus-outline","tags":[]},{"name":"mdi:content-save-move","tags":["floppy disc move"]},{"name":"mdi:content-save-move-outline","tags":["floppy disc move outline"]},{"name":"mdi:content-save-off","tags":[]},{"name":"mdi:content-save-off-outline","tags":[]},{"name":"mdi:content-save-plus","tags":["content save add"]},{"name":"mdi:content-save-plus-outline","tags":["content save add outline"]},{"name":"mdi:content-save-settings","tags":["settings","floppy disc settings"]},{"name":"mdi:content-save-settings-outline","tags":["settings","floppy disc settings outline"]},{"name":"mdi:contrast","tags":[]},{"name":"mdi:controller-classic","tags":["gaming / rpg","gamepad classic"]},{"name":"mdi:controller-classic-outline","tags":["gaming / rpg","gamepad classic outline"]},{"name":"mdi:cookie-alert","tags":["food / drink","alert / error","biscuit alert"]},{"name":"mdi:cookie-alert-outline","tags":["food / drink","alert / error","biscuit alert outline"]},{"name":"mdi:cookie-check","tags":["food / drink","biscuit check"]},{"name":"mdi:cookie-check-outline","tags":["food / drink","biscuit check outline"]},{"name":"mdi:cookie-clock","tags":["food / drink","date / time","biscuit clock"]},{"name":"mdi:cookie-clock-outline","tags":["food / drink","date / time","biscuit clock outline"]},{"name":"mdi:cookie-cog","tags":["food / drink","settings","biscuit cog"]},{"name":"mdi:cookie-cog-outline","tags":["food / drink","settings","biscuit cog outline"]},{"name":"mdi:cookie-edit","tags":["food / drink","edit / modify","biscuit edit"]},{"name":"mdi:cookie-edit-outline","tags":["food / drink","edit / modify","biscuit edit outline"]},{"name":"mdi:cookie-lock","tags":["food / drink","lock","biscuit lock"]},{"name":"mdi:cookie-lock-outline","tags":["food / drink","lock","biscuit lock outline"]},{"name":"mdi:cookie-minus","tags":["food / drink","biscuit minus"]},{"name":"mdi:cookie-minus-outline","tags":["food / drink","biscuit minus outline"]},{"name":"mdi:cookie-off","tags":["food / drink","biscuit off"]},{"name":"mdi:cookie-off-outline","tags":["food / drink","biscuit off outline"]},{"name":"mdi:cookie-outline","tags":["food / drink","biscuit outline"]},{"name":"mdi:cookie-plus","tags":["food / drink","biscuit plus"]},{"name":"mdi:cookie-plus-outline","tags":["food / drink","biscuit plus outline"]},{"name":"mdi:cookie-refresh","tags":["food / drink","biscuit refresh"]},{"name":"mdi:cookie-refresh-outline","tags":["food / drink","biscuit refresh outline"]},{"name":"mdi:cookie-remove","tags":["food / drink","biscuit remove"]},{"name":"mdi:cookie-remove-outline","tags":["food / drink","biscuit remove outline"]},{"name":"mdi:cookie-settings","tags":["food / drink","settings","biscuit settings","cookie crumbs","biscuit crumbs"]},{"name":"mdi:cookie-settings-outline","tags":["food / drink","settings","biscuit settings outline","cookie crumbs outline","biscuit crumbs outline"]},{"name":"mdi:coolant-temperature","tags":["automotive"]},{"name":"mdi:copyleft","tags":[]},{"name":"mdi:corn","tags":["agriculture","food / drink"]},{"name":"mdi:corn-off","tags":["food / drink","agriculture"]},{"name":"mdi:cosine-wave","tags":["audio","frequency","amplitude"]},{"name":"mdi:counter","tags":["automotive","score","numbers","odometer"]},{"name":"mdi:cow","tags":["animal","agriculture","emoji cow","emoticon cow"]},{"name":"mdi:cow-off","tags":["food / drink","agriculture","animal","dairy off","dairy free"]},{"name":"mdi:cpu-32-bit","tags":["chip 32 bit"]},{"name":"mdi:cpu-64-bit","tags":["chip 64 bit"]},{"name":"mdi:crane","tags":[]},{"name":"mdi:creation-outline","tags":["auto awesome outline"]},{"name":"mdi:credit-card","tags":["banking","currency"]},{"name":"mdi:credit-card-check","tags":["banking"]},{"name":"mdi:credit-card-check-outline","tags":["banking"]},{"name":"mdi:credit-card-chip","tags":["banking","credit card icc chip"]},{"name":"mdi:credit-card-chip-outline","tags":["banking","credit card icc chip outline"]},{"name":"mdi:credit-card-clock","tags":["banking","date / time"]},{"name":"mdi:credit-card-clock-outline","tags":["banking","date / time"]},{"name":"mdi:credit-card-edit","tags":["edit / modify","banking"]},{"name":"mdi:credit-card-edit-outline","tags":["edit / modify","banking"]},{"name":"mdi:credit-card-fast","tags":["banking","credit card swipe"]},{"name":"mdi:credit-card-fast-outline","tags":["banking","credit card swipe outline"]},{"name":"mdi:credit-card-lock","tags":["banking","lock"]},{"name":"mdi:credit-card-lock-outline","tags":["banking","lock"]},{"name":"mdi:credit-card-marker","tags":["banking","navigation","credit card location","payment on delivery"]},{"name":"mdi:credit-card-marker-outline","tags":["banking","navigation","cod","payment on delivery outline","credit card location outline"]},{"name":"mdi:credit-card-minus","tags":["banking"]},{"name":"mdi:credit-card-minus-outline","tags":["banking"]},{"name":"mdi:credit-card-multiple","tags":["banking"]},{"name":"mdi:credit-card-multiple-outline","tags":["banking","credit cards"]},{"name":"mdi:credit-card-off","tags":["banking"]},{"name":"mdi:credit-card-off-outline","tags":["banking"]},{"name":"mdi:credit-card-plus","tags":["banking"]},{"name":"mdi:credit-card-plus-outline","tags":["banking","credit card add"]},{"name":"mdi:credit-card-refresh","tags":["banking"]},{"name":"mdi:credit-card-refresh-outline","tags":["banking"]},{"name":"mdi:credit-card-refund","tags":["banking"]},{"name":"mdi:credit-card-refund-outline","tags":["banking"]},{"name":"mdi:credit-card-remove","tags":["banking"]},{"name":"mdi:credit-card-remove-outline","tags":["banking"]},{"name":"mdi:credit-card-scan","tags":["banking"]},{"name":"mdi:credit-card-scan-outline","tags":["banking"]},{"name":"mdi:credit-card-search","tags":["banking"]},{"name":"mdi:credit-card-search-outline","tags":["banking"]},{"name":"mdi:credit-card-settings","tags":["banking","settings"]},{"name":"mdi:credit-card-settings-outline","tags":["banking","settings","payment settings"]},{"name":"mdi:credit-card-sync","tags":["banking"]},{"name":"mdi:credit-card-sync-outline","tags":["banking"]},{"name":"mdi:credit-card-wireless","tags":["currency","banking"]},{"name":"mdi:credit-card-wireless-off","tags":["banking"]},{"name":"mdi:credit-card-wireless-off-outline","tags":["banking"]},{"name":"mdi:credit-card-wireless-outline","tags":["currency","banking","credit card contactless"]},{"name":"mdi:cross","tags":["religion","holiday","christianity","religion christian"]},{"name":"mdi:cross-bolnisi","tags":["religion"]},{"name":"mdi:cross-celtic","tags":["religion","holiday"]},{"name":"mdi:cross-outline","tags":["religion","religion christian outline","christianity outline"]},{"name":"mdi:crown","tags":[]},{"name":"mdi:crown-circle","tags":["gaming / rpg","checkers"]},{"name":"mdi:crown-circle-outline","tags":["gaming / rpg","checkers outline"]},{"name":"mdi:crown-outline","tags":[]},{"name":"mdi:crystal-ball","tags":["gaming / rpg"]},{"name":"mdi:cube","tags":["shape"]},{"name":"mdi:cube-off","tags":[]},{"name":"mdi:cube-off-outline","tags":["food / drink","sugar off","sugar cube off","sugar free"]},{"name":"mdi:cube-outline","tags":["shape","food / drink","sugar","sugar cube"]},{"name":"mdi:cube-send","tags":[]},{"name":"mdi:cube-unfolded","tags":[]},{"name":"mdi:cup","tags":["food / drink","glass","drink"]},{"name":"mdi:cup-off","tags":["food / drink","glass off","drink off"]},{"name":"mdi:cup-off-outline","tags":["food / drink","glass off outline","drink off outline"]},{"name":"mdi:cup-outline","tags":["food / drink","glass outline","drink outline","cup empty"]},{"name":"mdi:cupboard","tags":["home automation"]},{"name":"mdi:cupboard-outline","tags":["home automation"]},{"name":"mdi:cupcake","tags":["food / drink"]},{"name":"mdi:curling","tags":["sport"]},{"name":"mdi:currency-bdt","tags":["banking","currency","taka","bangladeshi taka"]},{"name":"mdi:currency-brl","tags":["banking","currency","brazilian real"]},{"name":"mdi:currency-eth","tags":["currency","banking","ethereum","xi"]},{"name":"mdi:currency-eur-off","tags":["currency","banking"]},{"name":"mdi:currency-ils","tags":["banking","currency"]},{"name":"mdi:currency-inr","tags":["currency","banking","rupee"]},{"name":"mdi:currency-krw","tags":["currency","banking","won"]},{"name":"mdi:currency-kzt","tags":["banking","currency","kazakhstani tenge"]},{"name":"mdi:currency-mnt","tags":["currency","banking","currency mongolian tugrug"]},{"name":"mdi:currency-ngn","tags":["currency","banking","naira"]},{"name":"mdi:currency-php","tags":["banking","currency","philippine peso"]},{"name":"mdi:currency-rial","tags":["currency","banking","currency riyal","currency irr","currency omr","currency yer","currency sar"]},{"name":"mdi:currency-sign","tags":["currency","banking","currency scarab"]},{"name":"mdi:currency-thb","tags":["banking","currency thai baht"]},{"name":"mdi:currency-twd","tags":["currency","banking","new taiwan dollar"]},{"name":"mdi:currency-uah","tags":["banking","currency hryvnia","currency ukraine"]},{"name":"mdi:current-ac","tags":["alternating current"]},{"name":"mdi:current-dc","tags":["battery","direct current"]},{"name":"mdi:cursor-default","tags":[]},{"name":"mdi:cursor-default-click","tags":[]},{"name":"mdi:cursor-default-click-outline","tags":[]},{"name":"mdi:cursor-default-gesture","tags":[]},{"name":"mdi:cursor-default-gesture-outline","tags":[]},{"name":"mdi:cursor-default-outline","tags":[]},{"name":"mdi:cursor-move","tags":[]},{"name":"mdi:cursor-pointer","tags":["cursor hand"]},{"name":"mdi:cursor-text","tags":[]},{"name":"mdi:curtains","tags":["home automation","drapes","window"]},{"name":"mdi:curtains-closed","tags":["home automation","drapes closed","window closed"]},{"name":"mdi:cylinder","tags":["shape"]},{"name":"mdi:cylinder-off","tags":["shape"]},{"name":"mdi:dance-ballroom","tags":["people / family","human dance ballroom"]},{"name":"mdi:dance-pole","tags":["sport","people / family","kho kho","human dance pole"]},{"name":"mdi:data-matrix","tags":[]},{"name":"mdi:data-matrix-edit","tags":["edit / modify"]},{"name":"mdi:data-matrix-minus","tags":[]},{"name":"mdi:data-matrix-plus","tags":[]},{"name":"mdi:data-matrix-remove","tags":[]},{"name":"mdi:data-matrix-scan","tags":[]},{"name":"mdi:database","tags":["geographic information system","database","storage"]},{"name":"mdi:database-alert","tags":["database","alert / error"]},{"name":"mdi:database-alert-outline","tags":["database","alert / error"]},{"name":"mdi:database-arrow-down","tags":["database"]},{"name":"mdi:database-arrow-down-outline","tags":["database"]},{"name":"mdi:database-arrow-left","tags":["database"]},{"name":"mdi:database-arrow-left-outline","tags":["database"]},{"name":"mdi:database-arrow-right","tags":["database"]},{"name":"mdi:database-arrow-right-outline","tags":["database"]},{"name":"mdi:database-arrow-up","tags":["database"]},{"name":"mdi:database-arrow-up-outline","tags":["database"]},{"name":"mdi:database-check","tags":["geographic information system","database","database tick"]},{"name":"mdi:database-check-outline","tags":["database"]},{"name":"mdi:database-clock","tags":["database","date / time"]},{"name":"mdi:database-clock-outline","tags":["database","date / time"]},{"name":"mdi:database-cog","tags":["database","settings"]},{"name":"mdi:database-cog-outline","tags":["database","settings"]},{"name":"mdi:database-edit","tags":["edit / modify","geographic information system","database"]},{"name":"mdi:database-edit-outline","tags":["database","edit / modify"]},{"name":"mdi:database-export","tags":["geographic information system","database"]},{"name":"mdi:database-export-outline","tags":["database"]},{"name":"mdi:database-eye","tags":["database","database view"]},{"name":"mdi:database-eye-off","tags":["database","database view off"]},{"name":"mdi:database-eye-off-outline","tags":["database","database view off outline"]},{"name":"mdi:database-eye-outline","tags":["database","database view outline"]},{"name":"mdi:database-import","tags":["geographic information system","database"]},{"name":"mdi:database-import-outline","tags":["database"]},{"name":"mdi:database-lock","tags":["lock","geographic information system","database"]},{"name":"mdi:database-lock-outline","tags":["database","lock"]},{"name":"mdi:database-marker","tags":["geographic information system","database","navigation","database location"]},{"name":"mdi:database-marker-outline","tags":["database","navigation","database location outline"]},{"name":"mdi:database-minus","tags":["geographic information system","database"]},{"name":"mdi:database-minus-outline","tags":["database"]},{"name":"mdi:database-off","tags":["database"]},{"name":"mdi:database-off-outline","tags":["database"]},{"name":"mdi:database-outline","tags":["database"]},{"name":"mdi:database-plus","tags":["geographic information system","database","database add"]},{"name":"mdi:database-plus-outline","tags":["database"]},{"name":"mdi:database-refresh","tags":["database"]},{"name":"mdi:database-refresh-outline","tags":["database"]},{"name":"mdi:database-remove","tags":["geographic information system","database"]},{"name":"mdi:database-remove-outline","tags":["database"]},{"name":"mdi:database-search","tags":["geographic information system","database","sql query"]},{"name":"mdi:database-search-outline","tags":["database"]},{"name":"mdi:database-settings","tags":["settings","geographic information system","database"]},{"name":"mdi:database-settings-outline","tags":["database","settings"]},{"name":"mdi:database-sync","tags":["geographic information system","database"]},{"name":"mdi:database-sync-outline","tags":["database"]},{"name":"mdi:death-star","tags":[]},{"name":"mdi:death-star-variant","tags":[]},{"name":"mdi:deathly-hallows","tags":["harry potter"]},{"name":"mdi:debug-step-into","tags":[]},{"name":"mdi:debug-step-out","tags":[]},{"name":"mdi:debug-step-over","tags":["skip","jump"]},{"name":"mdi:decagram","tags":["shape","starburst"]},{"name":"mdi:decagram-outline","tags":["shape","starburst outline"]},{"name":"mdi:decimal","tags":["math"]},{"name":"mdi:decimal-comma","tags":["math"]},{"name":"mdi:decimal-comma-decrease","tags":["math"]},{"name":"mdi:decimal-comma-increase","tags":["math"]},{"name":"mdi:decimal-decrease","tags":["math"]},{"name":"mdi:decimal-increase","tags":["math"]},{"name":"mdi:delete-alert","tags":["alert / error"]},{"name":"mdi:delete-alert-outline","tags":["alert / error"]},{"name":"mdi:delete-circle","tags":["trash circle","bin circle","garbage can circle","garbage circle","rubbish bin circle","rubbish circle","trash can circle"]},{"name":"mdi:delete-circle-outline","tags":["bin circle outline","garbage can circle outline","garbage circle outline","rubbish bin circle outline","rubbish circle outline","trash can circle outline","trash circle outline"]},{"name":"mdi:delete-clock","tags":["date / time"]},{"name":"mdi:delete-clock-outline","tags":["date / time"]},{"name":"mdi:delete-empty","tags":["trash empty","bin empty","rubbish empty","rubbish bin empty","trash can empty","garbage empty","garbage can empty"]},{"name":"mdi:delete-empty-outline","tags":[]},{"name":"mdi:delete-off","tags":[]},{"name":"mdi:delete-off-outline","tags":[]},{"name":"mdi:delete-variant","tags":["trash variant","bin variant","cup ice","drink ice"]},{"name":"mdi:desk","tags":[]},{"name":"mdi:desk-lamp","tags":["home automation"]},{"name":"mdi:desk-lamp-off","tags":["home automation"]},{"name":"mdi:desk-lamp-on","tags":["home automation"]},{"name":"mdi:deskphone","tags":["cellphone / phone","device / tech"]},{"name":"mdi:desktop-classic","tags":["device / tech","home automation","computer classic"]},{"name":"mdi:desktop-tower","tags":["device / tech","home automation"]},{"name":"mdi:desktop-tower-monitor","tags":["device / tech"]},{"name":"mdi:dharmachakra","tags":["religion","dharma wheel","religion buddhist","buddhism"]},{"name":"mdi:diabetes","tags":["medical / hospital","hand blood"]},{"name":"mdi:diameter","tags":["math","circle diameter","sphere diameter"]},{"name":"mdi:diameter-outline","tags":["math","circle diameter outline","sphere diameter outline"]},{"name":"mdi:diameter-variant","tags":["math","circle diameter variant","sphere diameter variant"]},{"name":"mdi:diamond","tags":[]},{"name":"mdi:diamond-outline","tags":[]},{"name":"mdi:diamond-stone","tags":["jewel"]},{"name":"mdi:dice-1","tags":["gaming / rpg","die 1","dice one"]},{"name":"mdi:dice-1-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-2","tags":["gaming / rpg","die 2","dice two"]},{"name":"mdi:dice-2-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-3","tags":["gaming / rpg","die 3","dice three"]},{"name":"mdi:dice-3-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-4","tags":["gaming / rpg","die 4","dice four"]},{"name":"mdi:dice-4-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-5","tags":["gaming / rpg","die 5","dice five"]},{"name":"mdi:dice-5-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-6","tags":["gaming / rpg","die 6","dice six"]},{"name":"mdi:dice-6-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-d10","tags":["gaming / rpg"]},{"name":"mdi:dice-d10-outline","tags":["gaming / rpg","die d10"]},{"name":"mdi:dice-d12","tags":["gaming / rpg"]},{"name":"mdi:dice-d12-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-d20","tags":["gaming / rpg"]},{"name":"mdi:dice-d20-outline","tags":["gaming / rpg","die d20"]},{"name":"mdi:dice-d4","tags":["gaming / rpg"]},{"name":"mdi:dice-d4-outline","tags":["gaming / rpg","die d4"]},{"name":"mdi:dice-d6","tags":["gaming / rpg"]},{"name":"mdi:dice-d6-outline","tags":["gaming / rpg","die d6"]},{"name":"mdi:dice-d8","tags":["gaming / rpg"]},{"name":"mdi:dice-d8-outline","tags":["gaming / rpg","die d8"]},{"name":"mdi:dice-multiple","tags":["gaming / rpg","die multiple"]},{"name":"mdi:dice-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:dip-switch","tags":[]},{"name":"mdi:disc","tags":["music","cd rom","dvd"]},{"name":"mdi:disc-player","tags":["home automation","device / tech"]},{"name":"mdi:dishwasher-alert","tags":["home automation","alert / error"]},{"name":"mdi:dishwasher-off","tags":["home automation"]},{"name":"mdi:distribute-horizontal-center","tags":[]},{"name":"mdi:distribute-horizontal-left","tags":[]},{"name":"mdi:distribute-horizontal-right","tags":[]},{"name":"mdi:distribute-vertical-bottom","tags":[]},{"name":"mdi:distribute-vertical-center","tags":[]},{"name":"mdi:distribute-vertical-top","tags":[]},{"name":"mdi:diversify","tags":[]},{"name":"mdi:diving-flippers","tags":["sport"]},{"name":"mdi:diving-helmet","tags":[]},{"name":"mdi:diving-scuba-flag","tags":[]},{"name":"mdi:diving-scuba-mask","tags":["sport"]},{"name":"mdi:diving-scuba-tank","tags":[]},{"name":"mdi:diving-scuba-tank-multiple","tags":[]},{"name":"mdi:diving-snorkel","tags":["sport"]},{"name":"mdi:division","tags":["math","obelus"]},{"name":"mdi:division-box","tags":["math"]},{"name":"mdi:dna","tags":["science","helix"]},{"name":"mdi:dock-bottom","tags":[]},{"name":"mdi:dock-left","tags":[]},{"name":"mdi:dock-right","tags":[]},{"name":"mdi:dock-top","tags":[]},{"name":"mdi:dock-window","tags":[]},{"name":"mdi:doctor","tags":["medical / hospital"]},{"name":"mdi:dog","tags":["animal","emoji dog","emoticon dog"]},{"name":"mdi:dog-service","tags":["animal","guide dog","k9","canine"]},{"name":"mdi:dog-side","tags":["animal","k9","canine"]},{"name":"mdi:dog-side-off","tags":["animal"]},{"name":"mdi:dolly","tags":["hand truck","trolley"]},{"name":"mdi:dolphin","tags":["animal","porpoise"]},{"name":"mdi:domain-plus","tags":[]},{"name":"mdi:domain-remove","tags":[]},{"name":"mdi:domain-switch","tags":[]},{"name":"mdi:dome-light","tags":[]},{"name":"mdi:domino-mask","tags":["robber mask","zorro mask"]},{"name":"mdi:donkey","tags":["animal"]},{"name":"mdi:door","tags":["home automation"]},{"name":"mdi:door-closed","tags":["home automation"]},{"name":"mdi:door-closed-lock","tags":["home automation","lock"]},{"name":"mdi:door-open","tags":["home automation"]},{"name":"mdi:door-sliding-lock","tags":["home automation","lock","patio door lock","french door lock"]},{"name":"mdi:door-sliding-open","tags":["home automation","patio door open","french door open"]},{"name":"mdi:doorbell","tags":["home automation"]},{"name":"mdi:doorbell-video","tags":["home automation"]},{"name":"mdi:dots-circle","tags":["perimeter"]},{"name":"mdi:dots-grid","tags":[]},{"name":"mdi:dots-hexagon","tags":[]},{"name":"mdi:dots-horizontal-circle-outline","tags":["ellipsis horizontal circle outline","more circle outline","menu"]},{"name":"mdi:dots-square","tags":["perimeter"]},{"name":"mdi:dots-triangle","tags":[]},{"name":"mdi:dots-vertical-circle","tags":["ellipsis vertical circle","menu"]},{"name":"mdi:dots-vertical-circle-outline","tags":["ellipsis vertical circle outline","menu"]},{"name":"mdi:download-box","tags":[]},{"name":"mdi:download-box-outline","tags":[]},{"name":"mdi:download-circle","tags":[]},{"name":"mdi:download-circle-outline","tags":[]},{"name":"mdi:download-lock","tags":["lock"]},{"name":"mdi:download-lock-outline","tags":["lock"]},{"name":"mdi:download-multiple","tags":["downloads"]},{"name":"mdi:download-network","tags":[]},{"name":"mdi:download-network-outline","tags":[]},{"name":"mdi:download-off","tags":[]},{"name":"mdi:download-off-outline","tags":[]},{"name":"mdi:drag","tags":[]},{"name":"mdi:drag-horizontal","tags":[]},{"name":"mdi:drag-variant","tags":[]},{"name":"mdi:drag-vertical","tags":[]},{"name":"mdi:drag-vertical-variant","tags":[]},{"name":"mdi:drama-masks","tags":["comedy","tragedy","theatre"]},{"name":"mdi:draw","tags":["drawing / art","form","sign","signature"]},{"name":"mdi:draw-pen","tags":["form","drawing / art","sign","signature"]},{"name":"mdi:drawing","tags":["drawing / art","shape"]},{"name":"mdi:dresser","tags":["home automation"]},{"name":"mdi:dresser-outline","tags":["home automation"]},{"name":"mdi:drone","tags":["transportation + flying"]},{"name":"mdi:duck","tags":["animal"]},{"name":"mdi:dump-truck","tags":["transportation + road","hardware / tools","tipper lorry"]},{"name":"mdi:ear-hearing-loop","tags":["medical / hospital","audio induction loop","telecoil"]},{"name":"mdi:ear-hearing-off","tags":["medical / hospital","hearing impaired"]},{"name":"mdi:earbuds","tags":["audio","music","headphones"]},{"name":"mdi:earbuds-off","tags":["audio","music","headphones off"]},{"name":"mdi:earbuds-off-outline","tags":["audio","music","headphones off outline"]},{"name":"mdi:earbuds-outline","tags":["audio","music","headphones outline"]},{"name":"mdi:earth-arrow-right","tags":["navigation","globe arrow right","world arrow right","planet arrow right"]},{"name":"mdi:earth-box","tags":["navigation","globe box","world box","planet box"]},{"name":"mdi:earth-box-minus","tags":["navigation","globe box minus","world box minus","planet box minus"]},{"name":"mdi:earth-box-off","tags":["navigation","globe box off","world box off","planet box off"]},{"name":"mdi:earth-box-plus","tags":["navigation","globe box plus","world box plus","planet box plus"]},{"name":"mdi:earth-box-remove","tags":["navigation","globe box remove","world box remove","planet box remove"]},{"name":"mdi:earth-minus","tags":["navigation","globe minus","world minus","planet minus"]},{"name":"mdi:earth-off","tags":["geographic information system","navigation","globe off","world off","planet off"]},{"name":"mdi:earth-plus","tags":["navigation","globe plus","world plus","planet plus"]},{"name":"mdi:earth-remove","tags":["navigation","globe remove","world remove","planet remove"]},{"name":"mdi:egg","tags":["food / drink","agriculture"]},{"name":"mdi:egg-easter","tags":["holiday"]},{"name":"mdi:egg-fried","tags":["food / drink"]},{"name":"mdi:egg-off","tags":["food / drink","agriculture"]},{"name":"mdi:egg-off-outline","tags":["food / drink","agriculture"]},{"name":"mdi:egg-outline","tags":["food / drink","agriculture"]},{"name":"mdi:eiffel-tower","tags":["places","paris","france"]},{"name":"mdi:eight-track","tags":["music","8 track"]},{"name":"mdi:eject-circle","tags":[]},{"name":"mdi:eject-circle-outline","tags":[]},{"name":"mdi:electric-switch","tags":[]},{"name":"mdi:electric-switch-closed","tags":[]},{"name":"mdi:elephant","tags":["animal"]},{"name":"mdi:elevation-decline","tags":[]},{"name":"mdi:elevation-rise","tags":[]},{"name":"mdi:elevator","tags":["transportation + other"]},{"name":"mdi:elevator-down","tags":["transportation + other"]},{"name":"mdi:elevator-passenger-off","tags":["transportation + other"]},{"name":"mdi:elevator-passenger-off-outline","tags":["transportation + other"]},{"name":"mdi:elevator-up","tags":["transportation + other"]},{"name":"mdi:ellipse","tags":["shape"]},{"name":"mdi:ellipse-outline","tags":["shape"]},{"name":"mdi:email-alert","tags":["alert / error","email warning","envelope alert","envelope warning"]},{"name":"mdi:email-alert-outline","tags":["alert / error"]},{"name":"mdi:email-arrow-left","tags":["email receive"]},{"name":"mdi:email-arrow-left-outline","tags":["email receive outline"]},{"name":"mdi:email-arrow-right","tags":["email send"]},{"name":"mdi:email-arrow-right-outline","tags":["email arrow right outline"]},{"name":"mdi:email-box","tags":["envelope box"]},{"name":"mdi:email-check","tags":["email tick"]},{"name":"mdi:email-check-outline","tags":["email tick outline"]},{"name":"mdi:email-edit","tags":["edit / modify"]},{"name":"mdi:email-edit-outline","tags":["edit / modify"]},{"name":"mdi:email-fast","tags":["envelope fast","email quick","email sent","email send"]},{"name":"mdi:email-fast-outline","tags":["email send outline","email sent outline","envelope fast outline","email quick outline"]},{"name":"mdi:email-heart-outline","tags":["love letter","envelope heart outline","greeting card"]},{"name":"mdi:email-lock","tags":["lock","envelope secure","email secure","envelope lock"]},{"name":"mdi:email-lock-outline","tags":["lock","email secure outline"]},{"name":"mdi:email-minus","tags":[]},{"name":"mdi:email-minus-outline","tags":[]},{"name":"mdi:email-multiple","tags":[]},{"name":"mdi:email-multiple-outline","tags":[]},{"name":"mdi:email-newsletter","tags":[]},{"name":"mdi:email-off","tags":[]},{"name":"mdi:email-off-outline","tags":[]},{"name":"mdi:email-open","tags":["drafts","envelope open"]},{"name":"mdi:email-open-heart-outline","tags":["love letter open","greeting card open","envelope open heart outline"]},{"name":"mdi:email-open-multiple","tags":[]},{"name":"mdi:email-open-multiple-outline","tags":[]},{"name":"mdi:email-open-outline","tags":["envelope open outline"]},{"name":"mdi:email-plus","tags":["email add","envelope add","envelope plus"]},{"name":"mdi:email-plus-outline","tags":["email add outline","envelope add outline","envelope plus outline"]},{"name":"mdi:email-remove","tags":[]},{"name":"mdi:email-remove-outline","tags":[]},{"name":"mdi:email-seal","tags":["email certified","mail certified","mail seal","email verified","mail verified"]},{"name":"mdi:email-seal-outline","tags":["email verified outline","email certified outline","mail verified outline","mail certified outline","mail seal outline"]},{"name":"mdi:email-search","tags":[]},{"name":"mdi:email-search-outline","tags":[]},{"name":"mdi:email-sync","tags":["email refresh","email resend"]},{"name":"mdi:email-sync-outline","tags":["email refresh outline","email resend outline"]},{"name":"mdi:email-variant","tags":["envelope variant"]},{"name":"mdi:emoticon-angry","tags":["emoji","smiley angry","face angry","emoji angry"]},{"name":"mdi:emoticon-angry-outline","tags":["emoji","smiley angry outline","face angry outline","emoji angry outline"]},{"name":"mdi:emoticon-confused","tags":["emoji","face confused","emoji confused"]},{"name":"mdi:emoticon-confused-outline","tags":["emoji","face confused outline","emoji confused outline"]},{"name":"mdi:emoticon-cool","tags":["emoji","smiley cool","face cool","face sunglasses","emoji cool"]},{"name":"mdi:emoticon-cool-outline","tags":["emoji","smiley cool outline","face cool outline","face sunglasses outline","emoji cool outline"]},{"name":"mdi:emoticon-cry","tags":["emoji","smiley cry","face cry","emoji cry"]},{"name":"mdi:emoticon-cry-outline","tags":["emoji","smiley cry outline","face cry outline","emoji cry outline"]},{"name":"mdi:emoticon-devil","tags":["emoji","smiley devil","face devil","emoji devil"]},{"name":"mdi:emoticon-devil-outline","tags":["emoji","smiley devil outline","face devil outline","emoji devil outline"]},{"name":"mdi:emoticon-frown","tags":["emoji","face frown","emoji frown"]},{"name":"mdi:emoticon-happy","tags":["emoji","smiley happy","face happy","emoji happy"]},{"name":"mdi:emoticon-happy-outline","tags":["emoji","smiley happy outline","face happy outline","emoji happy outline"]},{"name":"mdi:emoticon-kiss","tags":["emoji","smiley kiss","face kiss","emoji kiss"]},{"name":"mdi:emoticon-kiss-outline","tags":["emoji","smiley kiss outline","face kiss outline","emoji kiss outline"]},{"name":"mdi:emoticon-lol","tags":["emoji","face lol","emoji lol"]},{"name":"mdi:emoticon-lol-outline","tags":["emoji","face lol outline","emoji lol outline"]},{"name":"mdi:emoticon-neutral","tags":["emoji","smiley neutral","face neutral","emoji neutral"]},{"name":"mdi:emoticon-neutral-outline","tags":["emoji","smiley neutral outline","face neutral outline","emoji neutral outline"]},{"name":"mdi:emoticon-poop","tags":["emoji","smiley poop","face poop","emoji poop"]},{"name":"mdi:emoticon-poop-outline","tags":["emoji","face poop outline","emoji poop outline"]},{"name":"mdi:emoticon-sad","tags":["emoji","smiley sad","face sad","emoji sad"]},{"name":"mdi:emoticon-sad-outline","tags":["emoji","smiley sad outline","face sad outline","emoji sad outline"]},{"name":"mdi:emoticon-tongue","tags":["emoji","smiley tongue","face tongue","emoji tongue"]},{"name":"mdi:emoticon-tongue-outline","tags":["emoji","smiley tongue outline","face tongue outline","emoji tongue outline"]},{"name":"mdi:emoticon-wink","tags":["emoji","smiley wink","face wink","emoji wink"]},{"name":"mdi:emoticon-wink-outline","tags":["emoji","smiley wink outline","face wink outline","emoji wink outline"]},{"name":"mdi:engine","tags":["automotive","motor"]},{"name":"mdi:engine-off","tags":["automotive","motor off"]},{"name":"mdi:engine-off-outline","tags":["automotive","motor off outline"]},{"name":"mdi:engine-outline","tags":["automotive","motor outline"]},{"name":"mdi:epsilon","tags":["alpha / numeric"]},{"name":"mdi:equal","tags":["math"]},{"name":"mdi:equal-box","tags":["math"]},{"name":"mdi:equalizer-outline","tags":["audio"]},{"name":"mdi:eraser","tags":[]},{"name":"mdi:escalator","tags":["transportation + other"]},{"name":"mdi:escalator-box","tags":[]},{"name":"mdi:escalator-down","tags":["transportation + other"]},{"name":"mdi:escalator-up","tags":["transportation + other"]},{"name":"mdi:et","tags":[]},{"name":"mdi:ethernet","tags":[]},{"name":"mdi:ethernet-cable","tags":[]},{"name":"mdi:ethernet-cable-off","tags":[]},{"name":"mdi:ev-plug-ccs1","tags":["automotive","ev plug ccs combo 1","ev charger ccs1"]},{"name":"mdi:ev-plug-ccs2","tags":["automotive","ev plug ccs combo 2","ev charger ccs2"]},{"name":"mdi:ev-plug-chademo","tags":["automotive","ev charger chademo"]},{"name":"mdi:ev-plug-tesla","tags":["automotive","ev charger tesla"]},{"name":"mdi:ev-plug-type1","tags":["automotive","ev plug j1772","ev charger type1"]},{"name":"mdi:ev-plug-type2","tags":["automotive","ev plug mennekes","ev charger type2"]},{"name":"mdi:excavator","tags":["hardware / tools"]},{"name":"mdi:exclamation","tags":["math","factorial"]},{"name":"mdi:exclamation-thick","tags":["exclamation bold"]},{"name":"mdi:exit-run","tags":["home automation","emergency exit"]},{"name":"mdi:expand-all","tags":["animation plus"]},{"name":"mdi:expand-all-outline","tags":["animation plus outline"]},{"name":"mdi:expansion-card","tags":["gaming / rpg","gpu","graphics processing unit","nic","network interface card"]},{"name":"mdi:expansion-card-variant","tags":["graphics processing unit","gpu","network interface card","nice"]},{"name":"mdi:exponent","tags":["math","power"]},{"name":"mdi:exponent-box","tags":["math","power box"]},{"name":"mdi:export","tags":["output"]},{"name":"mdi:eye-arrow-left","tags":["view arrow left"]},{"name":"mdi:eye-arrow-left-outline","tags":["view arrow left outline"]},{"name":"mdi:eye-arrow-right","tags":["view arrow right"]},{"name":"mdi:eye-arrow-right-outline","tags":["view arrow right outline"]},{"name":"mdi:eye-check","tags":["eye tick"]},{"name":"mdi:eye-check-outline","tags":["eye tick outline"]},{"name":"mdi:eye-circle","tags":[]},{"name":"mdi:eye-circle-outline","tags":[]},{"name":"mdi:eye-lock","tags":[]},{"name":"mdi:eye-lock-open","tags":[]},{"name":"mdi:eye-lock-open-outline","tags":[]},{"name":"mdi:eye-lock-outline","tags":[]},{"name":"mdi:eye-minus","tags":[]},{"name":"mdi:eye-minus-outline","tags":[]},{"name":"mdi:eye-off-outline","tags":["hide outline","visibility off outline"]},{"name":"mdi:eye-outline","tags":["show outline","visibility outline"]},{"name":"mdi:eye-plus","tags":["eye add"]},{"name":"mdi:eye-plus-outline","tags":["eye add outline"]},{"name":"mdi:eye-refresh","tags":["view refresh"]},{"name":"mdi:eye-refresh-outline","tags":["view refresh outline"]},{"name":"mdi:eye-remove","tags":[]},{"name":"mdi:eye-remove-outline","tags":[]},{"name":"mdi:eye-settings","tags":["settings"]},{"name":"mdi:eye-settings-outline","tags":["settings"]},{"name":"mdi:eyedropper","tags":["color","drawing / art","science","pipette"]},{"name":"mdi:eyedropper-minus","tags":["science"]},{"name":"mdi:eyedropper-off","tags":["science"]},{"name":"mdi:eyedropper-plus","tags":["science"]},{"name":"mdi:eyedropper-remove","tags":["science"]},{"name":"mdi:face-agent","tags":["customer service","support","emoji agent","emoticon agent"]},{"name":"mdi:face-man-shimmer-outline","tags":["people / family","photography","health / beauty","account / user","face retouching natural outline","face male shimmer outline","emoji man shimmer outline","emoticon man shimmer outline"]},{"name":"mdi:face-mask","tags":["medical / hospital","clothing"]},{"name":"mdi:face-mask-outline","tags":["medical / hospital","clothing"]},{"name":"mdi:face-recognition","tags":["photography","facial recognition","scan"]},{"name":"mdi:face-woman","tags":["people / family","face female","emoji woman","emoticon woman"]},{"name":"mdi:face-woman-outline","tags":["people / family","face female outline","emoji woman outline","emoticon woman outline"]},{"name":"mdi:face-woman-profile","tags":["people / family","face female profile","emoji woman profile","emoticon woman profile"]},{"name":"mdi:face-woman-shimmer","tags":["people / family","photography","health / beauty","account / user","face retouching natural woman","face female shimmer","emoji woman shimmer","emoticon woman shimmer"]},{"name":"mdi:face-woman-shimmer-outline","tags":["people / family","photography","health / beauty","account / user","face retouching natural woman outline","face female shimmer outline","emoji woman shimmer outline","emoticon woman shimmer outline"]},{"name":"mdi:factory","tags":["places","industrial"]},{"name":"mdi:family-tree","tags":["people / family"]},{"name":"mdi:fan","tags":["home automation","automotive"]},{"name":"mdi:fan-alert","tags":["home automation","alert / error"]},{"name":"mdi:fan-auto","tags":[]},{"name":"mdi:fan-chevron-down","tags":["home automation","fan speed down"]},{"name":"mdi:fan-chevron-up","tags":["home automation","fan speed up"]},{"name":"mdi:fan-clock","tags":["home automation","date / time","fan clock","fan schedule","fan timer"]},{"name":"mdi:fan-minus","tags":["home automation"]},{"name":"mdi:fan-off","tags":["home automation","automotive"]},{"name":"mdi:fan-plus","tags":["home automation"]},{"name":"mdi:fan-remove","tags":["home automation"]},{"name":"mdi:fan-speed-1","tags":["home automation","fan speed low"]},{"name":"mdi:fan-speed-2","tags":["home automation","fan speed medium"]},{"name":"mdi:fan-speed-3","tags":["home automation","fan speed high"]},{"name":"mdi:fast-forward-10","tags":[]},{"name":"mdi:fast-forward-15","tags":[]},{"name":"mdi:fast-forward-30","tags":[]},{"name":"mdi:fast-forward-45","tags":[]},{"name":"mdi:fast-forward-5","tags":[]},{"name":"mdi:fast-forward-60","tags":[]},{"name":"mdi:faucet","tags":["home automation","kitchen tap","bathroom tap","sink"]},{"name":"mdi:faucet-variant","tags":["home automation","bathroom tap","kitchen tap","sink"]},{"name":"mdi:feather","tags":["nature","quill"]},{"name":"mdi:feature-search","tags":["box","box search"]},{"name":"mdi:feature-search-outline","tags":["box","box outline","box search outline"]},{"name":"mdi:fence","tags":["home automation","agriculture","railway","train track"]},{"name":"mdi:fence-electric","tags":["home automation","agriculture","railway electric","train track electric"]},{"name":"mdi:file-account","tags":["account / user","files / folders","file user","resume"]},{"name":"mdi:file-account-outline","tags":["files / folders","account / user"]},{"name":"mdi:file-alert","tags":["files / folders","alert / error","file warning"]},{"name":"mdi:file-alert-outline","tags":["files / folders","alert / error","file warning outline"]},{"name":"mdi:file-arrow-left-right","tags":["files / folders","file exchange","file transfer","file swap"]},{"name":"mdi:file-arrow-left-right-outline","tags":["files / folders","file exchange outline","file swap outline","file transfer outline"]},{"name":"mdi:file-arrow-up-down","tags":["files / folders","file exchange","file swap","file transfer","file upload download"]},{"name":"mdi:file-arrow-up-down-outline","tags":["files / folders","file exchange outline","file swap outline","file transfer outline","file upload download outline"]},{"name":"mdi:file-cabinet","tags":["files / folders","filing cabinet"]},{"name":"mdi:file-cad","tags":["files / folders"]},{"name":"mdi:file-cad-box","tags":["files / folders"]},{"name":"mdi:file-cancel","tags":["files / folders","ban","forbid"]},{"name":"mdi:file-cancel-outline","tags":["files / folders","ban","forbid"]},{"name":"mdi:file-certificate","tags":["files / folders"]},{"name":"mdi:file-certificate-outline","tags":["files / folders"]},{"name":"mdi:file-chart","tags":["files / folders","file report","file graph"]},{"name":"mdi:file-chart-check","tags":["files / folders"]},{"name":"mdi:file-chart-check-outline","tags":["files / folders"]},{"name":"mdi:file-chart-outline","tags":["files / folders","file graph outline","file report outline"]},{"name":"mdi:file-check","tags":["files / folders","file tick"]},{"name":"mdi:file-check-outline","tags":["files / folders"]},{"name":"mdi:file-clock","tags":["files / folders","date / time"]},{"name":"mdi:file-clock-outline","tags":["files / folders","date / time"]},{"name":"mdi:file-cloud","tags":["cloud","files / folders"]},{"name":"mdi:file-cloud-outline","tags":["files / folders","cloud"]},{"name":"mdi:file-code","tags":["files / folders","developer / languages"]},{"name":"mdi:file-code-outline","tags":["files / folders","developer / languages"]},{"name":"mdi:file-cog","tags":["settings","files / folders","file settings cog"]},{"name":"mdi:file-cog-outline","tags":["settings","files / folders","file settings cog outline"]},{"name":"mdi:file-compare","tags":["files / folders"]},{"name":"mdi:file-delimited","tags":["files / folders","file csv"]},{"name":"mdi:file-delimited-outline","tags":["files / folders","file csv outline"]},{"name":"mdi:file-document","tags":["files / folders","file text"]},{"name":"mdi:file-document-alert","tags":["files / folders","alert / error","file document error","file text alert","file text error"]},{"name":"mdi:file-document-alert-outline","tags":["files / folders","alert / error","file document error outline","file text error outline","file text alert outline"]},{"name":"mdi:file-document-arrow-right","tags":["files / folders","file document move","file text move","file text arrow right"]},{"name":"mdi:file-document-arrow-right-outline","tags":["files / folders","file document move outline","file text move outline","file text arrow right outline"]},{"name":"mdi:file-document-check","tags":["files / folders","file document tick","file text tick","file text check"]},{"name":"mdi:file-document-check-outline","tags":["files / folders","file document tick outline","file text tick outline","file text check outline"]},{"name":"mdi:file-document-edit","tags":["edit / modify","files / folders","contract","file text edit"]},{"name":"mdi:file-document-edit-outline","tags":["edit / modify","files / folders","contract outline","file text edit outline"]},{"name":"mdi:file-document-minus","tags":["files / folders","file text minus"]},{"name":"mdi:file-document-minus-outline","tags":["files / folders","file text minus outline"]},{"name":"mdi:file-document-multiple","tags":["files / folders","file text multiple"]},{"name":"mdi:file-document-multiple-outline","tags":["files / folders","file text multiple outline"]},{"name":"mdi:file-document-plus","tags":["files / folders","file document add","file text add","file text plus"]},{"name":"mdi:file-document-plus-outline","tags":["files / folders","file document add outline","file text plus outline","file text add outline"]},{"name":"mdi:file-document-refresh","tags":["files / folders"]},{"name":"mdi:file-document-refresh-outline","tags":["files / folders"]},{"name":"mdi:file-document-remove","tags":["files / folders","file document delete","file text remove","file text delete"]},{"name":"mdi:file-document-remove-outline","tags":["files / folders","file document delete outline","file text remove outline","file text delete outline"]},{"name":"mdi:file-download","tags":["files / folders"]},{"name":"mdi:file-download-outline","tags":["files / folders"]},{"name":"mdi:file-edit","tags":["edit / modify","files / folders"]},{"name":"mdi:file-edit-outline","tags":["edit / modify","files / folders"]},{"name":"mdi:file-excel","tags":["files / folders"]},{"name":"mdi:file-excel-box-outline","tags":["files / folders"]},{"name":"mdi:file-excel-outline","tags":["files / folders"]},{"name":"mdi:file-export","tags":["files / folders"]},{"name":"mdi:file-export-outline","tags":["files / folders"]},{"name":"mdi:file-eye","tags":["files / folders"]},{"name":"mdi:file-eye-outline","tags":["files / folders"]},{"name":"mdi:file-gif-box","tags":["files / folders"]},{"name":"mdi:file-hidden","tags":["files / folders"]},{"name":"mdi:file-image","tags":["files / folders"]},{"name":"mdi:file-image-marker","tags":["files / folders","navigation","file image location"]},{"name":"mdi:file-image-marker-outline","tags":["files / folders","navigation","file image location outline"]},{"name":"mdi:file-image-minus","tags":["files / folders"]},{"name":"mdi:file-image-minus-outline","tags":["files / folders"]},{"name":"mdi:file-image-outline","tags":["files / folders"]},{"name":"mdi:file-image-plus","tags":["files / folders","file image add"]},{"name":"mdi:file-image-plus-outline","tags":["files / folders","file image add outline"]},{"name":"mdi:file-image-remove","tags":["files / folders"]},{"name":"mdi:file-image-remove-outline","tags":["files / folders"]},{"name":"mdi:file-import","tags":["files / folders"]},{"name":"mdi:file-import-outline","tags":["files / folders"]},{"name":"mdi:file-jpg-box","tags":["files / folders","file jpeg box","image jpg box","image jpeg box"]},{"name":"mdi:file-key","tags":["files / folders"]},{"name":"mdi:file-key-outline","tags":["files / folders"]},{"name":"mdi:file-link","tags":["files / folders"]},{"name":"mdi:file-link-outline","tags":["files / folders"]},{"name":"mdi:file-lock","tags":["lock","files / folders"]},{"name":"mdi:file-lock-open","tags":["lock","files / folders"]},{"name":"mdi:file-lock-open-outline","tags":["lock","files / folders"]},{"name":"mdi:file-lock-outline","tags":["files / folders","lock"]},{"name":"mdi:file-marker","tags":["files / folders","navigation","file location"]},{"name":"mdi:file-marker-outline","tags":["files / folders","navigation","file location outline"]},{"name":"mdi:file-minus","tags":["files / folders"]},{"name":"mdi:file-minus-outline","tags":["files / folders"]},{"name":"mdi:file-move","tags":["files / folders"]},{"name":"mdi:file-move-outline","tags":["files / folders"]},{"name":"mdi:file-multiple","tags":["files / folders","files"]},{"name":"mdi:file-multiple-outline","tags":["files / folders"]},{"name":"mdi:file-music","tags":["files / folders","music"]},{"name":"mdi:file-music-outline","tags":["files / folders","music"]},{"name":"mdi:file-pdf-box","tags":["files / folders","file acrobat box","adobe acrobat"]},{"name":"mdi:file-percent","tags":["files / folders"]},{"name":"mdi:file-percent-outline","tags":["files / folders"]},{"name":"mdi:file-phone","tags":["files / folders","cellphone / phone"]},{"name":"mdi:file-phone-outline","tags":["files / folders","cellphone / phone"]},{"name":"mdi:file-plus","tags":["files / folders","note add"]},{"name":"mdi:file-plus-outline","tags":["files / folders"]},{"name":"mdi:file-png-box","tags":["files / folders"]},{"name":"mdi:file-powerpoint","tags":["files / folders"]},{"name":"mdi:file-powerpoint-box-outline","tags":["files / folders"]},{"name":"mdi:file-powerpoint-outline","tags":["files / folders"]},{"name":"mdi:file-question","tags":["files / folders"]},{"name":"mdi:file-question-outline","tags":["files / folders"]},{"name":"mdi:file-refresh","tags":["files / folders"]},{"name":"mdi:file-refresh-outline","tags":["files / folders"]},{"name":"mdi:file-remove","tags":["files / folders"]},{"name":"mdi:file-remove-outline","tags":["files / folders"]},{"name":"mdi:file-replace","tags":["files / folders"]},{"name":"mdi:file-replace-outline","tags":["files / folders"]},{"name":"mdi:file-restore-outline","tags":["files / folders"]},{"name":"mdi:file-rotate-left","tags":["files / folders","file rotate counter clockwise","file rotate ccw"]},{"name":"mdi:file-rotate-left-outline","tags":["files / folders","file rotate counter clockwise outline","file rotate ccw outline"]},{"name":"mdi:file-rotate-right","tags":["files / folders","file rotate clockwise"]},{"name":"mdi:file-rotate-right-outline","tags":["files / folders","file rotate clockwise"]},{"name":"mdi:file-search","tags":["files / folders"]},{"name":"mdi:file-search-outline","tags":["files / folders"]},{"name":"mdi:file-send","tags":["files / folders","file move"]},{"name":"mdi:file-send-outline","tags":["files / folders"]},{"name":"mdi:file-settings","tags":["settings","files / folders"]},{"name":"mdi:file-settings-outline","tags":["settings","files / folders"]},{"name":"mdi:file-sign","tags":["banking","files / folders","contract sign","document sign"]},{"name":"mdi:file-star","tags":["files / folders","file favorite"]},{"name":"mdi:file-star-four-points","tags":["files / folders","file auto"]},{"name":"mdi:file-star-four-points-outline","tags":["files / folders","file auto outline"]},{"name":"mdi:file-star-outline","tags":["files / folders","file favorite outline"]},{"name":"mdi:file-swap","tags":["files / folders","file transfer"]},{"name":"mdi:file-swap-outline","tags":["files / folders","file transfer outline"]},{"name":"mdi:file-sync","tags":["files / folders"]},{"name":"mdi:file-sync-outline","tags":["files / folders"]},{"name":"mdi:file-table","tags":["files / folders"]},{"name":"mdi:file-table-box","tags":["files / folders"]},{"name":"mdi:file-table-box-multiple","tags":["files / folders"]},{"name":"mdi:file-table-box-multiple-outline","tags":["files / folders"]},{"name":"mdi:file-table-box-outline","tags":["files / folders"]},{"name":"mdi:file-table-outline","tags":["files / folders"]},{"name":"mdi:file-tree","tags":["files / folders","subtasks"]},{"name":"mdi:file-tree-outline","tags":["files / folders"]},{"name":"mdi:file-undo","tags":["files / folders","file revert","file discard"]},{"name":"mdi:file-undo-outline","tags":["files / folders"]},{"name":"mdi:file-upload","tags":["files / folders"]},{"name":"mdi:file-upload-outline","tags":["files / folders"]},{"name":"mdi:file-video","tags":["video / movie","files / folders"]},{"name":"mdi:file-video-outline","tags":["files / folders"]},{"name":"mdi:file-word","tags":["files / folders"]},{"name":"mdi:file-word-box-outline","tags":["files / folders"]},{"name":"mdi:file-word-outline","tags":["files / folders"]},{"name":"mdi:file-xml-box","tags":["files / folders"]},{"name":"mdi:filmstrip-box","tags":[]},{"name":"mdi:filmstrip-off","tags":["video / movie"]},{"name":"mdi:filter","tags":["funnel"]},{"name":"mdi:filter-check","tags":["funnel check"]},{"name":"mdi:filter-check-outline","tags":["funnel check outline"]},{"name":"mdi:filter-cog","tags":["settings","funnel settings","filter settings","funnel cog","filter gear","funnel gear"]},{"name":"mdi:filter-cog-outline","tags":["settings","filter settings outline","filter gear outline","funnel cog outline","funnel settings outline","funnel gear outline"]},{"name":"mdi:filter-menu","tags":[]},{"name":"mdi:filter-menu-outline","tags":[]},{"name":"mdi:filter-minus","tags":["funnel minus"]},{"name":"mdi:filter-minus-outline","tags":["funnel minus outline"]},{"name":"mdi:filter-multiple","tags":["funnel multiple"]},{"name":"mdi:filter-multiple-outline","tags":["funnel multiple outline"]},{"name":"mdi:filter-off","tags":[]},{"name":"mdi:filter-off-outline","tags":[]},{"name":"mdi:filter-outline","tags":["funnel outline"]},{"name":"mdi:filter-plus","tags":["funnel plus"]},{"name":"mdi:filter-plus-outline","tags":["funnel plus outline"]},{"name":"mdi:filter-remove","tags":["funnel remove"]},{"name":"mdi:filter-remove-outline","tags":["funnel remove outline"]},{"name":"mdi:filter-settings","tags":["settings","funnel settings"]},{"name":"mdi:filter-settings-outline","tags":["settings","funnel settings outline"]},{"name":"mdi:filter-variant-minus","tags":[]},{"name":"mdi:filter-variant-plus","tags":[]},{"name":"mdi:filter-variant-remove","tags":[]},{"name":"mdi:fingerprint-off","tags":[]},{"name":"mdi:fire-alert","tags":["alert / error","home automation","flame alert"]},{"name":"mdi:fire-circle","tags":["home automation","flame circle","hot circle","gas circle","natural gas circle"]},{"name":"mdi:fire-extinguisher","tags":["hardware / tools","home automation"]},{"name":"mdi:fire-hydrant","tags":[]},{"name":"mdi:fire-hydrant-alert","tags":["alert / error"]},{"name":"mdi:fire-hydrant-off","tags":[]},{"name":"mdi:fire-off","tags":["home automation","flame off"]},{"name":"mdi:fire-truck","tags":["transportation + road","fire engine"]},{"name":"mdi:fireplace","tags":["home automation"]},{"name":"mdi:fireplace-off","tags":["home automation"]},{"name":"mdi:firewire","tags":[]},{"name":"mdi:firework","tags":["holiday","bottle rocket"]},{"name":"mdi:firework-off","tags":[]},{"name":"mdi:fish","tags":["animal","food / drink"]},{"name":"mdi:fish-off","tags":["food / drink"]},{"name":"mdi:fishbowl","tags":["animal","aquarium"]},{"name":"mdi:fishbowl-outline","tags":["animal","aquarium outline"]},{"name":"mdi:fit-to-page","tags":["text / content / format","arrow"]},{"name":"mdi:fit-to-page-outline","tags":["text / content / format","arrow"]},{"name":"mdi:flag-checkered","tags":["sport","goal"]},{"name":"mdi:flag-minus","tags":[]},{"name":"mdi:flag-minus-outline","tags":[]},{"name":"mdi:flag-off","tags":[]},{"name":"mdi:flag-off-outline","tags":[]},{"name":"mdi:flag-plus","tags":["flag add"]},{"name":"mdi:flag-plus-outline","tags":[]},{"name":"mdi:flag-remove","tags":[]},{"name":"mdi:flag-remove-outline","tags":[]},{"name":"mdi:flag-triangle","tags":["milestone"]},{"name":"mdi:flag-variant","tags":[]},{"name":"mdi:flag-variant-minus","tags":[]},{"name":"mdi:flag-variant-minus-outline","tags":[]},{"name":"mdi:flag-variant-off","tags":[]},{"name":"mdi:flag-variant-off-outline","tags":[]},{"name":"mdi:flag-variant-outline","tags":[]},{"name":"mdi:flag-variant-plus","tags":[]},{"name":"mdi:flag-variant-plus-outline","tags":[]},{"name":"mdi:flag-variant-remove","tags":[]},{"name":"mdi:flag-variant-remove-outline","tags":[]},{"name":"mdi:flash-alert","tags":["weather","alert / error","lightning alert","storm advisory"]},{"name":"mdi:flash-alert-outline","tags":["weather","alert / error","lightning alert outline","storm advisory outline"]},{"name":"mdi:flash-off-outline","tags":[]},{"name":"mdi:flash-outline","tags":["weather","lightning bolt outline"]},{"name":"mdi:flash-red-eye","tags":[]},{"name":"mdi:flash-triangle","tags":["home automation","high voltage"]},{"name":"mdi:flash-triangle-outline","tags":["home automation","high voltage outline"]},{"name":"mdi:flashlight","tags":["torch"]},{"name":"mdi:flashlight-off","tags":["torch off"]},{"name":"mdi:flask","tags":["science","gaming / rpg"]},{"name":"mdi:flask-empty","tags":["science","gaming / rpg"]},{"name":"mdi:flask-empty-minus","tags":["science"]},{"name":"mdi:flask-empty-minus-outline","tags":["science"]},{"name":"mdi:flask-empty-off","tags":[]},{"name":"mdi:flask-empty-off-outline","tags":[]},{"name":"mdi:flask-empty-outline","tags":["science","gaming / rpg"]},{"name":"mdi:flask-empty-plus","tags":["science"]},{"name":"mdi:flask-empty-plus-outline","tags":["science"]},{"name":"mdi:flask-empty-remove","tags":["science"]},{"name":"mdi:flask-empty-remove-outline","tags":["science"]},{"name":"mdi:flask-minus","tags":["science"]},{"name":"mdi:flask-minus-outline","tags":["science"]},{"name":"mdi:flask-off","tags":[]},{"name":"mdi:flask-off-outline","tags":[]},{"name":"mdi:flask-outline","tags":["science","gaming / rpg"]},{"name":"mdi:flask-plus","tags":["science"]},{"name":"mdi:flask-plus-outline","tags":["science"]},{"name":"mdi:flask-remove","tags":["science"]},{"name":"mdi:flask-remove-outline","tags":["science"]},{"name":"mdi:flask-round-bottom","tags":["science"]},{"name":"mdi:flask-round-bottom-empty","tags":["science"]},{"name":"mdi:flask-round-bottom-empty-outline","tags":["science"]},{"name":"mdi:flask-round-bottom-outline","tags":["science"]},{"name":"mdi:fleur-de-lis","tags":[]},{"name":"mdi:floor-lamp","tags":["home automation","floor light"]},{"name":"mdi:floor-lamp-dual","tags":["home automation","floor light dual"]},{"name":"mdi:floor-lamp-dual-outline","tags":["home automation","floor light dual outline"]},{"name":"mdi:floor-lamp-outline","tags":["home automation","floor light outline"]},{"name":"mdi:floor-lamp-torchiere","tags":["home automation","floor light torchiere"]},{"name":"mdi:floor-lamp-torchiere-outline","tags":["home automation"]},{"name":"mdi:floor-lamp-torchiere-variant","tags":["home automation","floor light torchiere variant"]},{"name":"mdi:floor-lamp-torchiere-variant-outline","tags":["home automation","floor light torchiere variant outline"]},{"name":"mdi:floor-plan","tags":["home automation"]},{"name":"mdi:floppy","tags":[]},{"name":"mdi:floppy-variant","tags":[]},{"name":"mdi:flower-pollen","tags":["nature","agriculture","allergy"]},{"name":"mdi:flower-pollen-outline","tags":["nature","agriculture","allergy outline"]},{"name":"mdi:flower-poppy","tags":["nature","agriculture","plant"]},{"name":"mdi:flower-tulip","tags":["nature","agriculture","plant"]},{"name":"mdi:flower-tulip-outline","tags":["nature","agriculture","plant"]},{"name":"mdi:focus-auto","tags":["photography"]},{"name":"mdi:focus-field","tags":["photography"]},{"name":"mdi:focus-field-horizontal","tags":["photography"]},{"name":"mdi:focus-field-vertical","tags":["photography"]},{"name":"mdi:folder-alert","tags":["files / folders","alert / error","folder warning"]},{"name":"mdi:folder-alert-outline","tags":["files / folders","alert / error","folder warning outline"]},{"name":"mdi:folder-arrow-down","tags":["files / folders","folder download"]},{"name":"mdi:folder-arrow-down-outline","tags":["files / folders","folder download outline"]},{"name":"mdi:folder-arrow-left","tags":["files / folders"]},{"name":"mdi:folder-arrow-left-outline","tags":["files / folders"]},{"name":"mdi:folder-arrow-left-right","tags":["files / folders"]},{"name":"mdi:folder-arrow-left-right-outline","tags":["files / folders"]},{"name":"mdi:folder-arrow-right","tags":["files / folders"]},{"name":"mdi:folder-arrow-right-outline","tags":["files / folders"]},{"name":"mdi:folder-arrow-up","tags":["files / folders","folder upload"]},{"name":"mdi:folder-arrow-up-down","tags":["files / folders","folder transfer"]},{"name":"mdi:folder-arrow-up-down-outline","tags":["files / folders","folder transfer outline"]},{"name":"mdi:folder-arrow-up-outline","tags":["files / folders","folder upload outline"]},{"name":"mdi:folder-cancel","tags":["files / folders"]},{"name":"mdi:folder-cancel-outline","tags":["files / folders"]},{"name":"mdi:folder-check","tags":["files / folders"]},{"name":"mdi:folder-check-outline","tags":["files / folders"]},{"name":"mdi:folder-clock","tags":["files / folders","date / time"]},{"name":"mdi:folder-clock-outline","tags":["files / folders","date / time"]},{"name":"mdi:folder-cog","tags":["settings","files / folders","folder cog"]},{"name":"mdi:folder-cog-outline","tags":["settings","files / folders","folder cog outline"]},{"name":"mdi:folder-download","tags":["files / folders"]},{"name":"mdi:folder-download-outline","tags":["files / folders"]},{"name":"mdi:folder-edit","tags":["files / folders","edit / modify"]},{"name":"mdi:folder-edit-outline","tags":["edit / modify","files / folders"]},{"name":"mdi:folder-eye","tags":["files / folders"]},{"name":"mdi:folder-eye-outline","tags":["files / folders"]},{"name":"mdi:folder-file","tags":["files / folders"]},{"name":"mdi:folder-file-outline","tags":["files / folders"]},{"name":"mdi:folder-heart","tags":["files / folders"]},{"name":"mdi:folder-heart-outline","tags":["files / folders"]},{"name":"mdi:folder-hidden","tags":["files / folders"]},{"name":"mdi:folder-home","tags":["files / folders","home automation","folder house"]},{"name":"mdi:folder-home-outline","tags":["files / folders","home automation","folder house outline"]},{"name":"mdi:folder-image","tags":["files / folders"]},{"name":"mdi:folder-information","tags":["files / folders"]},{"name":"mdi:folder-information-outline","tags":["files / folders"]},{"name":"mdi:folder-key","tags":["files / folders"]},{"name":"mdi:folder-key-network","tags":["files / folders"]},{"name":"mdi:folder-key-network-outline","tags":["files / folders"]},{"name":"mdi:folder-key-outline","tags":["files / folders"]},{"name":"mdi:folder-lock","tags":["lock","files / folders"]},{"name":"mdi:folder-lock-open","tags":["lock","files / folders"]},{"name":"mdi:folder-lock-open-outline","tags":["files / folders","lock"]},{"name":"mdi:folder-lock-outline","tags":["files / folders","lock"]},{"name":"mdi:folder-marker","tags":["geographic information system","files / folders","navigation","folder location"]},{"name":"mdi:folder-marker-outline","tags":["geographic information system","files / folders","navigation","folder location outline"]},{"name":"mdi:folder-minus","tags":["files / folders"]},{"name":"mdi:folder-minus-outline","tags":["files / folders"]},{"name":"mdi:folder-move-outline","tags":["files / folders"]},{"name":"mdi:folder-multiple","tags":["files / folders","folders"]},{"name":"mdi:folder-multiple-outline","tags":["files / folders","folders outline"]},{"name":"mdi:folder-multiple-plus","tags":["files / folders"]},{"name":"mdi:folder-multiple-plus-outline","tags":["files / folders"]},{"name":"mdi:folder-music","tags":["files / folders","music"]},{"name":"mdi:folder-music-outline","tags":["files / folders","music"]},{"name":"mdi:folder-network","tags":["files / folders"]},{"name":"mdi:folder-network-outline","tags":["files / folders"]},{"name":"mdi:folder-off","tags":["files / folders"]},{"name":"mdi:folder-off-outline","tags":["files / folders"]},{"name":"mdi:folder-open","tags":["files / folders"]},{"name":"mdi:folder-open-outline","tags":["files / folders"]},{"name":"mdi:folder-play","tags":["files / folders","folder media","folder music","folder video"]},{"name":"mdi:folder-play-outline","tags":["files / folders","folder media outline","folder music outline","folder video outline"]},{"name":"mdi:folder-plus","tags":["files / folders","create new folder","folder add"]},{"name":"mdi:folder-pound","tags":["files / folders","developer / languages","folder hash"]},{"name":"mdi:folder-pound-outline","tags":["files / folders","developer / languages","folder hash outline"]},{"name":"mdi:folder-question","tags":["files / folders","folder help"]},{"name":"mdi:folder-question-outline","tags":["files / folders","folder help outline"]},{"name":"mdi:folder-refresh","tags":["files / folders"]},{"name":"mdi:folder-refresh-outline","tags":["files / folders"]},{"name":"mdi:folder-remove","tags":["files / folders"]},{"name":"mdi:folder-remove-outline","tags":["files / folders"]},{"name":"mdi:folder-search","tags":["files / folders"]},{"name":"mdi:folder-search-outline","tags":["files / folders"]},{"name":"mdi:folder-settings","tags":["settings","files / folders"]},{"name":"mdi:folder-settings-outline","tags":["settings","files / folders"]},{"name":"mdi:folder-star-multiple","tags":["files / folders","folder favorite multiple"]},{"name":"mdi:folder-star-multiple-outline","tags":["files / folders","folder favorite multiple outline"]},{"name":"mdi:folder-swap","tags":["files / folders","folder transfer"]},{"name":"mdi:folder-swap-outline","tags":["files / folders","folder transfer outline"]},{"name":"mdi:folder-sync","tags":["files / folders"]},{"name":"mdi:folder-sync-outline","tags":["files / folders"]},{"name":"mdi:folder-table","tags":["files / folders"]},{"name":"mdi:folder-table-outline","tags":["files / folders"]},{"name":"mdi:folder-text","tags":["files / folders"]},{"name":"mdi:folder-text-outline","tags":["files / folders"]},{"name":"mdi:folder-upload","tags":["files / folders"]},{"name":"mdi:folder-upload-outline","tags":["files / folders"]},{"name":"mdi:folder-wrench","tags":["files / folders","folder settings"]},{"name":"mdi:folder-wrench-outline","tags":["files / folders","folder settings outline"]},{"name":"mdi:folder-zip","tags":["files / folders","compressed folder"]},{"name":"mdi:folder-zip-outline","tags":["files / folders","compressed folder outline"]},{"name":"mdi:food-apple","tags":["food / drink","agriculture"]},{"name":"mdi:food-apple-outline","tags":["food / drink","agriculture"]},{"name":"mdi:food-croissant","tags":["food / drink"]},{"name":"mdi:food-drumstick","tags":["food / drink","chicken leg","turkey leg","meat"]},{"name":"mdi:food-drumstick-off","tags":["food / drink","chicken leg off","turkey leg off","meat off"]},{"name":"mdi:food-drumstick-off-outline","tags":["food / drink","chicken leg off outline","turkey leg off outline","meat off outline"]},{"name":"mdi:food-drumstick-outline","tags":["food / drink","chicken leg outline","turkey leg outline","meat outline"]},{"name":"mdi:food-halal","tags":["food / drink","food muslim","dietary restriction"]},{"name":"mdi:food-hot-dog","tags":["food / drink","food weiner","food frankfurter"]},{"name":"mdi:food-kosher","tags":["food / drink","food jewish","dietary restriction"]},{"name":"mdi:food-steak","tags":["food / drink","meat","beef"]},{"name":"mdi:food-steak-off","tags":["food / drink","meat off","beef off"]},{"name":"mdi:food-turkey","tags":["food / drink","holiday","dinner","thanksgiving"]},{"name":"mdi:food-variant","tags":["food / drink"]},{"name":"mdi:food-variant-off","tags":["food / drink"]},{"name":"mdi:foot-print","tags":[]},{"name":"mdi:football-australian","tags":["sport"]},{"name":"mdi:football-helmet","tags":["sport"]},{"name":"mdi:forest-outline","tags":["nature","agriculture","places","forestry outline","pine tree multiple outline"]},{"name":"mdi:forklift","tags":["transportation + road"]},{"name":"mdi:form-dropdown","tags":["form"]},{"name":"mdi:form-select","tags":["form"]},{"name":"mdi:form-textarea","tags":["form"]},{"name":"mdi:form-textbox","tags":["form","rename"]},{"name":"mdi:form-textbox-lock","tags":["form","lock"]},{"name":"mdi:form-textbox-password","tags":["form"]},{"name":"mdi:format-align-bottom","tags":["text / content / format"]},{"name":"mdi:format-align-middle","tags":["text / content / format"]},{"name":"mdi:format-align-top","tags":["text / content / format"]},{"name":"mdi:format-annotation-minus","tags":["text / content / format"]},{"name":"mdi:format-annotation-plus","tags":["text / content / format","format annotation add"]},{"name":"mdi:format-color-highlight","tags":["color","text / content / format","format colour highlight"]},{"name":"mdi:format-color-marker-cancel","tags":["text / content / format","color","format color redact"]},{"name":"mdi:format-columns","tags":["text / content / format"]},{"name":"mdi:format-float-center","tags":["text / content / format","format float centre"]},{"name":"mdi:format-float-left","tags":["text / content / format"]},{"name":"mdi:format-float-none","tags":["text / content / format"]},{"name":"mdi:format-float-right","tags":["text / content / format"]},{"name":"mdi:format-font","tags":["text / content / format"]},{"name":"mdi:format-font-size-decrease","tags":["text / content / format"]},{"name":"mdi:format-font-size-increase","tags":["text / content / format"]},{"name":"mdi:format-header-1","tags":["text / content / format","format heading 1"]},{"name":"mdi:format-header-2","tags":["text / content / format","format heading 2"]},{"name":"mdi:format-header-3","tags":["text / content / format","format heading 3"]},{"name":"mdi:format-header-4","tags":["text / content / format","format heading 4"]},{"name":"mdi:format-header-5","tags":["text / content / format","format heading 5"]},{"name":"mdi:format-header-6","tags":["text / content / format","format heading 6"]},{"name":"mdi:format-header-decrease","tags":["text / content / format","format heading decease"]},{"name":"mdi:format-header-equal","tags":["text / content / format","format heading equal"]},{"name":"mdi:format-header-increase","tags":["text / content / format","format heading increase"]},{"name":"mdi:format-header-pound","tags":["text / content / format","format header hash","format heading pound","format heading hash","format heading markdown"]},{"name":"mdi:format-horizontal-align-center","tags":["text / content / format","format horizontal align centre","arrow horizontal collapse"]},{"name":"mdi:format-horizontal-align-left","tags":["text / content / format"]},{"name":"mdi:format-horizontal-align-right","tags":["text / content / format"]},{"name":"mdi:format-letter-case","tags":["text / content / format"]},{"name":"mdi:format-letter-case-lower","tags":["text / content / format","format lowercase"]},{"name":"mdi:format-letter-case-upper","tags":["text / content / format","format uppercase"]},{"name":"mdi:format-letter-ends-with","tags":["text / content / format"]},{"name":"mdi:format-letter-matches","tags":["text / content / format"]},{"name":"mdi:format-letter-spacing","tags":["text / content / format","format kerning"]},{"name":"mdi:format-letter-spacing-variant","tags":["text / content / format"]},{"name":"mdi:format-letter-starts-with","tags":["text / content / format"]},{"name":"mdi:format-line-height","tags":["text / content / format"]},{"name":"mdi:format-list-bulleted-triangle","tags":["text / content / format"]},{"name":"mdi:format-list-bulleted-type","tags":["text / content / format"]},{"name":"mdi:format-list-checks","tags":["text / content / format","to do"]},{"name":"mdi:format-list-group","tags":["text / content / format"]},{"name":"mdi:format-list-group-plus","tags":["text / content / format","format list group add"]},{"name":"mdi:format-list-text","tags":["text / content / format"]},{"name":"mdi:format-overline","tags":["text / content / format"]},{"name":"mdi:format-page-split","tags":["text / content / format"]},{"name":"mdi:format-paragraph","tags":["text / content / format"]},{"name":"mdi:format-paragraph-spacing","tags":["text / content / format"]},{"name":"mdi:format-pilcrow","tags":["text / content / format"]},{"name":"mdi:format-quote-close-outline","tags":["text / content / format"]},{"name":"mdi:format-quote-open","tags":["text / content / format"]},{"name":"mdi:format-quote-open-outline","tags":["text / content / format"]},{"name":"mdi:format-section","tags":["text / content / format"]},{"name":"mdi:format-subscript","tags":["text / content / format"]},{"name":"mdi:format-superscript","tags":["text / content / format","math","exponent"]},{"name":"mdi:format-text","tags":["text / content / format"]},{"name":"mdi:format-text-rotation-down-vertical","tags":["text / content / format"]},{"name":"mdi:format-text-variant","tags":["text / content / format"]},{"name":"mdi:format-text-variant-outline","tags":["text / content / format"]},{"name":"mdi:format-underline-wavy","tags":["text / content / format"]},{"name":"mdi:format-wrap-inline","tags":["text / content / format"]},{"name":"mdi:format-wrap-square","tags":["text / content / format"]},{"name":"mdi:format-wrap-tight","tags":["text / content / format"]},{"name":"mdi:format-wrap-top-bottom","tags":["text / content / format"]},{"name":"mdi:forum-minus","tags":["chat minus","forum subtract","chat subtract"]},{"name":"mdi:forum-minus-outline","tags":["chat minus outline","forum subtract outline","chat subtract outline"]},{"name":"mdi:forum-plus","tags":["chat plus","forum add","chat add"]},{"name":"mdi:forum-plus-outline","tags":["chat plus outline","chat add outline","forum add outline"]},{"name":"mdi:forum-remove","tags":["forum delete","chat remove","chat delete"]},{"name":"mdi:forum-remove-outline","tags":["forum delete outline","chat remove outline","chat delete outline"]},{"name":"mdi:forwardburger","tags":[]},{"name":"mdi:fountain","tags":[]},{"name":"mdi:fountain-pen","tags":["drawing / art"]},{"name":"mdi:fountain-pen-tip","tags":["drawing / art"]},{"name":"mdi:fraction-one-half","tags":[]},{"name":"mdi:french-fries","tags":["food / drink","chips","finger chips","french fry","fried potatoes","fries","frites"]},{"name":"mdi:frequently-asked-questions","tags":["faq"]},{"name":"mdi:fridge","tags":["home automation","fridge filled","refrigerator","kitchen"]},{"name":"mdi:fridge-alert","tags":["home automation","alert / error"]},{"name":"mdi:fridge-alert-outline","tags":["home automation","alert / error"]},{"name":"mdi:fridge-bottom","tags":["home automation","fridge filled top","refrigerator bottom"]},{"name":"mdi:fridge-industrial","tags":["home automation"]},{"name":"mdi:fridge-industrial-alert","tags":["home automation","alert / error"]},{"name":"mdi:fridge-industrial-alert-outline","tags":["home automation","alert / error"]},{"name":"mdi:fridge-industrial-off","tags":["home automation"]},{"name":"mdi:fridge-industrial-off-outline","tags":["home automation"]},{"name":"mdi:fridge-industrial-outline","tags":["home automation"]},{"name":"mdi:fridge-off","tags":["home automation"]},{"name":"mdi:fridge-off-outline","tags":["home automation"]},{"name":"mdi:fridge-outline","tags":["home automation","kitchen","refrigerator outline"]},{"name":"mdi:fridge-top","tags":["home automation","fridge filled bottom","refrigerator top"]},{"name":"mdi:fridge-variant","tags":["home automation"]},{"name":"mdi:fridge-variant-alert","tags":["home automation","alert / error"]},{"name":"mdi:fridge-variant-alert-outline","tags":["home automation","alert / error"]},{"name":"mdi:fridge-variant-off","tags":["home automation"]},{"name":"mdi:fridge-variant-off-outline","tags":["home automation"]},{"name":"mdi:fridge-variant-outline","tags":["home automation"]},{"name":"mdi:fruit-cherries","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-cherries-off","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-citrus","tags":["food / drink","agriculture","fruit lemon","fruit lime"]},{"name":"mdi:fruit-citrus-off","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-grapes","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-grapes-outline","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-pear","tags":["food / drink"]},{"name":"mdi:fruit-pineapple","tags":["food / drink","agriculture","fruit ananas"]},{"name":"mdi:fruit-watermelon","tags":["food / drink","agriculture"]},{"name":"mdi:fuel","tags":["automotive","petrol","gasoline"]},{"name":"mdi:fuel-cell","tags":["automotive","battery","battery"]},{"name":"mdi:function","tags":["math"]},{"name":"mdi:function-variant","tags":["math"]},{"name":"mdi:furigana-horizontal","tags":["text / content / format","ruby horizontal"]},{"name":"mdi:furigana-vertical","tags":["text / content / format","zhuyin","ruby vertical"]},{"name":"mdi:fuse","tags":["automotive"]},{"name":"mdi:fuse-alert","tags":["automotive","alert / error"]},{"name":"mdi:fuse-blade","tags":["automotive"]},{"name":"mdi:fuse-off","tags":["automotive"]},{"name":"mdi:gamepad-circle","tags":["gaming / rpg","controller circle"]},{"name":"mdi:gamepad-circle-down","tags":["gaming / rpg","controller circle down"]},{"name":"mdi:gamepad-circle-left","tags":["gaming / rpg","controller circle left"]},{"name":"mdi:gamepad-circle-outline","tags":["gaming / rpg","controller circle outline"]},{"name":"mdi:gamepad-circle-right","tags":["gaming / rpg","controller circle right"]},{"name":"mdi:gamepad-circle-up","tags":["gaming / rpg","controller circle up"]},{"name":"mdi:gamepad-down","tags":["gaming / rpg","controller down"]},{"name":"mdi:gamepad-left","tags":["gaming / rpg","controller left"]},{"name":"mdi:gamepad-outline","tags":["gaming / rpg","home automation","controller outline","games outline"]},{"name":"mdi:gamepad-right","tags":["gaming / rpg","controller right"]},{"name":"mdi:gamepad-round","tags":["gaming / rpg","controller round"]},{"name":"mdi:gamepad-round-down","tags":["gaming / rpg","controller round down"]},{"name":"mdi:gamepad-round-left","tags":["gaming / rpg","controller round left"]},{"name":"mdi:gamepad-round-outline","tags":["gaming / rpg","controller round outline"]},{"name":"mdi:gamepad-round-right","tags":["gaming / rpg","controller round right"]},{"name":"mdi:gamepad-round-up","tags":["gaming / rpg","controller round up"]},{"name":"mdi:gamepad-up","tags":["gaming / rpg","controller up"]},{"name":"mdi:gamepad-variant","tags":["gaming / rpg","controller variant"]},{"name":"mdi:gamepad-variant-outline","tags":["gaming / rpg","controller variant outline"]},{"name":"mdi:gamma","tags":["alpha / numeric"]},{"name":"mdi:gantry-crane","tags":[]},{"name":"mdi:garage","tags":["home automation"]},{"name":"mdi:garage-alert","tags":["home automation","alert / error","garage warning"]},{"name":"mdi:garage-alert-variant","tags":["home automation","alert / error"]},{"name":"mdi:garage-lock","tags":["home automation","lock"]},{"name":"mdi:garage-open","tags":["home automation"]},{"name":"mdi:garage-open-variant","tags":["home automation"]},{"name":"mdi:garage-variant","tags":["home automation"]},{"name":"mdi:garage-variant-lock","tags":["home automation","lock"]},{"name":"mdi:gas-burner","tags":["home automation","stove burner","cooktop burner","grill"]},{"name":"mdi:gas-cylinder","tags":["tank","oxygen tank"]},{"name":"mdi:gas-station-off","tags":[]},{"name":"mdi:gas-station-off-outline","tags":[]},{"name":"mdi:gate","tags":["home automation"]},{"name":"mdi:gate-alert","tags":["home automation","alert / error"]},{"name":"mdi:gate-and","tags":["logic gate and"]},{"name":"mdi:gate-arrow-left","tags":["home automation"]},{"name":"mdi:gate-arrow-right","tags":["home automation"]},{"name":"mdi:gate-buffer","tags":[]},{"name":"mdi:gate-nand","tags":["logic gate nand"]},{"name":"mdi:gate-nor","tags":["logic gate nor"]},{"name":"mdi:gate-not","tags":["logic gate not"]},{"name":"mdi:gate-open","tags":["home automation"]},{"name":"mdi:gate-or","tags":["logic gate or"]},{"name":"mdi:gate-xnor","tags":["logic gate xnor"]},{"name":"mdi:gate-xor","tags":["logic gate xor"]},{"name":"mdi:gauge-empty","tags":["automotive","home automation"]},{"name":"mdi:gauge-full","tags":["automotive","home automation"]},{"name":"mdi:gauge-low","tags":["automotive","home automation"]},{"name":"mdi:gavel","tags":["court hammer"]},{"name":"mdi:gender-female","tags":["venus"]},{"name":"mdi:gender-male","tags":["mars"]},{"name":"mdi:gender-male-female","tags":[]},{"name":"mdi:gender-male-female-variant","tags":["mercury"]},{"name":"mdi:gender-non-binary","tags":["gender enby"]},{"name":"mdi:gender-transgender","tags":[]},{"name":"mdi:gesture-double-tap","tags":["interaction double tap","hand double tap"]},{"name":"mdi:gesture-pinch","tags":[]},{"name":"mdi:gesture-spread","tags":[]},{"name":"mdi:gesture-swipe-down","tags":[]},{"name":"mdi:gesture-swipe-horizontal","tags":[]},{"name":"mdi:gesture-swipe-left","tags":[]},{"name":"mdi:gesture-swipe-right","tags":[]},{"name":"mdi:gesture-swipe-up","tags":[]},{"name":"mdi:gesture-swipe-vertical","tags":[]},{"name":"mdi:gesture-tap","tags":["interaction tap","hand tap","gesture touch"]},{"name":"mdi:gesture-tap-box","tags":["gesture touch box"]},{"name":"mdi:gesture-tap-button","tags":["form","call to action","cta","button pointer","gesture touch button"]},{"name":"mdi:gesture-two-double-tap","tags":[]},{"name":"mdi:gesture-two-tap","tags":[]},{"name":"mdi:ghost","tags":["gaming / rpg","inky","blinky","pinky","clyde"]},{"name":"mdi:ghost-off","tags":["gaming / rpg"]},{"name":"mdi:ghost-off-outline","tags":["gaming / rpg"]},{"name":"mdi:ghost-outline","tags":["gaming / rpg"]},{"name":"mdi:gift","tags":["holiday","present","package","donate"]},{"name":"mdi:gift-off","tags":["holiday","present off","package off","donate off"]},{"name":"mdi:gift-off-outline","tags":["holiday","present off outline","package off outline","donate off outline"]},{"name":"mdi:gift-open","tags":["holiday","present open","package open"]},{"name":"mdi:gift-open-outline","tags":["holiday","present open outline","package open outline"]},{"name":"mdi:gift-outline","tags":["shopping","holiday","donate outline","present outline","package outline"]},{"name":"mdi:glass-cocktail-off","tags":["food / drink"]},{"name":"mdi:glass-flute","tags":["food / drink","alcohol","cocktail","cup","drink"]},{"name":"mdi:glass-fragile","tags":["food / drink","glass broken"]},{"name":"mdi:glass-mug","tags":["food / drink","pub","bar","beer","alcohol","cup","drink","local bar"]},{"name":"mdi:glass-mug-off","tags":["food / drink"]},{"name":"mdi:glass-mug-variant","tags":["food / drink","pub","bar","beer","drink","alcohol","cup","local bar"]},{"name":"mdi:glass-mug-variant-off","tags":["food / drink"]},{"name":"mdi:glass-pint-outline","tags":["food / drink"]},{"name":"mdi:glass-stange","tags":["food / drink","alcohol","bar","cocktail","cup","drink"]},{"name":"mdi:glass-tulip","tags":["food / drink","bar","alcohol","cocktail","cup","drink"]},{"name":"mdi:glass-wine","tags":["food / drink","bar","alcohol","cocktail","cup","drink"]},{"name":"mdi:glasses","tags":["clothing"]},{"name":"mdi:globe-light","tags":["home automation"]},{"name":"mdi:globe-light-outline","tags":["home automation"]},{"name":"mdi:globe-model","tags":[]},{"name":"mdi:go-kart","tags":["sport","cart"]},{"name":"mdi:go-kart-track","tags":[]},{"name":"mdi:gold","tags":[]},{"name":"mdi:golf-cart","tags":["sport","transportation + other"]},{"name":"mdi:gondola","tags":["transportation + other","cable car"]},{"name":"mdi:gradient-horizontal","tags":["drawing / art"]},{"name":"mdi:graph","tags":["dependency","dependencies"]},{"name":"mdi:graph-outline","tags":["dependency","dependencies"]},{"name":"mdi:grave-stone","tags":["holiday","headstone","tombstone","cemetery","graveyard"]},{"name":"mdi:greater-than","tags":["math"]},{"name":"mdi:greater-than-or-equal","tags":["math"]},{"name":"mdi:greenhouse","tags":["home automation","agriculture","nature","glasshouse","hothouse","shed"]},{"name":"mdi:grid-large","tags":[]},{"name":"mdi:group","tags":[]},{"name":"mdi:guitar-acoustic","tags":["music"]},{"name":"mdi:guitar-electric","tags":["music"]},{"name":"mdi:guitar-pick","tags":["music"]},{"name":"mdi:guitar-pick-outline","tags":["music"]},{"name":"mdi:guy-fawkes-mask","tags":[]},{"name":"mdi:hair-dryer","tags":["health / beauty"]},{"name":"mdi:hair-dryer-outline","tags":["health / beauty"]},{"name":"mdi:halloween","tags":["holiday","pumpkin face","pumpkin carved","jack o lantern","emoji halloween","emoticon halloween"]},{"name":"mdi:hamburger","tags":["food / drink","burger","fast food","food"]},{"name":"mdi:hamburger-check","tags":["food / drink","burger check"]},{"name":"mdi:hamburger-minus","tags":["food / drink","burger minus"]},{"name":"mdi:hamburger-off","tags":["food / drink","burger off","fast food off","food off"]},{"name":"mdi:hamburger-plus","tags":["food / drink","burger plus","burger add"]},{"name":"mdi:hamburger-remove","tags":["food / drink","burger remove"]},{"name":"mdi:hammer-sickle","tags":["communism"]},{"name":"mdi:hand-back-left-off","tags":[]},{"name":"mdi:hand-back-left-off-outline","tags":[]},{"name":"mdi:hand-back-right-off","tags":[]},{"name":"mdi:hand-back-right-off-outline","tags":[]},{"name":"mdi:hand-clap","tags":["applause"]},{"name":"mdi:hand-clap-off","tags":["applause off"]},{"name":"mdi:hand-coin","tags":["banking","charity","donation"]},{"name":"mdi:hand-coin-outline","tags":["banking","charity outline","donation outline"]},{"name":"mdi:hand-cycle","tags":["sport","hand bike"]},{"name":"mdi:hand-extended","tags":["hand open","hand palm"]},{"name":"mdi:hand-extended-outline","tags":["hand open outline","hand palm outline"]},{"name":"mdi:hand-heart-outline","tags":[]},{"name":"mdi:hand-okay","tags":[]},{"name":"mdi:hand-peace","tags":[]},{"name":"mdi:hand-peace-variant","tags":[]},{"name":"mdi:hand-pointing-down","tags":[]},{"name":"mdi:hand-pointing-left","tags":[]},{"name":"mdi:hand-pointing-right","tags":[]},{"name":"mdi:hand-pointing-up","tags":[]},{"name":"mdi:hand-saw","tags":["hardware / tools"]},{"name":"mdi:hand-water","tags":["medical / hospital","hand wash"]},{"name":"mdi:handcuffs","tags":[]},{"name":"mdi:hands-pray","tags":[]},{"name":"mdi:handshake","tags":["business","deal","help","partnership"]},{"name":"mdi:handshake-outline","tags":["business outline","deal outline","help outline","partnership outline"]},{"name":"mdi:hanger","tags":["clothing","home automation","coat hanger","clothes hanger","closet"]},{"name":"mdi:hard-hat","tags":["hardware / tools","clothing","helmet"]},{"name":"mdi:harddisk","tags":["hdd"]},{"name":"mdi:harddisk-plus","tags":["hdd plus"]},{"name":"mdi:harddisk-remove","tags":["hdd remove"]},{"name":"mdi:hazard-lights","tags":["automotive","warning lights"]},{"name":"mdi:hdmi-port","tags":["video / movie","home automation"]},{"name":"mdi:head","tags":[]},{"name":"mdi:head-alert","tags":["alert / error"]},{"name":"mdi:head-alert-outline","tags":["alert / error"]},{"name":"mdi:head-check","tags":[]},{"name":"mdi:head-check-outline","tags":[]},{"name":"mdi:head-cog-outline","tags":["settings","psychology outline"]},{"name":"mdi:head-dots-horizontal","tags":["head thinking"]},{"name":"mdi:head-dots-horizontal-outline","tags":["head thinking outline"]},{"name":"mdi:head-flash","tags":["head ache"]},{"name":"mdi:head-flash-outline","tags":["head ache outline"]},{"name":"mdi:head-heart","tags":["head love"]},{"name":"mdi:head-heart-outline","tags":["head love outline"]},{"name":"mdi:head-lightbulb","tags":["head idea","head bulb"]},{"name":"mdi:head-lightbulb-outline","tags":["head idea outline","head bulb outline"]},{"name":"mdi:head-minus","tags":[]},{"name":"mdi:head-minus-outline","tags":[]},{"name":"mdi:head-outline","tags":[]},{"name":"mdi:head-plus","tags":[]},{"name":"mdi:head-plus-outline","tags":[]},{"name":"mdi:head-question","tags":[]},{"name":"mdi:head-question-outline","tags":[]},{"name":"mdi:head-remove","tags":[]},{"name":"mdi:head-remove-outline","tags":[]},{"name":"mdi:head-snowflake","tags":["head freeze","brain freeze"]},{"name":"mdi:head-snowflake-outline","tags":["head freeze outline","brain freeze outline"]},{"name":"mdi:head-sync","tags":["head reload","head refresh"]},{"name":"mdi:head-sync-outline","tags":["head reload outline","head refresh outline"]},{"name":"mdi:headphones-bluetooth","tags":[]},{"name":"mdi:headphones-off","tags":["audio","device / tech","music"]},{"name":"mdi:headphones-settings","tags":["audio","settings"]},{"name":"mdi:headset-dock","tags":["audio"]},{"name":"mdi:headset-off","tags":["audio","device / tech"]},{"name":"mdi:heart-box","tags":[]},{"name":"mdi:heart-box-outline","tags":[]},{"name":"mdi:heart-broken","tags":[]},{"name":"mdi:heart-broken-outline","tags":[]},{"name":"mdi:heart-circle","tags":[]},{"name":"mdi:heart-circle-outline","tags":[]},{"name":"mdi:heart-cog","tags":["settings"]},{"name":"mdi:heart-cog-outline","tags":["settings"]},{"name":"mdi:heart-flash","tags":["medical / hospital","aed","defibrillator"]},{"name":"mdi:heart-half","tags":["gaming / rpg"]},{"name":"mdi:heart-half-full","tags":["gaming / rpg"]},{"name":"mdi:heart-half-outline","tags":["gaming / rpg"]},{"name":"mdi:heart-minus","tags":[]},{"name":"mdi:heart-minus-outline","tags":[]},{"name":"mdi:heart-multiple","tags":["hearts"]},{"name":"mdi:heart-multiple-outline","tags":["hearts outline"]},{"name":"mdi:heart-off","tags":["medical / hospital"]},{"name":"mdi:heart-off-outline","tags":["medical / hospital"]},{"name":"mdi:heart-plus","tags":[]},{"name":"mdi:heart-plus-outline","tags":[]},{"name":"mdi:heart-remove","tags":[]},{"name":"mdi:heart-remove-outline","tags":[]},{"name":"mdi:heart-settings","tags":["settings"]},{"name":"mdi:heart-settings-outline","tags":["settings"]},{"name":"mdi:heat-wave","tags":["home automation","weather","agriculture","keep warm","warmth"]},{"name":"mdi:heating-coil","tags":["home automation","radiator coil","heated floor"]},{"name":"mdi:helicopter","tags":["transportation + flying"]},{"name":"mdi:help","tags":["question mark"]},{"name":"mdi:help-box","tags":["question mark box"]},{"name":"mdi:help-box-multiple","tags":["quiz","question box multiple"]},{"name":"mdi:help-box-multiple-outline","tags":["quiz outline","question box multiple outline"]},{"name":"mdi:help-box-outline","tags":["question box outline"]},{"name":"mdi:help-network","tags":["question network"]},{"name":"mdi:help-network-outline","tags":["question network outline"]},{"name":"mdi:help-rhombus","tags":["question mark rhombus"]},{"name":"mdi:help-rhombus-outline","tags":["question mark rhombus outline"]},{"name":"mdi:hexadecimal","tags":["developer / languages"]},{"name":"mdi:hexagon","tags":["shape"]},{"name":"mdi:hexagon-multiple","tags":["shape","hexagons"]},{"name":"mdi:hexagon-multiple-outline","tags":["nature"]},{"name":"mdi:hexagon-outline","tags":["shape"]},{"name":"mdi:hexagon-slice-1","tags":[]},{"name":"mdi:hexagon-slice-2","tags":[]},{"name":"mdi:hexagon-slice-3","tags":[]},{"name":"mdi:hexagon-slice-4","tags":[]},{"name":"mdi:hexagon-slice-5","tags":[]},{"name":"mdi:hexagon-slice-6","tags":[]},{"name":"mdi:hexagram","tags":["shape","holiday","star","christmas star"]},{"name":"mdi:hexagram-outline","tags":["shape","holiday","star outline","christmas star outline"]},{"name":"mdi:high-definition","tags":["video / movie","hd"]},{"name":"mdi:highway","tags":["transportation + road","autobahn","motorway"]},{"name":"mdi:hockey-puck","tags":["sport"]},{"name":"mdi:hololens","tags":["gaming / rpg"]},{"name":"mdi:home-account","tags":["account / user","home automation","home user","house account","house user"]},{"name":"mdi:home-alert","tags":["home automation","alert / error","home warning","house alert","house warning"]},{"name":"mdi:home-alert-outline","tags":["home automation","alert / error","house alert outline","home warning outline","house warning outline"]},{"name":"mdi:home-analytics","tags":["home automation","chart home","home chart","home report","house analytics","house chart"]},{"name":"mdi:home-automation","tags":["home automation","house automation","home wireless","house wireless","smart home","smart house"]},{"name":"mdi:home-battery","tags":["home automation","battery","home energy","home power","home electricity","house energy","house battery","house power"]},{"name":"mdi:home-battery-outline","tags":["home automation","battery","home energy outline","home power outline","home electricity outline","house battery outline","house power outline","house energy outline"]},{"name":"mdi:home-circle","tags":["home automation","house circle"]},{"name":"mdi:home-circle-outline","tags":["home automation","house circle outline"]},{"name":"mdi:home-clock","tags":["home automation","date / time","home time","home schedule","house time","house clock","house schedule"]},{"name":"mdi:home-clock-outline","tags":["home automation","date / time","home time outline","home schedule outline","house clock outline","house time outline","house schedule outline"]},{"name":"mdi:home-edit","tags":["home automation","edit / modify","house edit"]},{"name":"mdi:home-edit-outline","tags":["home automation","edit / modify","house edit outline"]},{"name":"mdi:home-export-outline","tags":["home automation","house export outline"]},{"name":"mdi:home-floor-0","tags":["home automation","house floor 0","home floor zero","house floor zero"]},{"name":"mdi:home-floor-1","tags":["home automation","house floor 1","home floor one","house floor one","home floor first","house floor first"]},{"name":"mdi:home-floor-2","tags":["home automation","house floor 2","home floor two","house floor two","home floor second","house floor second"]},{"name":"mdi:home-floor-3","tags":["home automation","house floor 3","home floor three","house floor three","home floor third","house floor third"]},{"name":"mdi:home-floor-a","tags":["home automation","home floor attic","house floor a","house floor attic"]},{"name":"mdi:home-floor-b","tags":["home automation","home floor basement","house floor b","house floor basement"]},{"name":"mdi:home-floor-g","tags":["home automation","home floor ground","house floor g","house floor ground"]},{"name":"mdi:home-floor-l","tags":["home automation","home floor loft","home floor lower","house floor l","house floor loft","house floor lower"]},{"name":"mdi:home-floor-negative-1","tags":["home automation","house floor negative 1","home floor negative one","home floor minus 1","home floor minus one","house floor negative one","house floor minus 1","house floor minus one"]},{"name":"mdi:home-group","tags":["home automation","house group","neighbourhood","estate","housing estate"]},{"name":"mdi:home-group-minus","tags":["home automation","house group minus"]},{"name":"mdi:home-group-plus","tags":["home automation","house group plus","home group add","house group add"]},{"name":"mdi:home-group-remove","tags":["home automation","house group remove"]},{"name":"mdi:home-import-outline","tags":["home automation","house import outline"]},{"name":"mdi:home-lightbulb","tags":["home automation","home bulb","house lightbulb","house bulb"]},{"name":"mdi:home-lightbulb-outline","tags":["home automation","home bulb outline","house lightbulb outline","house bulb outline"]},{"name":"mdi:home-lightning-bolt","tags":["home automation","home energy","home power","home electricity","home flash","house lightning bolt","house flash"]},{"name":"mdi:home-lightning-bolt-outline","tags":["home automation","home energy","home power","home electricity","home flash","house lightning bolt outline","house flash outline"]},{"name":"mdi:home-lock","tags":["home automation","lock","house lock","home secure","house secure"]},{"name":"mdi:home-lock-open","tags":["home automation","lock","house lock open"]},{"name":"mdi:home-map-marker","tags":["home automation","navigation","house map marker","home location"]},{"name":"mdi:home-minus","tags":["home automation","house minus"]},{"name":"mdi:home-minus-outline","tags":["home automation","house minus outline"]},{"name":"mdi:home-modern","tags":["home automation","house modern"]},{"name":"mdi:home-off","tags":["home automation","house off"]},{"name":"mdi:home-off-outline","tags":["home automation","house off outline"]},{"name":"mdi:home-percent","tags":[]},{"name":"mdi:home-percent-outline","tags":["home automation"]},{"name":"mdi:home-plus","tags":["home automation","home add","house plus","house add"]},{"name":"mdi:home-plus-outline","tags":["home automation","house plus outline","house add outline"]},{"name":"mdi:home-remove","tags":["home automation","house remove"]},{"name":"mdi:home-remove-outline","tags":["home automation","house remove outline"]},{"name":"mdi:home-roof","tags":["home automation","home chimney","home attic","house roof","house attic","house chimney"]},{"name":"mdi:home-search","tags":["home automation","house search","home find","house find"]},{"name":"mdi:home-search-outline","tags":["home automation","house search outline","home find outline","house find outline"]},{"name":"mdi:home-silo","tags":["home automation","agriculture","farm house","farm home"]},{"name":"mdi:home-silo-outline","tags":["agriculture","home automation","farm house outline","farm home outline"]},{"name":"mdi:home-sound-in","tags":["home automation"]},{"name":"mdi:home-sound-in-outline","tags":["home automation"]},{"name":"mdi:home-sound-out","tags":["home automation"]},{"name":"mdi:home-sound-out-outline","tags":["home automation"]},{"name":"mdi:home-switch","tags":["home automation","home swap","house switch","house swap"]},{"name":"mdi:home-switch-outline","tags":["home automation","home swap outline","house swap outline","house switch outline"]},{"name":"mdi:home-thermometer","tags":["home automation","home climate","home temperature","house thermometer","house climate","house temperature"]},{"name":"mdi:home-thermometer-outline","tags":["home automation","home climate outline","home temperature outline","house thermometer outline","house climate outline","house temperature outline"]},{"name":"mdi:hook","tags":[]},{"name":"mdi:hook-off","tags":[]},{"name":"mdi:hoop-house","tags":["agriculture","home automation","green house"]},{"name":"mdi:hops","tags":["food / drink","agriculture"]},{"name":"mdi:horizontal-rotate-clockwise","tags":[]},{"name":"mdi:horizontal-rotate-counterclockwise","tags":[]},{"name":"mdi:horse","tags":["transportation + other","animal","agriculture","equestrian"]},{"name":"mdi:horse-human","tags":["transportation + other","agriculture","people / family","horseback riding","horse riding","equestrian"]},{"name":"mdi:horse-variant","tags":["animal","agriculture","equestrian variant"]},{"name":"mdi:horse-variant-fast","tags":["animal","agriculture"]},{"name":"mdi:horseshoe","tags":["sport","agriculture","luck"]},{"name":"mdi:hospital","tags":["medical / hospital","swiss cross","dispensary"]},{"name":"mdi:hospital-box-outline","tags":["medical / hospital","swiss cross box outline","dispensary box outline"]},{"name":"mdi:hospital-building","tags":["places","medical / hospital"]},{"name":"mdi:hospital-marker","tags":["medical / hospital","navigation","hospital location"]},{"name":"mdi:hours-24","tags":["date / time"]},{"name":"mdi:hubspot","tags":[]},{"name":"mdi:human-baby-changing-table","tags":["people / family","medical / hospital"]},{"name":"mdi:human-capacity-increase","tags":["account / user","transportation + other","people / family"]},{"name":"mdi:human-child","tags":["people / family"]},{"name":"mdi:human-dolly","tags":["people / family","human hand truck","human trolley"]},{"name":"mdi:human-edit","tags":["people / family","edit / modify"]},{"name":"mdi:human-female-boy","tags":["people / family","mother","mom","woman child","mum"]},{"name":"mdi:human-female-dance","tags":["people / family","sport","ballet"]},{"name":"mdi:human-female-female","tags":["people / family","woman woman","women"]},{"name":"mdi:human-female-girl","tags":["people / family","mother","mom","woman child","mum"]},{"name":"mdi:human-male-board","tags":["people / family","teacher","teaching","lecture","college","blackboard","whiteboard","human man board"]},{"name":"mdi:human-male-board-poll","tags":["people / family","teach poll"]},{"name":"mdi:human-male-boy","tags":["people / family","father","dad","man child"]},{"name":"mdi:human-male-child","tags":["people / family"]},{"name":"mdi:human-male-girl","tags":["people / family","father","dad","man child"]},{"name":"mdi:human-male-height","tags":["medical / hospital","people / family"]},{"name":"mdi:human-male-height-variant","tags":["medical / hospital","people / family"]},{"name":"mdi:human-male-male","tags":["people / family","man man","men"]},{"name":"mdi:human-non-binary","tags":["people / family","human genderless","human transgender"]},{"name":"mdi:human-queue","tags":["people / family","human line"]},{"name":"mdi:human-wheelchair","tags":["people / family","medical / hospital","human accessible"]},{"name":"mdi:human-white-cane","tags":["people / family","medical / hospital","human blind"]},{"name":"mdi:hvac-off","tags":["home automation","heating off","ventilation off","air conditioning off"]},{"name":"mdi:hydraulic-oil-level","tags":["automotive"]},{"name":"mdi:hydraulic-oil-temperature","tags":["automotive"]},{"name":"mdi:hydro-power","tags":["device / tech","agriculture","hydraulic turbine","water turbine","watermill"]},{"name":"mdi:hydrogen-station","tags":["automotive"]},{"name":"mdi:ice-cream-off","tags":["food / drink"]},{"name":"mdi:ice-pop","tags":["food / drink","popsicle"]},{"name":"mdi:id-card","tags":[]},{"name":"mdi:identifier","tags":["developer / languages","key"]},{"name":"mdi:ideogram-cjk","tags":["alpha / numeric","ideogram chinese japanese korean","writing system cjk"]},{"name":"mdi:ideogram-cjk-variant","tags":["alpha / numeric","ideogram chinese japanese korean variant","writing system cjk variant"]},{"name":"mdi:image-area","tags":[]},{"name":"mdi:image-area-close","tags":[]},{"name":"mdi:image-broken","tags":[]},{"name":"mdi:image-check","tags":[]},{"name":"mdi:image-check-outline","tags":[]},{"name":"mdi:image-edit","tags":["edit / modify"]},{"name":"mdi:image-edit-outline","tags":["edit / modify"]},{"name":"mdi:image-filter-hdr-outline","tags":["photography","nature","mountain outline","landscape outline"]},{"name":"mdi:image-lock","tags":["lock","photography","image secure"]},{"name":"mdi:image-lock-outline","tags":["photography","lock","image secure outline"]},{"name":"mdi:image-marker","tags":["navigation","image location"]},{"name":"mdi:image-marker-outline","tags":["navigation","image location outline"]},{"name":"mdi:image-minus","tags":[]},{"name":"mdi:image-minus-outline","tags":[]},{"name":"mdi:image-move","tags":[]},{"name":"mdi:image-off","tags":[]},{"name":"mdi:image-off-outline","tags":[]},{"name":"mdi:image-outline","tags":[]},{"name":"mdi:image-plus","tags":["image add"]},{"name":"mdi:image-plus-outline","tags":["image add outline"]},{"name":"mdi:image-refresh","tags":["photography"]},{"name":"mdi:image-refresh-outline","tags":["photography"]},{"name":"mdi:image-remove","tags":[]},{"name":"mdi:image-remove-outline","tags":[]},{"name":"mdi:image-sync","tags":["photography"]},{"name":"mdi:image-sync-outline","tags":["photography"]},{"name":"mdi:import","tags":["input"]},{"name":"mdi:inbox-arrow-down-outline","tags":[]},{"name":"mdi:inbox-arrow-up","tags":["move from inbox"]},{"name":"mdi:inbox-arrow-up-outline","tags":[]},{"name":"mdi:inbox-full","tags":[]},{"name":"mdi:inbox-full-outline","tags":[]},{"name":"mdi:inbox-outline","tags":[]},{"name":"mdi:inbox-remove","tags":[]},{"name":"mdi:inbox-remove-outline","tags":[]},{"name":"mdi:incognito","tags":["anonymous","spy"]},{"name":"mdi:incognito-circle-off","tags":["anonymous circle off","spy circle off"]},{"name":"mdi:incognito-off","tags":["spy off","anonymous off"]},{"name":"mdi:induction","tags":["home automation","automotive","ignition"]},{"name":"mdi:infinity","tags":["math"]},{"name":"mdi:information-box","tags":["settings","info box"]},{"name":"mdi:information-box-outline","tags":["settings","info box outline"]},{"name":"mdi:information-off","tags":["info off","info circle off","information circle off"]},{"name":"mdi:information-off-outline","tags":["info circle off outline","information circle off outline","information off outline","info off outline"]},{"name":"mdi:information-slab-box","tags":["settings","info slab box"]},{"name":"mdi:information-slab-box-outline","tags":["settings","info slab box outline"]},{"name":"mdi:information-slab-circle","tags":["settings","info slab circle"]},{"name":"mdi:information-slab-circle-outline","tags":["settings","info slab circle outline"]},{"name":"mdi:information-slab-symbol","tags":["settings","info slab symbol"]},{"name":"mdi:information-symbol","tags":["settings","info symbol"]},{"name":"mdi:information-variant","tags":["info variant","about variant","information serif symbol","info variant symbol"]},{"name":"mdi:information-variant-box","tags":["settings","info variant box","information serif box","info serif box"]},{"name":"mdi:information-variant-box-outline","tags":["settings","info variant box outline","information serif box outline","info serif box outline"]},{"name":"mdi:information-variant-circle","tags":["settings","information serif circle","info serif circle","info variant circle"]},{"name":"mdi:information-variant-circle-outline","tags":["settings","information serif circle outline","info variant circle outline","info serif circle outline"]},{"name":"mdi:instrument-triangle","tags":["music","dinner bell"]},{"name":"mdi:integrated-circuit-chip","tags":["banking","icc","chip"]},{"name":"mdi:ip","tags":["internet protocol"]},{"name":"mdi:ip-network","tags":[]},{"name":"mdi:ip-network-outline","tags":[]},{"name":"mdi:ip-outline","tags":["internet protocol outline"]},{"name":"mdi:ipod","tags":["apple ipod"]},{"name":"mdi:iron-board","tags":["home automation","clothing"]},{"name":"mdi:island","tags":["places"]},{"name":"mdi:iv-bag","tags":["medical / hospital"]},{"name":"mdi:jeepney","tags":["transportation + road"]},{"name":"mdi:jellyfish","tags":["animal"]},{"name":"mdi:jellyfish-outline","tags":["animal"]},{"name":"mdi:jump-rope","tags":["sport"]},{"name":"mdi:kangaroo","tags":["animal","marsupial"]},{"name":"mdi:keg","tags":["food / drink"]},{"name":"mdi:kettle","tags":["home automation","food / drink","tea kettle","kettle full","tea kettle full"]},{"name":"mdi:kettle-alert","tags":["home automation","alert / error","food / drink","tea kettle alert","kettle full alert","tea kettle full alert"]},{"name":"mdi:kettle-alert-outline","tags":["home automation","alert / error","food / drink","tea kettle alert outline","kettle empty alert","tea kettle empty alert"]},{"name":"mdi:kettle-off","tags":["home automation","food / drink","tea kettle off","tea kettle full off","kettle full off"]},{"name":"mdi:kettle-off-outline","tags":["home automation","food / drink","tea kettle off outline","kettle empty off","tea kettle empty off"]},{"name":"mdi:kettle-outline","tags":["food / drink","home automation","tea kettle outline","kettle empty","tea kettle empty"]},{"name":"mdi:kettle-pour-over","tags":[]},{"name":"mdi:kettle-steam","tags":["home automation","food / drink","tea kettle steam","kettle full steam","tea kettle full steam"]},{"name":"mdi:kettle-steam-outline","tags":["home automation","food / drink","tea kettle steam outline","kettle empty steam","tea kettle empty steam"]},{"name":"mdi:kettlebell","tags":["sport"]},{"name":"mdi:key-alert","tags":["alert / error"]},{"name":"mdi:key-alert-outline","tags":["alert / error"]},{"name":"mdi:key-arrow-right","tags":[]},{"name":"mdi:key-chain","tags":["automotive","home automation"]},{"name":"mdi:key-chain-variant","tags":["automotive","home automation"]},{"name":"mdi:key-change","tags":[]},{"name":"mdi:key-link","tags":["foreign key","sql foreign key"]},{"name":"mdi:key-minus","tags":[]},{"name":"mdi:key-plus","tags":["key add"]},{"name":"mdi:key-remove","tags":[]},{"name":"mdi:key-star","tags":["primary key","sql primary key","key favorite"]},{"name":"mdi:key-variant","tags":["automotive"]},{"name":"mdi:key-wireless","tags":[]},{"name":"mdi:keyboard-close-outline","tags":["keyboard hide outline"]},{"name":"mdi:keyboard-esc","tags":[]},{"name":"mdi:keyboard-f1","tags":[]},{"name":"mdi:keyboard-f10","tags":[]},{"name":"mdi:keyboard-f11","tags":[]},{"name":"mdi:keyboard-f12","tags":[]},{"name":"mdi:keyboard-f2","tags":[]},{"name":"mdi:keyboard-f3","tags":[]},{"name":"mdi:keyboard-f4","tags":[]},{"name":"mdi:keyboard-f5","tags":[]},{"name":"mdi:keyboard-f6","tags":[]},{"name":"mdi:keyboard-f7","tags":[]},{"name":"mdi:keyboard-f8","tags":[]},{"name":"mdi:keyboard-f9","tags":[]},{"name":"mdi:keyboard-off","tags":[]},{"name":"mdi:keyboard-off-outline","tags":[]},{"name":"mdi:keyboard-settings","tags":["settings"]},{"name":"mdi:keyboard-settings-outline","tags":["settings"]},{"name":"mdi:keyboard-space","tags":[]},{"name":"mdi:keyboard-tab-reverse","tags":[]},{"name":"mdi:keyboard-variant","tags":[]},{"name":"mdi:khanda","tags":["religion","sikh"]},{"name":"mdi:klingon","tags":[]},{"name":"mdi:knife","tags":["silverware knife","cutlery knife"]},{"name":"mdi:knife-military","tags":["gaming / rpg","dagger"]},{"name":"mdi:knob","tags":["audio","volume knob","volume control","dial","tuner","switch","adjuster"]},{"name":"mdi:koala","tags":["animal","marsupial","emoji koala","emoticon koala"]},{"name":"mdi:label-multiple","tags":[]},{"name":"mdi:label-multiple-outline","tags":[]},{"name":"mdi:label-percent","tags":[]},{"name":"mdi:label-percent-outline","tags":[]},{"name":"mdi:ladder","tags":["hardware / tools"]},{"name":"mdi:lambda","tags":["gaming / rpg","math"]},{"name":"mdi:lamp","tags":["home automation"]},{"name":"mdi:lamp-outline","tags":["home automation"]},{"name":"mdi:lamps","tags":["home automation","lights"]},{"name":"mdi:lamps-outline","tags":["home automation","lights outline"]},{"name":"mdi:lan","tags":["local area network"]},{"name":"mdi:lan-check","tags":[]},{"name":"mdi:lan-connect","tags":["local area network connect"]},{"name":"mdi:lan-disconnect","tags":["local area network disconnect"]},{"name":"mdi:lan-pending","tags":["local area network pending"]},{"name":"mdi:land-fields","tags":["agriculture"]},{"name":"mdi:land-plots","tags":["agriculture"]},{"name":"mdi:land-plots-circle","tags":["agriculture"]},{"name":"mdi:land-plots-circle-variant","tags":["agriculture"]},{"name":"mdi:land-plots-marker","tags":["agriculture"]},{"name":"mdi:land-rows-horizontal","tags":["agriculture"]},{"name":"mdi:land-rows-vertical","tags":["agriculture"]},{"name":"mdi:laptop-account","tags":["account / user","device / tech","teleconference","virtual meeting","video chat"]},{"name":"mdi:laptop-off","tags":["device / tech"]},{"name":"mdi:lasso","tags":[]},{"name":"mdi:latitude","tags":["navigation","geographic information system"]},{"name":"mdi:lava-lamp","tags":["home automation"]},{"name":"mdi:layers-edit","tags":["geographic information system","edit / modify"]},{"name":"mdi:layers-minus","tags":["geographic information system"]},{"name":"mdi:layers-plus","tags":["geographic information system"]},{"name":"mdi:layers-remove","tags":["geographic information system"]},{"name":"mdi:layers-search","tags":["geographic information system"]},{"name":"mdi:layers-search-outline","tags":["geographic information system"]},{"name":"mdi:layers-triple","tags":[]},{"name":"mdi:layers-triple-outline","tags":[]},{"name":"mdi:leaf","tags":["nature","food / drink","agriculture"]},{"name":"mdi:leaf-circle","tags":["nature","agriculture","green circle","organic"]},{"name":"mdi:leaf-circle-outline","tags":["agriculture","nature","green circle outline","organic outline"]},{"name":"mdi:leaf-maple","tags":["nature"]},{"name":"mdi:leaf-maple-off","tags":["nature"]},{"name":"mdi:leaf-off","tags":["nature","food / drink","agriculture"]},{"name":"mdi:lectern","tags":["podium","dais","rostrum","lecturn"]},{"name":"mdi:led-off","tags":["home automation"]},{"name":"mdi:led-on","tags":["home automation"]},{"name":"mdi:led-outline","tags":["home automation"]},{"name":"mdi:led-strip","tags":["home automation","light strip"]},{"name":"mdi:led-strip-variant","tags":["home automation","light strip variant"]},{"name":"mdi:led-strip-variant-off","tags":["home automation","light strip variant off"]},{"name":"mdi:led-variant-off","tags":["home automation"]},{"name":"mdi:led-variant-on","tags":["home automation"]},{"name":"mdi:led-variant-outline","tags":["home automation"]},{"name":"mdi:leek","tags":["food / drink"]},{"name":"mdi:less-than","tags":["math"]},{"name":"mdi:less-than-or-equal","tags":["math"]},{"name":"mdi:library-outline","tags":["places","local library outline"]},{"name":"mdi:lifebuoy","tags":["transportation + water","life preserver","support","help","overboard"]},{"name":"mdi:light-flood-down","tags":["home automation","floodlight down"]},{"name":"mdi:light-flood-up","tags":["home automation","floodlight up"]},{"name":"mdi:light-recessed","tags":["home automation","can light","pot light","high hat light","hi hat light","downlight"]},{"name":"mdi:light-switch","tags":["home automation","toggle switch","rocker switch"]},{"name":"mdi:light-switch-off","tags":["home automation","toggle switch off","rocker switch off"]},{"name":"mdi:lightbulb-alert","tags":["home automation","alert / error","lightbulb error"]},{"name":"mdi:lightbulb-alert-outline","tags":["home automation","alert / error","lightbulb error outline"]},{"name":"mdi:lightbulb-auto","tags":["home automation","lightbulb automatic","lightbulb motion"]},{"name":"mdi:lightbulb-auto-outline","tags":["home automation","lightbulb automatic outline","lightbulb motion outline"]},{"name":"mdi:lightbulb-cfl","tags":["home automation","bulb cfl"]},{"name":"mdi:lightbulb-cfl-off","tags":["home automation","bulb cfl off"]},{"name":"mdi:lightbulb-cfl-spiral","tags":["home automation","bulb cfl spiral"]},{"name":"mdi:lightbulb-cfl-spiral-off","tags":["home automation","bulb cfl spiral off"]},{"name":"mdi:lightbulb-fluorescent-tube","tags":["home automation"]},{"name":"mdi:lightbulb-fluorescent-tube-outline","tags":["home automation"]},{"name":"mdi:lightbulb-group","tags":["home automation","bulb group"]},{"name":"mdi:lightbulb-group-off","tags":["home automation","bulb group off"]},{"name":"mdi:lightbulb-group-off-outline","tags":["home automation","bulb group off outline"]},{"name":"mdi:lightbulb-group-outline","tags":["home automation","bulb group outline"]},{"name":"mdi:lightbulb-multiple","tags":["home automation","lightbulbs","bulb multiple","bulbs"]},{"name":"mdi:lightbulb-multiple-off","tags":["home automation","lightbulbs off","bulb multiple off","bulbs off"]},{"name":"mdi:lightbulb-multiple-off-outline","tags":["home automation","lightbulbs off outline","bulb multiple off outline","bulbs off outline"]},{"name":"mdi:lightbulb-multiple-outline","tags":["home automation","lightbulbs outline","bulb multiple outline","bulbs outline"]},{"name":"mdi:lightbulb-night","tags":["home automation","night light","nite light","lightbulb moon star"]},{"name":"mdi:lightbulb-night-outline","tags":["home automation","night light outline","nite light outline","lightbulb moon star outline"]},{"name":"mdi:lightbulb-off","tags":["home automation","bulb off"]},{"name":"mdi:lightbulb-off-outline","tags":["home automation","bulb off outline"]},{"name":"mdi:lightbulb-on","tags":["home automation","idea","bulb on","lightbulb dimmer 100"]},{"name":"mdi:lightbulb-on-10","tags":["home automation","lightbulb dimmer 10"]},{"name":"mdi:lightbulb-on-20","tags":["home automation","lightbulb dimmer 20"]},{"name":"mdi:lightbulb-on-30","tags":["home automation","lightbulb dimmer 30"]},{"name":"mdi:lightbulb-on-40","tags":["home automation","lightbulb dimmer 40"]},{"name":"mdi:lightbulb-on-50","tags":["home automation","lightbulb dimmer 50"]},{"name":"mdi:lightbulb-on-60","tags":["home automation","lightbulb dimmer 60"]},{"name":"mdi:lightbulb-on-70","tags":["home automation","lightbulb dimmer 70"]},{"name":"mdi:lightbulb-on-80","tags":["home automation","lightbulb dimmer 80"]},{"name":"mdi:lightbulb-on-90","tags":["home automation","lightbulb dimmer 90"]},{"name":"mdi:lightbulb-on-outline","tags":["home automation","idea","bulb on outline"]},{"name":"mdi:lightbulb-outline","tags":["home automation","idea","bulb outline"]},{"name":"mdi:lightbulb-question","tags":["home automation","lightbulb help"]},{"name":"mdi:lightbulb-question-outline","tags":["home automation","lightbulb help outline"]},{"name":"mdi:lightbulb-spot","tags":["home automation","lightbulb halogen","lightbulb gu10"]},{"name":"mdi:lightbulb-spot-off","tags":["home automation","lightbulb halogen off","lightbulb gu10 off"]},{"name":"mdi:lightbulb-variant","tags":["home automation","lightbulb edison","lightbulb filament"]},{"name":"mdi:lightbulb-variant-outline","tags":["home automation","lightbulb edison outline","lightbulb filament outline"]},{"name":"mdi:lighthouse","tags":["beacon"]},{"name":"mdi:lighthouse-on","tags":["beacon"]},{"name":"mdi:lightning-bolt","tags":["home automation","weather","thunder","storm","energy","electricity"]},{"name":"mdi:lightning-bolt-outline","tags":["home automation","weather","thunder outline","storm outline","energy outline","electricity outline"]},{"name":"mdi:line-scan","tags":[]},{"name":"mdi:lingerie","tags":["clothing","underwear","bra","panties"]},{"name":"mdi:link-box","tags":[]},{"name":"mdi:link-box-outline","tags":[]},{"name":"mdi:link-box-variant","tags":[]},{"name":"mdi:link-box-variant-outline","tags":[]},{"name":"mdi:link-lock","tags":["lock","block chain"]},{"name":"mdi:link-variant","tags":[]},{"name":"mdi:link-variant-minus","tags":[]},{"name":"mdi:link-variant-off","tags":[]},{"name":"mdi:link-variant-plus","tags":[]},{"name":"mdi:link-variant-remove","tags":[]},{"name":"mdi:lipstick","tags":["health / beauty"]},{"name":"mdi:liquid-spot","tags":["automotive","medical / hospital","ink spot","puddle","water","blood","spill","oil","dirty"]},{"name":"mdi:list-box","tags":["form"]},{"name":"mdi:list-box-outline","tags":["form outline"]},{"name":"mdi:loading","tags":[]},{"name":"mdi:location-enter","tags":["home automation","presence enter"]},{"name":"mdi:location-exit","tags":["home automation","presence exit"]},{"name":"mdi:lock-alert","tags":["lock","alert / error","home automation","lock warning","password alert","encryption alert","password warning","encryption warning"]},{"name":"mdi:lock-alert-outline","tags":["home automation","alert / error","lock","lock warning outline","password alert outline","encryption alert outline","password warning outline","encryption warning outline"]},{"name":"mdi:lock-check","tags":["lock","password check","password secure","encryption check","encryption secure","password verified","encryption verified"]},{"name":"mdi:lock-check-outline","tags":["lock","password check outline","password secure outline","encryption check outline","encryption secure outline","password verified outline","encryption verified outline"]},{"name":"mdi:lock-minus","tags":["lock","password minus","encryption minus"]},{"name":"mdi:lock-minus-outline","tags":["lock","password minus outline","encryption minus"]},{"name":"mdi:lock-off","tags":["lock","password off","not protected","unsecure","encryption off"]},{"name":"mdi:lock-off-outline","tags":["lock","password off outline","unsecure outline","not protected outline","encryption off outline"]},{"name":"mdi:lock-open-alert","tags":["alert / error","home automation","lock","unlocked alert","decrypted alert","lock open warning","unlocked warning","decrypted warning"]},{"name":"mdi:lock-open-alert-outline","tags":["home automation","alert / error","lock","unlocked alert outline","lock open warning outline","decrypted alert outline","unlocked warning outline","decrypted warning outline"]},{"name":"mdi:lock-open-check","tags":["lock","unlocked check","decrypted check"]},{"name":"mdi:lock-open-check-outline","tags":["lock","unlocked check outline","decrypted check outline"]},{"name":"mdi:lock-open-minus","tags":["lock","unlocked minus","decrypted minus"]},{"name":"mdi:lock-open-minus-outline","tags":["lock","unlocked minus outline","decrypted minus outline"]},{"name":"mdi:lock-open-plus","tags":["lock","unlocked plus","decrypted plus","lock open add","unlocked add","decrypted add"]},{"name":"mdi:lock-open-plus-outline","tags":["lock","unlocked plus outline","lock open add outline","unlocked add outline","decrypted plus outline","decrypted add outline"]},{"name":"mdi:lock-open-remove","tags":["lock","unlocked remove","decrypted remove"]},{"name":"mdi:lock-open-remove-outline","tags":["lock","unlocked remove outline","decrypted remove outline"]},{"name":"mdi:lock-open-variant","tags":["lock","home automation","unlocked variant","decrypted variant"]},{"name":"mdi:lock-open-variant-outline","tags":["lock","home automation","unlocked variant outline","decrypted variant outline"]},{"name":"mdi:lock-pattern","tags":[]},{"name":"mdi:lock-percent","tags":["lock rate"]},{"name":"mdi:lock-percent-open","tags":["lock rate open"]},{"name":"mdi:lock-percent-open-outline","tags":["lock rate open outline"]},{"name":"mdi:lock-percent-open-variant","tags":["lock rate open variant"]},{"name":"mdi:lock-percent-open-variant-outline","tags":["lock rate open variant outline"]},{"name":"mdi:lock-percent-outline","tags":["lock rate outline"]},{"name":"mdi:lock-plus","tags":["lock","enhanced encryption","lock add","encryption add","password add","password plus","encryption plus"]},{"name":"mdi:lock-plus-outline","tags":["lock","lock add outline","password plus outline","password add outline","encryption plus outline","encryption add outline"]},{"name":"mdi:lock-question","tags":["lock","forgot password","password question","encryption question"]},{"name":"mdi:lock-remove","tags":["lock","password remove","encryption remove"]},{"name":"mdi:lock-remove-outline","tags":["lock","password remove outline","encryption remove outline"]},{"name":"mdi:lock-smart","tags":["home automation"]},{"name":"mdi:locker","tags":[]},{"name":"mdi:locker-multiple","tags":["lockers"]},{"name":"mdi:login","tags":["log in","sign in"]},{"name":"mdi:login-variant","tags":["log in variant","sign in variant"]},{"name":"mdi:logout","tags":["log out","sign out"]},{"name":"mdi:logout-variant","tags":["log out variant","sign out variant"]},{"name":"mdi:longitude","tags":["navigation","geographic information system"]},{"name":"mdi:lotion","tags":["medical / hospital","health / beauty"]},{"name":"mdi:lotion-outline","tags":["medical / hospital","health / beauty"]},{"name":"mdi:lungs","tags":["medical / hospital"]},{"name":"mdi:mace","tags":["gaming / rpg"]},{"name":"mdi:magazine-pistol","tags":["ammunition pistol"]},{"name":"mdi:magazine-rifle","tags":["ammunition rifle"]},{"name":"mdi:magic-staff","tags":["gaming / rpg","staff shimmer","magic wand"]},{"name":"mdi:magnet","tags":[]},{"name":"mdi:magnet-on","tags":[]},{"name":"mdi:magnify-close","tags":[]},{"name":"mdi:magnify-expand","tags":["geographic information system","search expand"]},{"name":"mdi:magnify-minus","tags":["zoom out","search minus"]},{"name":"mdi:magnify-minus-cursor","tags":["zoom out cursor"]},{"name":"mdi:magnify-plus","tags":["zoom in","magnify add","search plus","search add"]},{"name":"mdi:magnify-plus-cursor","tags":["zoom in cursor","magnify add cursor"]},{"name":"mdi:magnify-remove-cursor","tags":[]},{"name":"mdi:magnify-remove-outline","tags":["geographic information system"]},{"name":"mdi:magnify-scan","tags":[]},{"name":"mdi:mail","tags":[]},{"name":"mdi:mailbox","tags":[]},{"name":"mdi:mailbox-open","tags":[]},{"name":"mdi:mailbox-open-outline","tags":[]},{"name":"mdi:mailbox-open-up","tags":[]},{"name":"mdi:mailbox-open-up-outline","tags":[]},{"name":"mdi:mailbox-outline","tags":[]},{"name":"mdi:mailbox-up","tags":[]},{"name":"mdi:mailbox-up-outline","tags":[]},{"name":"mdi:map-check","tags":["navigation","geographic information system","map tick"]},{"name":"mdi:map-check-outline","tags":["navigation","geographic information system","map tick outline"]},{"name":"mdi:map-clock","tags":["navigation","geographic information system","date / time","timezone"]},{"name":"mdi:map-clock-outline","tags":["navigation","geographic information system","date / time","timezone outline"]},{"name":"mdi:map-legend","tags":["navigation","geographic information system"]},{"name":"mdi:map-marker-alert","tags":["navigation","alert / error","geographic information system","location alert","location warning"]},{"name":"mdi:map-marker-alert-outline","tags":["navigation","alert / error","geographic information system","location alert outline","location warning outline"]},{"name":"mdi:map-marker-check-outline","tags":["navigation","geographic information system","location check outline","where to vote outline"]},{"name":"mdi:map-marker-distance","tags":["navigation","geographic information system","location distance"]},{"name":"mdi:map-marker-down","tags":["navigation","geographic information system","location down"]},{"name":"mdi:map-marker-left","tags":["navigation","geographic information system","location left"]},{"name":"mdi:map-marker-left-outline","tags":["navigation","geographic information system","location left outline"]},{"name":"mdi:map-marker-minus","tags":["navigation","geographic information system","location minus"]},{"name":"mdi:map-marker-minus-outline","tags":["geographic information system","navigation","location minus outline"]},{"name":"mdi:map-marker-multiple","tags":["navigation","geographic information system","map markers","location multiple","locations"]},{"name":"mdi:map-marker-multiple-outline","tags":["navigation","geographic information system","locations outline","location multiple outline","map markers outline"]},{"name":"mdi:map-marker-off","tags":["navigation","geographic information system","location off"]},{"name":"mdi:map-marker-off-outline","tags":["navigation","geographic information system","location off outline"]},{"name":"mdi:map-marker-path","tags":["navigation","geographic information system","location path"]},{"name":"mdi:map-marker-plus","tags":["navigation","geographic information system","location plus","map marker add","location add"]},{"name":"mdi:map-marker-plus-outline","tags":["geographic information system","navigation","map marker add outline","location plus outline","location add outline"]},{"name":"mdi:map-marker-radius","tags":["navigation","geographic information system","home automation","location radius"]},{"name":"mdi:map-marker-radius-outline","tags":["navigation","geographic information system","home automation","location radius outline"]},{"name":"mdi:map-marker-remove","tags":["navigation","geographic information system","location remove"]},{"name":"mdi:map-marker-remove-outline","tags":["geographic information system","navigation","location remove outline"]},{"name":"mdi:map-marker-remove-variant","tags":["navigation","geographic information system","location remove variant outline"]},{"name":"mdi:map-marker-right","tags":["navigation","geographic information system","location right"]},{"name":"mdi:map-marker-right-outline","tags":["navigation","geographic information system","location right outline"]},{"name":"mdi:map-marker-star","tags":["navigation","map marker favorite","location star","location favorite"]},{"name":"mdi:map-marker-star-outline","tags":["navigation","map marker favorite outline","location star outline","location favorite outline"]},{"name":"mdi:map-marker-up","tags":["navigation","geographic information system","location up"]},{"name":"mdi:map-minus","tags":["navigation","geographic information system"]},{"name":"mdi:map-plus","tags":["navigation","geographic information system","map add"]},{"name":"mdi:map-search","tags":["navigation","geographic information system"]},{"name":"mdi:map-search-outline","tags":["navigation","geographic information system"]},{"name":"mdi:margin","tags":[]},{"name":"mdi:marker-cancel","tags":["text / content / format"]},{"name":"mdi:math-compass","tags":["math","drawing / art","navigation","maths compass"]},{"name":"mdi:math-cos","tags":["math","math cosine","maths cos"]},{"name":"mdi:math-integral","tags":["math"]},{"name":"mdi:math-integral-box","tags":["math"]},{"name":"mdi:math-log","tags":["math"]},{"name":"mdi:math-norm","tags":["math","developer / languages","code or","parallel"]},{"name":"mdi:math-norm-box","tags":["math","developer / languages","code or box","parallel box"]},{"name":"mdi:math-sin","tags":["math","math sine","maths sin"]},{"name":"mdi:math-tan","tags":["math","math tangent","maths tan"]},{"name":"mdi:matrix","tags":[]},{"name":"mdi:medal","tags":["gaming / rpg","sport","award"]},{"name":"mdi:medal-outline","tags":["sport"]},{"name":"mdi:medical-bag","tags":["medical / hospital","first aid kit","medicine"]},{"name":"mdi:menorah","tags":["religion","holiday","candelabrum","candelabra","candle"]},{"name":"mdi:menorah-fire","tags":["religion","holiday","menorah flame","candle flame","candelabra flame","candelabra fire","candle fire","candelabrum fire","candelabrum flame"]},{"name":"mdi:menu-down-outline","tags":["arrow","caret down outline"]},{"name":"mdi:menu-left","tags":["arrow","arrow left"]},{"name":"mdi:menu-left-outline","tags":[]},{"name":"mdi:menu-right","tags":["arrow","arrow right"]},{"name":"mdi:menu-right-outline","tags":[]},{"name":"mdi:menu-swap","tags":["arrow"]},{"name":"mdi:menu-swap-outline","tags":["arrow"]},{"name":"mdi:menu-up-outline","tags":["arrow","caret up outline"]},{"name":"mdi:message-alert-outline","tags":["alert / error","announcement outline","feedback outline","message warning outline","sms failed outline"]},{"name":"mdi:message-arrow-left","tags":[]},{"name":"mdi:message-arrow-left-outline","tags":[]},{"name":"mdi:message-arrow-right","tags":[]},{"name":"mdi:message-arrow-right-outline","tags":[]},{"name":"mdi:message-check","tags":[]},{"name":"mdi:message-check-outline","tags":[]},{"name":"mdi:message-cog","tags":["settings"]},{"name":"mdi:message-cog-outline","tags":["settings"]},{"name":"mdi:message-fast","tags":[]},{"name":"mdi:message-fast-outline","tags":[]},{"name":"mdi:message-image-outline","tags":[]},{"name":"mdi:message-lock","tags":["lock","message secure"]},{"name":"mdi:message-lock-outline","tags":["lock"]},{"name":"mdi:message-minus","tags":[]},{"name":"mdi:message-minus-outline","tags":[]},{"name":"mdi:message-off","tags":[]},{"name":"mdi:message-off-outline","tags":[]},{"name":"mdi:message-plus","tags":["message add"]},{"name":"mdi:message-plus-outline","tags":[]},{"name":"mdi:message-processing-outline","tags":[]},{"name":"mdi:message-question","tags":[]},{"name":"mdi:message-question-outline","tags":[]},{"name":"mdi:message-reply-outline","tags":[]},{"name":"mdi:message-reply-text-outline","tags":[]},{"name":"mdi:message-settings","tags":["settings"]},{"name":"mdi:message-settings-outline","tags":["settings"]},{"name":"mdi:message-star","tags":[]},{"name":"mdi:message-star-outline","tags":[]},{"name":"mdi:message-text-clock","tags":["date / time"]},{"name":"mdi:message-text-clock-outline","tags":["date / time"]},{"name":"mdi:message-text-fast","tags":[]},{"name":"mdi:message-text-fast-outline","tags":[]},{"name":"mdi:message-text-lock","tags":["lock","message text secure"]},{"name":"mdi:message-text-lock-outline","tags":["lock"]},{"name":"mdi:message-text-outline","tags":[]},{"name":"mdi:metronome","tags":["music","tempo","bpm","beats per minute"]},{"name":"mdi:metronome-tick","tags":["music","tempo tick","bpm tick","beats per minute tick"]},{"name":"mdi:micro-sd","tags":[]},{"name":"mdi:microphone-message","tags":["tts","text to speech"]},{"name":"mdi:microphone-message-off","tags":["tts off","text to speech off"]},{"name":"mdi:microphone-minus","tags":["microphone remove"]},{"name":"mdi:microphone-plus","tags":["microphone add"]},{"name":"mdi:microphone-question","tags":["audio","music","microphone help"]},{"name":"mdi:microphone-question-outline","tags":["audio","music","microphone help outline"]},{"name":"mdi:microphone-variant","tags":["music"]},{"name":"mdi:microphone-variant-off","tags":["music"]},{"name":"mdi:microscope","tags":["science"]},{"name":"mdi:microsoft-xbox-controller-battery-unknown","tags":["battery","gaming / rpg","microsoft xbox gamepad battery unknown"]},{"name":"mdi:microwave","tags":["home automation","food / drink","microwave oven"]},{"name":"mdi:microwave-off","tags":["home automation"]},{"name":"mdi:middleware","tags":["arrow"]},{"name":"mdi:middleware-outline","tags":["arrow"]},{"name":"mdi:midi-port","tags":["music"]},{"name":"mdi:mine","tags":[]},{"name":"mdi:mini-sd","tags":[]},{"name":"mdi:minidisc","tags":[]},{"name":"mdi:minus-box-multiple","tags":["form","library minus"]},{"name":"mdi:minus-box-multiple-outline","tags":["form","library minus outline"]},{"name":"mdi:minus-circle-multiple","tags":["form","coins minus"]},{"name":"mdi:minus-circle-multiple-outline","tags":["form","coins minus outline"]},{"name":"mdi:minus-circle-off","tags":["do not disturb off","remove circle off","do not enter off"]},{"name":"mdi:minus-circle-off-outline","tags":["do not disturb off outline","remove circle off outline","do not enter off outline"]},{"name":"mdi:minus-network","tags":[]},{"name":"mdi:minus-network-outline","tags":[]},{"name":"mdi:minus-thick","tags":[]},{"name":"mdi:mirror","tags":["home automation"]},{"name":"mdi:mirror-rectangle","tags":["home automation"]},{"name":"mdi:mirror-variant","tags":["home automation"]},{"name":"mdi:mixed-reality","tags":[]},{"name":"mdi:molecule","tags":["science"]},{"name":"mdi:molecule-co","tags":["home automation","science","carbon monoxide","gas co"]},{"name":"mdi:molecule-co2","tags":["science","home automation","periodic table carbon dioxide","gas co2"]},{"name":"mdi:monitor-account","tags":["account / user","device / tech","teleconference","virtual meeting","video chat"]},{"name":"mdi:monitor-arrow-down","tags":["device / tech","monitor download"]},{"name":"mdi:monitor-arrow-down-variant","tags":["device / tech","monitor download"]},{"name":"mdi:monitor-dashboard","tags":["device / tech"]},{"name":"mdi:monitor-edit","tags":["edit / modify"]},{"name":"mdi:monitor-eye","tags":[]},{"name":"mdi:monitor-lock","tags":["device / tech","lock"]},{"name":"mdi:monitor-multiple","tags":["device / tech","monitors"]},{"name":"mdi:monitor-shimmer","tags":["device / tech","monitor clean"]},{"name":"mdi:monitor-small","tags":["device / tech","monitor crt"]},{"name":"mdi:monitor-speaker","tags":["device / tech"]},{"name":"mdi:monitor-speaker-off","tags":["device / tech"]},{"name":"mdi:monitor-star","tags":["device / tech","monitor favorite"]},{"name":"mdi:monitor-vertical","tags":[]},{"name":"mdi:moon-first-quarter","tags":["weather"]},{"name":"mdi:moon-full","tags":["weather"]},{"name":"mdi:moon-last-quarter","tags":["weather"]},{"name":"mdi:moon-new","tags":["weather"]},{"name":"mdi:moon-waning-crescent","tags":["weather"]},{"name":"mdi:moon-waning-gibbous","tags":["weather"]},{"name":"mdi:moon-waxing-crescent","tags":["weather"]},{"name":"mdi:moon-waxing-gibbous","tags":["weather"]},{"name":"mdi:mortar-pestle","tags":[]},{"name":"mdi:mother-heart","tags":["people / family"]},{"name":"mdi:mother-nurse","tags":["medical / hospital","people / family","breast feed"]},{"name":"mdi:motion-sensor","tags":["home automation","motion detector"]},{"name":"mdi:motion-sensor-off","tags":["home automation"]},{"name":"mdi:motorbike-electric","tags":["transportation + road","motorcycle electric"]},{"name":"mdi:motorbike-off","tags":["transportation + road","motorcycle off"]},{"name":"mdi:mouse-bluetooth","tags":[]},{"name":"mdi:mouse-move-down","tags":[]},{"name":"mdi:mouse-move-up","tags":[]},{"name":"mdi:mouse-move-vertical","tags":[]},{"name":"mdi:mouse-off","tags":[]},{"name":"mdi:mouse-variant","tags":[]},{"name":"mdi:mouse-variant-off","tags":[]},{"name":"mdi:move-resize","tags":[]},{"name":"mdi:move-resize-variant","tags":[]},{"name":"mdi:movie-check","tags":["video / movie","slate check","clapperboard check","film check"]},{"name":"mdi:movie-check-outline","tags":["video / movie","slate check outline","clapperboard check outline","film check outline"]},{"name":"mdi:movie-cog","tags":["video / movie","settings","slate cog","clapperboard cog","film cog"]},{"name":"mdi:movie-cog-outline","tags":["video / movie","settings","slate cog outline","clapperboard cog outline","film cog outline"]},{"name":"mdi:movie-edit","tags":["video / movie","edit / modify","slate edit","clapperboard edit","film edit"]},{"name":"mdi:movie-edit-outline","tags":["video / movie","edit / modify","slate edit outline","clapperboard edit outline","film edit outline"]},{"name":"mdi:movie-minus","tags":["video / movie","slate minus","clapperboard minus","film minus"]},{"name":"mdi:movie-minus-outline","tags":["video / movie","slate minus outline","clapperboard minus outline","film minus outline"]},{"name":"mdi:movie-off","tags":["video / movie","slate off","clapperboard off","film off"]},{"name":"mdi:movie-off-outline","tags":["video / movie","slate off outline","clapperboard off outline","film off outline"]},{"name":"mdi:movie-open","tags":["video / movie","slate open","clapperboard open","film open","movie creation"]},{"name":"mdi:movie-open-check","tags":["video / movie","slate open check","clapperboard open check","film open check"]},{"name":"mdi:movie-open-check-outline","tags":["video / movie","slate open check outline","clapperboard open check outline","film open check outline"]},{"name":"mdi:movie-open-cog","tags":["video / movie","settings","slate open cog","clapperboard open cog","film open cog"]},{"name":"mdi:movie-open-cog-outline","tags":["video / movie","settings","slate open cog outline","clapperboard open cog outline","film open cog outline"]},{"name":"mdi:movie-open-edit","tags":["video / movie","edit / modify","slate open edit","clapperboard open edit","film open edit"]},{"name":"mdi:movie-open-edit-outline","tags":["video / movie","edit / modify","slate open edit outline","clapperboard open edit outline","film open edit outline"]},{"name":"mdi:movie-open-minus","tags":["video / movie","slate open minus","clapperboard open minus","film open minus"]},{"name":"mdi:movie-open-minus-outline","tags":["video / movie","slate open minus outline","clapperboard open minus outline","film open minus outline"]},{"name":"mdi:movie-open-off","tags":["video / movie","slate open off","clapperboard open off","film open off"]},{"name":"mdi:movie-open-off-outline","tags":["video / movie","slate open off outline","clapperboard open off outline","film open off outline"]},{"name":"mdi:movie-open-outline","tags":["video / movie","slate open outline","clapperboard open outline","film open outline","movie creation"]},{"name":"mdi:movie-open-play","tags":["video / movie","slate open play","clapperboard open play","film open play"]},{"name":"mdi:movie-open-play-outline","tags":["video / movie","slate open play outline","clapperboard open play outline","film open play outline"]},{"name":"mdi:movie-open-plus","tags":["video / movie","clapperboard open plus","slate open plus","flim open plus"]},{"name":"mdi:movie-open-plus-outline","tags":["video / movie","slate open plus outline","clapperboard open plus outline","film open plus outline"]},{"name":"mdi:movie-open-remove","tags":["video / movie","slate open remove","clapperboard open remove","film open remove"]},{"name":"mdi:movie-open-remove-outline","tags":["video / movie","slate open remove outline","clapperboard open remove outline","film open remove outline"]},{"name":"mdi:movie-open-settings","tags":["video / movie","settings","slate open settings","clapperboard open settings","film open settings"]},{"name":"mdi:movie-open-settings-outline","tags":["video / movie","settings","slate open settings outline","clapperboard open settings outline","film open settings outline"]},{"name":"mdi:movie-open-star","tags":["video / movie","slate open star","clapperboard open star","film open star","movie open favorite"]},{"name":"mdi:movie-open-star-outline","tags":["video / movie","slate open star outline","clapperboard open star outline","film open star outline","movie open favorite outline"]},{"name":"mdi:movie-play","tags":["video / movie","slate play","clapperboard play","film play"]},{"name":"mdi:movie-play-outline","tags":["video / movie","slate play outline","clapperboard play outline","film play outline"]},{"name":"mdi:movie-plus","tags":["video / movie","slate plus","clapperboard plus","film plus"]},{"name":"mdi:movie-plus-outline","tags":["video / movie","slate plus outline","clapperboard plus outline","film plus outline"]},{"name":"mdi:movie-remove","tags":["video / movie","slate remove","clapperboard remove","film remove"]},{"name":"mdi:movie-remove-outline","tags":["video / movie","slate remove outline","clapperboard remove outline","film remove outline"]},{"name":"mdi:movie-roll","tags":["video / movie","film reel"]},{"name":"mdi:movie-search","tags":["video / movie"]},{"name":"mdi:movie-search-outline","tags":["video / movie"]},{"name":"mdi:movie-settings","tags":["video / movie","settings","slate settings","clapperboard settings","film settings"]},{"name":"mdi:movie-settings-outline","tags":["video / movie","settings","slate settings outline","clapperboard settings outline","film settings outline"]},{"name":"mdi:movie-star","tags":["video / movie","slate star","clapperboard star","film star","movie favorite"]},{"name":"mdi:movie-star-outline","tags":["video / movie","slate star outline","clapperboard star outline","film star outline","movie favorite outline"]},{"name":"mdi:mower","tags":["hardware / tools","home automation"]},{"name":"mdi:mower-bag","tags":["hardware / tools","home automation"]},{"name":"mdi:mower-bag-on","tags":["hardware / tools","home automation"]},{"name":"mdi:mower-on","tags":["hardware / tools","home automation"]},{"name":"mdi:muffin","tags":["food / drink"]},{"name":"mdi:multicast","tags":["multiplex","broadcast"]},{"name":"mdi:multimedia","tags":["audio","video / movie","photography","audio","video","image","music","movie","picture"]},{"name":"mdi:multiplication","tags":["math"]},{"name":"mdi:multiplication-box","tags":["math"]},{"name":"mdi:mushroom","tags":["nature","food / drink","agriculture","fungus"]},{"name":"mdi:mushroom-off","tags":["food / drink","nature","agriculture"]},{"name":"mdi:mushroom-off-outline","tags":["food / drink","nature","agriculture"]},{"name":"mdi:mushroom-outline","tags":["nature","food / drink","agriculture","fungus outline"]},{"name":"mdi:music","tags":["audio","music"]},{"name":"mdi:music-accidental-double-flat","tags":["music"]},{"name":"mdi:music-accidental-double-sharp","tags":["music"]},{"name":"mdi:music-accidental-flat","tags":["music"]},{"name":"mdi:music-accidental-natural","tags":["music"]},{"name":"mdi:music-accidental-sharp","tags":["music"]},{"name":"mdi:music-box","tags":["audio","music"]},{"name":"mdi:music-box-multiple-outline","tags":["music","library music outline"]},{"name":"mdi:music-box-outline","tags":["audio","music"]},{"name":"mdi:music-circle","tags":["audio","music","note circle"]},{"name":"mdi:music-circle-outline","tags":["music","audio","note circle outline"]},{"name":"mdi:music-clef-alto","tags":["music","music c clef","music clef tenor","music clef soprano","music clef baritone"]},{"name":"mdi:music-clef-bass","tags":["music","music f clef"]},{"name":"mdi:music-clef-treble","tags":["music","music g clef"]},{"name":"mdi:music-note","tags":["audio","music"]},{"name":"mdi:music-note-bluetooth","tags":["audio","music"]},{"name":"mdi:music-note-bluetooth-off","tags":["audio","music"]},{"name":"mdi:music-note-eighth","tags":["audio","music"]},{"name":"mdi:music-note-eighth-dotted","tags":["music"]},{"name":"mdi:music-note-half","tags":["audio","music"]},{"name":"mdi:music-note-half-dotted","tags":["music"]},{"name":"mdi:music-note-minus","tags":[]},{"name":"mdi:music-note-off","tags":["audio","music"]},{"name":"mdi:music-note-off-outline","tags":["music"]},{"name":"mdi:music-note-outline","tags":["music"]},{"name":"mdi:music-note-plus","tags":["audio","music","music note add"]},{"name":"mdi:music-note-quarter","tags":["audio","music"]},{"name":"mdi:music-note-quarter-dotted","tags":["music"]},{"name":"mdi:music-note-sixteenth","tags":["audio","music"]},{"name":"mdi:music-note-sixteenth-dotted","tags":["music"]},{"name":"mdi:music-note-whole","tags":["audio","music"]},{"name":"mdi:music-note-whole-dotted","tags":["music"]},{"name":"mdi:music-off","tags":["audio","music"]},{"name":"mdi:music-rest-eighth","tags":["music"]},{"name":"mdi:music-rest-half","tags":["music"]},{"name":"mdi:music-rest-quarter","tags":["music"]},{"name":"mdi:music-rest-sixteenth","tags":["music"]},{"name":"mdi:music-rest-whole","tags":["music"]},{"name":"mdi:nail","tags":["hardware / tools"]},{"name":"mdi:nas","tags":["network attached storage"]},{"name":"mdi:nature-outline","tags":["nature"]},{"name":"mdi:nature-people-outline","tags":["account / user","nature"]},{"name":"mdi:necklace","tags":["clothing"]},{"name":"mdi:needle","tags":["medical / hospital","syringe","injection","medicine","shot","drug","immunization","pharmaceutical"]},{"name":"mdi:needle-off","tags":["medical / hospital","syringe off","injection off","medicine off","shot off","drug off","immunization off","pharmaceutical off"]},{"name":"mdi:network","tags":[]},{"name":"mdi:network-off","tags":[]},{"name":"mdi:network-off-outline","tags":[]},{"name":"mdi:network-outline","tags":[]},{"name":"mdi:network-pos","tags":["banking","network point of sale","network cash box"]},{"name":"mdi:network-strength-1","tags":["cellphone / phone"]},{"name":"mdi:network-strength-1-alert","tags":["cellphone / phone","alert / error","network strength 1 warning"]},{"name":"mdi:network-strength-2","tags":["cellphone / phone"]},{"name":"mdi:network-strength-2-alert","tags":["cellphone / phone","alert / error","network strength 2 warning"]},{"name":"mdi:network-strength-3","tags":["cellphone / phone"]},{"name":"mdi:network-strength-3-alert","tags":["cellphone / phone","alert / error","network strength 3 warning"]},{"name":"mdi:network-strength-4","tags":["cellphone / phone"]},{"name":"mdi:network-strength-4-alert","tags":["cellphone / phone","alert / error","network strength 4 warning"]},{"name":"mdi:network-strength-4-cog","tags":["settings","network strength 4 settings","data settings"]},{"name":"mdi:network-strength-off","tags":["cellphone / phone"]},{"name":"mdi:network-strength-off-outline","tags":["cellphone / phone"]},{"name":"mdi:network-strength-outline","tags":["cellphone / phone","network strength 0"]},{"name":"mdi:newspaper-check","tags":[]},{"name":"mdi:newspaper-minus","tags":[]},{"name":"mdi:newspaper-plus","tags":[]},{"name":"mdi:newspaper-remove","tags":[]},{"name":"mdi:newspaper-variant-multiple","tags":[]},{"name":"mdi:newspaper-variant-multiple-outline","tags":[]},{"name":"mdi:nfc-search-variant","tags":[]},{"name":"mdi:nfc-tap","tags":["near field communication tap"]},{"name":"mdi:nfc-variant-off","tags":["home automation","near field communication off"]},{"name":"mdi:ninja","tags":[]},{"name":"mdi:nintendo-game-boy","tags":["gaming / rpg"]},{"name":"mdi:not-equal","tags":[]},{"name":"mdi:not-equal-variant","tags":["math"]},{"name":"mdi:note","tags":["paper","sticky note","post it note"]},{"name":"mdi:note-alert","tags":["alert / error","paper alert","sticky note alert","post it note alert"]},{"name":"mdi:note-alert-outline","tags":["alert / error","paper alert outline","post it note alert outline","sticky note alert outline"]},{"name":"mdi:note-check","tags":["paper check","sticky note check","post it note check"]},{"name":"mdi:note-check-outline","tags":["paper check outline","sticky note check outline","post it note check outline"]},{"name":"mdi:note-edit","tags":["edit / modify","paper edit","sticky note edit","post it note edit"]},{"name":"mdi:note-edit-outline","tags":["edit / modify","paper edit outline","sticky note edit outline","post it note edit outline"]},{"name":"mdi:note-minus","tags":["paper minus","sticky note minus","post it note minus"]},{"name":"mdi:note-minus-outline","tags":["paper minus outline","sticky note minus outline","post it note minus outline"]},{"name":"mdi:note-multiple","tags":["notes","papers","sticky notes","post it notes"]},{"name":"mdi:note-multiple-outline","tags":["notes outline","papers outline","sticky notes outline","post it notes outline"]},{"name":"mdi:note-off","tags":["paper off","sticky note off","post it note off"]},{"name":"mdi:note-off-outline","tags":["paper off outline","sticky note off outline","post it note off outline"]},{"name":"mdi:note-outline","tags":["paper outline","sticky note outline","post it note outline"]},{"name":"mdi:note-plus","tags":["note add","paper plus","paper add","sticky note plus","sticky note add","post it note plus","post it note add"]},{"name":"mdi:note-plus-outline","tags":["note add outline","paper plus outline","paper add outline","sticky note plus outline","sticky note add outline","post it note plus outline","post it note add outline"]},{"name":"mdi:note-remove","tags":["paper remove","sticky note remove","post it note remove"]},{"name":"mdi:note-remove-outline","tags":[]},{"name":"mdi:note-search","tags":["paper search","sticky note search","post it note search"]},{"name":"mdi:note-search-outline","tags":["paper search outline","sticky note search outline","post it note search outline"]},{"name":"mdi:note-text","tags":["paper text","sticky note text","post it note text"]},{"name":"mdi:note-text-outline","tags":["paper text outline","sticky note text outline","post it note text outline"]},{"name":"mdi:notebook","tags":["journal","planner","diary"]},{"name":"mdi:notebook-check","tags":[]},{"name":"mdi:notebook-check-outline","tags":[]},{"name":"mdi:notebook-edit","tags":["edit / modify"]},{"name":"mdi:notebook-edit-outline","tags":["edit / modify"]},{"name":"mdi:notebook-heart","tags":["notebook favorite","notebook love"]},{"name":"mdi:notebook-heart-outline","tags":["notebook favorite outline","notebook love outline"]},{"name":"mdi:notebook-minus","tags":[]},{"name":"mdi:notebook-minus-outline","tags":[]},{"name":"mdi:notebook-multiple","tags":["journal multiple","planner multiple"]},{"name":"mdi:notebook-outline","tags":["journal outline","planner outline"]},{"name":"mdi:notebook-plus","tags":[]},{"name":"mdi:notebook-plus-outline","tags":[]},{"name":"mdi:notebook-remove","tags":[]},{"name":"mdi:notebook-remove-outline","tags":[]},{"name":"mdi:nuke","tags":["nuclear","atomic bomb"]},{"name":"mdi:null","tags":[]},{"name":"mdi:numeric","tags":["alpha / numeric","numbers","1 2 3","one two three","123"]},{"name":"mdi:numeric-0","tags":["alpha / numeric","number 0","numeric zero"]},{"name":"mdi:numeric-0-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-0-circle","tags":["alpha / numeric","numeric zero circle","number 0 circle","number zero circle"]},{"name":"mdi:numeric-0-circle-outline","tags":["alpha / numeric","numeric zero circle outline","number 0 circle outline","number zero circle outline"]},{"name":"mdi:numeric-1","tags":["alpha / numeric","number 1","numeric one"]},{"name":"mdi:numeric-1-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-1-circle","tags":["alpha / numeric","numeric one circle","number 1 circle","number one circle"]},{"name":"mdi:numeric-1-circle-outline","tags":["alpha / numeric","numeric one circle outline","number 1 circle outline","number one circle outline"]},{"name":"mdi:numeric-10","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-box","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-box-multiple-outline","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-box-outline","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-circle","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-circle-outline","tags":["alpha / numeric"]},{"name":"mdi:numeric-2","tags":["alpha / numeric","number 2","numeric two"]},{"name":"mdi:numeric-2-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-2-circle","tags":["alpha / numeric","numeric two circle","number 2 circle","number two circle"]},{"name":"mdi:numeric-2-circle-outline","tags":["alpha / numeric","numeric two circle outline","number 2 circle outline","number two circle outline"]},{"name":"mdi:numeric-3","tags":["alpha / numeric","number 3","numeric three"]},{"name":"mdi:numeric-3-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-3-circle","tags":["alpha / numeric","numeric three circle","number 3 circle","number three circle"]},{"name":"mdi:numeric-3-circle-outline","tags":["alpha / numeric","numeric three circle outline","number 3 circle outline","number three circle outline"]},{"name":"mdi:numeric-4","tags":["alpha / numeric","number 4","numeric four"]},{"name":"mdi:numeric-4-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-4-circle","tags":["alpha / numeric","numeric four circle","number 4 circle","number four circle"]},{"name":"mdi:numeric-4-circle-outline","tags":["alpha / numeric","numeric four circle outline","number 4 circle outline","number four circle outline"]},{"name":"mdi:numeric-5","tags":["alpha / numeric","number 5","numeric five"]},{"name":"mdi:numeric-5-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-5-circle","tags":["alpha / numeric","numeric five circle","number 5 circle","number five circle"]},{"name":"mdi:numeric-5-circle-outline","tags":["alpha / numeric","numeric five circle outline","number 5 circle outline","number five circle outline"]},{"name":"mdi:numeric-6","tags":["alpha / numeric","number 6","numeric six"]},{"name":"mdi:numeric-6-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-6-circle","tags":["alpha / numeric","numeric six circle","number 6 circle","number six circle"]},{"name":"mdi:numeric-6-circle-outline","tags":["alpha / numeric","numeric six circle outline","number 6 circle outline","number six circle outline"]},{"name":"mdi:numeric-7","tags":["alpha / numeric","number 7","numeric seven"]},{"name":"mdi:numeric-7-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-7-circle","tags":["alpha / numeric","numeric seven circle","number 7 circle","number seven circle"]},{"name":"mdi:numeric-7-circle-outline","tags":["alpha / numeric","numeric seven circle outline","number 7 circle outline","number seven circle outline"]},{"name":"mdi:numeric-8","tags":["alpha / numeric","number 8","numeric eight"]},{"name":"mdi:numeric-8-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-8-circle","tags":["alpha / numeric","numeric eight circle","number 8 circle","number eight circle"]},{"name":"mdi:numeric-8-circle-outline","tags":["alpha / numeric","numeric eight circle outline","number 8 circle outline","number eight circle outline"]},{"name":"mdi:numeric-9","tags":["alpha / numeric","number 9","numeric nine"]},{"name":"mdi:numeric-9-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-9-circle","tags":["alpha / numeric","numeric nine circle","number 9 circle","number nine circle"]},{"name":"mdi:numeric-9-circle-outline","tags":["alpha / numeric","numeric nine circle outline","number 9 circle outline","number nine circle outline"]},{"name":"mdi:numeric-9-plus","tags":["alpha / numeric"]},{"name":"mdi:numeric-9-plus-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-9-plus-circle","tags":["alpha / numeric","numeric nine plus circle","number 9 plus circle","number nine plus circle"]},{"name":"mdi:numeric-9-plus-circle-outline","tags":["alpha / numeric","numeric nine plus circle outline","number 9 plus circle outline","number nine plus circle outline"]},{"name":"mdi:numeric-negative-1","tags":["alpha / numeric","decrement","minus one"]},{"name":"mdi:numeric-off","tags":["alpha / numeric","numbers off","123 off","one two three off"]},{"name":"mdi:numeric-positive-1","tags":["alpha / numeric","increment","plus one"]},{"name":"mdi:nut","tags":["hardware / tools"]},{"name":"mdi:nutrition","tags":["food / drink"]},{"name":"mdi:oar","tags":[]},{"name":"mdi:ocarina","tags":["music","gaming / rpg"]},{"name":"mdi:ocr","tags":["optical character recognition"]},{"name":"mdi:octagon","tags":["shape","transportation + road","stop"]},{"name":"mdi:octagon-outline","tags":["shape","transportation + road","stop outline"]},{"name":"mdi:octagram","tags":["shape","starburst"]},{"name":"mdi:octagram-edit","tags":["shape","starburst edit"]},{"name":"mdi:octagram-edit-outline","tags":["shape","starburst edit outline"]},{"name":"mdi:octagram-minus","tags":["shape","starburst plus"]},{"name":"mdi:octagram-minus-outline","tags":["shape","starburst minus outline"]},{"name":"mdi:octagram-outline","tags":["shape","starburst outline"]},{"name":"mdi:octagram-plus","tags":["shape","starburst plus"]},{"name":"mdi:octagram-plus-outline","tags":[]},{"name":"mdi:octahedron","tags":["shape"]},{"name":"mdi:octahedron-off","tags":["shape"]},{"name":"mdi:offer","tags":[]},{"name":"mdi:office-building","tags":["places"]},{"name":"mdi:office-building-cog","tags":["settings","places","office building settings"]},{"name":"mdi:office-building-cog-outline","tags":["settings","places","office building settings outline"]},{"name":"mdi:office-building-marker","tags":["navigation","places","office building location"]},{"name":"mdi:office-building-marker-outline","tags":["navigation","places","office building location outline"]},{"name":"mdi:office-building-minus","tags":[]},{"name":"mdi:office-building-minus-outline","tags":[]},{"name":"mdi:office-building-outline","tags":["places"]},{"name":"mdi:office-building-plus","tags":[]},{"name":"mdi:office-building-plus-outline","tags":[]},{"name":"mdi:office-building-remove","tags":[]},{"name":"mdi:office-building-remove-outline","tags":[]},{"name":"mdi:oil","tags":["automotive"]},{"name":"mdi:oil-lamp","tags":["wish","genie lamp"]},{"name":"mdi:oil-level","tags":["automotive"]},{"name":"mdi:oil-temperature","tags":["automotive"]},{"name":"mdi:om","tags":["religion","religion hindu","hinduism"]},{"name":"mdi:omega","tags":["ohm","electrical resistance"]},{"name":"mdi:one-up","tags":["gaming / rpg","1up","extra life"]},{"name":"mdi:orbit","tags":["science"]},{"name":"mdi:orbit-variant","tags":["photography","camera flip"]},{"name":"mdi:order-alphabetical-ascending","tags":["text / content / format"]},{"name":"mdi:order-alphabetical-descending","tags":["text / content / format"]},{"name":"mdi:order-bool-ascending","tags":["text / content / format"]},{"name":"mdi:order-bool-ascending-variant","tags":["text / content / format","order checkbox ascending"]},{"name":"mdi:order-bool-descending","tags":["text / content / format","order checkbox descending"]},{"name":"mdi:order-bool-descending-variant","tags":["text / content / format"]},{"name":"mdi:order-numeric-ascending","tags":["text / content / format"]},{"name":"mdi:order-numeric-descending","tags":["text / content / format"]},{"name":"mdi:ornament","tags":["holiday"]},{"name":"mdi:ornament-variant","tags":["holiday"]},{"name":"mdi:outdoor-lamp","tags":["home automation","outdoor light"]},{"name":"mdi:owl","tags":["animal","holiday"]},{"name":"mdi:pac-man","tags":["gaming / rpg"]},{"name":"mdi:package","tags":["box"]},{"name":"mdi:package-check","tags":["package delivered"]},{"name":"mdi:package-up","tags":["unarchive","box up","this side up"]},{"name":"mdi:package-variant","tags":["box variant"]},{"name":"mdi:package-variant-closed","tags":["box variant closed"]},{"name":"mdi:package-variant-closed-check","tags":["package variant closed delivered"]},{"name":"mdi:package-variant-closed-minus","tags":["package variant closed subtract","box variant closed minus","box variant closed subtract"]},{"name":"mdi:package-variant-closed-plus","tags":["box variant closed plus","package variant closed add","box variant closed add"]},{"name":"mdi:package-variant-closed-remove","tags":["box variant closed remove"]},{"name":"mdi:package-variant-minus","tags":["box variant minus","package variant subtract","box variant subtract"]},{"name":"mdi:package-variant-plus","tags":["box variant plus","package variant add","box variant add"]},{"name":"mdi:package-variant-remove","tags":["box variant remove"]},{"name":"mdi:page-layout-body","tags":[]},{"name":"mdi:page-layout-footer","tags":[]},{"name":"mdi:page-layout-header","tags":[]},{"name":"mdi:page-layout-header-footer","tags":["page layout marginals"]},{"name":"mdi:page-layout-sidebar-left","tags":[]},{"name":"mdi:page-layout-sidebar-right","tags":[]},{"name":"mdi:page-next","tags":["read more"]},{"name":"mdi:page-next-outline","tags":["read more outline"]},{"name":"mdi:page-previous","tags":[]},{"name":"mdi:page-previous-outline","tags":[]},{"name":"mdi:pail","tags":["bucket"]},{"name":"mdi:pail-minus","tags":["bucket minus"]},{"name":"mdi:pail-minus-outline","tags":["bucket minus outline"]},{"name":"mdi:pail-off","tags":["bucket off"]},{"name":"mdi:pail-off-outline","tags":["bucket off outline"]},{"name":"mdi:pail-outline","tags":["bucket outline"]},{"name":"mdi:pail-plus","tags":["bucket plus"]},{"name":"mdi:pail-plus-outline","tags":["bucket plus outline"]},{"name":"mdi:pail-remove","tags":["bucket remove"]},{"name":"mdi:pail-remove-outline","tags":["bucket remove outline"]},{"name":"mdi:palette-advanced","tags":["color","drawing / art","paint"]},{"name":"mdi:palette-swatch-variant","tags":["drawing / art","color","style","paint","material"]},{"name":"mdi:palm-tree","tags":["nature"]},{"name":"mdi:pan","tags":[]},{"name":"mdi:pan-bottom-left","tags":["pan down left"]},{"name":"mdi:pan-bottom-right","tags":["pan down right"]},{"name":"mdi:pan-down","tags":[]},{"name":"mdi:pan-horizontal","tags":[]},{"name":"mdi:pan-left","tags":[]},{"name":"mdi:pan-right","tags":[]},{"name":"mdi:pan-top-left","tags":["pan up left"]},{"name":"mdi:pan-top-right","tags":["pan up right"]},{"name":"mdi:pan-up","tags":[]},{"name":"mdi:pan-vertical","tags":[]},{"name":"mdi:panda","tags":["animal","emoji panda","emoticon panda"]},{"name":"mdi:paper-cut-vertical","tags":[]},{"name":"mdi:paper-roll","tags":["home automation","printer","lavatory roll","bathroom tissue","toilet paper","kitchen roll","paper towels","receipt roll"]},{"name":"mdi:paper-roll-outline","tags":["home automation","printer","lavatory roll outline","bathroom tissue outline","kitchen roll outline","paper towels outline","toilet paper outline","receipt roll outline"]},{"name":"mdi:paperclip-check","tags":["paperclip tick","attachment check","attachment tick"]},{"name":"mdi:paperclip-lock","tags":["lock","attachment lock"]},{"name":"mdi:paperclip-minus","tags":["paperclip subtract","attachment minus","attachment subtract"]},{"name":"mdi:paperclip-off","tags":["attachment off"]},{"name":"mdi:paperclip-plus","tags":["paperclip add","attachment plus","attachment add"]},{"name":"mdi:paperclip-remove","tags":["attachment remove"]},{"name":"mdi:parachute","tags":["transportation + flying"]},{"name":"mdi:parachute-outline","tags":["transportation + flying"]},{"name":"mdi:passport","tags":[]},{"name":"mdi:passport-biometric","tags":["passport electronic"]},{"name":"mdi:patio-heater","tags":["home automation"]},{"name":"mdi:pause-box","tags":["audio","music"]},{"name":"mdi:pause-box-outline","tags":["audio","music"]},{"name":"mdi:pause-octagon","tags":["stop pause"]},{"name":"mdi:pause-octagon-outline","tags":["stop pause outline"]},{"name":"mdi:paw","tags":["animal","nature","pets"]},{"name":"mdi:paw-off","tags":["animal"]},{"name":"mdi:paw-off-outline","tags":["animal"]},{"name":"mdi:paw-outline","tags":["animal"]},{"name":"mdi:peace","tags":[]},{"name":"mdi:peanut","tags":["food / drink","agriculture","allergen","food allergy"]},{"name":"mdi:peanut-off","tags":["food / drink","agriculture","allergen off","food allergy off"]},{"name":"mdi:peanut-off-outline","tags":["food / drink","agriculture","allergen off outline","food allergy off outline"]},{"name":"mdi:peanut-outline","tags":["food / drink","agriculture","allergen outline","food allergy outline"]},{"name":"mdi:pen","tags":["drawing / art"]},{"name":"mdi:pen-lock","tags":["lock"]},{"name":"mdi:pen-minus","tags":[]},{"name":"mdi:pen-off","tags":[]},{"name":"mdi:pen-plus","tags":["pen add"]},{"name":"mdi:pen-remove","tags":[]},{"name":"mdi:pencil-box","tags":["drawing / art","edit box"]},{"name":"mdi:pencil-box-multiple","tags":["edit / modify","library edit"]},{"name":"mdi:pencil-box-multiple-outline","tags":["edit / modify","library edit outline"]},{"name":"mdi:pencil-box-outline","tags":["drawing / art","edit box outline"]},{"name":"mdi:pencil-circle","tags":["drawing / art","edit circle"]},{"name":"mdi:pencil-circle-outline","tags":["drawing / art","edit circle outline"]},{"name":"mdi:pencil-lock","tags":["lock"]},{"name":"mdi:pencil-lock-outline","tags":["lock"]},{"name":"mdi:pencil-minus","tags":[]},{"name":"mdi:pencil-minus-outline","tags":[]},{"name":"mdi:pencil-off","tags":["edit off"]},{"name":"mdi:pencil-off-outline","tags":["edit off outline"]},{"name":"mdi:pencil-plus","tags":["pencil add"]},{"name":"mdi:pencil-plus-outline","tags":["pencil add outline"]},{"name":"mdi:pencil-remove","tags":[]},{"name":"mdi:pencil-remove-outline","tags":[]},{"name":"mdi:pencil-ruler","tags":["drawing / art","design"]},{"name":"mdi:pencil-ruler-outline","tags":["drawing / art"]},{"name":"mdi:penguin","tags":["animal","emoji penguin","emoticon penguin","linux"]},{"name":"mdi:pentagon","tags":["shape"]},{"name":"mdi:pentagon-outline","tags":["shape"]},{"name":"mdi:pentagram","tags":[]},{"name":"mdi:percent","tags":["math","shopping","discount","sale"]},{"name":"mdi:percent-box","tags":["math","shopping","discount box","sale box"]},{"name":"mdi:percent-box-outline","tags":["math","shopping","discount box outline","sale box outline"]},{"name":"mdi:percent-circle","tags":["math","shopping","discount circle","sale circle"]},{"name":"mdi:percent-circle-outline","tags":["math","shopping","discount circle outline","sale circle outline"]},{"name":"mdi:percent-outline","tags":["math","shopping","discount outline","sale outline"]},{"name":"mdi:periodic-table","tags":["science"]},{"name":"mdi:perspective-less","tags":["math","perspective decrease"]},{"name":"mdi:perspective-more","tags":["math","perspective increase"]},{"name":"mdi:ph","tags":["science","home automation","acid","base","potential of hydrogen","power of hydrogen"]},{"name":"mdi:phone-alert","tags":["cellphone / phone","alert / error"]},{"name":"mdi:phone-alert-outline","tags":["cellphone / phone","alert / error"]},{"name":"mdi:phone-cancel","tags":["cellphone / phone","phone block"]},{"name":"mdi:phone-cancel-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-check","tags":["cellphone / phone"]},{"name":"mdi:phone-check-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-classic","tags":["cellphone / phone"]},{"name":"mdi:phone-classic-off","tags":[]},{"name":"mdi:phone-clock","tags":["cellphone / phone","date / time","phone schedule","phone time"]},{"name":"mdi:phone-dial","tags":["cellphone / phone","phone keypad"]},{"name":"mdi:phone-dial-outline","tags":["cellphone / phone","phone keypad outline"]},{"name":"mdi:phone-incoming","tags":["cellphone / phone","telephone incoming"]},{"name":"mdi:phone-incoming-outgoing","tags":["cellphone / phone"]},{"name":"mdi:phone-incoming-outgoing-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-log","tags":["cellphone / phone"]},{"name":"mdi:phone-log-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-off","tags":["cellphone / phone"]},{"name":"mdi:phone-outgoing","tags":["cellphone / phone"]},{"name":"mdi:phone-outgoing-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-refresh","tags":["cellphone / phone","phone redial"]},{"name":"mdi:phone-refresh-outline","tags":["cellphone / phone","phone redial outline"]},{"name":"mdi:phone-remove","tags":["cellphone / phone"]},{"name":"mdi:phone-remove-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-return","tags":["cellphone / phone"]},{"name":"mdi:phone-return-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-rotate-landscape","tags":["cellphone / phone"]},{"name":"mdi:phone-rotate-portrait","tags":["cellphone / phone"]},{"name":"mdi:phone-sync","tags":["cellphone / phone","phone redial"]},{"name":"mdi:phone-sync-outline","tags":["cellphone / phone","phone redial outline"]},{"name":"mdi:phone-voip","tags":["cellphone / phone"]},{"name":"mdi:pi","tags":["math"]},{"name":"mdi:pi-box","tags":["math"]},{"name":"mdi:pickaxe","tags":[]},{"name":"mdi:pier","tags":["places","transportation + water"]},{"name":"mdi:pier-crane","tags":["transportation + water","places"]},{"name":"mdi:pig","tags":["animal","agriculture","emoji pig","emoticon pig"]},{"name":"mdi:pill","tags":["medical / hospital","medicine","capsule","drug","pharmaceutical"]},{"name":"mdi:pill-multiple","tags":["medical / hospital","medicine","medication","drugs"]},{"name":"mdi:pill-off","tags":["medical / hospital","medicine off","capsule off","drug off","pharmaceutical off"]},{"name":"mdi:pillar","tags":["historic","column"]},{"name":"mdi:pin-off","tags":["keep off"]},{"name":"mdi:pin-off-outline","tags":["keep off outline"]},{"name":"mdi:pine-tree","tags":["holiday","nature","places","agriculture","forest","plant"]},{"name":"mdi:pine-tree-box","tags":["holiday","nature","agriculture","plant"]},{"name":"mdi:pine-tree-fire","tags":["nature","agriculture","wildfire","controlled burn"]},{"name":"mdi:pine-tree-variant","tags":["nature","places","agriculture"]},{"name":"mdi:pine-tree-variant-outline","tags":["places","nature","agriculture"]},{"name":"mdi:pipe","tags":["home automation"]},{"name":"mdi:pipe-disconnected","tags":["home automation"]},{"name":"mdi:pipe-leak","tags":["home automation"]},{"name":"mdi:pipe-valve","tags":["home automation"]},{"name":"mdi:pirate","tags":[]},{"name":"mdi:pistol","tags":["gun"]},{"name":"mdi:piston","tags":["automotive"]},{"name":"mdi:pitchfork","tags":["hardware / tools"]},{"name":"mdi:plane-car","tags":["transportation + flying","transportation + road","airport shuttle","airport taxi","airplane car"]},{"name":"mdi:plane-train","tags":["transportation + flying","transportation + other","airport shuttle","airplane train"]},{"name":"mdi:play-box","tags":[]},{"name":"mdi:play-box-edit-outline","tags":[]},{"name":"mdi:play-box-lock","tags":["video / movie","lock"]},{"name":"mdi:play-box-lock-open","tags":["video / movie","lock"]},{"name":"mdi:play-box-lock-open-outline","tags":["video / movie","lock"]},{"name":"mdi:play-box-lock-outline","tags":["video / movie","lock"]},{"name":"mdi:play-network","tags":["media network"]},{"name":"mdi:play-network-outline","tags":["media network outline"]},{"name":"mdi:play-outline","tags":[]},{"name":"mdi:play-pause","tags":["home automation"]},{"name":"mdi:playlist-edit","tags":["edit / modify"]},{"name":"mdi:playlist-minus","tags":[]},{"name":"mdi:pliers","tags":["hardware / tools"]},{"name":"mdi:plus-box-multiple-outline","tags":[]},{"name":"mdi:plus-circle-multiple","tags":["coins plus"]},{"name":"mdi:plus-lock","tags":["lock","plus secure"]},{"name":"mdi:plus-lock-open","tags":["lock"]},{"name":"mdi:plus-minus","tags":["math"]},{"name":"mdi:plus-minus-box","tags":["math"]},{"name":"mdi:plus-minus-variant","tags":["math"]},{"name":"mdi:plus-network","tags":["add network"]},{"name":"mdi:plus-network-outline","tags":["add network outline"]},{"name":"mdi:plus-outline","tags":[]},{"name":"mdi:plus-thick","tags":["math","add thick","add bold","plus bold"]},{"name":"mdi:podium","tags":["sport"]},{"name":"mdi:podium-bronze","tags":["sport","podium third"]},{"name":"mdi:podium-gold","tags":["sport","podium first"]},{"name":"mdi:podium-silver","tags":["sport","podium second"]},{"name":"mdi:point-of-sale","tags":[]},{"name":"mdi:pokeball","tags":["gaming / rpg"]},{"name":"mdi:poker-chip","tags":["gaming / rpg","casino chip","gambling chip"]},{"name":"mdi:polaroid","tags":[]},{"name":"mdi:police-badge","tags":[]},{"name":"mdi:police-badge-outline","tags":[]},{"name":"mdi:police-station","tags":["places"]},{"name":"mdi:poll","tags":["bar chart","report","performance","analytics"]},{"name":"mdi:pool","tags":["places","home automation","swimming pool"]},{"name":"mdi:pool-thermometer","tags":["home automation","pool temperature"]},{"name":"mdi:popcorn","tags":["food / drink"]},{"name":"mdi:post-lamp","tags":["home automation","post light"]},{"name":"mdi:post-outline","tags":["blog outline"]},{"name":"mdi:postage-stamp","tags":[]},{"name":"mdi:pot","tags":["food / drink","holiday"]},{"name":"mdi:pot-mix","tags":["food / drink","holiday"]},{"name":"mdi:pot-mix-outline","tags":["food / drink","holiday"]},{"name":"mdi:pot-outline","tags":["food / drink","holiday"]},{"name":"mdi:pot-steam","tags":["food / drink","holiday"]},{"name":"mdi:pot-steam-outline","tags":["food / drink","holiday"]},{"name":"mdi:pound","tags":["hashtag"]},{"name":"mdi:pound-box","tags":["hashtag box"]},{"name":"mdi:pound-box-outline","tags":["hashtag box outline"]},{"name":"mdi:power-cycle","tags":[]},{"name":"mdi:power-off","tags":[]},{"name":"mdi:power-on","tags":[]},{"name":"mdi:power-plug-battery","tags":["home automation","battery","battery backup"]},{"name":"mdi:power-plug-battery-outline","tags":["home automation","battery","battery backup outline"]},{"name":"mdi:power-plug-off","tags":["home automation","power off"]},{"name":"mdi:power-plug-off-outline","tags":["home automation"]},{"name":"mdi:power-plug-outline","tags":["home automation"]},{"name":"mdi:power-sleep","tags":[]},{"name":"mdi:power-socket","tags":["home automation","plug socket"]},{"name":"mdi:power-socket-au","tags":["home automation","plug socket au","power socket type i","power socket cn","power socket ar","power socket nz","power socket pg","power socket australia","power socket china","power socket argentina","power socket new zealand","power socket papua new guinea"]},{"name":"mdi:power-socket-ch","tags":["home automation","plug socket ch","power socket type j","plug socket type j","power socket switzerland","plug socket switzerland"]},{"name":"mdi:power-socket-de","tags":["home automation"]},{"name":"mdi:power-socket-eu","tags":["home automation","plug socket eu","power socket europe"]},{"name":"mdi:power-socket-fr","tags":["home automation"]},{"name":"mdi:power-socket-it","tags":[]},{"name":"mdi:power-socket-jp","tags":["home automation"]},{"name":"mdi:power-socket-uk","tags":["home automation","plug socket uk","power socket type g","power socket ie","power socket hk","power socket my","power socket cy","power socket mt","power socket sg","power socket united kingdom","power socket ireland","power socket hong kong","power socket malaysia","power socket cyprus","power socket malta","power socket singapore"]},{"name":"mdi:power-socket-us","tags":["home automation","plug socket us","power socket ca","power socket mx","power socket type b","power socket united states","power socket japan","power socket canada","power socket mexico"]},{"name":"mdi:power-standby","tags":[]},{"name":"mdi:powershell","tags":[]},{"name":"mdi:prescription","tags":["medical / hospital"]},{"name":"mdi:presentation","tags":[]},{"name":"mdi:presentation-play","tags":[]},{"name":"mdi:pretzel","tags":["food / drink"]},{"name":"mdi:printer-3d","tags":["printer","home automation"]},{"name":"mdi:printer-3d-nozzle","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-alert","tags":["alert / error","printer"]},{"name":"mdi:printer-3d-nozzle-alert-outline","tags":["alert / error","printer"]},{"name":"mdi:printer-3d-nozzle-heat","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-heat-outline","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-off","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-off-outline","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-outline","tags":["printer"]},{"name":"mdi:printer-3d-off","tags":["printer"]},{"name":"mdi:printer-alert","tags":["printer","home automation","alert / error","printer warning","paper jam"]},{"name":"mdi:printer-check","tags":["printer"]},{"name":"mdi:printer-eye","tags":["printer","printer preview","printer view"]},{"name":"mdi:printer-off","tags":["printer"]},{"name":"mdi:printer-pos","tags":["printer","printer point of sale","printer receipt"]},{"name":"mdi:printer-pos-alert","tags":["alert / error","printer","printer point of sale alert","printer receipt alert"]},{"name":"mdi:printer-pos-alert-outline","tags":["printer","alert / error","printer point of sale alert outline","printer receipt alert outline"]},{"name":"mdi:printer-pos-cancel","tags":["printer","printer point of sale cancel","printer receipt cancel"]},{"name":"mdi:printer-pos-cancel-outline","tags":["printer","printer point of sale cancel outline","printer receipt cancel outline"]},{"name":"mdi:printer-pos-check","tags":["printer","printer point of sale check","printer receipt check"]},{"name":"mdi:printer-pos-check-outline","tags":["printer","printer point of sale check outline","printer receipt check outline"]},{"name":"mdi:printer-pos-cog","tags":["printer","printer point of sale cog","printer receipt cog"]},{"name":"mdi:printer-pos-cog-outline","tags":["printer","printer point of sale cog outline","printer receipt cog outline"]},{"name":"mdi:printer-pos-edit","tags":["printer","printer point of sale edit","printer receipt edit"]},{"name":"mdi:printer-pos-edit-outline","tags":["printer","printer point of sale edit outline","printer receipt edit outline"]},{"name":"mdi:printer-pos-minus","tags":["printer","printer point of sale minus","printer receipt minus"]},{"name":"mdi:printer-pos-minus-outline","tags":["printer","printer point of sale minus outline","printer receipt minus outline"]},{"name":"mdi:printer-pos-network","tags":["printer","printer point of sale network","printer receipt network"]},{"name":"mdi:printer-pos-network-outline","tags":["printer","printer point of sale network outline","printer receipt network outline"]},{"name":"mdi:printer-pos-off","tags":["printer","printer point of sale off","printer receipt off"]},{"name":"mdi:printer-pos-off-outline","tags":["printer","printer point of sale off outline","printer receipt off outline"]},{"name":"mdi:printer-pos-outline","tags":["printer","printer point of sale outline","printer receipt outline"]},{"name":"mdi:printer-pos-pause","tags":["printer","printer point of sale pause","printer receipt pause"]},{"name":"mdi:printer-pos-pause-outline","tags":["printer","printer point of sale pause outline","printer receipt pause outline"]},{"name":"mdi:printer-pos-play","tags":["printer","printer point of sale play","printer receipt play"]},{"name":"mdi:printer-pos-play-outline","tags":["printer","printer point of sale play outline","printer receipt play outline"]},{"name":"mdi:printer-pos-plus","tags":["printer","printer point of sale plus","printer receipt plus"]},{"name":"mdi:printer-pos-plus-outline","tags":["printer","printer point of sale plus outline","printer receipt plus outline"]},{"name":"mdi:printer-pos-refresh","tags":["printer","printer point of sale refresh","printer receipt refresh"]},{"name":"mdi:printer-pos-refresh-outline","tags":["printer","printer point of sale refresh outline","printer receipt refresh outline"]},{"name":"mdi:printer-pos-remove","tags":["printer","printer point of sale remove","printer receipt remove"]},{"name":"mdi:printer-pos-remove-outline","tags":["printer","printer point of sale remove outline","printer receipt remove outline"]},{"name":"mdi:printer-pos-star","tags":["printer","printer point of sale star","printer receipt star","printer favorite","printer primary"]},{"name":"mdi:printer-pos-star-outline","tags":["printer","printer point of sale star outline","printer receipt star outline"]},{"name":"mdi:printer-pos-stop","tags":["printer","printer point of sale stop","printer receipt stop"]},{"name":"mdi:printer-pos-stop-outline","tags":["printer","printer point of sale stop outline","printer receipt stop outline"]},{"name":"mdi:printer-pos-sync","tags":["printer","printer point of sale sync","printer receipt sync"]},{"name":"mdi:printer-pos-sync-outline","tags":["printer","printer point of sale sync outline","printer receipt sync outline"]},{"name":"mdi:printer-pos-wrench","tags":["printer","printer point of sale wrench","printer receipt wrench"]},{"name":"mdi:printer-pos-wrench-outline","tags":["printer","printer point of sale wrench outline","printer receipt wrench outline"]},{"name":"mdi:printer-search","tags":["printer","printer preview","printer magnify"]},{"name":"mdi:printer-settings","tags":["settings","printer"]},{"name":"mdi:printer-wireless","tags":["printer"]},{"name":"mdi:professional-hexagon","tags":[]},{"name":"mdi:progress-alert","tags":["alert / error","progress warning"]},{"name":"mdi:progress-check","tags":["progress tick"]},{"name":"mdi:progress-clock","tags":["date / time"]},{"name":"mdi:progress-close","tags":[]},{"name":"mdi:progress-download","tags":[]},{"name":"mdi:progress-helper","tags":[]},{"name":"mdi:progress-pencil","tags":[]},{"name":"mdi:progress-question","tags":[]},{"name":"mdi:progress-star","tags":[]},{"name":"mdi:progress-star-four-points","tags":["progress auto"]},{"name":"mdi:progress-upload","tags":[]},{"name":"mdi:progress-wrench","tags":["hardware / tools","progress spanner"]},{"name":"mdi:projector","tags":["device / tech","home automation"]},{"name":"mdi:projector-off","tags":["device / tech","home automation"]},{"name":"mdi:projector-screen","tags":["device / tech","home automation"]},{"name":"mdi:projector-screen-off","tags":["home automation"]},{"name":"mdi:projector-screen-off-outline","tags":["home automation"]},{"name":"mdi:projector-screen-outline","tags":["home automation"]},{"name":"mdi:projector-screen-variant","tags":["home automation"]},{"name":"mdi:projector-screen-variant-off","tags":["home automation"]},{"name":"mdi:projector-screen-variant-off-outline","tags":["home automation"]},{"name":"mdi:projector-screen-variant-outline","tags":["home automation"]},{"name":"mdi:protocol","tags":[]},{"name":"mdi:publish-off","tags":["arrow","publish disabled"]},{"name":"mdi:pulse","tags":["medical / hospital","vitals"]},{"name":"mdi:pump","tags":[]},{"name":"mdi:pump-off","tags":[]},{"name":"mdi:pumpkin","tags":["holiday"]},{"name":"mdi:purse","tags":[]},{"name":"mdi:purse-outline","tags":[]},{"name":"mdi:puzzle-check","tags":["gaming / rpg"]},{"name":"mdi:puzzle-check-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-edit","tags":["gaming / rpg","edit / modify"]},{"name":"mdi:puzzle-edit-outline","tags":["gaming / rpg","edit / modify"]},{"name":"mdi:puzzle-heart","tags":["gaming / rpg"]},{"name":"mdi:puzzle-heart-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-minus","tags":["gaming / rpg"]},{"name":"mdi:puzzle-minus-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-plus","tags":["gaming / rpg"]},{"name":"mdi:puzzle-plus-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-remove","tags":["gaming / rpg"]},{"name":"mdi:puzzle-remove-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-star","tags":["gaming / rpg","puzzle favorite"]},{"name":"mdi:puzzle-star-outline","tags":["gaming / rpg","puzzle favorite outline"]},{"name":"mdi:pyramid","tags":["shape"]},{"name":"mdi:pyramid-off","tags":["shape"]},{"name":"mdi:qrcode","tags":[]},{"name":"mdi:qrcode-edit","tags":["edit / modify"]},{"name":"mdi:qrcode-minus","tags":[]},{"name":"mdi:qrcode-plus","tags":[]},{"name":"mdi:qrcode-remove","tags":[]},{"name":"mdi:qrcode-scan","tags":[]},{"name":"mdi:quadcopter","tags":["drone"]},{"name":"mdi:quality-low","tags":["low quality","lq"]},{"name":"mdi:quality-medium","tags":["medium quality","mq"]},{"name":"mdi:quora","tags":[]},{"name":"mdi:rabbit","tags":["animal","nature","bunny","hare"]},{"name":"mdi:radiator","tags":["home automation","heater"]},{"name":"mdi:radiator-disabled","tags":["home automation","heater disabled"]},{"name":"mdi:radiator-off","tags":["home automation","heater off"]},{"name":"mdi:radio-am","tags":["audio"]},{"name":"mdi:radio-fm","tags":["audio"]},{"name":"mdi:radio-handheld","tags":["device / tech"]},{"name":"mdi:radio-off","tags":[]},{"name":"mdi:radio-tower","tags":[]},{"name":"mdi:radioactive","tags":["science","radiation"]},{"name":"mdi:radioactive-circle","tags":["science","radiation circle"]},{"name":"mdi:radioactive-circle-outline","tags":["science","radiation circle outline"]},{"name":"mdi:radioactive-off","tags":["science","radiation off"]},{"name":"mdi:radiobox-indeterminate-variant","tags":["form","radio button indeterminate","radiobox intermediate variant"]},{"name":"mdi:radiology-box","tags":["medical / hospital","x ray box"]},{"name":"mdi:radiology-box-outline","tags":["medical / hospital","x ray box outline"]},{"name":"mdi:radius","tags":["math","circle radius","sphere radius"]},{"name":"mdi:radius-outline","tags":["math","circle radius outline","sphere radius outline"]},{"name":"mdi:railroad-light","tags":["transportation + other","railroad crossing light","train crossing light","level crossing signals"]},{"name":"mdi:rake","tags":["hardware / tools"]},{"name":"mdi:raspberry-pi","tags":["raspberrypi"]},{"name":"mdi:ray-end","tags":[]},{"name":"mdi:ray-end-arrow","tags":[]},{"name":"mdi:ray-start","tags":[]},{"name":"mdi:ray-start-arrow","tags":[]},{"name":"mdi:ray-start-end","tags":[]},{"name":"mdi:ray-vertex","tags":[]},{"name":"mdi:razor-double-edge","tags":["health / beauty","hardware / tools"]},{"name":"mdi:razor-single-edge","tags":["hardware / tools"]},{"name":"mdi:read","tags":[]},{"name":"mdi:receipt","tags":["cloth","fabric","swatch"]},{"name":"mdi:receipt-clock","tags":["receipt pending"]},{"name":"mdi:receipt-clock-outline","tags":["receipt pending"]},{"name":"mdi:receipt-outline","tags":["cloth outline","fabric outline","swatch outline"]},{"name":"mdi:receipt-send","tags":[]},{"name":"mdi:receipt-send-outline","tags":[]},{"name":"mdi:receipt-text-arrow-left","tags":["invoice arrow left","invoice receive"]},{"name":"mdi:receipt-text-arrow-left-outline","tags":["invoice arrow left outline","invoice receive outline"]},{"name":"mdi:receipt-text-arrow-right","tags":["invoice arrow right","invoice send"]},{"name":"mdi:receipt-text-arrow-right-outline","tags":["invoice arrow right outline","invoice send outline"]},{"name":"mdi:receipt-text-check","tags":["invoice check"]},{"name":"mdi:receipt-text-check-outline","tags":["invoice check outline"]},{"name":"mdi:receipt-text-clock","tags":["invoice clock","invoice schedule","receipt text pending"]},{"name":"mdi:receipt-text-clock-outline","tags":["invoice clock outline","invoice schedule outline","receipt text pending"]},{"name":"mdi:receipt-text-edit","tags":["invoice edit"]},{"name":"mdi:receipt-text-edit-outline","tags":["invoice edit outline"]},{"name":"mdi:receipt-text-minus","tags":["invoice minus"]},{"name":"mdi:receipt-text-minus-outline","tags":["invoice minus outline"]},{"name":"mdi:receipt-text-plus","tags":["invoice plus","invoice add","receipt text add"]},{"name":"mdi:receipt-text-plus-outline","tags":["invoice plus","invoice add","receipt text add"]},{"name":"mdi:receipt-text-remove","tags":["invoice remove"]},{"name":"mdi:receipt-text-remove-outline","tags":["invoice remove outline"]},{"name":"mdi:receipt-text-send","tags":[]},{"name":"mdi:receipt-text-send-outline","tags":[]},{"name":"mdi:record","tags":["home automation","fiber manual record"]},{"name":"mdi:record-circle","tags":[]},{"name":"mdi:record-circle-outline","tags":[]},{"name":"mdi:record-player","tags":["home automation"]},{"name":"mdi:record-rec","tags":["home automation"]},{"name":"mdi:rectangle","tags":["shape"]},{"name":"mdi:rectangle-outline","tags":["shape"]},{"name":"mdi:recycle","tags":[]},{"name":"mdi:recycle-variant","tags":[]},{"name":"mdi:redo-variant","tags":["arrow"]},{"name":"mdi:reflect-horizontal","tags":[]},{"name":"mdi:reflect-vertical","tags":[]},{"name":"mdi:refresh-auto","tags":["automotive","auto start","automatic start","auto stop","automatic stop","automatic","refresh automatic"]},{"name":"mdi:refresh-circle","tags":[]},{"name":"mdi:regex","tags":["regular expression"]},{"name":"mdi:registered-trademark","tags":[]},{"name":"mdi:reiterate","tags":["arrow"]},{"name":"mdi:relation-many-to-many","tags":["database"]},{"name":"mdi:relation-many-to-one","tags":["database"]},{"name":"mdi:relation-many-to-one-or-many","tags":["database"]},{"name":"mdi:relation-many-to-only-one","tags":["database"]},{"name":"mdi:relation-many-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-many-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-one-or-many-to-many","tags":["database"]},{"name":"mdi:relation-one-or-many-to-one","tags":["database"]},{"name":"mdi:relation-one-or-many-to-one-or-many","tags":["database"]},{"name":"mdi:relation-one-or-many-to-only-one","tags":["database"]},{"name":"mdi:relation-one-or-many-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-one-or-many-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-one-to-many","tags":["database"]},{"name":"mdi:relation-one-to-one","tags":["database"]},{"name":"mdi:relation-one-to-one-or-many","tags":["database"]},{"name":"mdi:relation-one-to-only-one","tags":["database"]},{"name":"mdi:relation-one-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-one-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-only-one-to-many","tags":["database"]},{"name":"mdi:relation-only-one-to-one","tags":["database"]},{"name":"mdi:relation-only-one-to-one-or-many","tags":["database"]},{"name":"mdi:relation-only-one-to-only-one","tags":["database"]},{"name":"mdi:relation-only-one-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-only-one-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-many","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-one","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-one-or-many","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-only-one","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-many","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-one","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-one-or-many","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-only-one","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-zero-or-one","tags":["database"]},{"name":"mdi:reload","tags":["automotive","arrow","car engine start","loop","rotate clockwise"]},{"name":"mdi:reload-alert","tags":["alert / error"]},{"name":"mdi:remote-desktop","tags":[]},{"name":"mdi:remote-off","tags":[]},{"name":"mdi:remote-tv","tags":["device / tech"]},{"name":"mdi:remote-tv-off","tags":["device / tech"]},{"name":"mdi:rename-box","tags":[]},{"name":"mdi:rename-box-outline","tags":[]},{"name":"mdi:reorder-vertical","tags":[]},{"name":"mdi:repeat-off","tags":[]},{"name":"mdi:repeat-variant","tags":["arrow","twitter retweet","repost"]},{"name":"mdi:reply-all-outline","tags":["arrow"]},{"name":"mdi:reply-circle","tags":["arrow"]},{"name":"mdi:reply-outline","tags":["arrow"]},{"name":"mdi:reproduction","tags":["medical / hospital"]},{"name":"mdi:resistor","tags":[]},{"name":"mdi:resistor-nodes","tags":[]},{"name":"mdi:resize","tags":[]},{"name":"mdi:resize-bottom-right","tags":["drag"]},{"name":"mdi:responsive","tags":[]},{"name":"mdi:restart-alert","tags":["alert / error"]},{"name":"mdi:restart-off","tags":[]},{"name":"mdi:restore-alert","tags":["alert / error"]},{"name":"mdi:rewind-10","tags":[]},{"name":"mdi:rewind-15","tags":[]},{"name":"mdi:rewind-30","tags":[]},{"name":"mdi:rewind-45","tags":[]},{"name":"mdi:rewind-5","tags":[]},{"name":"mdi:rewind-60","tags":[]},{"name":"mdi:rhombus","tags":["shape","diamond"]},{"name":"mdi:rhombus-medium","tags":["shape"]},{"name":"mdi:rhombus-medium-outline","tags":["shape"]},{"name":"mdi:rhombus-outline","tags":["shape","diamond outline"]},{"name":"mdi:rhombus-split","tags":["shape","collection"]},{"name":"mdi:rhombus-split-outline","tags":["shape"]},{"name":"mdi:rice","tags":["food / drink"]},{"name":"mdi:rickshaw","tags":["transportation + road","transportation + other"]},{"name":"mdi:rickshaw-electric","tags":["transportation + road","transportation + other"]},{"name":"mdi:ring","tags":[]},{"name":"mdi:rivet","tags":["hardware / tools"]},{"name":"mdi:road","tags":["transportation + road"]},{"name":"mdi:road-variant","tags":["transportation + road"]},{"name":"mdi:robber","tags":[]},{"name":"mdi:robot","tags":["home automation","emoji robot","emoticon robot"]},{"name":"mdi:robot-angry","tags":["emoji robot angry","emoticon robot angry"]},{"name":"mdi:robot-angry-outline","tags":["emoji robot angry outline","emoticon robot angry outline"]},{"name":"mdi:robot-confused","tags":["emoji robot confused","emoticon robot confused"]},{"name":"mdi:robot-confused-outline","tags":["emoji robot confused outline","emoticon robot confused outline"]},{"name":"mdi:robot-dead","tags":["emoji robot dead","emoticon robot dead"]},{"name":"mdi:robot-dead-outline","tags":["emoji robot dead outline","emoticon robot dead outline"]},{"name":"mdi:robot-excited","tags":["emoticon robot excited","emoji robot excited"]},{"name":"mdi:robot-excited-outline","tags":["emoji robot excited outline","emoticon robot excited outline"]},{"name":"mdi:robot-happy","tags":["emoji robot happy","emoticon robot happy"]},{"name":"mdi:robot-happy-outline","tags":["emoji robot happy outline","emoticon robot happy outline"]},{"name":"mdi:robot-industrial","tags":["autonomous","assembly"]},{"name":"mdi:robot-industrial-outline","tags":[]},{"name":"mdi:robot-love","tags":["emoji robot love","emoticon robot love"]},{"name":"mdi:robot-love-outline","tags":[]},{"name":"mdi:robot-mower","tags":["home automation","lawn mower"]},{"name":"mdi:robot-mower-outline","tags":["home automation","lawn mower outline"]},{"name":"mdi:robot-off","tags":["emoji robot off","emoticon robot off"]},{"name":"mdi:robot-off-outline","tags":[]},{"name":"mdi:robot-outline","tags":["emoji robot outline","emoticon robot outline"]},{"name":"mdi:robot-vacuum","tags":["device / tech","home automation","roomba"]},{"name":"mdi:robot-vacuum-alert","tags":["alert / error","home automation","robot vacuum error"]},{"name":"mdi:robot-vacuum-off","tags":["home automation"]},{"name":"mdi:robot-vacuum-variant","tags":["home automation","neato"]},{"name":"mdi:robot-vacuum-variant-alert","tags":["alert / error","home automation","robot vacuum variant error"]},{"name":"mdi:robot-vacuum-variant-off","tags":["home automation"]},{"name":"mdi:rocket-launch","tags":["science","transportation + flying"]},{"name":"mdi:rocket-launch-outline","tags":["science","transportation + flying"]},{"name":"mdi:roller-skate","tags":["sport"]},{"name":"mdi:roller-skate-off","tags":["sport"]},{"name":"mdi:rollerblade","tags":["sport"]},{"name":"mdi:rollerblade-off","tags":["sport"]},{"name":"mdi:rolodex","tags":[]},{"name":"mdi:rolodex-outline","tags":[]},{"name":"mdi:roman-numeral-1","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-10","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-2","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-3","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-4","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-5","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-6","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-7","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-8","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-9","tags":["alpha / numeric"]},{"name":"mdi:rotate-3d-variant","tags":["3d rotation"]},{"name":"mdi:rotate-left-variant","tags":[]},{"name":"mdi:rotate-orbit","tags":["gyro","accelerometer"]},{"name":"mdi:rotate-right-variant","tags":[]},{"name":"mdi:router","tags":[]},{"name":"mdi:router-network","tags":[]},{"name":"mdi:router-wireless-off","tags":[]},{"name":"mdi:routes","tags":["sign routes"]},{"name":"mdi:routes-clock","tags":["date / time"]},{"name":"mdi:rss-box","tags":["rss feed box"]},{"name":"mdi:rss-off","tags":[]},{"name":"mdi:rug","tags":["home automation","carpet"]},{"name":"mdi:ruler","tags":["hardware / tools","drawing / art"]},{"name":"mdi:ruler-square","tags":["hardware / tools","drawing / art","square","carpentry","architecture"]},{"name":"mdi:ruler-square-compass","tags":["hardware / tools","mason","masonic","freemasonry"]},{"name":"mdi:run-fast","tags":["home automation","sport","people / family","velocity","human run fast"]},{"name":"mdi:rv-truck","tags":["transportation + road","recreational vehicle","campervan"]},{"name":"mdi:sack","tags":["gaming / rpg"]},{"name":"mdi:sack-outline","tags":[]},{"name":"mdi:sack-percent","tags":[]},{"name":"mdi:safe","tags":["banking"]},{"name":"mdi:safe-square","tags":[]},{"name":"mdi:safe-square-outline","tags":[]},{"name":"mdi:safety-goggles","tags":["science","safety glasses"]},{"name":"mdi:sail-boat-sink","tags":["transportation + water","sail boat crash","sail boat wreck"]},{"name":"mdi:sale","tags":["shopping","discount"]},{"name":"mdi:sale-outline","tags":["shopping","discount outline"]},{"name":"mdi:satellite-uplink","tags":[]},{"name":"mdi:satellite-variant","tags":[]},{"name":"mdi:sausage","tags":["food / drink"]},{"name":"mdi:sausage-off","tags":["food / drink"]},{"name":"mdi:saw-blade","tags":["hardware / tools"]},{"name":"mdi:sawtooth-wave","tags":["audio"]},{"name":"mdi:scale","tags":["food / drink","science"]},{"name":"mdi:scale-balance","tags":["science","justice","legal"]},{"name":"mdi:scale-bathroom","tags":["home automation","medical / hospital"]},{"name":"mdi:scale-off","tags":["science"]},{"name":"mdi:scale-unbalanced","tags":[]},{"name":"mdi:scan-helper","tags":[]},{"name":"mdi:scanner-off","tags":["device / tech"]},{"name":"mdi:scent","tags":["aroma","fragrance","smell","odor"]},{"name":"mdi:scent-off","tags":["aroma off","smell off","fragrance off","odor off"]},{"name":"mdi:scissors-cutting","tags":[]},{"name":"mdi:scoreboard","tags":["sport"]},{"name":"mdi:scoreboard-outline","tags":["sport"]},{"name":"mdi:screw-flat-top","tags":["hardware / tools"]},{"name":"mdi:screw-lag","tags":["hardware / tools"]},{"name":"mdi:screw-machine-flat-top","tags":["hardware / tools"]},{"name":"mdi:screw-machine-round-top","tags":["hardware / tools"]},{"name":"mdi:screw-round-top","tags":["hardware / tools"]},{"name":"mdi:screwdriver","tags":["hardware / tools"]},{"name":"mdi:script","tags":["gaming / rpg","scroll"]},{"name":"mdi:script-outline","tags":["gaming / rpg","scroll outline"]},{"name":"mdi:script-text","tags":["gaming / rpg","scroll text"]},{"name":"mdi:script-text-key","tags":[]},{"name":"mdi:script-text-key-outline","tags":[]},{"name":"mdi:script-text-outline","tags":["gaming / rpg","scroll text outline"]},{"name":"mdi:script-text-play","tags":[]},{"name":"mdi:script-text-play-outline","tags":[]},{"name":"mdi:seal","tags":["ribbon","prize","award"]},{"name":"mdi:seal-variant","tags":["ribbon","prize","award"]},{"name":"mdi:search-web","tags":["search globe","global search","internet search"]},{"name":"mdi:seat-passenger","tags":[]},{"name":"mdi:seatbelt","tags":["automotive","seat belt","safety belt"]},{"name":"mdi:security-network","tags":["shield network","uac network","administrator network"]},{"name":"mdi:seed","tags":["agriculture","nature","food / drink"]},{"name":"mdi:seed-off","tags":["nature","food / drink","agriculture"]},{"name":"mdi:seed-off-outline","tags":["nature","food / drink","agriculture"]},{"name":"mdi:seed-outline","tags":["agriculture","nature","food / drink"]},{"name":"mdi:seed-plus","tags":["agriculture","nature","seed add"]},{"name":"mdi:seed-plus-outline","tags":["agriculture","nature","seed add outline"]},{"name":"mdi:seesaw","tags":["playground seesaw"]},{"name":"mdi:select","tags":[]},{"name":"mdi:select-arrow-down","tags":[]},{"name":"mdi:select-arrow-up","tags":[]},{"name":"mdi:select-compare","tags":[]},{"name":"mdi:select-drag","tags":[]},{"name":"mdi:select-inverse","tags":["selection invert"]},{"name":"mdi:select-marker","tags":["navigation","select location"]},{"name":"mdi:select-multiple","tags":[]},{"name":"mdi:select-multiple-marker","tags":["navigation","select multiple location"]},{"name":"mdi:select-off","tags":[]},{"name":"mdi:select-place","tags":[]},{"name":"mdi:select-remove","tags":[]},{"name":"mdi:select-search","tags":[]},{"name":"mdi:selection","tags":[]},{"name":"mdi:selection-drag","tags":[]},{"name":"mdi:selection-ellipse","tags":[]},{"name":"mdi:selection-ellipse-remove","tags":[]},{"name":"mdi:selection-marker","tags":["navigation","selection location"]},{"name":"mdi:selection-multiple","tags":[]},{"name":"mdi:selection-multiple-marker","tags":["navigation","selection multiple location"]},{"name":"mdi:selection-off","tags":[]},{"name":"mdi:selection-remove","tags":[]},{"name":"mdi:selection-search","tags":[]},{"name":"mdi:send-check","tags":[]},{"name":"mdi:send-check-outline","tags":[]},{"name":"mdi:send-circle","tags":[]},{"name":"mdi:send-circle-outline","tags":[]},{"name":"mdi:send-lock","tags":["lock","send secure"]},{"name":"mdi:send-lock-outline","tags":["lock"]},{"name":"mdi:send-outline","tags":["paper airplane outline","paper plane outline"]},{"name":"mdi:send-variant-clock","tags":[]},{"name":"mdi:send-variant-clock-outline","tags":[]},{"name":"mdi:serial-port","tags":["vga"]},{"name":"mdi:server","tags":["storage"]},{"name":"mdi:server-minus","tags":["server remove"]},{"name":"mdi:server-network","tags":[]},{"name":"mdi:server-network-off","tags":[]},{"name":"mdi:server-off","tags":[]},{"name":"mdi:server-plus","tags":["server add"]},{"name":"mdi:server-remove","tags":[]},{"name":"mdi:server-security","tags":["server shield"]},{"name":"mdi:set-all","tags":["database","set union","set or","full outer join","sql full outer join"]},{"name":"mdi:set-center","tags":["database","set centre","set intersection","set and","inner join","sql inner join"]},{"name":"mdi:set-center-right","tags":["database","set centre right","outer join right","sql right outer join"]},{"name":"mdi:set-left","tags":["database","difference left"]},{"name":"mdi:set-left-center","tags":["database","set left centre","outer join left","sql left outer join"]},{"name":"mdi:set-left-right","tags":["database","exclusion","set xor"]},{"name":"mdi:set-merge","tags":[]},{"name":"mdi:set-none","tags":["database","set null","set not","venn diagram"]},{"name":"mdi:set-right","tags":["database","difference right"]},{"name":"mdi:set-split","tags":[]},{"name":"mdi:set-top-box","tags":["home automation"]},{"name":"mdi:settings-helper","tags":["settings"]},{"name":"mdi:shaker","tags":["food / drink","pepper","fish food"]},{"name":"mdi:shaker-outline","tags":["food / drink","salt","fish food outline"]},{"name":"mdi:shape-circle-plus","tags":["shape","shape circle add"]},{"name":"mdi:shape-oval-plus","tags":[]},{"name":"mdi:shape-plus","tags":["shape","shape add","category plus"]},{"name":"mdi:shape-plus-outline","tags":["shape","shape add outline","category plus outline"]},{"name":"mdi:shape-polygon-plus","tags":["shape","shape polygon add"]},{"name":"mdi:shape-rectangle-plus","tags":["shape","shape rectangle add"]},{"name":"mdi:shape-square-plus","tags":["shape","shape square add"]},{"name":"mdi:shape-square-rounded-plus","tags":[]},{"name":"mdi:share-all","tags":[]},{"name":"mdi:share-all-outline","tags":[]},{"name":"mdi:share-circle","tags":["arrow"]},{"name":"mdi:share-off","tags":["arrow","forward off"]},{"name":"mdi:share-off-outline","tags":["arrow","forward off outline"]},{"name":"mdi:share-outline","tags":["arrow","forward outline"]},{"name":"mdi:share-variant-outline","tags":[]},{"name":"mdi:shark","tags":["animal","jaws"]},{"name":"mdi:shark-fin","tags":["animal"]},{"name":"mdi:shark-fin-outline","tags":["animal"]},{"name":"mdi:shark-off","tags":["animal","jaws off"]},{"name":"mdi:sheep","tags":["animal","agriculture","emoji sheep","emoticon sheep"]},{"name":"mdi:shield","tags":["gaming / rpg"]},{"name":"mdi:shield-account","tags":["account / user","home automation","security account","shield user","shield person","alarm arm home"]},{"name":"mdi:shield-account-outline","tags":["account / user","home automation","security account outline","shield user outline","shield person outline","alarm arm home outline"]},{"name":"mdi:shield-airplane","tags":["transportation + flying","shield aeroplane","shield plane","plane shield"]},{"name":"mdi:shield-airplane-outline","tags":["transportation + flying","shield aeroplane outline","shield plane outline"]},{"name":"mdi:shield-alert","tags":["alert / error","shield warning"]},{"name":"mdi:shield-alert-outline","tags":["alert / error","shield warning outline"]},{"name":"mdi:shield-bug","tags":["antivirus"]},{"name":"mdi:shield-bug-outline","tags":["antivirus outline"]},{"name":"mdi:shield-car","tags":["automotive","car security","car insurance"]},{"name":"mdi:shield-check-outline","tags":["shield tick outline"]},{"name":"mdi:shield-cross","tags":["gaming / rpg","religion","shield templar","shield christianity"]},{"name":"mdi:shield-cross-outline","tags":["gaming / rpg","religion","shield templar outline","shield christianity outline"]},{"name":"mdi:shield-crown","tags":["gaming / rpg","administrator"]},{"name":"mdi:shield-crown-outline","tags":["gaming / rpg","administrator outline"]},{"name":"mdi:shield-edit","tags":["edit / modify"]},{"name":"mdi:shield-edit-outline","tags":["edit / modify"]},{"name":"mdi:shield-half","tags":[]},{"name":"mdi:shield-half-full","tags":[]},{"name":"mdi:shield-home","tags":["home automation","security home","shield house","alarm arm home"]},{"name":"mdi:shield-home-outline","tags":["home automation","shield house outline","alarm arm home"]},{"name":"mdi:shield-link-variant","tags":[]},{"name":"mdi:shield-link-variant-outline","tags":[]},{"name":"mdi:shield-lock","tags":["lock","home automation","security lock","alarm arm away"]},{"name":"mdi:shield-lock-open","tags":["home automation","lock","shield unlocked"]},{"name":"mdi:shield-lock-open-outline","tags":["home automation","lock","shield unlocked outline"]},{"name":"mdi:shield-lock-outline","tags":["lock","home automation","alarm arm away outline","security lock outline"]},{"name":"mdi:shield-moon","tags":["home automation","alarm arm night"]},{"name":"mdi:shield-moon-outline","tags":["home automation","alarm arm night outline"]},{"name":"mdi:shield-off","tags":["security off"]},{"name":"mdi:shield-off-outline","tags":[]},{"name":"mdi:shield-outline","tags":["gaming / rpg"]},{"name":"mdi:shield-refresh","tags":[]},{"name":"mdi:shield-refresh-outline","tags":[]},{"name":"mdi:shield-remove","tags":[]},{"name":"mdi:shield-remove-outline","tags":[]},{"name":"mdi:shield-star","tags":["badge","shield favorite"]},{"name":"mdi:shield-star-outline","tags":["badge outline","shield favorite outline"]},{"name":"mdi:shield-sun","tags":["weather","sun protection"]},{"name":"mdi:shield-sun-outline","tags":["weather","sun protection outline"]},{"name":"mdi:shield-sword","tags":["gaming / rpg","moderator"]},{"name":"mdi:shield-sword-outline","tags":["gaming / rpg","moderator outline"]},{"name":"mdi:shield-sync","tags":[]},{"name":"mdi:shield-sync-outline","tags":[]},{"name":"mdi:shimmer","tags":["sparkles"]},{"name":"mdi:shipping-pallet","tags":[]},{"name":"mdi:shoe-ballet","tags":["sport","clothing","slippers ballet"]},{"name":"mdi:shoe-cleat","tags":["sport","clothing"]},{"name":"mdi:shoe-formal","tags":["clothing"]},{"name":"mdi:shoe-heel","tags":["clothing"]},{"name":"mdi:shoe-print","tags":["footprints"]},{"name":"mdi:shoe-sneaker","tags":["sport","clothing","shoe running"]},{"name":"mdi:shopping-music","tags":["shopping"]},{"name":"mdi:shopping-search","tags":["shopping"]},{"name":"mdi:shopping-search-outline","tags":["shopping"]},{"name":"mdi:shore","tags":[]},{"name":"mdi:shovel","tags":["hardware / tools","gardening"]},{"name":"mdi:shovel-off","tags":["hardware / tools"]},{"name":"mdi:shower","tags":["home automation","bathtub","bathroom"]},{"name":"mdi:shower-head","tags":["home automation","bathroom"]},{"name":"mdi:shredder","tags":[]},{"name":"mdi:shuffle-disabled","tags":["arrow"]},{"name":"mdi:shuffle-variant","tags":["arrow"]},{"name":"mdi:shuriken","tags":["ninja star"]},{"name":"mdi:sickle","tags":["hardware / tools"]},{"name":"mdi:sigma-lower","tags":[]},{"name":"mdi:sign-caution","tags":["transportation + road","barrier"]},{"name":"mdi:sign-direction","tags":["milestone"]},{"name":"mdi:sign-direction-minus","tags":["milestone minus"]},{"name":"mdi:sign-direction-plus","tags":["milestone plus","sign direction add","milestone add"]},{"name":"mdi:sign-direction-remove","tags":["milestone remove"]},{"name":"mdi:sign-pole","tags":[]},{"name":"mdi:sign-real-estate","tags":[]},{"name":"mdi:sign-text","tags":[]},{"name":"mdi:sign-yield","tags":["transportation + road","give way"]},{"name":"mdi:signal","tags":["cellphone / phone"]},{"name":"mdi:signal-2g","tags":["cellphone / phone"]},{"name":"mdi:signal-3g","tags":["cellphone / phone"]},{"name":"mdi:signal-4g","tags":["cellphone / phone"]},{"name":"mdi:signal-5g","tags":["cellphone / phone"]},{"name":"mdi:signal-cellular-1","tags":["cellphone / phone"]},{"name":"mdi:signal-cellular-2","tags":["cellphone / phone"]},{"name":"mdi:signal-cellular-3","tags":["cellphone / phone"]},{"name":"mdi:signal-cellular-outline","tags":["cellphone / phone","signal cellular 0"]},{"name":"mdi:signal-distance-variant","tags":[]},{"name":"mdi:signal-hspa","tags":["cellphone / phone"]},{"name":"mdi:signal-hspa-plus","tags":["cellphone / phone"]},{"name":"mdi:signal-off","tags":["cellphone / phone"]},{"name":"mdi:signal-variant","tags":[]},{"name":"mdi:signature","tags":["form"]},{"name":"mdi:signature-freehand","tags":["form"]},{"name":"mdi:signature-image","tags":["form"]},{"name":"mdi:signature-text","tags":["form"]},{"name":"mdi:silo","tags":["agriculture","farm"]},{"name":"mdi:silo-outline","tags":["agriculture","farm outline"]},{"name":"mdi:silverware-clean","tags":["food / drink","silverware shimmer","cutlery clean"]},{"name":"mdi:silverware-fork","tags":["food / drink","cutlery fork"]},{"name":"mdi:silverware-spoon","tags":["food / drink","cutlery spoon"]},{"name":"mdi:silverware-variant","tags":["food / drink","places","cutlery variant"]},{"name":"mdi:sim-alert-outline","tags":["cellphone / phone","alert / error"]},{"name":"mdi:sim-off-outline","tags":["cellphone / phone"]},{"name":"mdi:sim-outline","tags":["cellphone / phone","sim card outline","subscriber identity module outline","subscriber identification module outline"]},{"name":"mdi:sine-wave","tags":["audio","alternating current","current ac","wave","analog","frequency","amplitude"]},{"name":"mdi:sitemap","tags":["workflow","flowchart"]},{"name":"mdi:sitemap-outline","tags":["workflow outline","flowchart outline"]},{"name":"mdi:size-l","tags":["size large"]},{"name":"mdi:size-m","tags":["size medium"]},{"name":"mdi:size-s","tags":["size small"]},{"name":"mdi:size-xl","tags":["size extra large"]},{"name":"mdi:size-xs","tags":["size extra small"]},{"name":"mdi:size-xxl","tags":["size extra extra large"]},{"name":"mdi:size-xxs","tags":["size extra extra small"]},{"name":"mdi:size-xxxl","tags":[]},{"name":"mdi:skate-off","tags":["sport"]},{"name":"mdi:skew-less","tags":["math","skew decrease"]},{"name":"mdi:skew-more","tags":["math","skew increase"]},{"name":"mdi:ski-water","tags":["sport","people / family","transportation + water","human ski water"]},{"name":"mdi:skip-backward","tags":["home automation","title backward","previous title"]},{"name":"mdi:skip-backward-outline","tags":[]},{"name":"mdi:skip-forward","tags":["home automation","title forward","next title"]},{"name":"mdi:skip-forward-outline","tags":[]},{"name":"mdi:skip-next-circle","tags":[]},{"name":"mdi:skip-next-circle-outline","tags":[]},{"name":"mdi:skip-next-outline","tags":[]},{"name":"mdi:skip-previous-circle","tags":[]},{"name":"mdi:skip-previous-circle-outline","tags":[]},{"name":"mdi:skip-previous-outline","tags":[]},{"name":"mdi:skull","tags":["holiday","gaming / rpg"]},{"name":"mdi:skull-crossbones","tags":["gaming / rpg","holiday","jolly roger"]},{"name":"mdi:skull-crossbones-outline","tags":["gaming / rpg","holiday","jolly roger outline"]},{"name":"mdi:skull-outline","tags":["holiday","gaming / rpg"]},{"name":"mdi:skull-scan","tags":["medical / hospital","x ray","radiology"]},{"name":"mdi:skull-scan-outline","tags":["medical / hospital","x ray outline","radiology outline"]},{"name":"mdi:slash-forward","tags":["math","divide","division"]},{"name":"mdi:slash-forward-box","tags":["math","divide box","division box"]},{"name":"mdi:sleep-off","tags":[]},{"name":"mdi:slide","tags":["playground slide"]},{"name":"mdi:slope-downhill","tags":[]},{"name":"mdi:slope-uphill","tags":[]},{"name":"mdi:slot-machine","tags":["casino","gambling"]},{"name":"mdi:slot-machine-outline","tags":["casino outline","gambling outline"]},{"name":"mdi:smart-card","tags":["account / user"]},{"name":"mdi:smart-card-off","tags":["account / user"]},{"name":"mdi:smart-card-off-outline","tags":["account / user"]},{"name":"mdi:smart-card-outline","tags":["account / user"]},{"name":"mdi:smart-card-reader","tags":["account / user"]},{"name":"mdi:smart-card-reader-outline","tags":["account / user"]},{"name":"mdi:smog","tags":[]},{"name":"mdi:smoke","tags":["smog","fire"]},{"name":"mdi:smoke-detector-alert","tags":["home automation","alert / error"]},{"name":"mdi:smoke-detector-alert-outline","tags":["home automation","alert / error"]},{"name":"mdi:smoke-detector-off","tags":["home automation"]},{"name":"mdi:smoke-detector-off-outline","tags":["home automation"]},{"name":"mdi:smoke-detector-outline","tags":["home automation"]},{"name":"mdi:smoke-detector-variant","tags":["home automation"]},{"name":"mdi:smoke-detector-variant-alert","tags":["home automation","alert / error"]},{"name":"mdi:smoke-detector-variant-off","tags":["home automation"]},{"name":"mdi:smoking-pipe","tags":[]},{"name":"mdi:smoking-pipe-off","tags":[]},{"name":"mdi:snail","tags":["animal","gastropod"]},{"name":"mdi:snake","tags":["animal","reptile"]},{"name":"mdi:snowflake-alert","tags":["weather","alert / error","home automation","cold alert","snow advisory","freeze advisory"]},{"name":"mdi:snowflake-check","tags":["weather","snowflake approve"]},{"name":"mdi:snowflake-melt","tags":["weather","defrost"]},{"name":"mdi:snowflake-off","tags":["weather"]},{"name":"mdi:snowflake-thermometer","tags":["weather","home automation","frost point","freezing point","snowflake temperature"]},{"name":"mdi:snowflake-variant","tags":["holiday","weather"]},{"name":"mdi:snowman","tags":["holiday"]},{"name":"mdi:soccer-field","tags":["sport","football pitch"]},{"name":"mdi:social-distance-2-meters","tags":["medical / hospital"]},{"name":"mdi:sofa","tags":["home automation","couch","living room","family room"]},{"name":"mdi:sofa-outline","tags":["home automation","couch outline","living room outline","family room outline"]},{"name":"mdi:sofa-single","tags":["home automation","loveseat","love seat","couch","chair accent","living room","family room"]},{"name":"mdi:sofa-single-outline","tags":["home automation","loveseat outline","love seat outline","couch outline","chair accent outline","living room outline","family room outline"]},{"name":"mdi:solar-panel","tags":["home automation","solar energy","solar electricity"]},{"name":"mdi:solar-panel-large","tags":["home automation","solar panel energy","solar panel electricity"]},{"name":"mdi:solar-power","tags":["home automation","solar energy","solar electricity"]},{"name":"mdi:soldering-iron","tags":[]},{"name":"mdi:solid","tags":[]},{"name":"mdi:sort","tags":["text / content / format"]},{"name":"mdi:sort-alphabetical-ascending","tags":["text / content / format"]},{"name":"mdi:sort-alphabetical-ascending-variant","tags":["text / content / format"]},{"name":"mdi:sort-alphabetical-descending","tags":["text / content / format"]},{"name":"mdi:sort-alphabetical-descending-variant","tags":["text / content / format"]},{"name":"mdi:sort-ascending","tags":["text / content / format"]},{"name":"mdi:sort-bool-ascending","tags":["text / content / format"]},{"name":"mdi:sort-bool-ascending-variant","tags":["text / content / format","sort checkbox ascending"]},{"name":"mdi:sort-bool-descending","tags":["text / content / format"]},{"name":"mdi:sort-bool-descending-variant","tags":["text / content / format","sort checkbox descending"]},{"name":"mdi:sort-calendar-ascending","tags":["text / content / format","date / time","sort date ascending"]},{"name":"mdi:sort-calendar-descending","tags":["text / content / format","date / time","sort date descending"]},{"name":"mdi:sort-clock-ascending","tags":["text / content / format","date / time","sort time ascending"]},{"name":"mdi:sort-clock-ascending-outline","tags":["text / content / format","date / time","sort time ascending outline"]},{"name":"mdi:sort-clock-descending","tags":["text / content / format","date / time","sort time descending"]},{"name":"mdi:sort-clock-descending-outline","tags":["text / content / format","date / time","sort time descending outline"]},{"name":"mdi:sort-descending","tags":["text / content / format"]},{"name":"mdi:sort-numeric-ascending","tags":["text / content / format"]},{"name":"mdi:sort-numeric-ascending-variant","tags":["text / content / format"]},{"name":"mdi:sort-numeric-descending","tags":["text / content / format"]},{"name":"mdi:sort-numeric-descending-variant","tags":["text / content / format"]},{"name":"mdi:sort-reverse-variant","tags":["text / content / format"]},{"name":"mdi:sort-variant-lock","tags":["text / content / format","lock"]},{"name":"mdi:sort-variant-lock-open","tags":["text / content / format","lock"]},{"name":"mdi:sort-variant-off","tags":["text / content / format"]},{"name":"mdi:sort-variant-remove","tags":["text / content / format"]},{"name":"mdi:soundbar","tags":["home automation","speaker bar"]},{"name":"mdi:source-branch","tags":["developer / languages"]},{"name":"mdi:source-branch-check","tags":["developer / languages"]},{"name":"mdi:source-branch-minus","tags":["developer / languages"]},{"name":"mdi:source-branch-plus","tags":["developer / languages"]},{"name":"mdi:source-branch-refresh","tags":["developer / languages"]},{"name":"mdi:source-branch-remove","tags":["developer / languages"]},{"name":"mdi:source-branch-sync","tags":["developer / languages"]},{"name":"mdi:source-commit","tags":[]},{"name":"mdi:source-commit-end","tags":[]},{"name":"mdi:source-commit-end-local","tags":[]},{"name":"mdi:source-commit-local","tags":[]},{"name":"mdi:source-commit-next-local","tags":[]},{"name":"mdi:source-commit-start","tags":[]},{"name":"mdi:source-commit-start-next-local","tags":[]},{"name":"mdi:source-fork","tags":["developer / languages"]},{"name":"mdi:source-merge","tags":["developer / languages"]},{"name":"mdi:source-pull","tags":["developer / languages"]},{"name":"mdi:source-repository","tags":["developer / languages"]},{"name":"mdi:source-repository-multiple","tags":["developer / languages","source repositories"]},{"name":"mdi:soy-sauce","tags":["food / drink","soya sauce"]},{"name":"mdi:soy-sauce-off","tags":[]},{"name":"mdi:space-invaders","tags":["gaming / rpg"]},{"name":"mdi:space-station","tags":[]},{"name":"mdi:spade","tags":["hardware / tools"]},{"name":"mdi:speaker-bluetooth","tags":["audio"]},{"name":"mdi:speaker-message","tags":["home automation","audio","text to speech"]},{"name":"mdi:speaker-multiple","tags":["audio","speakers"]},{"name":"mdi:speaker-off","tags":["audio","home automation"]},{"name":"mdi:speaker-pause","tags":["audio","music"]},{"name":"mdi:speaker-play","tags":["audio","music"]},{"name":"mdi:speaker-stop","tags":["audio","music"]},{"name":"mdi:speaker-wireless","tags":["audio","home automation"]},{"name":"mdi:spear","tags":["gaming / rpg","staff","fishing"]},{"name":"mdi:speedometer","tags":["automotive"]},{"name":"mdi:speedometer-medium","tags":["automotive"]},{"name":"mdi:speedometer-slow","tags":["automotive"]},{"name":"mdi:sphere","tags":["shape"]},{"name":"mdi:sphere-off","tags":["shape"]},{"name":"mdi:spider","tags":["holiday","nature","animal","arachnid","bug"]},{"name":"mdi:spider-outline","tags":["animal","holiday","nature","arachnid outline"]},{"name":"mdi:spider-thread","tags":["holiday","nature","animal","arachnid thread","bug"]},{"name":"mdi:spider-web","tags":["holiday","cobweb","arachnid web"]},{"name":"mdi:spirit-level","tags":["hardware / tools"]},{"name":"mdi:spoon-sugar","tags":["food / drink"]},{"name":"mdi:spotlight","tags":["home automation"]},{"name":"mdi:spotlight-beam","tags":["home automation"]},{"name":"mdi:spray","tags":["agriculture","drawing / art","color","paint","aerosol"]},{"name":"mdi:spray-bottle","tags":["cleaning"]},{"name":"mdi:sprinkler","tags":["home automation","agriculture","irrigation"]},{"name":"mdi:sprinkler-fire","tags":["home automation","agriculture","sprinkler mist","mister","sprinkler head"]},{"name":"mdi:sprinkler-variant","tags":["home automation","agriculture","irrigation"]},{"name":"mdi:sprout","tags":["agriculture","nature","seedling","plant","ecology","environment"]},{"name":"mdi:sprout-outline","tags":["agriculture","nature","seedling outline","plant outline","ecology outline","environment outline"]},{"name":"mdi:square","tags":["shape"]},{"name":"mdi:square-circle","tags":["food / drink","vegetarian","lacto vegetarian"]},{"name":"mdi:square-circle-outline","tags":[]},{"name":"mdi:square-edit-outline","tags":["edit / modify"]},{"name":"mdi:square-medium","tags":["shape"]},{"name":"mdi:square-medium-outline","tags":["shape"]},{"name":"mdi:square-off","tags":[]},{"name":"mdi:square-off-outline","tags":[]},{"name":"mdi:square-opacity","tags":["drawing / art","shape","square transparent"]},{"name":"mdi:square-outline","tags":["shape"]},{"name":"mdi:square-root","tags":["math"]},{"name":"mdi:square-root-box","tags":[]},{"name":"mdi:square-rounded","tags":[]},{"name":"mdi:square-rounded-badge","tags":["shape","notification","app badge","push notification"]},{"name":"mdi:square-rounded-badge-outline","tags":["shape","notification","app badge outline","push notification outline"]},{"name":"mdi:square-rounded-outline","tags":[]},{"name":"mdi:square-small","tags":["bullet"]},{"name":"mdi:square-wave","tags":["audio"]},{"name":"mdi:squeegee","tags":[]},{"name":"mdi:ssh","tags":[]},{"name":"mdi:stadium-variant","tags":["places","sport","arena"]},{"name":"mdi:stairs","tags":["transportation + other"]},{"name":"mdi:stairs-box","tags":[]},{"name":"mdi:stairs-down","tags":["transportation + other"]},{"name":"mdi:stairs-up","tags":["transportation + other"]},{"name":"mdi:stamper","tags":[]},{"name":"mdi:standard-definition","tags":["video / movie"]},{"name":"mdi:star-box","tags":["favorite box"]},{"name":"mdi:star-box-multiple","tags":["favorite box multiple"]},{"name":"mdi:star-box-multiple-outline","tags":["favorite box multiple outline"]},{"name":"mdi:star-box-outline","tags":["favorite box outline"]},{"name":"mdi:star-check","tags":["shape","favorite check"]},{"name":"mdi:star-check-outline","tags":["shape","favorite check outline"]},{"name":"mdi:star-cog","tags":["settings","favorite cog"]},{"name":"mdi:star-cog-outline","tags":["settings","favorite cog outline"]},{"name":"mdi:star-crescent","tags":["religion","islam","religion islamic","religion muslim"]},{"name":"mdi:star-david","tags":["religion","jewish","religion judaic","judaism","magen david"]},{"name":"mdi:star-four-points","tags":["shape"]},{"name":"mdi:star-four-points-box","tags":["shape","auto box"]},{"name":"mdi:star-four-points-box-outline","tags":["shape","auto box outline"]},{"name":"mdi:star-four-points-circle","tags":["shape","auto circle"]},{"name":"mdi:star-four-points-circle-outline","tags":["shape","auto circle outline"]},{"name":"mdi:star-four-points-outline","tags":["shape"]},{"name":"mdi:star-four-points-small","tags":["shape"]},{"name":"mdi:star-half","tags":["shape","favorite half"]},{"name":"mdi:star-minus","tags":["shape","favorite minus"]},{"name":"mdi:star-minus-outline","tags":["shape","favorite minus outline"]},{"name":"mdi:star-off","tags":["favorite off"]},{"name":"mdi:star-off-outline","tags":["favorite off outline"]},{"name":"mdi:star-plus","tags":["shape","favorite plus","star add","favorite add"]},{"name":"mdi:star-plus-outline","tags":["shape","star add outline","favorite plus outline","favorite add outline"]},{"name":"mdi:star-remove","tags":["shape","favorite remove"]},{"name":"mdi:star-remove-outline","tags":["shape","favorite remove outline"]},{"name":"mdi:star-settings","tags":["settings","favorite settings"]},{"name":"mdi:star-settings-outline","tags":["settings","favorite settings outline"]},{"name":"mdi:star-shooting","tags":["favorite shooting"]},{"name":"mdi:star-shooting-outline","tags":["favorite shooting outline"]},{"name":"mdi:star-three-points","tags":["shape"]},{"name":"mdi:star-three-points-outline","tags":["shape"]},{"name":"mdi:state-machine","tags":[]},{"name":"mdi:step-backward","tags":[]},{"name":"mdi:step-backward-2","tags":["frame backward"]},{"name":"mdi:step-forward","tags":[]},{"name":"mdi:step-forward-2","tags":["frame forward"]},{"name":"mdi:stethoscope","tags":["medical / hospital"]},{"name":"mdi:sticker","tags":[]},{"name":"mdi:sticker-alert","tags":["alert / error"]},{"name":"mdi:sticker-alert-outline","tags":["alert / error"]},{"name":"mdi:sticker-check","tags":[]},{"name":"mdi:sticker-check-outline","tags":[]},{"name":"mdi:sticker-circle-outline","tags":[]},{"name":"mdi:sticker-minus","tags":[]},{"name":"mdi:sticker-minus-outline","tags":[]},{"name":"mdi:sticker-outline","tags":[]},{"name":"mdi:sticker-plus","tags":[]},{"name":"mdi:sticker-plus-outline","tags":[]},{"name":"mdi:sticker-remove","tags":[]},{"name":"mdi:sticker-remove-outline","tags":[]},{"name":"mdi:sticker-text","tags":[]},{"name":"mdi:sticker-text-outline","tags":[]},{"name":"mdi:stocking","tags":["holiday"]},{"name":"mdi:stomach","tags":["medical / hospital"]},{"name":"mdi:stool","tags":[]},{"name":"mdi:stool-outline","tags":[]},{"name":"mdi:stop-circle","tags":[]},{"name":"mdi:stop-circle-outline","tags":[]},{"name":"mdi:store-alert","tags":["places","shopping","alert / error","shop alert"]},{"name":"mdi:store-alert-outline","tags":["places","shopping","alert / error","shop alert outline"]},{"name":"mdi:store-check","tags":["shopping","places","shop check","shop complete","store complete"]},{"name":"mdi:store-check-outline","tags":["shopping","places","shop complete","store complete outline","shop check outline"]},{"name":"mdi:store-clock","tags":["places","shopping","store schedule","store hours","shop clock","shop hours","shop schedule","store time","shop time"]},{"name":"mdi:store-clock-outline","tags":["places","shopping","date / time","shop clock outline","store hours outline","shop hours outline","store time outline","shop time outline","store schedule outline","shop schedule outline"]},{"name":"mdi:store-cog","tags":["places","shopping","settings","store settings","shop settings"]},{"name":"mdi:store-cog-outline","tags":["places","shopping","settings","store settings outline","shop settings outline","shop cog outline"]},{"name":"mdi:store-edit","tags":["places","shopping","edit / modify","shop edit"]},{"name":"mdi:store-edit-outline","tags":["places","shopping","edit / modify","shop edit outline"]},{"name":"mdi:store-marker","tags":["places","shopping","navigation","store location","shop marker","shop location"]},{"name":"mdi:store-marker-outline","tags":["places","shopping","navigation","store location outline","shop marker outline","shop location outline"]},{"name":"mdi:store-minus","tags":["places","shopping","shop minus"]},{"name":"mdi:store-minus-outline","tags":["places","shopping","shop minus outline"]},{"name":"mdi:store-off","tags":["places","shopping","shop off"]},{"name":"mdi:store-off-outline","tags":["places","shopping","shop off outline"]},{"name":"mdi:store-plus","tags":["places","shopping","shop plus"]},{"name":"mdi:store-plus-outline","tags":["places","shopping","shop plus outline"]},{"name":"mdi:store-remove","tags":["places","shopping","shop remove","store delete","shop delete"]},{"name":"mdi:store-remove-outline","tags":["places","shopping","shop remove outline","store delete outline","shop delete outline"]},{"name":"mdi:store-search","tags":["places","shopping","shop search","store find","shop find","store locator","shop locator","store look up","shop look up"]},{"name":"mdi:store-search-outline","tags":["places","shopping","store find outline","shop search outline","shop find outline","store locator outline","shop locator outline","store look up outline","shop look up outline"]},{"name":"mdi:store-settings","tags":["places","shopping","settings","shop settings"]},{"name":"mdi:store-settings-outline","tags":["places","shopping","settings","shop settings outline"]},{"name":"mdi:storefront","tags":["places","awning"]},{"name":"mdi:storefront-check","tags":[]},{"name":"mdi:storefront-check-outline","tags":[]},{"name":"mdi:storefront-edit","tags":["edit / modify"]},{"name":"mdi:storefront-edit-outline","tags":["edit / modify"]},{"name":"mdi:storefront-minus","tags":[]},{"name":"mdi:storefront-minus-outline","tags":[]},{"name":"mdi:storefront-plus","tags":[]},{"name":"mdi:storefront-plus-outline","tags":[]},{"name":"mdi:storefront-remove","tags":[]},{"name":"mdi:storefront-remove-outline","tags":[]},{"name":"mdi:stove","tags":["food / drink","home automation","cooker","oven"]},{"name":"mdi:strategy","tags":["sport","football play"]},{"name":"mdi:stretch-to-page","tags":["text / content / format","arrow"]},{"name":"mdi:stretch-to-page-outline","tags":["text / content / format","arrow"]},{"name":"mdi:string-lights","tags":["home automation","italian lights","christmas lights","fairy lights"]},{"name":"mdi:string-lights-off","tags":["home automation","italian lights off","christmas lights off","fairy lights off"]},{"name":"mdi:submarine","tags":[]},{"name":"mdi:subway-alert-variant","tags":["alert / error","transportation + other","subway warning variant"]},{"name":"mdi:summit","tags":["peak"]},{"name":"mdi:sun-angle","tags":["weather","solar angle"]},{"name":"mdi:sun-angle-outline","tags":["weather","solar angle outline"]},{"name":"mdi:sun-clock","tags":["weather","home automation","sun schedule","sun time","time of day"]},{"name":"mdi:sun-clock-outline","tags":["weather","home automation","date / time","sun schedule outline","sun time outline","time of day outline"]},{"name":"mdi:sun-compass","tags":["weather","home automation","navigation","sun azimuth","solar compass","solar asimuth"]},{"name":"mdi:sun-snowflake-variant","tags":["home automation","weather","hot cold","heat cool"]},{"name":"mdi:sun-thermometer","tags":["weather","home automation","heat index","sun temperature","day temperature","external temperature","outdoor temperature"]},{"name":"mdi:sun-thermometer-outline","tags":["home automation","weather","external temperature","outside temperature","heat index","day temperature"]},{"name":"mdi:sun-wireless","tags":["home automation","weather","weather sun wireless","illuminance","uv ray","ultraviolet"]},{"name":"mdi:sun-wireless-outline","tags":["home automation","weather","weather sun wireless outline","illuminance outline","uv ray outline","ultraviolet outline"]},{"name":"mdi:sunglasses","tags":["clothing"]},{"name":"mdi:surround-sound-2-0","tags":["audio","stereo"]},{"name":"mdi:surround-sound-2-1","tags":[]},{"name":"mdi:surround-sound-3-1","tags":["audio"]},{"name":"mdi:surround-sound-5-1","tags":["audio"]},{"name":"mdi:surround-sound-5-1-2","tags":[]},{"name":"mdi:surround-sound-7-1","tags":["audio"]},{"name":"mdi:swap-horizontal-circle-outline","tags":["arrow"]},{"name":"mdi:swap-vertical-circle","tags":["arrow"]},{"name":"mdi:swap-vertical-circle-outline","tags":["arrow"]},{"name":"mdi:swim","tags":["sport"]},{"name":"mdi:switch","tags":[]},{"name":"mdi:sword","tags":["gaming / rpg"]},{"name":"mdi:sword-cross","tags":["gaming / rpg"]},{"name":"mdi:syllabary-hangul","tags":["alpha / numeric","writing system hangul"]},{"name":"mdi:syllabary-hiragana","tags":["alpha / numeric","writing system hiragana"]},{"name":"mdi:syllabary-katakana","tags":["alpha / numeric","writing system katakana"]},{"name":"mdi:syllabary-katakana-halfwidth","tags":["alpha / numeric","writing system katakana half width"]},{"name":"mdi:symbol","tags":[]},{"name":"mdi:sync-circle","tags":[]},{"name":"mdi:tab-minus","tags":[]},{"name":"mdi:tab-plus","tags":["tab add"]},{"name":"mdi:tab-remove","tags":[]},{"name":"mdi:tab-search","tags":["tab find"]},{"name":"mdi:table","tags":["text / content / format"]},{"name":"mdi:table-account","tags":["account / user","table user"]},{"name":"mdi:table-alert","tags":["alert / error"]},{"name":"mdi:table-arrow-down","tags":["table download"]},{"name":"mdi:table-arrow-left","tags":["table import"]},{"name":"mdi:table-arrow-right","tags":["table share","table export"]},{"name":"mdi:table-arrow-up","tags":["table upload"]},{"name":"mdi:table-border","tags":["text / content / format"]},{"name":"mdi:table-cancel","tags":[]},{"name":"mdi:table-chair","tags":["home automation","restaurant","kitchen","dining","dining room"]},{"name":"mdi:table-check","tags":[]},{"name":"mdi:table-clock","tags":["date / time"]},{"name":"mdi:table-cog","tags":["settings","table settings"]},{"name":"mdi:table-column","tags":["text / content / format"]},{"name":"mdi:table-column-plus-after","tags":["text / content / format","table column add after"]},{"name":"mdi:table-column-plus-before","tags":["text / content / format","table column add before"]},{"name":"mdi:table-column-remove","tags":["text / content / format"]},{"name":"mdi:table-column-width","tags":["text / content / format"]},{"name":"mdi:table-edit","tags":["edit / modify","text / content / format"]},{"name":"mdi:table-eye","tags":[]},{"name":"mdi:table-eye-off","tags":[]},{"name":"mdi:table-filter","tags":[]},{"name":"mdi:table-furniture","tags":["home automation","kitchen","dining room"]},{"name":"mdi:table-headers-eye","tags":[]},{"name":"mdi:table-headers-eye-off","tags":[]},{"name":"mdi:table-heart","tags":["table favorite"]},{"name":"mdi:table-key","tags":[]},{"name":"mdi:table-large","tags":["text / content / format","geographic information system"]},{"name":"mdi:table-large-plus","tags":["text / content / format","geographic information system","table large add"]},{"name":"mdi:table-large-remove","tags":["text / content / format","geographic information system"]},{"name":"mdi:table-lock","tags":["lock"]},{"name":"mdi:table-minus","tags":[]},{"name":"mdi:table-multiple","tags":[]},{"name":"mdi:table-network","tags":[]},{"name":"mdi:table-off","tags":[]},{"name":"mdi:table-picnic","tags":[]},{"name":"mdi:table-pivot","tags":["text / content / format"]},{"name":"mdi:table-plus","tags":["text / content / format","table add"]},{"name":"mdi:table-question","tags":["table help"]},{"name":"mdi:table-refresh","tags":[]},{"name":"mdi:table-remove","tags":["text / content / format"]},{"name":"mdi:table-row","tags":["text / content / format"]},{"name":"mdi:table-row-height","tags":["text / content / format"]},{"name":"mdi:table-row-plus-after","tags":["text / content / format","table row add after"]},{"name":"mdi:table-row-plus-before","tags":["text / content / format","table row add before"]},{"name":"mdi:table-row-remove","tags":["text / content / format"]},{"name":"mdi:table-search","tags":[]},{"name":"mdi:table-settings","tags":["settings"]},{"name":"mdi:table-split-cell","tags":["text / content / format"]},{"name":"mdi:table-star","tags":["table favorite"]},{"name":"mdi:table-sync","tags":[]},{"name":"mdi:tablet-dashboard","tags":["device / tech"]},{"name":"mdi:taco","tags":["food / drink"]},{"name":"mdi:tag-arrow-down","tags":[]},{"name":"mdi:tag-arrow-down-outline","tags":[]},{"name":"mdi:tag-arrow-left","tags":[]},{"name":"mdi:tag-arrow-left-outline","tags":[]},{"name":"mdi:tag-arrow-right","tags":[]},{"name":"mdi:tag-arrow-right-outline","tags":[]},{"name":"mdi:tag-arrow-up","tags":[]},{"name":"mdi:tag-arrow-up-outline","tags":[]},{"name":"mdi:tag-check","tags":["tag approve"]},{"name":"mdi:tag-check-outline","tags":["tag approve outline"]},{"name":"mdi:tag-hidden","tags":[]},{"name":"mdi:tag-minus","tags":[]},{"name":"mdi:tag-minus-outline","tags":[]},{"name":"mdi:tag-multiple","tags":["tags"]},{"name":"mdi:tag-multiple-outline","tags":[]},{"name":"mdi:tag-off","tags":[]},{"name":"mdi:tag-off-outline","tags":[]},{"name":"mdi:tag-plus","tags":["tag add"]},{"name":"mdi:tag-plus-outline","tags":[]},{"name":"mdi:tag-remove","tags":[]},{"name":"mdi:tag-remove-outline","tags":[]},{"name":"mdi:tag-search","tags":["tag find"]},{"name":"mdi:tag-search-outline","tags":["tag find outline"]},{"name":"mdi:tag-text","tags":[]},{"name":"mdi:tag-text-outline","tags":[]},{"name":"mdi:tally-mark-1","tags":["math","counting 1","one"]},{"name":"mdi:tally-mark-2","tags":["math","counting 2","two"]},{"name":"mdi:tally-mark-3","tags":["math","counting 3","three"]},{"name":"mdi:tally-mark-4","tags":["math","counting 4","four"]},{"name":"mdi:tally-mark-5","tags":["math","counting 5","five"]},{"name":"mdi:tangram","tags":["gaming / rpg","puzzle"]},{"name":"mdi:tank","tags":[]},{"name":"mdi:tanker-truck","tags":["transportation + road","fuel truck","oil truck","water truck","tanker"]},{"name":"mdi:tape-drive","tags":[]},{"name":"mdi:tape-measure","tags":["hardware / tools","measuring tape"]},{"name":"mdi:target","tags":["registration mark"]},{"name":"mdi:target-account","tags":["account / user","crosshairs account","target user"]},{"name":"mdi:target-variant","tags":["registration mark"]},{"name":"mdi:tea-outline","tags":["food / drink"]},{"name":"mdi:teddy-bear","tags":["holiday","home automation","child toy","children toy","kids room","childrens room","play room"]},{"name":"mdi:telescope","tags":["science"]},{"name":"mdi:television-ambient-light","tags":["home automation"]},{"name":"mdi:television-classic","tags":["device / tech","home automation","tv classic"]},{"name":"mdi:television-classic-off","tags":["device / tech","home automation","tv classic off"]},{"name":"mdi:television-guide","tags":["device / tech","home automation"]},{"name":"mdi:television-off","tags":["device / tech","home automation","tv off"]},{"name":"mdi:television-pause","tags":["device / tech"]},{"name":"mdi:television-shimmer","tags":["device / tech","television clean"]},{"name":"mdi:television-speaker","tags":["audio","video / movie"]},{"name":"mdi:television-speaker-off","tags":["audio","video / movie"]},{"name":"mdi:television-stop","tags":["device / tech"]},{"name":"mdi:temperature-celsius","tags":["weather","temperature centigrade"]},{"name":"mdi:temperature-fahrenheit","tags":["weather"]},{"name":"mdi:temperature-kelvin","tags":["weather"]},{"name":"mdi:tennis-ball-outline","tags":["sport"]},{"name":"mdi:tent","tags":["camping"]},{"name":"mdi:test-tube","tags":["science"]},{"name":"mdi:test-tube-empty","tags":["science"]},{"name":"mdi:test-tube-off","tags":["science"]},{"name":"mdi:text-account","tags":["account / user","biography","text user"]},{"name":"mdi:text-box-check","tags":["files / folders","file document box tick","file document box check"]},{"name":"mdi:text-box-check-outline","tags":["files / folders","file document box tick outline","file document box check outline"]},{"name":"mdi:text-box-edit","tags":["files / folders","edit / modify"]},{"name":"mdi:text-box-edit-outline","tags":["files / folders","edit / modify"]},{"name":"mdi:text-box-minus","tags":["files / folders","file document box minus"]},{"name":"mdi:text-box-minus-outline","tags":["files / folders","file document box minus outline"]},{"name":"mdi:text-box-multiple","tags":["files / folders","file document boxes","file document box multiple"]},{"name":"mdi:text-box-multiple-outline","tags":["files / folders","file document boxes outline","file document box multiple outline"]},{"name":"mdi:text-box-outline","tags":["files / folders","file document box outline"]},{"name":"mdi:text-box-plus","tags":["files / folders","file document box plus"]},{"name":"mdi:text-box-plus-outline","tags":["files / folders","file document box plus outline"]},{"name":"mdi:text-box-remove","tags":["files / folders","file document box remove"]},{"name":"mdi:text-box-remove-outline","tags":["files / folders","file document box remove outline"]},{"name":"mdi:text-box-search","tags":["files / folders","file document box search"]},{"name":"mdi:text-box-search-outline","tags":["files / folders","file document box search outline"]},{"name":"mdi:text-recognition","tags":[]},{"name":"mdi:text-search","tags":["notes search"]},{"name":"mdi:text-search-variant","tags":["notes search variant"]},{"name":"mdi:text-shadow","tags":[]},{"name":"mdi:texture-box","tags":["math","surface area"]},{"name":"mdi:theater","tags":["places","home automation","cinema","theatre"]},{"name":"mdi:theme-light-dark","tags":["weather","sun moon stars"]},{"name":"mdi:thermometer","tags":["weather","home automation","automotive","temperature"]},{"name":"mdi:thermometer-alert","tags":["home automation","weather","alert / error","thermometer warning","temperature alert","temperature warning"]},{"name":"mdi:thermometer-auto","tags":["home automation","weather","temperature auto"]},{"name":"mdi:thermometer-bluetooth","tags":["weather","home automation","automotive","temperature bluetooth"]},{"name":"mdi:thermometer-check","tags":["weather","home automation","thermometer approve","temperature check","temperature approve"]},{"name":"mdi:thermometer-chevron-down","tags":["home automation","weather","temperature chevron down","temperature decrease","thermometer decrease"]},{"name":"mdi:thermometer-chevron-up","tags":["home automation","weather","temperature chevron up","temperature increase","thermometer increase"]},{"name":"mdi:thermometer-high","tags":["home automation","weather","temperature high"]},{"name":"mdi:thermometer-lines","tags":["weather","home automation","temperature lines"]},{"name":"mdi:thermometer-low","tags":["home automation","weather","temperature low"]},{"name":"mdi:thermometer-minus","tags":["home automation","weather","temperature minus","thermometer decrease","temperature decrease"]},{"name":"mdi:thermometer-off","tags":["weather","home automation","temperature off"]},{"name":"mdi:thermometer-plus","tags":["home automation","weather","thermometer add","thermometer increase","temperature plus","temperature add","temperature increase"]},{"name":"mdi:thermometer-probe","tags":[]},{"name":"mdi:thermometer-probe-off","tags":[]},{"name":"mdi:thermometer-water","tags":["weather","home automation","dew point","water temperature","boiling point"]},{"name":"mdi:thermostat-auto","tags":["home automation"]},{"name":"mdi:thermostat-box","tags":["home automation","device / tech"]},{"name":"mdi:thermostat-box-auto","tags":["home automation"]},{"name":"mdi:thermostat-cog","tags":[]},{"name":"mdi:thought-bubble","tags":["comic bubble","thinking"]},{"name":"mdi:thought-bubble-outline","tags":["comic thought bubble outline","thinking outline","think outline"]},{"name":"mdi:ticket-account","tags":["account / user","ticket user"]},{"name":"mdi:ticket-outline","tags":[]},{"name":"mdi:ticket-percent","tags":["coupon","voucher"]},{"name":"mdi:ticket-percent-outline","tags":["coupon outline","voucher outline"]},{"name":"mdi:tie","tags":["clothing"]},{"name":"mdi:tilde","tags":[]},{"name":"mdi:tilde-off","tags":[]},{"name":"mdi:timeline","tags":[]},{"name":"mdi:timeline-alert","tags":["alert / error"]},{"name":"mdi:timeline-alert-outline","tags":["alert / error"]},{"name":"mdi:timeline-check","tags":[]},{"name":"mdi:timeline-check-outline","tags":[]},{"name":"mdi:timeline-clock","tags":["date / time"]},{"name":"mdi:timeline-clock-outline","tags":["date / time"]},{"name":"mdi:timeline-minus","tags":[]},{"name":"mdi:timeline-minus-outline","tags":[]},{"name":"mdi:timeline-outline","tags":[]},{"name":"mdi:timeline-plus","tags":[]},{"name":"mdi:timeline-plus-outline","tags":[]},{"name":"mdi:timeline-question","tags":["timeline help"]},{"name":"mdi:timeline-question-outline","tags":["timeline help outline"]},{"name":"mdi:timeline-remove","tags":[]},{"name":"mdi:timeline-remove-outline","tags":[]},{"name":"mdi:timeline-text","tags":[]},{"name":"mdi:timeline-text-outline","tags":[]},{"name":"mdi:timer","tags":["sport","date / time","stopwatch"]},{"name":"mdi:timer-alert","tags":["date / time","alert / error","stopwatch alert"]},{"name":"mdi:timer-alert-outline","tags":["date / time","alert / error","stopwatch alert outline"]},{"name":"mdi:timer-cancel","tags":["date / time","stopwatch cancel"]},{"name":"mdi:timer-cancel-outline","tags":["date / time","stopwatch cancel outline"]},{"name":"mdi:timer-check","tags":["date / time","stopwatch check","timer tick","stopwatch tick"]},{"name":"mdi:timer-check-outline","tags":["date / time","timer tick outline","stopwatch check outline","stopwatch tick outline"]},{"name":"mdi:timer-cog","tags":["date / time","settings","timer settings"]},{"name":"mdi:timer-cog-outline","tags":["date / time","settings","timer settings outline"]},{"name":"mdi:timer-edit","tags":["date / time","edit / modify","stopwatch edit"]},{"name":"mdi:timer-edit-outline","tags":["date / time","edit / modify","stopwatch edit outline"]},{"name":"mdi:timer-lock","tags":["date / time","lock","stopwatch lock","timer secure","stopwatch secure"]},{"name":"mdi:timer-lock-open","tags":["date / time","lock","stopwatch lock open"]},{"name":"mdi:timer-lock-open-outline","tags":["date / time","lock","stopwatch lock open outline"]},{"name":"mdi:timer-lock-outline","tags":["date / time","lock","stopwatch lock outline","stopwatch secure outline","timer secure outline"]},{"name":"mdi:timer-marker","tags":["date / time","navigation","stopwatch marker","timer location","stopwatch location"]},{"name":"mdi:timer-marker-outline","tags":["date / time","navigation","stopwatch marker outline","timer location outline","stopwatch location outline"]},{"name":"mdi:timer-minus","tags":["date / time","timer subtract","stopwatch minus","stopwatch subtract"]},{"name":"mdi:timer-minus-outline","tags":["date / time","timer subtract outline","stopwatch minus outline","stopwatch subtract outline"]},{"name":"mdi:timer-music","tags":["date / time","music","stopwatch music"]},{"name":"mdi:timer-music-outline","tags":["date / time","music","stopwatch music outline"]},{"name":"mdi:timer-off","tags":["date / time","stopwatch off"]},{"name":"mdi:timer-pause","tags":["date / time","stopwatch pause"]},{"name":"mdi:timer-pause-outline","tags":["date / time","stopwatch pause outline"]},{"name":"mdi:timer-play","tags":["date / time","timer start","stopwatch play","stopwatch start"]},{"name":"mdi:timer-play-outline","tags":["date / time","timer start outline","stopwatch play outline","stopwatch start outline"]},{"name":"mdi:timer-plus","tags":["date / time","timer add","stopwatch plus","stopwatch add"]},{"name":"mdi:timer-plus-outline","tags":["date / time","timer add outline","stopwatch plus outline","stopwatch add outline"]},{"name":"mdi:timer-refresh","tags":["date / time","stopwatch refresh"]},{"name":"mdi:timer-refresh-outline","tags":["date / time","stopwatch refresh outline"]},{"name":"mdi:timer-remove","tags":["date / time","stopwatch remove"]},{"name":"mdi:timer-remove-outline","tags":["date / time","stopwatch remove outline"]},{"name":"mdi:timer-sand","tags":["date / time","hourglass"]},{"name":"mdi:timer-sand-complete","tags":["date / time","hourglass complete"]},{"name":"mdi:timer-sand-paused","tags":["date / time","hourglass paused"]},{"name":"mdi:timer-settings","tags":["date / time","settings"]},{"name":"mdi:timer-settings-outline","tags":["date / time","settings"]},{"name":"mdi:timer-star","tags":["date / time","timer favorite","stopwatch star","stopwatch favorite"]},{"name":"mdi:timer-star-outline","tags":["date / time","timer favorite outline","stopwatch star outline","stopwatch favorite outline"]},{"name":"mdi:timer-stop","tags":["date / time","stopwatch stop"]},{"name":"mdi:timer-stop-outline","tags":["date / time","stopwatch stop outline"]},{"name":"mdi:timer-sync","tags":["date / time","stopwatch sync"]},{"name":"mdi:timer-sync-outline","tags":["date / time","stopwatch sync outline"]},{"name":"mdi:timetable","tags":["date / time"]},{"name":"mdi:tire","tags":["automotive","agriculture","tyre","wheel"]},{"name":"mdi:toaster","tags":["home automation"]},{"name":"mdi:toaster-off","tags":["home automation"]},{"name":"mdi:toaster-oven","tags":["home automation","food / drink"]},{"name":"mdi:toggle-switch-variant","tags":["home automation","light switch on"]},{"name":"mdi:toggle-switch-variant-off","tags":["home automation","light switch off","rocker switch off"]},{"name":"mdi:toilet","tags":["home automation","bathroom","lavatory","bidet"]},{"name":"mdi:tools","tags":["hardware / tools","wrench","screwdriver"]},{"name":"mdi:tooltip","tags":["tooltip"]},{"name":"mdi:tooltip-cellphone","tags":["cellphone / phone","tooltip","cellphone location","cellphone gps","find my phone"]},{"name":"mdi:tooltip-check","tags":["tooltip"]},{"name":"mdi:tooltip-check-outline","tags":["tooltip"]},{"name":"mdi:tooltip-edit","tags":["tooltip","edit / modify"]},{"name":"mdi:tooltip-edit-outline","tags":["edit / modify","tooltip"]},{"name":"mdi:tooltip-image","tags":["tooltip"]},{"name":"mdi:tooltip-image-outline","tags":["tooltip"]},{"name":"mdi:tooltip-minus","tags":["tooltip"]},{"name":"mdi:tooltip-minus-outline","tags":["tooltip"]},{"name":"mdi:tooltip-outline","tags":["tooltip"]},{"name":"mdi:tooltip-plus","tags":["tooltip","tooltip add"]},{"name":"mdi:tooltip-plus-outline","tags":["tooltip","tooltip outline plus","tooltip add outline"]},{"name":"mdi:tooltip-question","tags":["tooltip","tooltip help"]},{"name":"mdi:tooltip-question-outline","tags":["tooltip","tooltip help outline"]},{"name":"mdi:tooltip-remove","tags":["tooltip"]},{"name":"mdi:tooltip-remove-outline","tags":["tooltip"]},{"name":"mdi:tooltip-text","tags":["tooltip"]},{"name":"mdi:tooltip-text-outline","tags":["tooltip"]},{"name":"mdi:tooth","tags":["medical / hospital","dentist"]},{"name":"mdi:tooth-outline","tags":["medical / hospital"]},{"name":"mdi:toothbrush","tags":["medical / hospital","dentist","oral hygiene"]},{"name":"mdi:toothbrush-electric","tags":["medical / hospital","dentist","oral hygiene"]},{"name":"mdi:toothbrush-paste","tags":["medical / hospital","dentist","oral hygiene"]},{"name":"mdi:torch","tags":["sport","olympics"]},{"name":"mdi:tortoise","tags":["animal","turtle","reptile"]},{"name":"mdi:toslink","tags":["audio","optical audio"]},{"name":"mdi:touch-text-outline","tags":[]},{"name":"mdi:tournament","tags":["gaming / rpg","sport","bracket"]},{"name":"mdi:tower-beach","tags":[]},{"name":"mdi:tower-fire","tags":[]},{"name":"mdi:town-hall","tags":["places","school"]},{"name":"mdi:toy-brick","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-marker","tags":["navigation","lego","plugin","extension","lego location","toy brick location"]},{"name":"mdi:toy-brick-marker-outline","tags":["navigation","extension outline","lego location outline","toy brick location outline","plugin outline","lego outline"]},{"name":"mdi:toy-brick-minus","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-minus-outline","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-outline","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-plus","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-plus-outline","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-remove","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-remove-outline","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-search","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-search-outline","tags":["lego","plugin","extension"]},{"name":"mdi:track-light","tags":["home automation"]},{"name":"mdi:track-light-off","tags":[]},{"name":"mdi:trackpad","tags":[]},{"name":"mdi:trackpad-lock","tags":["lock"]},{"name":"mdi:tractor","tags":["agriculture","transportation + road","farm"]},{"name":"mdi:trademark","tags":["tm"]},{"name":"mdi:traffic-cone","tags":["transportation + road"]},{"name":"mdi:train-car-autorack","tags":["transportation + other"]},{"name":"mdi:train-car-box","tags":["transportation + other"]},{"name":"mdi:train-car-box-full","tags":["transportation + other"]},{"name":"mdi:train-car-box-open","tags":["transportation + other"]},{"name":"mdi:train-car-caboose","tags":["transportation + other"]},{"name":"mdi:train-car-centerbeam","tags":["transportation + other"]},{"name":"mdi:train-car-centerbeam-full","tags":["transportation + other"]},{"name":"mdi:train-car-container","tags":["transportation + other"]},{"name":"mdi:train-car-flatbed","tags":["transportation + other"]},{"name":"mdi:train-car-flatbed-car","tags":["transportation + other"]},{"name":"mdi:train-car-flatbed-tank","tags":["transportation + other"]},{"name":"mdi:train-car-gondola","tags":["transportation + other"]},{"name":"mdi:train-car-gondola-full","tags":["transportation + other"]},{"name":"mdi:train-car-hopper","tags":["transportation + other"]},{"name":"mdi:train-car-hopper-covered","tags":["transportation + other"]},{"name":"mdi:train-car-hopper-full","tags":["transportation + other"]},{"name":"mdi:train-car-intermodal","tags":["transportation + other"]},{"name":"mdi:train-car-passenger","tags":["transportation + other"]},{"name":"mdi:train-car-passenger-door","tags":["transportation + other"]},{"name":"mdi:train-car-passenger-door-open","tags":["transportation + other"]},{"name":"mdi:train-car-passenger-variant","tags":["transportation + other"]},{"name":"mdi:train-car-tank","tags":["transportation + other"]},{"name":"mdi:transcribe","tags":[]},{"name":"mdi:transcribe-close","tags":[]},{"name":"mdi:transfer","tags":[]},{"name":"mdi:transfer-down","tags":["arrow"]},{"name":"mdi:transfer-left","tags":["arrow"]},{"name":"mdi:transfer-right","tags":["arrow"]},{"name":"mdi:transfer-up","tags":["arrow"]},{"name":"mdi:transit-connection","tags":["transportation + other","navigation"]},{"name":"mdi:transit-connection-horizontal","tags":["transportation + other"]},{"name":"mdi:transit-connection-variant","tags":["transportation + other","navigation"]},{"name":"mdi:transit-detour","tags":["transportation + other","navigation"]},{"name":"mdi:transit-skip","tags":["transportation + other"]},{"name":"mdi:translate-off","tags":[]},{"name":"mdi:translate-variant","tags":["developer / languages","spoken language"]},{"name":"mdi:transmission-tower","tags":["home automation","pylon","powerline","electricity","energy","power","grid"]},{"name":"mdi:transmission-tower-export","tags":["home automation","power from grid","energy from grid","electricity from grid"]},{"name":"mdi:transmission-tower-import","tags":["home automation","power to grid","energy to grid","electricity to grid","return to grid"]},{"name":"mdi:transmission-tower-off","tags":["home automation","powerline off","pylon off","grid off"]},{"name":"mdi:trash-can","tags":["delete","rubbish bin","trashcan","garbage can"]},{"name":"mdi:trash-can-outline","tags":["delete outline","rubbish bin outline","trashcan outline","garbage can outline"]},{"name":"mdi:tray","tags":["queue","printer","inbox"]},{"name":"mdi:tray-alert","tags":["alert / error","queue","printer","inbox"]},{"name":"mdi:tray-arrow-down","tags":["arrow","tray download"]},{"name":"mdi:tray-arrow-up","tags":["arrow","tray upload"]},{"name":"mdi:tray-full","tags":["queue","printer","inbox"]},{"name":"mdi:tray-minus","tags":["queue","printer","inbox"]},{"name":"mdi:tray-plus","tags":["queue","printer","inbox"]},{"name":"mdi:tray-remove","tags":["queue","printer","inbox"]},{"name":"mdi:treasure-chest","tags":["gaming / rpg","shopping","lock","jewelry box","jewel case"]},{"name":"mdi:treasure-chest-outline","tags":["gaming / rpg","lock","shopping","jewel case outline","jewelry box outline"]},{"name":"mdi:tree","tags":["nature","agriculture","plant"]},{"name":"mdi:tree-outline","tags":["nature","agriculture","plant"]},{"name":"mdi:triangle","tags":["shape"]},{"name":"mdi:triangle-down","tags":["shape"]},{"name":"mdi:triangle-down-outline","tags":["shape"]},{"name":"mdi:triangle-outline","tags":["shape"]},{"name":"mdi:triangle-small-down","tags":["shape","trending down variant"]},{"name":"mdi:triangle-small-up","tags":["shape","trending up variant"]},{"name":"mdi:triangle-wave","tags":["audio"]},{"name":"mdi:triforce","tags":["gaming / rpg","zelda"]},{"name":"mdi:trophy","tags":["sport","achievement"]},{"name":"mdi:trophy-award","tags":["sport","achievement award"]},{"name":"mdi:trophy-broken","tags":["sport"]},{"name":"mdi:trophy-outline","tags":["sport","achievement outline"]},{"name":"mdi:trophy-variant","tags":["sport","achievement variant"]},{"name":"mdi:trophy-variant-outline","tags":["sport","achievement variant outline"]},{"name":"mdi:truck-alert","tags":["transportation + road","alert / error","truck error"]},{"name":"mdi:truck-alert-outline","tags":["transportation + road","alert / error","truck error outline"]},{"name":"mdi:truck-cargo-container","tags":["transportation + road","truck shipping"]},{"name":"mdi:truck-check","tags":["transportation + road","truck tick","lorry check","courier check"]},{"name":"mdi:truck-check-outline","tags":["transportation + road"]},{"name":"mdi:truck-delivery","tags":["transportation + road","lorry delivery"]},{"name":"mdi:truck-delivery-outline","tags":["transportation + road"]},{"name":"mdi:truck-fast","tags":["transportation + road","lorry fast","courier fast"]},{"name":"mdi:truck-fast-outline","tags":["transportation + road"]},{"name":"mdi:truck-flatbed","tags":["automotive","transportation + road","truck flatbed tow"]},{"name":"mdi:truck-minus","tags":["transportation + road","truck subtract"]},{"name":"mdi:truck-minus-outline","tags":["transportation + road","truck subtract outline"]},{"name":"mdi:truck-plus","tags":["transportation + road","medical / hospital","truck add"]},{"name":"mdi:truck-plus-outline","tags":["transportation + road","medical / hospital","truck add outline"]},{"name":"mdi:truck-remove","tags":["transportation + road"]},{"name":"mdi:truck-remove-outline","tags":["transportation + road"]},{"name":"mdi:truck-snowflake","tags":["transportation + road","truck refrigerator","truck freezer"]},{"name":"mdi:truck-trailer","tags":["transportation + road"]},{"name":"mdi:trumpet","tags":["music"]},{"name":"mdi:tshirt-crew","tags":["clothing","t shirt crew"]},{"name":"mdi:tshirt-crew-outline","tags":["clothing","t shirt crew outline"]},{"name":"mdi:tshirt-v","tags":["clothing","t shirt v"]},{"name":"mdi:tshirt-v-outline","tags":["clothing","t shirt v outline"]},{"name":"mdi:tumble-dryer","tags":["home automation","laundry room"]},{"name":"mdi:tumble-dryer-alert","tags":["home automation","alert / error","laundry room alert"]},{"name":"mdi:tumble-dryer-off","tags":["home automation","laundry room off"]},{"name":"mdi:tune-variant","tags":["audio","settings","settings","equalizer"]},{"name":"mdi:tune-vertical-variant","tags":["audio","settings","settings vertical","equalizer vertical"]},{"name":"mdi:tunnel","tags":["transportation + road","transportation + other"]},{"name":"mdi:tunnel-outline","tags":["transportation + road","transportation + other"]},{"name":"mdi:turbine","tags":["transportation + flying","jet engine","wind turbine"]},{"name":"mdi:turkey","tags":["animal","holiday","agriculture","thanksgiving"]},{"name":"mdi:turnstile","tags":[]},{"name":"mdi:turnstile-outline","tags":[]},{"name":"mdi:turtle","tags":["animal","reptile"]},{"name":"mdi:two-factor-authentication","tags":[]},{"name":"mdi:typewriter","tags":[]},{"name":"mdi:ufo","tags":["unidentified flying object","alien"]},{"name":"mdi:ufo-outline","tags":["unidentified flying object outline","alien"]},{"name":"mdi:ultra-high-definition","tags":["video / movie","uhd"]},{"name":"mdi:umbrella","tags":["weather"]},{"name":"mdi:umbrella-closed","tags":["weather"]},{"name":"mdi:umbrella-closed-outline","tags":["weather"]},{"name":"mdi:umbrella-closed-variant","tags":["weather"]},{"name":"mdi:umbrella-outline","tags":["weather"]},{"name":"mdi:undo-variant","tags":["arrow"]},{"name":"mdi:unfold-less-vertical","tags":["chevron right left","collapse vertical"]},{"name":"mdi:unfold-more-vertical","tags":["chevron left right","expand vertical"]},{"name":"mdi:ungroup","tags":[]},{"name":"mdi:unicorn","tags":["animal","fantasy"]},{"name":"mdi:unicorn-variant","tags":["animal","fantasy variant"]},{"name":"mdi:unicycle","tags":["sport","transportation + other"]},{"name":"mdi:upload-lock","tags":["lock"]},{"name":"mdi:upload-lock-outline","tags":["lock"]},{"name":"mdi:upload-multiple","tags":["uploads"]},{"name":"mdi:upload-network","tags":[]},{"name":"mdi:upload-network-outline","tags":[]},{"name":"mdi:upload-off","tags":[]},{"name":"mdi:upload-off-outline","tags":[]},{"name":"mdi:upload-outline","tags":["file upload outline"]},{"name":"mdi:usb-flash-drive","tags":[]},{"name":"mdi:usb-flash-drive-outline","tags":[]},{"name":"mdi:usb-port","tags":[]},{"name":"mdi:valve","tags":["home automation"]},{"name":"mdi:valve-closed","tags":["home automation"]},{"name":"mdi:valve-open","tags":["home automation"]},{"name":"mdi:van-passenger","tags":["transportation + road"]},{"name":"mdi:van-utility","tags":["transportation + road","van candy"]},{"name":"mdi:vanish","tags":[]},{"name":"mdi:vanish-quarter","tags":[]},{"name":"mdi:vanity-light","tags":["home automation"]},{"name":"mdi:variable","tags":["developer / languages","math"]},{"name":"mdi:variable-box","tags":["developer / languages"]},{"name":"mdi:vector-arrange-above","tags":["vector","arrange","geographic information system"]},{"name":"mdi:vector-arrange-below","tags":["vector","arrange","geographic information system"]},{"name":"mdi:vector-bezier","tags":["vector"]},{"name":"mdi:vector-circle","tags":["vector","geographic information system"]},{"name":"mdi:vector-circle-variant","tags":["vector"]},{"name":"mdi:vector-combine","tags":["vector","geographic information system"]},{"name":"mdi:vector-curve","tags":["vector","geographic information system","bezier"]},{"name":"mdi:vector-difference","tags":["vector","geographic information system"]},{"name":"mdi:vector-difference-ab","tags":["vector","geographic information system"]},{"name":"mdi:vector-difference-ba","tags":["vector","geographic information system"]},{"name":"mdi:vector-ellipse","tags":["vector","geographic information system"]},{"name":"mdi:vector-intersection","tags":["vector","geographic information system"]},{"name":"mdi:vector-line","tags":["vector","geographic information system"]},{"name":"mdi:vector-link","tags":["vector","geographic information system"]},{"name":"mdi:vector-point","tags":["vector"]},{"name":"mdi:vector-point-edit","tags":["vector","edit / modify"]},{"name":"mdi:vector-point-minus","tags":["vector"]},{"name":"mdi:vector-point-plus","tags":["vector","vector point add"]},{"name":"mdi:vector-point-select","tags":["vector","geographic information system"]},{"name":"mdi:vector-polygon","tags":["vector","geographic information system"]},{"name":"mdi:vector-polygon-variant","tags":["vector"]},{"name":"mdi:vector-polyline","tags":["vector","geographic information system"]},{"name":"mdi:vector-polyline-edit","tags":["edit / modify"]},{"name":"mdi:vector-polyline-minus","tags":[]},{"name":"mdi:vector-polyline-plus","tags":[]},{"name":"mdi:vector-polyline-remove","tags":[]},{"name":"mdi:vector-radius","tags":["vector","geographic information system"]},{"name":"mdi:vector-rectangle","tags":["vector","geographic information system"]},{"name":"mdi:vector-selection","tags":["vector","geographic information system"]},{"name":"mdi:vector-square","tags":["vector","geographic information system","mdi"]},{"name":"mdi:vector-square-close","tags":["vector"]},{"name":"mdi:vector-square-edit","tags":["vector","edit / modify"]},{"name":"mdi:vector-square-minus","tags":["vector","vector square subtract"]},{"name":"mdi:vector-square-open","tags":["vector"]},{"name":"mdi:vector-square-plus","tags":["vector","vector square add"]},{"name":"mdi:vector-square-remove","tags":["vector","vector square delete"]},{"name":"mdi:vector-triangle","tags":["vector","geographic information system"]},{"name":"mdi:vector-union","tags":["vector","geographic information system"]},{"name":"mdi:vhs","tags":["video / movie","video home system","vhs cassette","vhs tape"]},{"name":"mdi:vibrate-off","tags":[]},{"name":"mdi:video-2d","tags":["video / movie"]},{"name":"mdi:video-3d","tags":["video / movie"]},{"name":"mdi:video-3d-off","tags":["video / movie"]},{"name":"mdi:video-3d-variant","tags":["video / movie"]},{"name":"mdi:video-check","tags":["video / movie"]},{"name":"mdi:video-check-outline","tags":["video / movie"]},{"name":"mdi:video-high-definition","tags":["video / movie"]},{"name":"mdi:video-input-scart","tags":["video / movie"]},{"name":"mdi:video-marker","tags":["video / movie","navigation","video location"]},{"name":"mdi:video-marker-outline","tags":["video / movie","navigation","video location outline"]},{"name":"mdi:video-minus-outline","tags":["video / movie"]},{"name":"mdi:video-plus-outline","tags":["video / movie"]},{"name":"mdi:video-vintage","tags":["video / movie","video film","video classic"]},{"name":"mdi:video-wireless","tags":["video / movie"]},{"name":"mdi:video-wireless-outline","tags":["video / movie"]},{"name":"mdi:view-dashboard-edit","tags":["view","edit / modify"]},{"name":"mdi:view-dashboard-edit-outline","tags":["view","edit / modify"]},{"name":"mdi:view-dashboard-variant-outline","tags":["view"]},{"name":"mdi:view-gallery","tags":["view"]},{"name":"mdi:view-gallery-outline","tags":["view"]},{"name":"mdi:view-grid","tags":["view"]},{"name":"mdi:view-grid-compact","tags":[]},{"name":"mdi:view-grid-outline","tags":["view"]},{"name":"mdi:view-grid-plus-outline","tags":["view"]},{"name":"mdi:view-parallel","tags":["view"]},{"name":"mdi:view-parallel-outline","tags":["view"]},{"name":"mdi:view-sequential","tags":["view"]},{"name":"mdi:view-sequential-outline","tags":["view"]},{"name":"mdi:virtual-reality","tags":["vr"]},{"name":"mdi:virus","tags":["science","medical / hospital"]},{"name":"mdi:virus-off","tags":["science"]},{"name":"mdi:virus-off-outline","tags":["science"]},{"name":"mdi:virus-outline","tags":["science","medical / hospital"]},{"name":"mdi:volume-equal","tags":["audio"]},{"name":"mdi:volume-minus","tags":["audio","home automation","cellphone / phone","volume decrease"]},{"name":"mdi:volume-mute","tags":["audio","cellphone / phone"]},{"name":"mdi:volume-plus","tags":["audio","home automation","cellphone / phone","volume increase"]},{"name":"mdi:volume-variant-off","tags":["audio","cellphone / phone"]},{"name":"mdi:volume-vibrate","tags":["cellphone / phone","audio"]},{"name":"mdi:vpn","tags":["virtual private network"]},{"name":"mdi:wall","tags":["bricks"]},{"name":"mdi:wall-fire","tags":["device / tech","firewall"]},{"name":"mdi:wall-sconce","tags":["home automation"]},{"name":"mdi:wall-sconce-flat","tags":["home automation","ceiling light flat","pot light flat"]},{"name":"mdi:wall-sconce-flat-outline","tags":["home automation"]},{"name":"mdi:wall-sconce-flat-variant","tags":["home automation","pot light flat variant"]},{"name":"mdi:wall-sconce-flat-variant-outline","tags":["home automation"]},{"name":"mdi:wall-sconce-outline","tags":["home automation"]},{"name":"mdi:wall-sconce-round","tags":["home automation","pot light round"]},{"name":"mdi:wall-sconce-round-outline","tags":["home automation"]},{"name":"mdi:wall-sconce-round-variant","tags":["home automation","pot light round variant"]},{"name":"mdi:wall-sconce-round-variant-outline","tags":["home automation"]},{"name":"mdi:wallet-bifold","tags":["currency","banking"]},{"name":"mdi:wallet-bifold-outline","tags":["banking","currency"]},{"name":"mdi:wallet-plus","tags":["banking","wallet add"]},{"name":"mdi:wallet-plus-outline","tags":["banking","wallet add outline"]},{"name":"mdi:wan","tags":["wide area network"]},{"name":"mdi:wardrobe","tags":["home automation","closet"]},{"name":"mdi:wardrobe-outline","tags":["home automation","closet outline"]},{"name":"mdi:warehouse","tags":["places"]},{"name":"mdi:washing-machine-alert","tags":["home automation","alert / error","laundry room alert"]},{"name":"mdi:washing-machine-off","tags":["home automation","laundry room off"]},{"name":"mdi:watch-export","tags":["device / tech"]},{"name":"mdi:watch-export-variant","tags":["device / tech"]},{"name":"mdi:watch-import","tags":["device / tech"]},{"name":"mdi:watch-import-variant","tags":["device / tech"]},{"name":"mdi:watch-variant","tags":["device / tech"]},{"name":"mdi:watch-vibrate","tags":["device / tech"]},{"name":"mdi:watch-vibrate-off","tags":["device / tech"]},{"name":"mdi:water-alert","tags":["alert / error","agriculture","drop alert","blood alert","ink alert"]},{"name":"mdi:water-alert-outline","tags":["alert / error","agriculture","drop alert outline","blood alert outline","ink alert outline"]},{"name":"mdi:water-boiler","tags":["home automation","water heater","gas water boiler","electric water boiler","gas water heater","electric water heater"]},{"name":"mdi:water-boiler-alert","tags":["home automation","alert / error","water heater alert","water boiler error","water heater error"]},{"name":"mdi:water-boiler-auto","tags":["home automation","water heater auto"]},{"name":"mdi:water-boiler-off","tags":["home automation","water heater off"]},{"name":"mdi:water-check","tags":["drop check","blood check","ink check"]},{"name":"mdi:water-check-outline","tags":["drop check outline","blood check outline","ink check outline"]},{"name":"mdi:water-circle","tags":["home automation","drop circle","blood circle","ink circle"]},{"name":"mdi:water-minus","tags":["drop minus","blood minus","ink minus"]},{"name":"mdi:water-minus-outline","tags":["drop minus outline","blood minus outline","ink minus outline"]},{"name":"mdi:water-off-outline","tags":["drop off outline","blood off outline","trans fat off outline","ink off outline"]},{"name":"mdi:water-opacity","tags":["home automation","drawing / art","weather","water transparent","water saver","blood saver","blood transparent","oil saver","oil transparent","drop transparent","drop saver"]},{"name":"mdi:water-outline","tags":["home automation","weather","drop outline","blood outline","water drop outline","ink outline"]},{"name":"mdi:water-percent","tags":["weather","home automation","nature","humidity","ink percent"]},{"name":"mdi:water-percent-alert","tags":["alert / error","nature","humidity alert","ink percent alert"]},{"name":"mdi:water-plus","tags":["drop plus","blood plus","ink plus"]},{"name":"mdi:water-plus-outline","tags":["drop plus outline","blood plus outline","ink plus outline"]},{"name":"mdi:water-polo","tags":["sport"]},{"name":"mdi:water-pump","tags":["agriculture","home automation","tap","kitchen tap","faucet"]},{"name":"mdi:water-pump-off","tags":["agriculture","home automation","tap off","kitchen tap off","faucet off"]},{"name":"mdi:water-remove","tags":["drop remove","blood remove","ink remove"]},{"name":"mdi:water-remove-outline","tags":["drop remove outline","blood remove outline","ink remove outline"]},{"name":"mdi:water-sync","tags":["agriculture","water recycle","water reuse"]},{"name":"mdi:water-thermometer","tags":["weather","home automation","boil point","water temperature","dew point"]},{"name":"mdi:water-thermometer-outline","tags":["weather","home automation","dew point outline","water temperature outline","boil point outline"]},{"name":"mdi:water-well","tags":[]},{"name":"mdi:water-well-outline","tags":[]},{"name":"mdi:waterfall","tags":["home automation","nature"]},{"name":"mdi:watering-can","tags":["agriculture","watering pot"]},{"name":"mdi:watering-can-outline","tags":["agriculture","watering pot outline"]},{"name":"mdi:wave","tags":["transportation + water","water"]},{"name":"mdi:waveform","tags":["audio"]},{"name":"mdi:waves","tags":["weather","transportation + water","agriculture","ocean","lake","flood","water"]},{"name":"mdi:waves-arrow-left","tags":["nature","weather","tide in","water flow"]},{"name":"mdi:waves-arrow-right","tags":["nature","weather","tide out","water flow"]},{"name":"mdi:waves-arrow-up","tags":["nature","weather","water evaporation","humidity","sea level rise","ocean level rise","climate change"]},{"name":"mdi:weather-cloudy","tags":["weather","cloud","agriculture"]},{"name":"mdi:weather-cloudy-alert","tags":["weather","alert / error","cloud"]},{"name":"mdi:weather-cloudy-arrow-right","tags":["weather","cloud"]},{"name":"mdi:weather-cloudy-clock","tags":["weather","cloud","weather history","weather time","weather date"]},{"name":"mdi:weather-dust","tags":["weather","agriculture","dust storm","windy"]},{"name":"mdi:weather-fog","tags":["weather","agriculture","weather mist"]},{"name":"mdi:weather-hail","tags":["weather","agriculture"]},{"name":"mdi:weather-hazy","tags":["weather","agriculture"]},{"name":"mdi:weather-hurricane","tags":["weather","nature","agriculture","cyclone"]},{"name":"mdi:weather-hurricane-outline","tags":["weather","nature","agriculture","cyclone outline"]},{"name":"mdi:weather-lightning","tags":["weather","agriculture","weather storm","weather thunder","weather flash"]},{"name":"mdi:weather-lightning-rainy","tags":["weather","weather thunder rainy","weather storm"]},{"name":"mdi:weather-night","tags":["weather","holiday","moon and stars","night sky"]},{"name":"mdi:weather-night-partly-cloudy","tags":["weather","cloud"]},{"name":"mdi:weather-partly-cloudy","tags":["weather","cloud","weather partlycloudy"]},{"name":"mdi:weather-partly-lightning","tags":["weather"]},{"name":"mdi:weather-partly-rainy","tags":["weather"]},{"name":"mdi:weather-partly-snowy","tags":["weather"]},{"name":"mdi:weather-partly-snowy-rainy","tags":["weather"]},{"name":"mdi:weather-pouring","tags":["weather","agriculture","weather heavy rain"]},{"name":"mdi:weather-rainy","tags":["weather","agriculture","weather drizzle","weather spitting"]},{"name":"mdi:weather-snowy","tags":["weather"]},{"name":"mdi:weather-snowy-heavy","tags":["weather","flurries"]},{"name":"mdi:weather-snowy-rainy","tags":["weather","weather sleet"]},{"name":"mdi:weather-sunny","tags":["weather"]},{"name":"mdi:weather-sunny-alert","tags":["weather","alert / error","home automation","heat alert","heat advisory","sun advisory"]},{"name":"mdi:weather-sunny-off","tags":["weather"]},{"name":"mdi:weather-sunset","tags":["weather"]},{"name":"mdi:weather-sunset-down","tags":["weather"]},{"name":"mdi:weather-sunset-up","tags":["weather","sunrise"]},{"name":"mdi:weather-tornado","tags":["weather"]},{"name":"mdi:weather-windy","tags":["weather"]},{"name":"mdi:weather-windy-variant","tags":["weather"]},{"name":"mdi:web-box","tags":["geographic information system","language box","globe box","internet box"]},{"name":"mdi:web-cancel","tags":[]},{"name":"mdi:web-check","tags":[]},{"name":"mdi:web-clock","tags":["date / time"]},{"name":"mdi:web-minus","tags":[]},{"name":"mdi:web-off","tags":[]},{"name":"mdi:web-plus","tags":[]},{"name":"mdi:web-refresh","tags":[]},{"name":"mdi:web-remove","tags":[]},{"name":"mdi:web-sync","tags":[]},{"name":"mdi:webcam","tags":["video / movie","home automation","web camera"]},{"name":"mdi:webcam-off","tags":[]},{"name":"mdi:webhook","tags":[]},{"name":"mdi:weight","tags":[]},{"name":"mdi:weight-gram","tags":[]},{"name":"mdi:weight-kilogram","tags":["weight kg"]},{"name":"mdi:weight-lifter","tags":["sport","people / family","crossfit","gym","fitness center","human barbell"]},{"name":"mdi:weight-pound","tags":["weight lb"]},{"name":"mdi:wheel-barrow","tags":["hardware / tools"]},{"name":"mdi:wheelchair","tags":["medical / hospital","people / family","accessible","isa","international symbol of access"]},{"name":"mdi:wheelchair-accessibility","tags":["medical / hospital","accessible"]},{"name":"mdi:whistle","tags":["sport"]},{"name":"mdi:whistle-outline","tags":["sport"]},{"name":"mdi:wifi","tags":[]},{"name":"mdi:wifi-alert","tags":["alert / error"]},{"name":"mdi:wifi-arrow-down","tags":[]},{"name":"mdi:wifi-arrow-left","tags":[]},{"name":"mdi:wifi-arrow-left-right","tags":[]},{"name":"mdi:wifi-arrow-right","tags":[]},{"name":"mdi:wifi-arrow-up","tags":[]},{"name":"mdi:wifi-arrow-up-down","tags":[]},{"name":"mdi:wifi-cancel","tags":[]},{"name":"mdi:wifi-check","tags":[]},{"name":"mdi:wifi-cog","tags":["settings"]},{"name":"mdi:wifi-lock","tags":["lock"]},{"name":"mdi:wifi-lock-open","tags":["lock"]},{"name":"mdi:wifi-marker","tags":["navigation","wifi location"]},{"name":"mdi:wifi-minus","tags":[]},{"name":"mdi:wifi-off","tags":[]},{"name":"mdi:wifi-plus","tags":[]},{"name":"mdi:wifi-refresh","tags":[]},{"name":"mdi:wifi-remove","tags":[]},{"name":"mdi:wifi-settings","tags":["settings"]},{"name":"mdi:wifi-star","tags":["wifi favourite","network favourite","wifi favorite","network favorite"]},{"name":"mdi:wifi-strength-1","tags":[]},{"name":"mdi:wifi-strength-1-alert","tags":["alert / error","wifi strength 1 warning"]},{"name":"mdi:wifi-strength-1-lock","tags":["lock"]},{"name":"mdi:wifi-strength-1-lock-open","tags":["lock"]},{"name":"mdi:wifi-strength-2","tags":[]},{"name":"mdi:wifi-strength-2-alert","tags":["alert / error","wifi strength 2 warning"]},{"name":"mdi:wifi-strength-2-lock","tags":["lock"]},{"name":"mdi:wifi-strength-2-lock-open","tags":["lock"]},{"name":"mdi:wifi-strength-3","tags":[]},{"name":"mdi:wifi-strength-3-alert","tags":["alert / error","wifi strength 3 warning"]},{"name":"mdi:wifi-strength-3-lock","tags":["lock"]},{"name":"mdi:wifi-strength-3-lock-open","tags":["lock"]},{"name":"mdi:wifi-strength-4","tags":[]},{"name":"mdi:wifi-strength-4-alert","tags":["alert / error","wifi strength 4 warning"]},{"name":"mdi:wifi-strength-4-lock","tags":["lock"]},{"name":"mdi:wifi-strength-4-lock-open","tags":["lock"]},{"name":"mdi:wifi-strength-alert-outline","tags":["alert / error","wifi strength warning outline","wifi strength 0 alert","wifi strength 0 warning"]},{"name":"mdi:wifi-strength-lock-open-outline","tags":["lock"]},{"name":"mdi:wifi-strength-lock-outline","tags":["lock","wifi strength 0 lock"]},{"name":"mdi:wifi-strength-off","tags":[]},{"name":"mdi:wifi-strength-off-outline","tags":[]},{"name":"mdi:wifi-strength-outline","tags":["wifi strength 0"]},{"name":"mdi:wifi-sync","tags":[]},{"name":"mdi:wind-turbine-alert","tags":["home automation","alert / error","wind power alert","wind turbine warning"]},{"name":"mdi:wind-turbine-check","tags":["home automation","wind power check","wind turbine success","wind power success"]},{"name":"mdi:window-close","tags":["cancel","close"]},{"name":"mdi:window-closed","tags":["home automation"]},{"name":"mdi:window-closed-variant","tags":["home automation"]},{"name":"mdi:window-maximize","tags":[]},{"name":"mdi:window-minimize","tags":[]},{"name":"mdi:window-open","tags":["home automation"]},{"name":"mdi:window-open-variant","tags":["home automation"]},{"name":"mdi:window-restore","tags":[]},{"name":"mdi:window-shutter","tags":["home automation"]},{"name":"mdi:window-shutter-alert","tags":["home automation","alert / error"]},{"name":"mdi:window-shutter-auto","tags":["home automation"]},{"name":"mdi:window-shutter-cog","tags":["home automation","settings","window shutter settings"]},{"name":"mdi:window-shutter-open","tags":["home automation"]},{"name":"mdi:window-shutter-settings","tags":["home automation","settings"]},{"name":"mdi:windsock","tags":["weather"]},{"name":"mdi:wiper","tags":[]},{"name":"mdi:wiper-wash","tags":["automotive","wiper fluid","washer fluid"]},{"name":"mdi:wiper-wash-alert","tags":["alert / error","automotive","wiper fluid alert","washer fluid alert","wiper fluid low","washer fluid low"]},{"name":"mdi:wizard-hat","tags":["clothing","gaming / rpg"]},{"name":"mdi:wrap","tags":[]},{"name":"mdi:wrap-disabled","tags":["unwrap"]},{"name":"mdi:wrench-check","tags":[]},{"name":"mdi:wrench-check-outline","tags":[]},{"name":"mdi:wrench-clock","tags":["date / time","hardware / tools","scheduled maintenance","wrench time","tool time","tool clock"]},{"name":"mdi:wrench-clock-outline","tags":["date / time"]},{"name":"mdi:wrench-cog","tags":["settings","wrench settings"]},{"name":"mdi:wrench-cog-outline","tags":["settings","wrench settings outline"]},{"name":"mdi:xml","tags":["developer / languages","code"]},{"name":"mdi:yeast","tags":[]},{"name":"mdi:yin-yang","tags":["taoism"]},{"name":"mdi:yoga","tags":["sport"]},{"name":"mdi:yurt","tags":[]},{"name":"mdi:zip-box-outline","tags":["files / folders","compressed file outline"]},{"name":"mdi:zip-disk","tags":[]},{"name":"mdi:zodiac-aquarius","tags":["horoscope aquarius"]},{"name":"mdi:zodiac-aries","tags":["horoscope aries"]},{"name":"mdi:zodiac-cancer","tags":["horoscope cancer"]},{"name":"mdi:zodiac-capricorn","tags":["horoscope capricorn"]},{"name":"mdi:zodiac-gemini","tags":["horoscope gemini"]},{"name":"mdi:zodiac-leo","tags":["horoscope leo"]},{"name":"mdi:zodiac-libra","tags":["horoscope libra"]},{"name":"mdi:zodiac-pisces","tags":["horoscope pisces"]},{"name":"mdi:zodiac-sagittarius","tags":["horoscope sagittarius"]},{"name":"mdi:zodiac-scorpio","tags":["horoscope scorpio"]},{"name":"mdi:zodiac-taurus","tags":["horoscope taurus"]},{"name":"mdi:zodiac-virgo","tags":["horoscope virgo"]}] \ No newline at end of file diff --git a/ui-ngx/src/assets/metadata/units.json b/ui-ngx/src/assets/metadata/units.json new file mode 100644 index 0000000000..988c3f34ce --- /dev/null +++ b/ui-ngx/src/assets/metadata/units.json @@ -0,0 +1,2013 @@ +[{ + "name": "unit.millimeter", + "symbol": "mm", + "tags": ["level","height","distance","length","width","gap","depth","millimeter","millimeters","rainfall","precipitation", + "displacement","position","movement","transition","mm"] +}, +{ + "name": "unit.centimeter", + "symbol": "cm", + "tags": ["level","height","distance","length","width","gap","depth","centimeter","centimeters","rainfall","precipitation", + "displacement","position","movement","transition","cm"] +}, +{ + "name": "unit.angstrom", + "symbol": "Å", + "tags": ["level","height","distance","length","width","gap","depth","atomic scale","atomic distance","nanoscale", + "angstrom","angstroms","Å"] +}, +{ + "name": "unit.nanometer", + "symbol": "nm", + "tags": ["level","height","distance","length","width","gap","depth","nanoscale","atomic scale","molecular scale", + "nanometer","nanometers","nm"] +}, +{ + "name": "unit.micrometer", + "symbol": "µm", + "tags": ["level","height","distance","length","width","gap","depth","microns","micrometer","micrometers","µm"] +}, +{ + "name": "unit.meter", + "symbol": "m", + "tags": ["level","height","distance","length","width","gap","depth","meter","meters","m"] +}, +{ + "name": "unit.kilometer", + "symbol": "km", + "tags": ["distance","height","length","width","gap","depth","kilometer","kilometers","km"] +}, +{ + "name": "unit.inch", + "symbol": "in", + "tags": ["level","height","distance","length","width","gap","depth","inch","inches","in"] +}, +{ + "name": "unit.foot", + "symbol": "ft", + "tags": ["level","height","distance","length","width","gap","depth","foot","feet","ft"] +}, +{ + "name": "unit.yard", + "symbol": "yd", + "tags": ["level","height","distance","length","width","gap","depth","yard","yards","yd"] +}, +{ + "name": "unit.mile", + "symbol": "mi", + "tags": ["level","height","distance","length","width","gap","depth","mile","miles","mi"] +}, +{ + "name": "unit.nautical-mile", + "symbol": "nm", + "tags": ["level","height","distance","length","width","gap","depth","nautical mile","nm"] +}, +{ + "name": "unit.astronomical-unit", + "symbol": "AU", + "tags": ["distance","celestial bodies","solar system","AU"] +}, +{ + "name": "unit.reciprocal-metre", + "symbol": "m⁻¹", + "tags": ["wavenumber","wave density","wave frequency","m⁻¹"] +}, +{ + "name": "unit.meter-per-meter", + "symbol": "m/m", + "tags": ["ratio of length to length","meter per meter","m/m"] +}, +{ + "name": "unit.steradian", + "symbol": "sr", + "tags": ["solid angle","spatial extent","steradian","sr"] +}, +{ + "name": "unit.thou", + "symbol": "thou", + "tags": ["length","measurement","thou"] +}, +{ + "name": "unit.barleycorn", + "symbol": "barleycorn", + "tags": ["length","shoe size","barleycorn"] +}, +{ + "name": "unit.hand", + "symbol": "hand", + "tags": ["length","horse measurement","hand"] +}, +{ + "name": "unit.chain", + "symbol": "ch", + "tags": ["length","land surveying","ch"] +}, +{ + "name": "unit.furlong", + "symbol": "fur", + "tags": ["length","land surveying","fur"] +}, +{ + "name": "unit.league", + "symbol": "league", + "tags": ["length","historical measurement","league"] +}, +{ + "name": "unit.fathom", + "symbol": "fathom", + "tags": ["depth","nautical measurement","fathom"] +}, +{ + "name": "unit.cable", + "symbol": "cable", + "tags": ["distance","nautical measurement","cable"] +}, +{ + "name": "unit.link", + "symbol": "link", + "tags": ["length","land surveying","link"] +}, +{ + "name": "unit.rod", + "symbol": "rod", + "tags": ["length","land surveying","rod"] +}, +{ + "name": "unit.nanogram", + "symbol": "ng", + "tags": ["mass","weight","heaviness","load","nanogram","nanograms","ng"] +}, +{ + "name": "unit.microgram", + "symbol": "μg", + "tags": ["mass","weight","heaviness","load","μg","microgram"] +}, +{ + "name": "unit.milligram", + "symbol": "mg", + "tags": ["mass","weight","heaviness","load","milligram","miligrams","mg"] +}, +{ + "name": "unit.gram", + "symbol": "g", + "tags": ["mass","weight","heaviness","load","gram","grams","g"] +}, +{ + "name": "unit.kilogram", + "symbol": "kg", + "tags": ["mass","weight","heaviness","load","kilogram","kilograms","kg"] +}, +{ + "name": "unit.tonne", + "symbol": "t", + "tags": ["mass","weight","heaviness","load","tonne","tons","t"] +}, +{ + "name": "unit.ounce", + "symbol": "oz", + "tags": ["mass","weight","heaviness","load","ounce","ounces","oz"] +}, +{ + "name": "unit.pound", + "symbol": "lb", + "tags": ["mass","weight","heaviness","load","pound","pounds","lb"] +}, +{ + "name": "unit.stone", + "symbol": "st", + "tags": ["mass","weight","heaviness","load","stone","stones","st"] +}, +{ + "name": "unit.hundredweight-count", + "symbol": "cwt", + "tags": ["mass","weight","heaviness","load","hundredweight count","cwt"] +}, +{ + "name": "unit.short-tons", + "symbol": "short tons", + "tags": ["mass","weight","heaviness","load","short ton","short tons"] +}, +{ + "name": "unit.dalton", + "symbol": "Da", + "tags": ["atomic mass unit","AMU","unified atomic mass unit","dalton","Da"] +}, +{ + "name": "unit.grain", + "symbol": "gr", + "tags": ["mass","measurement","grain","gr"] +}, +{ + "name": "unit.drachm", + "symbol": "dr", + "tags": ["mass","measurement","drachm","dr"] +}, +{ + "name": "unit.quarter", + "symbol": "qr", + "tags": ["mass","measurement","quarter","qr"] +}, +{ + "name": "unit.slug", + "symbol": "slug", + "tags": ["mass","measurement","slug"] +}, +{ + "name": "unit.carat", + "symbol": "ct", + "tags": ["gemstone","pearl","jewelry","carat","ct"] +}, +{ + "name": "unit.cubic-millimeter", + "symbol": "mm³", + "tags": ["volume","capacity","extent","cubic millimeter","mm³"] +}, +{ + "name": "unit.cubic-centimeter", + "symbol": "cm³", + "tags": ["volume","capacity","extent","cubic centimeter","cubic centimeters","cm³"] +}, +{ + "name": "unit.cubic-meter", + "symbol": "m³", + "tags": ["volume","capacity","extent","cubic meter","cubic meters","m³"] +}, +{ + "name": "unit.cubic-kilometer", + "symbol": "km³", + "tags": ["volume","capacity","extent","cubic kilometer","cubic kilometers","km³"] +}, +{ + "name": "unit.microliter", + "symbol": "µL", + "tags": ["volume","liquid measurement","microliter","µL"] +}, +{ + "name": "unit.milliliter", + "symbol": "mL", + "tags": ["volume","capacity","extent","milliliter","milliliters","mL"] +}, +{ + "name": "unit.liter", + "symbol": "l", + "tags": ["volume","capacity","extent","liter","liters","l"] +}, +{ + "name": "unit.hectoliter", + "symbol": "hl", + "tags": ["volume","capacity","extent","hectoliter","hectoliters","hl"] +}, +{ + "name": "unit.cubic-inch", + "symbol": "in³", + "tags": ["volume","capacity","extent","cubic inch","cubic inches","in³"] +}, +{ + "name": "unit.cubic-foot", + "symbol": "ft³", + "tags": ["volume","capacity","extent","cubic foot","cubic feet","ft³"] +}, +{ + "name": "unit.cubic-yard", + "symbol": "yd³", + "tags": ["volume","capacity","extent","cubic yard","cubic yards","yd³"] +}, +{ + "name": "unit.fluid-ounce", + "symbol": "fl-oz", + "tags": ["volume","capacity","extent","fluid ounce","fluid ounces","fl-oz"] +}, +{ + "name": "unit.pint", + "symbol": "pt", + "tags": ["volume","capacity","extent","pint","pints","pt"] +}, +{ + "name": "unit.quart", + "symbol": "qt", + "tags": ["volume","capacity","extent","quart","quarts","qt"] +}, +{ + "name": "unit.gallon", + "symbol": "gal", + "tags": ["volume","capacity","extent","gallon","gallons","gal"] +}, +{ + "name": "unit.oil-barrels", + "symbol": "bbl", + "tags": ["volume","capacity","extent","oil barrel","oil barrels","bbl"] +}, +{ + "name": "unit.cubic-meter-per-kilogram", + "symbol": "m³/kg", + "tags": ["specific volume","volume per unit mass","cubic meter per kilogram","m³/kg"] +}, +{ + "name": "unit.gill", + "symbol": "gi", + "tags": ["volume","liquid measurement","gi"] +}, +{ + "name": "unit.hogshead", + "symbol": "hhd", + "tags": ["volume","liquid measurement","hhd"] +}, +{ + "name": "unit.teaspoon", + "symbol": "tsp", + "tags": ["volume","cooking measurement","tsp"] +}, +{ + "name": "unit.tablespoon", + "symbol": "tbsp", + "tags": ["volume","cooking measurement","tbsp"] +}, +{ + "name": "unit.cup", + "symbol": "cup", + "tags": ["volume","cooking measurement","cup"] +}, +{ + "name": "unit.celsius", + "symbol": "°C", + "tags": ["temperature","heat","cold","warmth","degrees","celsius","shipment condition","°C"] +}, +{ + "name": "unit.kelvin", + "symbol": "K", + "tags": ["temperature","heat","cold","warmth","degrees","kelvin","K","color quality","white balance","color temperature"] +}, +{ + "name": "unit.rankine", + "symbol": "°R", + "tags": ["temperature","heat","cold","warmth","Rankine","°R"] +}, +{ + "name": "unit.fahrenheit", + "symbol": "°F", + "tags": ["temperature","heat","cold","warmth","degrees","fahrenheit","°F"] +}, +{ + "name": "unit.meter-per-second", + "symbol": "m/s", + "tags": ["speed","velocity","pace","meter per second","m/s","peak","peak to peak","root mean square (RMS)", + "vibration","wind speed","weather"] +}, +{ + "name": "unit.kilometer-per-hour", + "symbol": "km/h", + "tags": ["speed","velocity","pace","kilometer per hour","km/h"] +}, +{ + "name": "unit.foot-per-second", + "symbol": "ft/s", + "tags": ["speed","velocity","pace","foot per second","ft/s"] +}, +{ + "name": "unit.mile-per-hour", + "symbol": "mph", + "tags": ["speed","velocity","pace","mile per hour","mph"] +}, +{ + "name": "unit.knot", + "symbol": "kt", + "tags": ["speed","velocity","pace","knot","knots","kt"] +}, +{ + "name": "unit.millimeters-per-minute", + "symbol": "mm/min", + "tags": ["feed rate","cutting feed rate","millimeters per minute","mm/min"] +}, +{ + "name": "unit.kilometer-per-hour-squared", + "symbol": "km/h²", + "tags": ["acceleration","rate of change of velocity","kilometer per hour squared","km/h²"] +}, +{ + "name": "unit.foot-per-second-squared", + "symbol": "ft/s²", + "tags": ["acceleration","rate of change of velocity","foot per second squared","ft/s²"] +}, +{ + "name": "unit.pascal", + "symbol": "Pa", + "tags": ["pressure","force","compression","tension","pascal","pascals","Pa","atmospheric pressure","air pressure", + "weather","altitude","flight"] +}, +{ + "name": "unit.kilopascal", + "symbol": "kPa", + "tags": ["pressure","force","compression","tension","kilopascal","kilopascals","kPa"] +}, +{ + "name": "unit.megapascal", + "symbol": "MPa", + "tags": ["pressure","force","compression","tension","megapascal","megapascals","MPa"] +}, +{ + "name": "unit.gigapascal", + "symbol": "GPa", + "tags": ["pressure","force","compression","tension","gigapascal","gigapascals","GPa"] +}, +{ + "name": "unit.millibar", + "symbol": "mbar", + "tags": ["pressure","force","compression","tension","millibar","millibars","mbar"] +}, +{ + "name": "unit.bar", + "symbol": "bar", + "tags": ["pressure","force","compression","tension","bar","bars"] +}, +{ + "name": "unit.kilobar", + "symbol": "kbar", + "tags": ["pressure","force","compression","tension","kilobar","kilobars","kbar"] +}, +{ + "name": "unit.newton", + "symbol": "N", + "tags": ["force","pressure","newton","newtons","N","push","pull","weight","gravity","N"] +}, +{ + "name": "unit.newton-meter", + "symbol": "Nm", + "tags": ["torque","rotational force","newton meter","Nm"] +}, +{ + "name": "unit.foot-pounds", + "symbol": "ft·lbf", + "tags": ["torque","rotational force","foot-pound","foot-pounds","ft·lbf"] +}, +{ + "name": "unit.inch-pounds", + "symbol": "in·lbf", + "tags": ["torque","rotational force","inch-pounds","inch-pound","in·lbf"] +}, +{ + "name": "unit.newton-per-meter", + "symbol": "N/m", + "tags": ["linear density","force per unit length","newton per meter","N/m"] +}, +{ + "name": "unit.atmospheres", + "symbol": "atm", + "tags": ["pressure","force","compression","tension","atmosphere","atmospheres","atmospheric pressure","atm"] +}, +{ + "name": "unit.pounds-per-square-inch", + "symbol": "psi", + "tags": ["pressure","force","compression","tension","pounds per square inch","psi"] +}, +{ + "name": "unit.torr", + "symbol": "Torr", + "tags": ["pressure","force","compression","tension","vacuum pressure","torr"] +}, +{ + "name": "unit.inches-of-mercury", + "symbol": "inHg", + "tags": ["pressure","force","compression","tension","vacuum pressure","inHg","atmospheric pressure","barometric pressure"] +}, +{ + "name": "unit.pascal-per-square-meter", + "symbol": "Pa/m²", + "tags": ["pressure","stress","mechanical strength","pascal per square meter","Pa/m²"] +}, +{ + "name": "unit.pound-per-square-inch", + "symbol": "psi/in²", + "tags": ["pressure","stress","mechanical strength","pound per square inch","psi/in²"] +}, +{ + "name": "unit.newton-per-square-meter", + "symbol": "N/m²", + "tags": ["pressure","stress","mechanical strength","newton per square meter","N/m²"] +}, +{ + "name": "unit.kilogram-force-per-square-meter", + "symbol": "kgf/m²", + "tags": ["pressure","stress","mechanical strength","kilogram-force per square meter","kgf/m²"] +}, +{ + "name": "unit.pascal-per-square-centimeter", + "symbol": "Pa/cm²", + "tags": ["pressure","stress","mechanical strength","pascal per square centimeter","Pa/cm²"] +}, +{ + "name": "unit.ton-force-per-square-inch", + "symbol": "tonf/in²", + "tags": ["pressure","stress","mechanical strength","ton-force per square inch","tonf/in²"] +}, +{ + "name": "unit.kilonewton-per-square-meter", + "symbol": "kN/m²", + "tags": ["stress","pressure","mechanical strength","kilonewton per square meter","kN/m²"] +}, +{ + "name": "unit.newton-per-square-millimeter", + "symbol": "N/mm²", + "tags": ["stress","pressure","mechanical strength","newton per square millimeter","N/mm²"] +}, +{ + "name": "unit.microjoule", + "symbol": "μJ", + "tags": ["energy","microjoule","microjoules","μJ"] +}, +{ + "name": "unit.millijoule", + "symbol": "mJ", + "tags": ["energy","millijoule","millijoules","mJ"] +}, +{ + "name": "unit.joule", + "symbol": "J", + "tags": ["joule","joules","energy","work done","heat","electricity","mechanical work"] +}, +{ + "name": "unit.kilojoule", + "symbol": "kJ", + "tags": ["energy","kilojoule","kilojoules","kJ"] +}, +{ + "name": "unit.megajoule", + "symbol": "MJ", + "tags": ["energy","megajoule","megajoules","MJ"] +}, +{ + "name": "unit.gigajoule", + "symbol": "GJ", + "tags": ["energy","gigajoule","gigajoules","GJ"] +}, +{ + "name": "unit.watt-hour", + "symbol": "Wh", + "tags": ["energy","watt-hour","watt-hours","energy usage","power consumption","energy consumption","electricity usage"] +}, +{ + "name": "unit.kilowatt-hour", + "symbol": "kWh", + "tags": ["energy","kilowatt-hour","kilowatt-hours","energy usage","power consumption","energy consumption","electricity usage"] +}, +{ + "name": "unit.electron-volts", + "symbol": "eV", + "tags": ["energy","subatomic particles","radiation"] +}, +{ + "name": "unit.joules-per-coulomb", + "symbol": "J/C", + "tags": ["electrical potential energy","voltage","joules per coulomb","J/C"] +}, +{ + "name": "unit.british-thermal-unit", + "symbol": "BTU", + "tags": ["energy","heat","work done","british thermal unit","british thermal units","BTU"] +}, +{ + "name": "unit.foot-pound", + "symbol": "ft·lb", + "tags": ["energy","foot-pound","foot-pounds","ft·lb","ft⋅lbf"] +}, +{ + "name": "unit.calorie", + "symbol": "Cal", + "tags": ["energy","food energy","Calorie","Calories","Cal"] +}, +{ + "name": "unit.small-calorie", + "symbol": "cal", + "tags": ["energy","small calorie","calories","cal"] +}, +{ + "name": "unit.kilocalorie", + "symbol": "kcal", + "tags": ["energy","small calorie","kilocalories","kcal"] +}, +{ + "name": "unit.joule-per-kelvin", + "symbol": "J/K", + "tags": ["specific heat capacity","heat capacity per unit temperature","joule per kelvin","J/K"] +}, +{ + "name": "unit.joule-per-kilogram-kelvin", + "symbol": "J/(kg·K)", + "tags": ["specific heat capacity","heat capacity per unit mass and temperature","joule per kilogram-kelvin","J/(kg·K)"] +}, +{ + "name": "unit.joule-per-kilogram", + "symbol": "J/kg", + "tags": ["specific energy","specific energy capacity","joule per kilogram","J/kg"] +}, +{ + "name": "unit.watt-per-meter-kelvin", + "symbol": "W/(m·K)", + "tags": ["thermal conductivity","watt per meter-kelvin","W/(m·K)"] +}, +{ + "name": "unit.joule-per-cubic-meter", + "symbol": "J/m³", + "tags": ["energy density","joule per cubic meter","J/m³"] +}, +{ + "name": "unit.therm", + "symbol": "thm", + "tags": ["energy","natural gas consumption","BTU","therm","thm"] +}, +{ + "name": "unit.electric-dipole-moment", + "symbol": "C·m", + "tags": ["electric dipole","dipole moment","coulomb meter","C·m"] +}, +{ + "name": "unit.magnetic-dipole-moment", + "symbol": "A·m²", + "tags": ["magnetic dipole","dipole moment","ampere square meter","A·m²"] +}, +{ + "name": "unit.debye", + "symbol": "D", + "tags": ["polarization","electric dipole moment","debye","D"] +}, +{ + "name": "unit.coulomb-per-square-meter-per-volt", + "symbol": "C·m²/V", + "tags": ["polarization","electric field","coulomb per square meter per volt","C·m²/V"] +}, +{ + "name": "unit.milliwatt", + "symbol": "mW", + "tags": ["power","horsepower","performance","milliwatt","milliwatts","electricity","mW"] +}, +{ + "name": "unit.microwatt", + "symbol": "μW", + "tags": ["power","horsepower","performance","microwatt","microwatts","electricity","μW"] +}, +{ + "name": "unit.watt", + "symbol": "W", + "tags": ["power","horsepower","performance","watt","watts","electricity","W"] +}, +{ + "name": "unit.kilowatt", + "symbol": "kW", + "tags": ["power","horsepower","performance","kilowatt","kilowatts","electricity","kW"] +}, +{ + "name": "unit.megawatt", + "symbol": "MW", + "tags": ["power","horsepower","performance","megawatt","megawatts","electricity","MW"] +}, +{ + "name": "unit.gigawatt", + "symbol": "GW", + "tags": ["power","horsepower","performance","gigawatt","gigawatts","electricity","GW"] +}, +{ + "name": "unit.metric-horsepower", + "symbol": "PS", + "tags": ["power","performance","metric horsepower","PS"] +}, +{ + "name": "unit.milliwatt-per-square-centimeter", + "symbol": "mW/cm²", + "tags": ["power density","radiation intensity","sunlight intensity","signal power","intensity", + "milliwatts per square centimeter","UV Intensity","mW/cm²"] +}, +{ + "name": "unit.watt-per-square-centimeter", + "symbol": "W/cm²", + "tags": ["power density","intensity of power","watts per square centimeter","W/cm²"] +}, +{ + "name": "unit.kilowatt-per-square-centimeter", + "symbol": "kW/cm²", + "tags": ["power density","intensity of power","kilowatts per square centimeter","kW/cm²"] +}, +{ + "name": "unit.milliwatt-per-square-meter", + "symbol": "mW/m²", + "tags": ["power density","intensity of power","milliwatts per square meter","mW/m²"] +}, +{ + "name": "unit.watt-per-square-meter", + "symbol": "W/m²", + "tags": ["power density","intensity of power","watts per square meter","W/m²"] +}, +{ + "name": "unit.kilowatt-per-square-meter", + "symbol": "kW/m²", + "tags": ["power density","intensity of power","kilowatts per square meter","kW/m²"] +}, +{ + "name": "unit.watt-per-square-inch", + "symbol": "W/in²", + "tags": ["power density","intensity of power","watts per square inch","W/in²"] +}, +{ + "name": "unit.kilowatt-per-square-inch", + "symbol": "kW/in²", + "tags": ["power density","intensity of power","kilowatts per square inch","kW/in²"] +}, +{ + "name": "unit.horsepower", + "symbol": "hp", + "tags": ["power","horsepower","performance","electricity","horsepowers","hp"] +}, +{ + "name": "unit.btu-per-hour", + "symbol": "BTU/h", + "tags": ["power","heat transfer","thermal energy","HVAC","BTU/h"] +}, +{ + "name": "unit.coulomb", + "symbol": "C", + "tags": ["charge","electricity","electrostatics","Coulomb","C"] +}, +{ + "name": "unit.millicoulomb", + "symbol": "mC", + "tags": ["charge","electricity","electrostatics","millicoulombs","mC"] +}, +{ + "name": "unit.microcoulomb", + "symbol": "µC", + "tags": ["charge","electricity","electrostatics","microcoulomb","µC"] +}, +{ + "name": "unit.picocoulomb", + "symbol": "pC", + "tags": ["charge","electricity","electrostatics","picocoulomb","pC"] +}, +{ + "name": "unit.coulomb-per-meter", + "symbol": "C/m", + "tags": ["electric displacement field per length","coulomb per meter","C/m"] +}, +{ + "name": "unit.coulomb-per-cubic-meter", + "symbol": "C/m³", + "tags": ["electric charge density","coulomb per cubic meter","C/m³"] +}, +{ + "name": "unit.coulomb-per-square-meter", + "symbol": "C/m²", + "tags": ["electric surface charge density","coulomb per square meter","C/m²"] +}, +{ + "name": "unit.square-millimeter", + "symbol": "mm²", + "tags": ["area","lot","zone","space","region","square millimeter","square millimeters","mm²","sq-mm"] +}, +{ + "name": "unit.square-centimeter", + "symbol": "cm²", + "tags": ["area","lot","zone","space","region","square centimeter","square centimeters","cm²","sq-cm"] +}, +{ + "name": "unit.square-meter", + "symbol": "m²", + "tags": ["area","lot","zone","space","region","square meter","square meters","m²","sq-m"] +}, +{ + "name": "unit.hectare", + "symbol": "ha", + "tags": ["area","lot","zone","space","region","hectare","hectares","ha"] +}, +{ + "name": "unit.square-kilometer", + "symbol": "km²", + "tags": ["area","lot","zone","space","region","square kilometer","square kilometers","km²","sq-km"] +}, +{ + "name": "unit.square-inch", + "symbol": "in²", + "tags": ["area","lot","zone","space","region","square inch","square inches","in²","sq-in"] +}, +{ + "name": "unit.square-foot", + "symbol": "ft²", + "tags": ["area","lot","zone","space","region","square foot","square feet","ft²","sq-ft"] +}, +{ + "name": "unit.square-yard", + "symbol": "yd²", + "tags": ["area","lot","zone","space","region","square yard","square yards","yd²","sq-yd"] +}, +{ + "name": "unit.acre", + "symbol": "a", + "tags": ["area","lot","zone","space","region","acre","acres","a"] +}, +{ + "name": "unit.square-mile", + "symbol": "ml²", + "tags": ["area","lot","zone","space","region","square mile","square miles","ml²","sq-mi"] +}, +{ + "name": "unit.are", + "symbol": "are", + "tags": ["area","land measurement","are"] +}, +{ + "name": "unit.barn", + "symbol": "barn", + "tags": ["cross-sectional area","particle physics","nuclear physics","barn"] +}, +{ + "name": "unit.circular-inch", + "symbol": "circin", + "tags": ["area","circular measurement","circular inch","circin"] +}, +{ + "name": "unit.milliampere-hour", + "symbol": "mAh", + "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity", + "electrical flow","milliampere-hour","milliampere-hours","mAh"] +}, +{ + "name": "unit.ampere-hours", + "symbol": "Ah", + "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity", + "electrical flow","ampere","ampere-hours","Ah"] +}, +{ + "name": "unit.kiloampere-hours", + "symbol": "kAh", + "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity","electrical flow", + "kiloampere-hours","kiloampere-hour","kAh"] +}, +{ + "name": "unit.nanoampere", + "symbol": "nA", + "tags": ["current","amperes","nanoampere","nA"] +}, +{ + "name": "unit.picoampere", + "symbol": "pA", + "tags": ["current","amperes","picoampere","pA"] +}, +{ + "name": "unit.microampere", + "symbol": "μA", + "tags": ["electric current","microampere","microamperes","μA"] +}, +{ + "name": "unit.milliampere", + "symbol": "mA", + "tags": ["electric current","milliampere","milliamperes","mA"] +}, +{ + "name": "unit.ampere", + "symbol": "A", + "tags": ["electric current","current flow","flow of electricity","electrical flow","ampere","amperes","amperage","A"] +}, +{ + "name": "unit.kiloamperes", + "symbol": "kA", + "tags": ["electric current","current flow","kiloamperes","kA"] +}, +{ + "name": "unit.microampere-per-square-centimeter", + "symbol": "µA/cm²", + "tags": ["Current density","microampere per square centimeter","µA/cm²"] +}, +{ + "name": "unit.ampere-per-square-meter", + "symbol": "A/m²", + "tags": ["current density","current per unit area","ampere per square meter","A/m²"] +}, +{ + "name": "unit.ampere-per-meter", + "symbol": "A/m", + "tags": ["magnetic field strength","magnetic field intensity","ampere per meter","A/m"] +}, +{ + "name": "unit.oersted", + "symbol": "Oe", + "tags": ["magnetic field","oersted","Oe"] +}, +{ + "name": "unit.bohr-magneton", + "symbol": "μB", + "tags": ["atomic physics","magnetic moment","bohr magneton","μB"] +}, +{ + "name": "unit.ampere-meter-squared", + "symbol": "A·m²", + "tags": ["magnetic moment","dipole moment","ampere-meter squared","A·m²"] +}, +{ + "name": "unit.ampere-meter", + "symbol": "A·m", + "tags": ["magnetic field","current loop","ampere-meter","A·m"] +}, +{ + "name": "unit.nanovolt", + "symbol": "nV", + "tags": ["voltage","volts","nanovolt","nV"] +}, +{ + "name": "unit.picovolt", + "symbol": "pV", + "tags": ["voltage","volts","picovolt","pV"] +}, +{ + "name": "unit.millivolts", + "symbol": "mV", + "tags": ["electric potential","electric tension","voltage","millivolt","millivolts","mV"] +}, +{ + "name": "unit.microvolts", + "symbol": "μV", + "tags": ["electric potential","electric tension","voltage","microvolt","microvolts","μV"] +}, +{ + "name": "unit.volt", + "symbol": "V", + "tags": ["electric potential","electric tension","voltage","volt","volts","V","power source","battery","battery level"] +}, +{ + "name": "unit.kilovolts", + "symbol": "kV", + "tags": ["electric potential","electric tension","voltage","kilovolt","kilovolts","kV"] +}, +{ + "name": "unit.dbmV", + "symbol": "dBmV", + "tags": ["decibels millivolt","voltage level","signal","dBmV"] +}, +{ + "name": "unit.volt-meter", + "symbol": "V·m", + "tags": ["electric flux","volt-meter","V·m"] +}, +{ + "name": "unit.kilovolt-meter", + "symbol": "kV·m", + "tags": ["electric flux","kilovolt-meter","kV·m"] +}, +{ + "name": "unit.megavolt-meter", + "symbol": "MV·m", + "tags": ["electric flux","megavolt-meter","MV·m"] +}, +{ + "name": "unit.microvolt-meter", + "symbol": "µV·m", + "tags": ["electric flux","microvolt-meter","µV·m"] +}, +{ + "name": "unit.millivolt-meter", + "symbol": "mV·m", + "tags": ["electric flux","millivolt-meter","mV·m"] +}, +{ + "name": "unit.nanovolt-meter", + "symbol": "nV·m", + "tags": ["electric flux","nanovolt-meter","nV·m"] +}, +{ + "name": "unit.ohm", + "symbol": "Ω", + "tags": ["electrical resistance","resistance","impedance","ohm"] +}, +{ + "name": "unit.microohm", + "symbol": "μΩ", + "tags": ["electrical resistance","resistance","microohm","μΩ"] +}, +{ + "name": "unit.milliohm", + "symbol": "mΩ", + "tags": ["electrical resistance","resistance","milliohm","mΩ"] +}, +{ + "name": "unit.kilohm", + "symbol": "kΩ", + "tags": ["electrical resistance","resistance","kilohm","kΩ"] +}, +{ + "name": "unit.megohm", + "symbol": "MΩ", + "tags": ["electrical resistance","resistance","megohm","MΩ"] +}, +{ + "name": "unit.gigohm", + "symbol": "GΩ", + "tags": ["electrical resistance","resistance","gigohm","GΩ"] +}, +{ + "name": "unit.hertz", + "symbol": "Hz", + "tags": ["frequency","cycles per second","hertz","Hz"] +}, +{ + "name": "unit.kilohertz", + "symbol": "kHz", + "tags": ["frequency","cycles per second","kilohertz","kHz"] +}, +{ + "name": "unit.megahertz", + "symbol": "MHz", + "tags": ["frequency","cycles per second","megahertz","MHz"] +}, +{ + "name": "unit.gigahertz", + "symbol": "GHz", + "tags": ["frequency","cycles per second","gigahertz","GHz"] +}, +{ + "name": "unit.rpm", + "symbol": "RPM", + "tags": ["speed","velocity","cycle","engine","Revolutions Per Minute","RPM","angular velocity","rotation speed"] +}, +{ + "name": "unit.candela-per-square-meter", + "symbol": "cd/m²", + "tags": ["brightness","light level","Luminance","Candela per square meter","cd/m²"] +}, +{ + "name": "unit.candela", + "symbol": "cd", + "tags": ["light intensity","candle power","luminous intensity","Candela","cd"] +}, +{ + "name": "unit.lumen", + "symbol": "lm", + "tags": ["total light output","light power","luminous flux","Lumen","lm"] +}, +{ + "name": "unit.lux", + "symbol": "lx", + "tags": ["illumination","light level on a surface","illuminance","Lux","lx"] +}, +{ + "name": "unit.foot-candle", + "symbol": "fc", + "tags": ["illuminance","light level","foot-candle","fc"] +}, +{ + "name": "unit.lumen-per-square-meter", + "symbol": "lm/m²", + "tags": ["illuminance","light level","lumen per square meter","lm/m²"] +}, +{ + "name": "unit.lux-second", + "symbol": "lx·s", + "tags": ["light exposure","illumination time","light dosage","Lux second","lx·s"] +}, +{ + "name": "unit.lumen-second", + "symbol": "lm·s", + "tags": ["total light energy","luminous energy","Lumen second","lm·s"] +}, +{ + "name": "unit.lumens-per-watt", + "symbol": "lm/W", + "tags": ["lighting efficiency","light output per energy","luminous efficacy","Lumens per watt","lm/W"] +}, +{ + "name": "unit.absorbance", + "symbol": "AU", + "tags": ["optical density","light absorption","absorbance","AU"] +}, +{ + "name": "unit.mole", + "symbol": "mol", + "tags": ["amount of substance","substance quantity","mole","moles","mol"] +}, +{ + "name": "unit.nanomole", + "symbol": "nmol", + "tags": ["amount of substance","substance quantity","concentration","nanomole","nmol"] +}, +{ + "name": "unit.micromole", + "symbol": "μmol", + "tags": ["amount of substance","substance quantity","micromole","μmol"] +}, +{ + "name": "unit.millimole", + "symbol": "mmol", + "tags": ["amount of substance","substance quantity","millimole","mmol"] +}, +{ + "name": "unit.kilomole", + "symbol": "kmol", + "tags": ["amount of substance","substance quantity","kilomole","kmol"] +}, +{ + "name": "unit.mole-per-cubic-meter", + "symbol": "mol/m³", + "tags": ["concentration","amount of substance","mole per cubic meter","mol/m³"] +}, +{ + "name": "unit.percent", + "symbol": "%", + "tags": ["power source","state of charge (SoC)","battery","battery level","level","humidity","moisture","percentage", + "relative humidity","water content","soil moisture","irrigation","water in soil","soil water content","VWC", + "Volumetric Water Content","Total Harmonic Distortion","THD","power quality","UV Transmittance","%"] +}, +{ + "name": "unit.rssi", + "symbol": "rssi", + "tags": ["signal strength","signal level","received signal strength indicator","rssi","dBm"] +}, +{ + "name": "unit.ppm", + "symbol": "ppm", + "tags": ["carbon dioxide","co²","carbon monoxide","co","aqi","air quality","total volatile organic compounds","tvoc","ppm"] +}, +{ + "name": "unit.ppb", + "symbol": "ppb", + "tags": ["ozone","o³","nitrogen dioxide","no²","sulfur dioxide","so²","aqi","air quality","tvoc","ppb"] +}, +{ + "name": "unit.micrograms-per-cubic-meter", + "symbol": "µg/m³", + "tags": ["coarse particulate matter","pm10","fine particulate matter","pm2.5","aqi","air quality", + "total volatile organic compounds","tvoc","micrograms per cubic meter","µg/m³"] +}, +{ + "name": "unit.aqi", + "symbol": "aqi", + "tags": ["AQI","air quality index"] +}, +{ + "name": "unit.gram-per-cubic-meter", + "symbol": "g/m³", + "tags": ["humidity","moisture","absolute humidity","g/m³"] +}, +{ + "name": "unit.gram-per-kilogram", + "symbol": "g/kg", + "tags": ["humidity","moisture","specific humidity","g/kg"] +}, +{ + "name": "unit.millimeters-per-second", + "symbol": "mm/s", + "tags": ["velocity","speed","rate of motion","peak","peak to peak","root mean square (RMS)","vibration","mm/s"] +}, +{ + "name": "unit.neper", + "symbol": "Np", + "tags": ["logarithmic unit","ratio","gain","loss","attenuation","neper","Np"] +}, +{ + "name": "unit.bel", + "symbol": "B", + "tags": ["logarithmic unit","power ratio","intensity ratio","bel","B"] +}, +{ + "name": "unit.decibel", + "symbol": "dB", + "tags": ["noise level","sound level","volume","acoustics","decibel","dB"] +}, +{ + "name": "unit.meters-per-second-squared", + "symbol": "m/s²", + "tags": ["peak","peak to peak","root mean square (RMS)","vibration","meters per second squared","m/s²"] +}, +{ + "name": "unit.becquerel", + "symbol": "Bq", + "tags": ["radioactivity","radiation","becquerel","Bq"] +}, +{ + "name": "unit.curie", + "symbol": "Ci", + "tags": ["radioactivity","radiation","curie","Ci"] +}, +{ + "name": "unit.gray", + "symbol": "Gy", + "tags": ["radiation dose","gray","Gy"] +}, +{ + "name": "unit.sievert", + "symbol": "Sv", + "tags": ["radiation dose","sievert","radiation dose equivalent2","Sv"] +}, +{ + "name": "unit.roentgen", + "symbol": "R", + "tags": ["radiation exposure","roentgen","R"] +}, +{ + "name": "unit.cps", + "symbol": "cps", + "tags": ["radiation detection","counts per second","cps"] +}, +{ + "name": "unit.rad", + "symbol": "Rad", + "tags": ["radiation dose","rad"] +}, +{ + "name": "unit.rem", + "symbol": "Rem", + "tags": ["radiation dose equivalent","rem"] +}, +{ + "name": "unit.dps", + "symbol": "dps", + "tags": ["radioactive decay","radioactivity","disintegrations per second","dps"] +}, +{ + "name": "unit.rutherford", + "symbol": "Rd", + "tags": ["radioactive decay","radioactivity","rutherford","Rd"] +}, +{ + "name": "unit.coulombs-per-kilogram", + "symbol": "C/kg", + "tags": ["radiation exposure","dose","coulombs per kilogram","electric charge-to-mass ratio","C/kg"] +}, +{ + "name": "unit.becquerels-per-cubic-meter", + "symbol": "Bq/m³", + "tags": ["radioactivity","radiation","becquerels per cubic meter","Bq/m³"] +}, +{ + "name": "unit.curies-per-liter", + "symbol": "Ci/L", + "tags": ["radioactivity","radiation","curies per liter","Ci/L"] +}, +{ + "name": "unit.becquerels-per-second", + "symbol": "Bq/s", + "tags": ["radioactive decay rate","becquerels per second","Bq/s"] +}, +{ + "name": "unit.curies-per-second", + "symbol": "Ci/s", + "tags": ["radioactive decay rate","curies per second","Ci/s"] +}, +{ + "name": "unit.gy-per-second", + "symbol": "Gy/s", + "tags": ["absorbed dose rate","radiation dose rate","gray per second","Gy/s"] +}, +{ + "name": "unit.watt-per-steradian", + "symbol": "W/sr", + "tags": ["radiant intensity","power per unit solid angle","watt per steradian","W/sr"] +}, +{ + "name": "unit.watt-per-square-metre-steradian", + "symbol": "W/(m²·sr)", + "tags": ["radiance","radiant flux density","watt per square metre-steradian","W/(m²·sr)"] +}, +{ + "name": "unit.ph-level", + "symbol": "pH", + "tags": ["acidity","alkalinity","neutral","acid","base","pH","soil pH","water quality","water pH"] +}, +{ + "name": "unit.turbidity", + "symbol": "NTU", + "tags": ["water turbidity","water clarity","Nephelometric Turbidity Units","NTU"] +}, +{ + "name": "unit.mg-per-liter", + "symbol": "mg/L", + "tags": ["dissolved oxygen","water quality","mg/L"] +}, +{ + "name": "unit.microsiemens-per-centimeter", + "symbol": "µS/cm", + "tags": ["Electrical conductivity","water quality","soil quality","microsiemens per centimeter","µS/cm"] +}, +{ + "name": "unit.millisiemens-per-meter", + "symbol": "mS/m", + "tags": ["Electrical conductivity","water quality","soil quality","millisiemens per meter","mS/m"] +}, +{ + "name": "unit.siemens-per-meter", + "symbol": "S/m", + "tags": ["Electrical conductivity","water quality","soil quality","siemens per meter","S/m"] +}, +{ + "name": "unit.kilogram-per-cubic-meter", + "symbol": "kg/m³", + "tags": ["density","mass per unit volume","kg/m³"] +}, +{ + "name": "unit.gram-per-cubic-centimeter", + "symbol": "g/cm³", + "tags": ["density","mass per unit volume","g/cm³"] +}, +{ + "name": "unit.kilogram-per-square-meter", + "symbol": "kg/m²", + "tags": ["density","surface density","areal density","mass per unit area","kg/m²"] +}, +{ + "name": "unit.milligram-per-milliliter", + "symbol": "mg/mL", + "tags": ["concentration","mass per volume","mg/mL"] +}, +{ + "name": "unit.pound-per-cubic-foot", + "symbol": "lb/ft³", + "tags": ["Density","mass per unit volume","lb/ft³"] +}, +{ + "name": "unit.ounces-per-cubic-inch", + "symbol": "oz/in³", + "tags": ["density","mass per unit volume","oz/in³"] +}, +{ + "name": "unit.tons-per-cubic-yard", + "symbol": "ton/yd³", + "tags": ["density","mass per unit volume","ton/yd³"] +}, +{ + "name": "unit.particle-density", + "symbol": "particles/mL", + "tags": ["particle concentration","count","particles/mL"] +}, +{ + "name": "unit.kilometers-per-liter", + "symbol": "km/L", + "tags": ["fuel efficiency","km/L"] +}, +{ + "name": "unit.miles-per-gallon", + "symbol": "mpg", + "tags": ["fuel efficiency","mpg"] +}, +{ + "name": "unit.liters-per-100-km", + "symbol": "L/100km", + "tags": ["fuel efficiency","L/100km"] +}, +{ + "name": "unit.gallons-per-mile", + "symbol": "gal/mi", + "tags": ["fuel efficiency","gal/mi"] +}, +{ + "name": "unit.liters-per-hour", + "symbol": "L/hr", + "tags": ["fuel consumption","L/hr"] +}, +{ + "name": "unit.gallons-per-hour", + "symbol": "gal/hr", + "tags": ["fuel consumption","gal/hr"] +}, +{ + "name": "unit.beats-per-minute", + "symbol": "bpm", + "tags": ["heart rate","pulse","bpm"] +}, +{ + "name": "unit.millimeters-of-mercury", + "symbol": "mmHg", + "tags": ["blood pressure","systolic","diastolic","mmHg"] +}, +{ + "name": "unit.milligrams-per-deciliter", + "symbol": "mg/dL", + "tags": ["glucose","blood sugar","glucose level","mg/dL"] +}, +{ + "name": "unit.g-force", + "symbol": "G", + "tags": ["acceleration","gravity","force","g-load","G"] +}, +{ + "name": "unit.kilonewton", + "symbol": "kN", + "tags": ["force","kN"] +}, +{ + "name": "unit.kilogram-force", + "symbol": "kgf", + "tags": ["force","kgf"] +}, +{ + "name": "unit.pound-force", + "symbol": "lbf", + "tags": ["force","lbf"] +}, +{ + "name": "unit.kilopound-force", + "symbol": "klbf", + "tags": ["force","klbf"] +}, +{ + "name": "unit.dyne", + "symbol": "dyn", + "tags": ["force","dyn"] +}, +{ + "name": "unit.poundal", + "symbol": "pdl", + "tags": ["force","pdl"] +}, +{ + "name": "unit.kip", + "symbol": "kip", + "tags": ["force","kip"] +}, +{ + "name": "unit.gal", + "symbol": "Gal", + "tags": ["acceleration","gravity","g-force","Gal"] +}, +{ + "name": "unit.gravity", + "symbol": "gravity", + "tags": ["acceleration","gravity","g-force"] +}, +{ + "name": "unit.hectopascal", + "symbol": "hPa", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","hPa"] +}, +{ + "name": "unit.atmosphere", + "symbol": "atm", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","atm"] +}, +{ + "name": "unit.millibars", + "symbol": "mb", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","mb"] +}, +{ + "name": "unit.inch-of-mercury", + "symbol": "inHg", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","inHg","richter"] +}, +{ + "name": "unit.richter-scale", + "symbol": "richter", + "tags": ["earthquake","seismic activity","richter"] +}, +{ + "name": "unit.second", + "symbol": "s", + "tags": ["time","duration","interval","angle","second","arcsecond","sec"] +}, +{ + "name": "unit.minute", + "symbol": "min", + "tags": ["time","duration","interval","angle","minute","arcminute","min"] +}, +{ + "name": "unit.hour", + "symbol": "h", + "tags": ["time","duration","interval","h"] +}, +{ + "name": "unit.day", + "symbol": "d", + "tags": ["time","duration","interval","d"] +}, +{ + "name": "unit.week", + "symbol": "wk", + "tags": ["time","duration","interval","wk"] +}, +{ + "name": "unit.month", + "symbol": "mo", + "tags": ["time","duration","interval","mo"] +}, +{ + "name": "unit.year", + "symbol": "yr", + "tags": ["time","duration","interval","yr"] +}, +{ + "name": "unit.cubic-foot-per-minute", + "symbol": "ft³/min", + "tags": ["airflow","ventilation","HVAC","gas flow rate","CFM","flow rate","fluid flow","cubic foot per minute","ft³/min"] +}, +{ + "name": "unit.cubic-meters-per-hour", + "symbol": "m³/hr", + "tags": ["airflow","ventilation","HVAC","gas flow rate","cubic meters per hour","m³/hr"] +}, +{ + "name": "unit.cubic-meters-per-second", + "symbol": "m³/s", + "tags": ["airflow","ventilation","HVAC","gas flow rate","cubic meters per second","m³/s"] +}, +{ + "name": "unit.liter-per-second", + "symbol": "L/s", + "tags": ["airflow","ventilation","HVAC","gas flow rate","liter per second","L/s"] +}, +{ + "name": "unit.liter-per-minute", + "symbol": "L/min", + "tags": ["airflow","ventilation","HVAC","gas flow rate","liter per minute","L/min"] +}, +{ + "name": "unit.gallons-per-minute", + "symbol": "GPM", + "tags": ["airflow","ventilation","HVAC","gas flow rate","gallons per minute","GPM"] +}, +{ + "name": "unit.cubic-foot-per-second", + "symbol": "ft³/s", + "tags": ["flow rate","fluid flow","cubic foot per second","cubic feet per second","ft³/s"] +}, +{ + "name": "unit.milliliters-per-minute", + "symbol": "mL/min", + "tags": ["Flow rate","fluid dynamics","milliliters per minute","mL/min"] +}, +{ + "name": "unit.bit", + "symbol": "bit", + "tags": ["data","binary digit","information","bit"] +}, +{ + "name": "unit.byte", + "symbol": "B", + "tags": ["data","byte","information","storage","memory","B"] +}, +{ + "name": "unit.kilobyte", + "symbol": "KB", + "tags": ["data","kilobyte","KB"] +}, +{ + "name": "unit.megabyte", + "symbol": "MB", + "tags": ["data","megabyte","MB"] +}, +{ + "name": "unit.gigabyte", + "symbol": "GB", + "tags": ["data","gigabyte","GB"] +}, +{ + "name": "unit.terabyte", + "symbol": "TB", + "tags": ["data","terabyte","TB"] +}, +{ + "name": "unit.petabyte", + "symbol": "PB", + "tags": ["data","petabyte","PB"] +}, +{ + "name": "unit.exabyte", + "symbol": "EB", + "tags": ["data","exabyte","EB"] +}, +{ + "name": "unit.zettabyte", + "symbol": "ZB", + "tags": ["data","zettabyte","ZB"] +}, +{ + "name": "unit.yottabyte", + "symbol": "YB", + "tags": ["data","yottabyte","YB"] +}, +{ + "name": "unit.bit-per-second", + "symbol": "bps", + "tags": ["data transfer rate","bps"] +}, +{ + "name": "unit.kilobit-per-second", + "symbol": "kbps", + "tags": ["data transfer rate","kbps"] +}, +{ + "name": "unit.megabit-per-second", + "symbol": "Mbps", + "tags": ["data transfer rate","Mbps"] +}, +{ + "name": "unit.gigabit-per-second", + "symbol": "Gbps", + "tags": ["data transfer rate","Gbps"] +}, +{ + "name": "unit.terabit-per-second", + "symbol": "Tbps", + "tags": ["data transfer rate","Tbps"] +}, +{ + "name": "unit.byte-per-second", + "symbol": "B/s", + "tags": ["data transfer rate","B/s"] +}, +{ + "name": "unit.kilobyte-per-second", + "symbol": "KB/s", + "tags": ["data transfer rate","KB/s"] +}, +{ + "name": "unit.megabyte-per-second", + "symbol": "MB/s", + "tags": ["data transfer rate","MB/s"] +}, +{ + "name": "unit.gigabyte-per-second", + "symbol": "GB/s", + "tags": ["data transfer rate","GB/s"] +}, +{ + "name": "unit.degree", + "symbol": "deg", + "tags": ["angle","degree","degrees","deg"] +}, +{ + "name": "unit.radian", + "symbol": "rad", + "tags": ["angle","radian","radians","rad"] +}, +{ + "name": "unit.gradian", + "symbol": "grad", + "tags": ["angle","gradian","grades","grad"] +}, +{ + "name": "unit.mil", + "symbol": "mil", + "tags": ["angle","military angle","angular mil","mil"] +}, +{ + "name": "unit.revolution", + "symbol": "rev", + "tags": ["angle","revolution","full circle","complete turn","rev"] +}, +{ + "name": "unit.siemens", + "symbol": "S", + "tags": ["electrical conductance","conductance","siemens","S"] +}, +{ + "name": "unit.millisiemens", + "symbol": "mS", + "tags": ["electrical conductance","conductance","millisiemens","mS"] +}, +{ + "name": "unit.microsiemens", + "symbol": "μS", + "tags": ["electrical conductance","conductance","microsiemens","μS"] +}, +{ + "name": "unit.kilosiemens", + "symbol": "kS", + "tags": ["electrical conductance","conductance","kilosiemens","kS"] +}, +{ + "name": "unit.megasiemens", + "symbol": "MS", + "tags": ["electrical conductance","conductance","megasiemens","MS"] +}, +{ + "name": "unit.gigasiemens", + "symbol": "GS", + "tags": ["electrical conductance","conductance","gigasiemens","GS"] +}, +{ + "name": "unit.farad", + "symbol": "F", + "tags": ["electric capacitance","capacitance","farad","F"] +}, +{ + "name": "unit.millifarad", + "symbol": "mF", + "tags": ["electric capacitance","capacitance","millifarad","mF"] +}, +{ + "name": "unit.microfarad", + "symbol": "μF", + "tags": ["electric capacitance","capacitance","microfarad","μF"] +}, +{ + "name": "unit.nanofarad", + "symbol": "nF", + "tags": ["electric capacitance","capacitance","nanofarad","nF"] +}, +{ + "name": "unit.picofarad", + "symbol": "pF", + "tags": ["electric capacitance","capacitance","picofarad","pF"] +}, +{ + "name": "unit.kilofarad", + "symbol": "kF", + "tags": ["electric capacitance","capacitance","kilofarad","kF"] +}, +{ + "name": "unit.megafarad", + "symbol": "MF", + "tags": ["electric capacitance","capacitance","megafarad","MF"] +}, +{ + "name": "unit.gigafarad", + "symbol": "GF", + "tags": ["electric capacitance","capacitance","gigafarad","GF"] +}, +{ + "name": "unit.terfarad", + "symbol": "TF", + "tags": ["electric capacitance","capacitance","terafarad","TF"] +}, +{ + "name": "unit.farad-per-meter", + "symbol": "F/m", + "tags": ["electric permittivity","farad per meter","F/m"] +}, +{ + "name": "unit.tesla", + "symbol": "T", + "tags": ["magnetic field","magnetic field strength","tesla","T","magnetic flux density"] +}, +{ + "name": "unit.gauss", + "symbol": "G", + "tags": ["magnetic field","magnetic field strength","gauss","G","magnetic flux density"] +}, +{ + "name": "unit.kilogauss", + "symbol": "kG", + "tags": ["magnetic field","magnetic field strength","kilogauss","kG","magnetic flux density"] +}, +{ + "name": "unit.millitesla", + "symbol": "mT", + "tags": ["magnetic field","magnetic field strength","millitesla","mT"] +}, +{ + "name": "unit.microtesla", + "symbol": "μT", + "tags": ["magnetic field","magnetic field strength","microtesla","μT"] +}, +{ + "name": "unit.nanotesla", + "symbol": "nT", + "tags": ["magnetic field","magnetic field strength","nanotesla","nT"] +}, +{ + "name": "unit.kilotesla", + "symbol": "kT", + "tags": ["magnetic field","magnetic field strength","kilotesla","kT"] +}, +{ + "name": "unit.megatesla", + "symbol": "MT", + "tags": ["magnetic field","magnetic field strength","megatesla","MT"] +}, +{ + "name": "unit.millitesla-square-meters", + "symbol": "millitesla square meters", + "tags": ["magnetic field","millitesla square meters"] +}, +{ + "name": "unit.gamma", + "symbol": "γ", + "tags": ["magnetic flux density","gamma","γ"] +}, +{ + "name": "unit.lambda", + "symbol": "λ", + "tags": ["wavelength","lambda","λ"] +}, +{ + "name": "unit.square-meter-per-second", + "symbol": "m²/s", + "tags": ["kinematic viscosity","m²/s"] +}, +{ + "name": "unit.square-centimeter-per-second", + "symbol": "cm²/s", + "tags": ["kinematic viscosity","cm²/s"] +}, +{ + "name": "unit.stoke", + "symbol": "St", + "tags": ["kinematic viscosity","stokes","St"] +}, +{ + "name": "unit.centistokes", + "symbol": "cSt", + "tags": ["kinematic viscosity","centistokes","cSt"] +}, +{ + "name": "unit.square-foot-per-second", + "symbol": "ft²/s", + "tags": ["kinematic viscosity","ft²/s"] +}, +{ + "name": "unit.square-inch-per-second", + "symbol": "in²/s", + "tags": ["kinematic viscosity","in²/s"] +}, +{ + "name": "unit.pascal-second", + "symbol": "Pa·s", + "tags": ["dynamic viscosity","viscosity","fluid mechanics","pascal-second","Pa·s"] +}, +{ + "name": "unit.centipoise", + "symbol": "cP", + "tags": ["viscosity","dynamic viscosity","fluid viscosity","centipoise","cP"] +}, +{ + "name": "unit.poise", + "symbol": "P", + "tags": ["viscosity","dynamic viscosity","fluid viscosity","poise","P"] +}, +{ + "name": "unit.reynolds", + "symbol": "Re", + "tags": ["fluid flow regime","fluid mechanics","reynolds","Re"] +}, +{ + "name": "unit.pound-per-foot-hour", + "symbol": "lb/(ft·h)", + "tags": ["pound per foot-hour","lb/(ft·h)"] +}, +{ + "name": "unit.newton-second-per-square-meter", + "symbol": "N·s/m²", + "tags": ["newton second per square meter","N·s/m²"] +}, +{ + "name": "unit.dyne-second-per-square-centimeter", + "symbol": "dyn·s/cm²", + "tags": ["dyne second per square centimeter","dyn·s/cm²"] +}, +{ + "name": "unit.kilogram-per-meter-second", + "symbol": "kg/(m·s)", + "tags": ["kilogram per meter-second","kg/(m·s)"] +}, +{ + "name": "unit.tesla-square-meters", + "symbol": "T/m²", + "tags": ["magnetic flux density","tesla square meters","T/m²"] +}, +{ + "name": "unit.maxwell", + "symbol": "Mx", + "tags": ["magnetic flux","magnetic field","maxwell","Mx"] +}, +{ + "name": "unit.tesla-per-meter", + "symbol": "T/m", + "tags": ["magnetic field","tesla per meter","T/m"] +}, +{ + "name": "unit.gauss-per-centimeter", + "symbol": "G/cm", + "tags": ["magnetic field","gauss per centimeter","G/cm"] +}, +{ + "name": "unit.weber", + "symbol": "Wb", + "tags": ["magnetic flux","weber","Wb"] +}, +{ + "name": "unit.microweber", + "symbol": "µWb", + "tags": ["magnetic flux","microweber","µWb"] +}, +{ + "name": "unit.milliweber", + "symbol": "mWb", + "tags": ["magnetic flux","milliweber","mWb"] +}, +{ + "name": "unit.gauss-square-centimeter", + "symbol": "G·cm²", + "tags": ["magnetic flux","gauss-square centimeter","G·cm²"] +}, +{ + "name": "unit.kilogauss-square-centimeter", + "symbol": "kG·cm²", + "tags": ["magnetic flux","kilogauss-square centimeter","kG·cm²"] +}, +{ + "name": "unit.henry", + "symbol": "H", + "tags": ["inductance","magnetic induction","H"] +}, +{ + "name": "unit.millihenry", + "symbol": "mH", + "tags": ["inductance","millihenry","mH"] +}, +{ + "name": "unit.microhenry", + "symbol": "µH", + "tags": ["inductance","microhenry","µH"] +}, +{ + "name": "unit.nanohenry", + "symbol": "nH", + "tags": ["inductance","nanohenry","nH"] +}, +{ + "name": "unit.henry-per-meter", + "symbol": "H/m", + "tags": ["magnetic permeability","henry per meter","H/m"] +}, +{ + "name": "unit.tesla-meter-per-ampere", + "symbol": "T·m/A", + "tags": ["magnetic field","Tesla Meter per Ampere","T·m/A","magnetic flux"] +}, +{ + "name": "unit.gauss-per-oersted", + "symbol": "G/Oe", + "tags": ["magnetic field","Gauss per Oersted","G/Oe"] +}, +{ + "name": "unit.kilogram-per-mole", + "symbol": "kg/mol", + "tags": ["molar mass","kilogram per mole","kg/mol"] +}, +{ + "name": "unit.gram-per-mole", + "symbol": "g/mol", + "tags": ["molar mass","gram per mole","g/mol"] +}, +{ + "name": "unit.milligram-per-mole", + "symbol": "mg/mol", + "tags": ["molar mass","milligram per mole","mg/mol"] +}, +{ + "name": "unit.joule-per-mole", + "symbol": "J/mol", + "tags": ["molar energy","joule per mole","J/mol"] +}, +{ + "name": "unit.joule-per-mole-kelvin", + "symbol": "J/(mol·K)", + "tags": ["molar heat capacity","joule per mole-kelvin","J/(mol·K)"] +}, +{ + "name": "unit.millivolts-per-meter", + "symbol": "mV/m", + "tags": ["electric field strength","millivolts per meter","mV/m"] +}, +{ + "name": "unit.volts-per-meter", + "symbol": "V/m", + "tags": ["electric field strength","volts per meter","V/m"] +}, +{ + "name": "unit.kilovolts-per-meter", + "symbol": "kV/m", + "tags": ["electric field strength","kilovolts per meter","kV/m"] +}, +{ + "name": "unit.radian-per-second", + "symbol": "rad/s", + "tags": ["angular velocity","rotation speed","rad/s"] +}, +{ + "name": "unit.radian-per-second-squared", + "symbol": "rad/s²", + "tags": ["angular acceleration","rotation rate of change","rad/s²"] +}, +{ + "name": "unit.revolutions-per-minute-per-second", + "symbol": "rpm/s", + "tags": ["angular acceleration","rotation rate of change","rpm/s"] +}, +{ + "name": "unit.revolutions-per-minute-per-second-squared", + "symbol": "rpm/s²", + "tags": ["angular acceleration","rotation rate of change","rpm/s²"] +}, +{ + "name": "unit.deg-per-second", + "symbol": "deg/s", + "tags": ["angular velocity","degrees per second","deg/s"] +}, +{ + "name": "unit.degrees-brix", + "symbol": "°Bx", + "tags": ["sugar content","fruit ripeness","Bx"] +}, +{ + "name": "unit.katal", + "symbol": "kat", + "tags": ["catalytic activity","enzyme activity","kat"] +}, +{ + "name": "unit.katal-per-cubic-metre", + "symbol": "kat/m³", + "tags": ["catalytic activity concentration","enzyme concentration","kat/m³"] +}] diff --git a/ui-ngx/src/assets/widget/value-card/centered-layout.svg b/ui-ngx/src/assets/widget/value-card/centered-layout.svg new file mode 100644 index 0000000000..9c8d5f38ae --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/centered-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/horizontal-layout.svg b/ui-ngx/src/assets/widget/value-card/horizontal-layout.svg new file mode 100644 index 0000000000..283ddd461d --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/horizontal-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/horizontal-reversed-layout.svg b/ui-ngx/src/assets/widget/value-card/horizontal-reversed-layout.svg new file mode 100644 index 0000000000..275f45fab9 --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/horizontal-reversed-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/simplified-layout.svg b/ui-ngx/src/assets/widget/value-card/simplified-layout.svg new file mode 100644 index 0000000000..9488bc78e5 --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/simplified-layout.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/square-layout.svg b/ui-ngx/src/assets/widget/value-card/square-layout.svg new file mode 100644 index 0000000000..87b087cdad --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/square-layout.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/vertical-layout.svg b/ui-ngx/src/assets/widget/value-card/vertical-layout.svg new file mode 100644 index 0000000000..e2baba8ce4 --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/vertical-layout.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/windows.svg b/ui-ngx/src/assets/windows.svg new file mode 100644 index 0000000000..1f168c099e --- /dev/null +++ b/ui-ngx/src/assets/windows.svg @@ -0,0 +1 @@ + diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss new file mode 100644 index 0000000000..00e9492af0 --- /dev/null +++ b/ui-ngx/src/form.scss @@ -0,0 +1,460 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import './scss/constants'; + +.tb-default, .tb-dark { + .tb-form-panel { + box-shadow: 0 0 10px 6px rgba(11, 17, 51, 0.04); + border-radius: 4px; + padding: 16px; + gap: 16px; + display: flex; + flex-direction: column; + color: rgba(0, 0, 0, 0.87); + letter-spacing: 0.15px; + position: relative; + &.no-padding-bottom { + padding-bottom: 0; + } + &.no-padding { + padding: 0; + } + &.stroked { + box-shadow: none; + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 6px; + } + &.no-border { + box-shadow: none; + border-radius: 0; + } + &.tb-slide-toggle { + padding: 0; + gap: 0; + > .tb-form-panel-title { + padding-top: 16px; + padding-left: 16px; + } + > .mat-expansion-panel { + padding: 16px; + .mat-expansion-panel-header { + height: 32px; + .mat-slide { + margin: 0; + } + } + } + } + .mat-expansion-panel { + &.tb-settings { + box-shadow: none; + .mat-content { + overflow: visible; + } + > .mat-expansion-panel-header { + user-select: none; + font-weight: 500; + font-size: 16px; + line-height: 24px; + letter-spacing: 0.25px; + padding: 0; + .mat-content { + flex: 0; + white-space: nowrap; + } + &.fill-width { + .mat-content { + flex: 1; + } + } + &:hover { + background: none; + } + .mat-expansion-indicator { + height: 32px; + padding: 2px; + } + } + > .mat-expansion-panel-header-description { + align-items: center; + } + > .mat-expansion-panel-content { + > .mat-expansion-panel-body { + display: flex; + flex-direction: column; + gap: 16px; + padding: 16px 0 0 !important; + } + } + .tb-json-object-panel, .tb-css-content-panel { + margin: 0 0 8px; + } + } + .mat-expansion-panel-content { + font: inherit; + } + } + .mat-slide { + margin: 0; + &.margin { + margin: 8px 0; + } + .mdc-form-field>label { + font-weight: 400; + font-size: 16px; + line-height: 24px; + margin-left: 12px; + } + } + } + + .tb-form-panel-title { + font-weight: 500; + font-size: 16px; + } + .tb-form-panel-hint { + font-size: 12px; + color: #808080; + } + .tb-form-row { + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + gap: 16px; + padding: 7px 7px 7px 16px; + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 6px; + &.no-border { + border: none; + border-radius: 0; + } + &.no-padding { + padding: 0; + } + &.same-padding { + padding-right: 16px; + } + &.space-between { + justify-content: space-between; + } + .mat-divider-vertical { + height: 56px; + margin-top: -7px; + margin-bottom: -7px; + } + .mat-mdc-form-field { + width: 106px; + &.medium-width { + width: 220px; + } + @media #{$mat-xs} { + width: auto; + &.medium-width { + width: auto; + } + } + } + .fixed-title-width { + min-width: 200px; + @media #{$mat-xs} { + min-width: 0; + } + } + .mat-slide:only-child { + margin: 8px 0; + } + } + + .tb-form-row .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { + &.mat-form-field-appearance-fill { + .mdc-text-field--filled:not(.mdc-text-field--disabled) { + &:before { + opacity: 0; + } + .mdc-line-ripple::before { + border-bottom-color: rgba(0, 0, 0, 0.12); + } + } + .mat-mdc-form-field-focus-overlay { + opacity: 0; + } + } + &:not(.mat-mdc-form-field-has-icon-prefix) { + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + padding-left: 12px; + } + } + } + &:not(.mat-mdc-form-field-has-icon-suffix) { + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + padding-right: 12px; + } + } + } + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + &:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(.mdc-text-field--invalid):not(:hover) { + .mdc-notched-outline__leading, .mdc-notched-outline__trailing { + border-color: rgba(0, 0, 0, 0.12); + } + } + .mat-mdc-form-field-infix { + padding-top: 8px; + padding-bottom: 8px; + min-height: 40px; + width: auto; + .mdc-text-field__input, .mat-mdc-select { + font-weight: 400; + font-size: 14px; + line-height: 20px; + } + } + .mat-mdc-form-field-icon-prefix, .mat-mdc-form-field-icon-suffix { + height: 40px; + font-size: 14px; + line-height: 40px; + letter-spacing: 0.2px; + color: rgba(0, 0, 0, 0.38); + > button.mat-mdc-icon-button { + width: 40px; + height: 40px; + padding: 8px; + .mat-icon { + width: 20px; + height: 20px; + font-size: 20px; + } + .mat-mdc-button-touch-target { + width: 40px; + height: 40px; + } + &.tb-icon-24 { + width: 24px; + height: 24px; + padding: 0; + .mat-mdc-button-touch-target { + width: 24px; + height: 24px; + } + } + } + > .mat-icon { + width: 20px; + height: 20px; + padding: 10px; + font-size: 20px; + } + } + } + } + &.center { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-infix { + .mdc-text-field__input { + text-align: center; + } + } + } + } + &.number { + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + padding-right: 4px; + } + .mat-mdc-form-field-infix { + input.mdc-text-field__input[type=number]::-webkit-inner-spin-button, + input.mdc-text-field__input[type=number]::-webkit-outer-spin-button { + opacity: 1; + } + } + } + } + &.tb-chips { + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + .mat-mdc-form-field-infix { + padding-top: 4px; + padding-bottom: 4px; + + .mdc-evolution-chip-set { + min-height: 32px; + + .mdc-evolution-chip { + height: 24px; + } + } + } + } + } + } + &.tb-suffix-show-on-hover { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-icon-suffix { + padding: 0; + display: none; + } + } + &:hover { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-icon-suffix { + display: flex; + align-items: center; + } + } + } + } + } + + .tb-form-table { + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 6px; + display: flex; + flex-direction: column; + gap: 12px; + padding-bottom: 12px; + + .tb-form-table-body { + display: flex; + flex-direction: column; + gap: 12px; + } + + .tb-prompt { + height: 38px; + } + } + + .tb-form-table-header, .tb-form-table-row { + display: flex; + flex-direction: row; + gap: 12px; + padding-left: 12px; + place-content: center flex-start; + align-items: center; + &-cell { + font-weight: 400; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.2px; + } + } + + .tb-form-table-header { + height: 48px; + border-bottom: 1px solid rgba(0, 0, 0, 0.12); + &-cell { + color: rgba(0, 0, 0, 0.54); + } + } + + .tb-form-table-row { + height: 38px; + + &.tb-draggable { + gap: 0; + padding-left: 0; + background: #fff; + } + + &-cell { + color: rgba(0, 0, 0, 0.87); + } + + &-cell-buttons { + display: flex; + flex-direction: row; + button.mat-mdc-icon-button.mat-mdc-button-base { + padding: 7px; + width: 38px; + height: 38px; + .mat-icon { + color: rgba(0, 0, 0, 0.38); + } + &.tb-hidden { + visibility: hidden; + } + } + } + } + + .tb-no-data-available { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + .tb-no-data-bg { + margin: 10px; + position: relative; + flex: 1; + width: 100%; + max-height: 100px; + &:before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: #305680; + mask-image: url(/assets/home/no_data_folder_bg.svg); + mask-repeat: no-repeat; + mask-size: contain; + mask-position: center; + } + } + + .tb-no-data-text { + font-weight: 500; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.54); + @media #{$mat-md-lg} { + font-size: 12px; + line-height: 16px; + } + } + + button.mat-mdc-button-base.tb-box-button { + width: 40px; + min-width: 40px; + height: 40px; + padding: 7px; + .mat-mdc-button-touch-target { + width: 40px; + height: 40px; + } + &:not(:disabled) { + color: rgba(0, 0, 0, 0.54); + } + &:disabled { + color: rgba(0, 0, 0, 0.12); + } + > .mat-icon { + width: 24px; + height: 24px; + font-size: 24px; + margin: 0; + } + } +} diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index 760ffe88c6..75fc0845cf 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -224,6 +224,8 @@ div { line-height: var(--mdc-typography-caption-line-height, 20px); font-weight: var(--mdc-typography-caption-font-weight, 400); letter-spacing: var(--mdc-typography-caption-letter-spacing, 0.0333333333em); + color: rgba(0, 0, 0, 0.6); + white-space: normal; } .mat-caption { @@ -304,10 +306,7 @@ pre.tb-highlight { .tb-fullscreen { position: fixed !important; - top: 0; - left: 0; - width: 100% !important; - height: 100% !important; + inset: 0 !important; } .tb-fullscreen-parent { @@ -622,7 +621,7 @@ mat-label { .mat-toolbar.mat-primary { button.mat-mdc-icon-button { - mat-icon { + .mat-icon { color: white; } } @@ -646,11 +645,11 @@ mat-label { mat-toolbar.mat-mdc-table-toolbar:not(.mat-primary), .mat-mdc-cell, .mat-expansion-panel-header { button.mat-mdc-icon-button { - mat-icon { + .mat-icon { color: rgba(0, 0, 0, .54); } &[disabled][disabled] { - mat-icon { + .mat-icon { color: rgba(0, 0, 0, .26); } } @@ -789,7 +788,7 @@ mat-label { &.mat-number-cell { text-align: end; } - mat-icon { + .mat-icon { color: rgba(0, 0, 0, .54); } } @@ -949,7 +948,7 @@ mat-label { padding: 0 6px; min-width: 88px; } - mat-icon { + .mat-icon { margin-right: 5px; } } @@ -981,10 +980,7 @@ mat-label { min-width: 100%; max-width: none !important; position: absolute !important; - top: 0; - bottom: 0; - left: 0; - right: 0; + inset: 0; .mat-mdc-dialog-container { > *:first-child, form { min-width: 100% !important; @@ -1002,10 +998,7 @@ mat-label { min-width: 100%; max-width: none !important; position: absolute !important; - top: 0; - bottom: 0; - left: 0; - right: 0; + inset: 0; .mat-mdc-dialog-container { > *:first-child, form { min-width: 100% !important; @@ -1020,10 +1013,7 @@ mat-label { .tb-absolute-fill { position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; + inset: 0; } .tb-layout-fill { @@ -1035,10 +1025,7 @@ mat-label { .tb-progress-cover { position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; + inset: 0; z-index: 6; background-color: #eee; opacity: 1; @@ -1049,7 +1036,7 @@ mat-label { background: #ccc; opacity: .85; - mat-icon { + .mat-icon { color: #666; } } @@ -1092,7 +1079,17 @@ mat-label { box-shadow: none; border-radius: 4px; .tb-color-result { - border: 1px solid rgba(0, 0, 0, 0.12); + position: relative; + &:after { + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + border-radius: 4px; + border: 1px solid rgba(0, 0, 0, 0.12); + } } &.disabled { cursor: initial; @@ -1153,7 +1150,7 @@ mat-label { .tb-drag-handle { cursor: move; - mat-icon { + .mat-icon { pointer-events: none; } } @@ -1184,165 +1181,4 @@ mat-label { color: inherit; } - // Widget config - - .tb-widget-config-panel { - box-shadow: 0 0 10px 6px rgba(11, 17, 51, 0.04); - border-radius: 4px; - padding: 16px; - gap: 16px; - display: flex; - flex-direction: column; - color: rgba(0, 0, 0, 0.87); - letter-spacing: 0.15px; - position: relative; - &.no-padding-bottom { - padding-bottom: 0; - } - &.stroked { - box-shadow: none; - border: 1px solid rgba(0, 0, 0, 0.12); - border-radius: 6px; - } - .mat-expansion-panel { - &.tb-settings { - box-shadow: none; - .mat-content { - overflow: visible; - } - .mat-expansion-panel-header { - font-weight: 500; - font-size: 16px; - line-height: 24px; - letter-spacing: 0.25px; - padding: 0; - .mat-content { - flex: 0; - white-space: nowrap; - } - &:hover { - background: none; - } - .mat-expansion-indicator { - height: 32px; - padding: 2px; - } - } - .mat-expansion-panel-header-description { - align-items: center; - } - > .mat-expansion-panel-content { - > .mat-expansion-panel-body { - padding: 0; - } - } - .tb-json-object-panel, .tb-css-content-panel { - margin: 0 0 8px; - } - } - .mat-expansion-panel-content { - font: inherit; - } - } - .mat-slide { - margin: 8px 0; - .mdc-form-field>label { - font-weight: 400; - font-size: 16px; - line-height: 24px; - margin-left: 12px; - } - } - } - - .tb-widget-config-panel-title { - font-weight: 500; - font-size: 16px; - } - .tb-widget-config-panel-hint { - font-size: 12px; - color: #808080; - } - .tb-widget-config-row { - height: 56px; - display: flex; - flex-direction: row; - align-items: center; - gap: 16px; - padding-left: 16px; - padding-right: 12px; - border: 1px solid rgba(0, 0, 0, 0.12); - border-radius: 6px; - &.same-padding { - padding-right: 16px; - } - &.space-between { - justify-content: space-between; - } - .mat-divider-vertical { - height: 56px; - } - .mat-mdc-form-field { - width: 80px; - } - } - - .tb-widget-config-row .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { - &.mat-form-field-appearance-fill { - .mdc-text-field--filled:not(.mdc-text-field--disabled) { - &:before { - opacity: 0; - } - .mdc-line-ripple::before { - border-bottom-color: rgba(0, 0, 0, 0.12); - } - } - .mat-mdc-form-field-focus-overlay { - opacity: 0; - } - } - .mat-mdc-text-field-wrapper { - &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { - padding-right: 12px; - padding-left: 12px; - &:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(:hover) { - .mdc-notched-outline__leading, .mdc-notched-outline__trailing { - border-color: rgba(0, 0, 0, 0.12); - } - } - .mat-mdc-form-field-infix { - padding-top: 7px; - padding-bottom: 7px; - min-height: 38px; - width: auto; - .mdc-text-field__input, .mat-mdc-select { - font-weight: 400; - font-size: 14px; - line-height: 20px; - } - } - } - } - &.center { - .mat-mdc-text-field-wrapper { - .mat-mdc-form-field-infix { - .mdc-text-field__input { - text-align: center; - } - } - } - } - &.number { - .mat-mdc-text-field-wrapper { - padding-right: 4px; - .mat-mdc-form-field-infix { - input.mdc-text-field__input[type=number]::-webkit-inner-spin-button, - input.mdc-text-field__input[type=number]::-webkit-outer-spin-button { - opacity: 1; - } - } - } - } - } - } diff --git a/ui-ngx/src/theme.scss b/ui-ngx/src/theme.scss index 9aa3e61d39..df1b2bca3e 100644 --- a/ui-ngx/src/theme.scss +++ b/ui-ngx/src/theme.scss @@ -212,7 +212,7 @@ $tb-dark-theme: map_merge($tb-dark-theme, $color); &.mat-primary { @include _mat-toolbar-inverse-color($primary); button.mat-mdc-icon-button { - mat-icon { + .mat-icon { color: mat.get-color-from-palette($primary); } } diff --git a/ui-ngx/src/typings/jquery.flot.typings.d.ts b/ui-ngx/src/typings/jquery.flot.typings.d.ts index 5bcc9b9b3e..e832a36e7a 100644 --- a/ui-ngx/src/typings/jquery.flot.typings.d.ts +++ b/ui-ngx/src/typings/jquery.flot.typings.d.ts @@ -119,6 +119,7 @@ interface JQueryPlotSelection { color?: string; shape?: JQueryPlotSelectionShape; minSize?: number; + touch?: boolean; } interface JQueryPlotSelectionRanges { diff --git a/ui-ngx/src/typings/utils.d.ts b/ui-ngx/src/typings/utils.d.ts new file mode 100644 index 0000000000..7557501bea --- /dev/null +++ b/ui-ngx/src/typings/utils.d.ts @@ -0,0 +1,21 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +type NestedKeyOf = + {[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object + ? `${Key}` | `${Key}.${NestedKeyOf extends infer U extends string ? U : never}` + : `${Key}` + }[keyof ObjectType & (string | number)];