Browse Source

UI: Add Alarm and entity count widgets.

pull/9264/head
Igor Kulikov 3 years ago
parent
commit
e255b6ec42
  1. 5
      application/src/main/data/json/system/widget_bundles/alarm_widgets.json
  2. 14
      application/src/main/data/json/system/widget_bundles/count_widgets.json
  3. 1
      application/src/main/data/json/system/widget_bundles/entity_widgets.json
  4. 23
      application/src/main/data/json/system/widget_types/alarm_count.json
  5. 23
      application/src/main/data/json/system/widget_types/entity_count.json
  6. 1
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  7. 61
      ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.html
  8. 107
      ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.ts
  9. 25
      ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html
  10. 14
      ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts
  11. 20
      ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts
  12. 0
      ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entities-table-basic-config.component.html
  13. 0
      ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entities-table-basic-config.component.ts
  14. 56
      ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.html
  15. 98
      ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.ts
  16. 6
      ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html
  17. 8
      ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts
  18. 2
      ui-ngx/src/app/modules/home/components/widget/config/datasources.component.html
  19. 15
      ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts
  20. 0
      ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.html
  21. 0
      ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.scss
  22. 2
      ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts
  23. 37
      ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.html
  24. 80
      ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.scss
  25. 148
      ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts
  26. 122
      ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.models.ts
  27. 0
      ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.html
  28. 0
      ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.scss
  29. 2
      ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.ts
  30. 0
      ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.models.ts
  31. 0
      ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.html
  32. 0
      ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.scss
  33. 2
      ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts
  34. 23
      ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.html
  35. 62
      ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.ts
  36. 1
      ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts
  37. 103
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.html
  38. 201
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts
  39. 9
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts
  40. 0
      ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.html
  41. 0
      ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.ts
  42. 0
      ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.html
  43. 0
      ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.ts
  44. 0
      ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.html
  45. 0
      ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.ts
  46. 23
      ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.html
  47. 62
      ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.ts
  48. 24
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
  49. 3
      ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
  50. 13
      ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
  51. 2
      ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts
  52. 3
      ui-ngx/src/app/shared/components/material-icon-select.component.html
  53. 3
      ui-ngx/src/app/shared/components/material-icon-select.component.ts
  54. 26
      ui-ngx/src/app/shared/models/widget-settings.models.ts
  55. 1
      ui-ngx/src/app/shared/models/widget.models.ts
  56. 19
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  57. 21
      ui-ngx/src/assets/widget/alarm-count/column-layout.svg
  58. 21
      ui-ngx/src/assets/widget/alarm-count/row-layout.svg
  59. 21
      ui-ngx/src/assets/widget/entity-count/column-layout.svg
  60. 21
      ui-ngx/src/assets/widget/entity-count/row-layout.svg

5
application/src/main/data/json/system/widget_bundles/alarm_widgets.json

@ -2,12 +2,13 @@
"widgetsBundle": {
"alias": "alarm_widgets",
"title": "Alarm widgets",
"image": "data:image/png;base64,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",
"image": "data:image/png;base64,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",
"description": "Visualization of alarms for devices, assets and other entities.",
"externalId": null,
"name": "Alarm widgets"
},
"widgetTypeFqns": [
"alarm_widgets.alarms_table"
"alarm_widgets.alarms_table",
"alarm_count"
]
}

14
application/src/main/data/json/system/widget_bundles/count_widgets.json

@ -0,0 +1,14 @@
{
"widgetsBundle": {
"alias": "count_widgets",
"title": "Count widgets",
"image": "data:image/png;base64,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",
"description": "Cards to display the number of alarms or entities based on selected filter.",
"externalId": null,
"name": "Count widgets"
},
"widgetTypeFqns": [
"alarm_count",
"entity_count"
]
}

1
application/src/main/data/json/system/widget_bundles/entity_widgets.json

@ -9,6 +9,7 @@
},
"widgetTypeFqns": [
"cards.entities_table",
"entity_count",
"cards.entities_hierarchy"
]
}

23
application/src/main/data/json/system/widget_types/alarm_count.json

@ -0,0 +1,23 @@
{
"fqn": "alarm_count",
"name": "Alarm count",
"deprecated": false,
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAolBMVEXg4ODf39/g4OAAAADg4ODf39/////g4OD8/Pz+/v7RJzD29vb6+vr7+/v09PTt7e3z8/P4+Pjx8fHv7+/ok5fXQkqXl5chISHk5OTIyMi6urqpqamgoKDDw8P55OXurrI8PDzc3NyxsbF0dHRYWFjlhYrUND3V1dXroKT88fLR0dHzycvwu76QkJDieH7eY2pKSkovLy/219jieH1mZmbTND12Tj45AAAABnRSTlPvIL8Ar7DvmsykAAAEx0lEQVR42u2aiXLaMBBATdMuUmU5yEBJgEDanL3v//+1rpDI2khA087U63RfjGRJa4k3a5sMpjgZPCuGfef54KQYFGMFPUfVqPG8hifAGE+r3ufDo4piCE+CoYgwQ0S4ISLcEBFuiAg3RIQbIsINEeGGiHBDRLghItwQEW6ICDdEhBsiwg0R4YaIcENEuCEi3BARbogIN0SEGyLCDRHhhohwQ0S48X+IaDiKBibsiGit/hit/i06J0IatkRsaWPZxoZR3OIgheKYjUHbkoLj/jawOWOjsDQ3rUfTUXcIQ5c9IqhROlPlMf5lwm6saYx2KC4dJSg6BhsKzMZTBK3hSqV0XsQ6p9ic9EexximtMyJaOdMfDURjTnIiyrqe/d5fOauyIgb6ha4wJRmRsoKekRXRyvVPxKUiGkVGEFnfvswwXQMzRiiik4xYEpm+zHILDS4Wy8UFeE7jtfUK/i15Ea2seRB5uQeI0Bs/ew1mcWGw7kKkNjYrUj9aZP7m4o1Zzg1W512IOKVSEZUVufm+XyRu89dwOl/OmWQEdFbkHuD+gMgSNy+yNK+7EcllxLpUZEqXflbk3QIv+HdLc7FYvOlCxFkNuiWitc5dIx8AeU8iKSa8DHRBnd61NOREPoXm5wcRZmBGVJIRlRFZAawxKatbriK/efud+AtkisWkRyKZUwsVosjbKVMR91sZWQMyuW9c77vz1NAVlBGAY3etT9Dgcypy/mU2uz6DzsiLQCqyAs/NDXhWicjZ7Mt88fUaOoJOrWMZmQDEa2TDZFfk7uoO4GoGHUGf7PpIRlbQ4m32Yr+8hI4gETgi8g1arFKR8+uvl3fQFXT7PfKBOJ00uZlmRK5+zD5CJ1BGNBw+tfLALlezGjrgkZ8jKe18nAF8nGHRDfTf79+KzK7Pz7u+2J2Fg9fIbd5jCk2Wlyw+EA/etdbTnMfPNbQ56/5fFLVHpGf4jMDTEMl+r+VGvXqqsO8LOq1c1bPHCuWe736t6VdKdGXKVkbo3KpGJfQFbUeVs9mMqBJNxuPT8SnRbKS940MhcaOOXCgu9whoYTyw3nikIt7EOlONPNWorkeBUFe176lDGxuhDANYhMjQsymo8qMRf1gaQathSZ3bmCqO163p8LlufKybnlooosrSObMX95iBdOR4jHtEqEOPRIRyosLjfB/msLKhahYIFiECxzF486IOfPliU1Fo+ENiUSI0l2/EJeKiYeUQZ2NJK/mmRQ0EMiJqg03xevinwm4Thd1xI9R2YBtfKhqIsc3jFM2llI8uYwD2UMAGmlQhwSMRQVSfCBqpCOgNyuuEDaEq9oYOKg9BR+5O125ovTtCA1TRHKEH0EOnIqTixx8ARaXC2pcB5RsQ+o6zEwR4dLuNTZoqzrpdAFqRcS6gfJAIETUASIl2qBGrGA5JCNAOJKPUBiROQiHxXcBma8ydLpKIJMSc6WYrzkz7YY94eAeNYJonjEWzzHK0FwV20Nsh/T//FLBPiAg3RIQbIsINEeGGiHBDRLghItwQEW6ICDdEhBsiwg0R4YaIcENEuCEi3BARbogIN0SEGyLCDRHhhohwQ0S4ISLcGBZFz37Zn0cNi2djeALUL4pBUfc+J2qMGieD58O+UzwbnPwC9rQ9R9RHLAMAAAAASUVORK5CYII=",
"description": "Displays the number of alarms based on selected filter.",
"descriptor": {
"type": "latest",
"sizeX": 3.5,
"sizeY": 1.5,
"resources": [],
"templateHtml": "<tb-count-widget \n [ctx]=\"ctx\"\n [widgetTitlePanel]=\"widgetTitlePanel\"\n alarmElseEntity=\"true\">\n</tb-count-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.countWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.countWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '220px',\n previewHeight: '100px',\n embedTitlePanel: true,\n hideDataSettings: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n",
"settingsSchema": "",
"dataKeySettingsSchema": "",
"settingsDirective": "tb-alarm-count-widget-settings",
"hasBasicMode": true,
"basicModeDirective": "tb-alarm-count-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"count\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = Number((prevValue + Math.random() * 4 - 2).toFixed(0));\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"],\"assignedToCurrentUser\":false,\"assigneeId\":null}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"showLabel\":true,\"label\":\"Total\",\"labelFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.54)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":20,\"iconSizeUnit\":\"px\",\"icon\":\"warning\",\"iconColor\":{\"type\":\"constant\",\"color\":\"rgba(255, 255, 255, 1)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIconBackground\":true,\"iconBackgroundSize\":36,\"iconBackgroundSizeUnit\":\"px\",\"iconBackgroundColor\":{\"type\":\"range\",\"color\":\"rgba(0, 105, 92, 1)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"rgba(0, 105, 92, 1)\"},{\"from\":1,\"to\":null,\"color\":\"rgba(209, 39, 48, 1)\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":20,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"24px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showChevron\":false,\"chevronSize\":24,\"chevronSizeUnit\":\"px\",\"chevronColor\":\"rgba(0, 0, 0, 0.38)\",\"layout\":\"column\"},\"title\":\"Alarm count\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":null,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.54)\"}"
},
"externalId": null
}

23
application/src/main/data/json/system/widget_types/entity_count.json

@ -0,0 +1,23 @@
{
"fqn": "entity_count",
"name": "Entity count",
"deprecated": false,
"image": "data:image/png;base64,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",
"description": "Displays the number of entities based on selected filter.",
"descriptor": {
"type": "latest",
"sizeX": 3.5,
"sizeY": 1.5,
"resources": [],
"templateHtml": "<tb-count-widget \n [ctx]=\"ctx\"\n [widgetTitlePanel]=\"widgetTitlePanel\"\n alarmElseEntity=\"false\">\n</tb-count-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.countWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.countWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '220px',\n previewHeight: '100px',\n embedTitlePanel: true,\n hideDataSettings: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n",
"settingsSchema": "",
"dataKeySettingsSchema": "",
"settingsDirective": "tb-entity-count-widget-settings",
"hasBasicMode": true,
"basicModeDirective": "tb-entity-count-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"count\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"return 150;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"],\"assignedToCurrentUser\":false,\"assigneeId\":null}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"showLabel\":true,\"label\":\"Devices\",\"labelFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.54)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":20,\"iconSizeUnit\":\"px\",\"icon\":\"devices\",\"iconColor\":{\"type\":\"constant\",\"color\":\"rgba(255, 255, 255, 1)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIconBackground\":true,\"iconBackgroundSize\":36,\"iconBackgroundSizeUnit\":\"px\",\"iconBackgroundColor\":{\"type\":\"constant\",\"color\":\"rgb(241, 141, 23)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":20,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"24px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showChevron\":false,\"chevronSize\":24,\"chevronSizeUnit\":\"px\",\"chevronColor\":\"rgba(0, 0, 0, 0.38)\",\"layout\":\"column\"},\"title\":\"Entity count\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":null,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.54)\"}"
},
"externalId": null
}

1
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -523,6 +523,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
this.deleteSystemWidgetBundle("entity_widgets");
this.deleteSystemWidgetBundle("html_widgets");
this.deleteSystemWidgetBundle("tables");
this.deleteSystemWidgetBundle("count_widgets");
installScripts.loadSystemWidgets();
}

61
ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.html

@ -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.
-->
<ng-container [formGroup]="alarmCountWidgetConfigForm">
<div class="tb-form-panel">
<div fxLayout="row" fxLayoutAlign="space-between center">
<div class="tb-form-panel-title" translate>alarm.filter</div>
<button mat-button color="primary"
(click)="alarmFilterConfig.reset()">
{{ 'action.reset' | translate }}
</button>
</div>
<tb-alarm-filter-config #alarmFilterConfig buttonMode="false"
propagatedFilter="false"
formControlName="alarmFilterConfig"
[initialAlarmFilterConfig]="{ statusList: [alarmSearchStatus.ACTIVE] }"></tb-alarm-filter-config>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.appearance</div>
<tb-count-widget-settings alarmElseEntity="true" formControlName="settings"></tb-count-widget-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="backgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

107
ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.ts

@ -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.
///
import { Component } 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 { DatasourceType, WidgetConfig, widgetType, } 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 { getAlarmFilterConfig, setAlarmFilterConfig } from '@shared/models/widget-settings.models';
import { UtilsService } from '@core/services/utils.service';
import { AlarmSearchStatus } from '@shared/models/alarm.models';
import {
countDefaultSettings,
CountWidgetSettings
} from '@home/components/widget/lib/count/count-widget.models';
@Component({
selector: 'tb-alarm-count-basic-config',
templateUrl: './alarm-count-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class AlarmCountBasicConfigComponent extends BasicWidgetConfigComponent {
alarmSearchStatus = AlarmSearchStatus;
alarmCountWidgetConfigForm: UntypedFormGroup;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private utils: UtilsService,
private fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.alarmCountWidgetConfigForm;
}
protected setupDefaults(configData: WidgetConfigComponentData) {
let datasources = configData.config.datasources;
if (!datasources || !datasources.length) {
datasources = [{}];
configData.config.datasources = datasources;
}
datasources[0].type = DatasourceType.alarmCount;
datasources[0].alarmFilterConfig = {statusList: [AlarmSearchStatus.ACTIVE]};
datasources[0].dataKeys = [this.utils.createKey({name: 'count'}, DataKeyType.count)];
}
protected onConfigSet(configData: WidgetConfigComponentData) {
const settings: CountWidgetSettings = {...countDefaultSettings(true), ...(configData.config.settings || {})};
this.alarmCountWidgetConfigForm = this.fb.group({
alarmFilterConfig: [getAlarmFilterConfig(configData.config.datasources), []],
settings: [settings, []],
backgroundColor: [configData.config.backgroundColor, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
actions: [configData.config.actions || {}, []]
});
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setAlarmFilterConfig(config.alarmFilterConfig, this.widgetConfig.config.datasources);
this.widgetConfig.config.settings = {...(this.widgetConfig.config.settings || {}), ...config.settings};
this.widgetConfig.config.backgroundColor = config.backgroundColor;
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.borderRadius = config.borderRadius;
this.widgetConfig.config.actions = config.actions;
return this.widgetConfig;
}
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');
}
}

25
ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html

@ -49,7 +49,7 @@
formControlName="columns">
</tb-data-keys-panel>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-panel-title" translate>widget-config.appearance</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.card-title' | translate }}
@ -85,6 +85,29 @@
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.table.table-buttons</div>
<div class="tb-form-row column">
<mat-slide-toggle class="mat-slide" formControlName="displayActivity">
{{ 'widgets.table.display-alarm-activity' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="displayDetails">
{{ 'widgets.table.display-alarm-details' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="allowAssign">
{{ 'widgets.table.allow-alarms-assign' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="allowAcknowledgment">
{{ 'widgets.table.allow-alarms-ack' | translate }}
</mat-slide-toggle>
<mat-slide-toggle class="mat-slide" formControlName="allowClear">
{{ 'widgets.table.allow-alarms-clear' | translate }}
</mat-slide-toggle>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">

14
ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts

@ -69,6 +69,13 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent
showTitleIcon: [configData.config.showTitleIcon, []],
titleIcon: [configData.config.titleIcon, []],
iconColor: [configData.config.iconColor, []],
displayActivity: [configData.config.settings?.displayActivity, []],
displayDetails: [configData.config.settings?.displayDetails, []],
allowAssign: [configData.config.settings?.allowAssign, []],
allowAcknowledgment: [configData.config.settings?.allowAcknowledgment, []],
allowClear: [configData.config.settings?.allowClear, []],
cardButtons: [this.getCardButtons(configData.config), []],
color: [configData.config.color, []],
backgroundColor: [configData.config.backgroundColor, []],
@ -84,7 +91,14 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent
this.widgetConfig.config.actions = config.actions;
this.widgetConfig.config.showTitle = config.showTitle;
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
this.widgetConfig.config.settings.alarmsTitle = config.title;
this.widgetConfig.config.settings.displayActivity = config.displayActivity;
this.widgetConfig.config.settings.displayDetails = config.displayDetails;
this.widgetConfig.config.settings.allowAssign = config.allowAssign;
this.widgetConfig.config.settings.allowAcknowledgment = config.allowAcknowledgment;
this.widgetConfig.config.settings.allowClear = config.allowClear;
this.widgetConfig.config.titleFont = config.titleFont;
this.widgetConfig.config.titleColor = config.titleColor;
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;

20
ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts

@ -27,7 +27,7 @@ import {
} from '@home/components/widget/config/basic/common/widget-actions-panel.component';
import {
EntitiesTableBasicConfigComponent
} from '@home/components/widget/config/basic/cards/entities-table-basic-config.component';
} from '@home/components/widget/config/basic/entity/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 {
@ -49,6 +49,12 @@ import {
import {
AggregatedDataKeysPanelComponent
} from '@home/components/widget/config/basic/cards/aggregated-data-keys-panel.component';
import {
AlarmCountBasicConfigComponent
} from '@home/components/widget/config/basic/alarm/alarm-count-basic-config.component';
import {
EntityCountBasicConfigComponent
} from '@home/components/widget/config/basic/entity/entity-count-basic-config.component';
@NgModule({
declarations: [
@ -63,7 +69,9 @@ import {
AggregatedDataKeyRowComponent,
AggregatedDataKeysPanelComponent,
DataKeyRowComponent,
DataKeysPanelComponent
DataKeysPanelComponent,
AlarmCountBasicConfigComponent,
EntityCountBasicConfigComponent
],
imports: [
CommonModule,
@ -82,7 +90,9 @@ import {
AggregatedDataKeyRowComponent,
AggregatedDataKeysPanelComponent,
DataKeyRowComponent,
DataKeysPanelComponent
DataKeysPanelComponent,
AlarmCountBasicConfigComponent,
EntityCountBasicConfigComponent
]
})
export class BasicWidgetConfigModule {
@ -95,5 +105,7 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type<IBasicWidgetCo
'tb-flot-basic-config': FlotBasicConfigComponent,
'tb-alarms-table-basic-config': AlarmsTableBasicConfigComponent,
'tb-value-card-basic-config': ValueCardBasicConfigComponent,
'tb-aggregated-value-card-basic-config': AggregatedValueCardBasicConfigComponent
'tb-aggregated-value-card-basic-config': AggregatedValueCardBasicConfigComponent,
'tb-alarm-count-basic-config': AlarmCountBasicConfigComponent,
'tb-entity-count-basic-config': EntityCountBasicConfigComponent
};

0
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html → ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entities-table-basic-config.component.html

0
ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts → ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entities-table-basic-config.component.ts

56
ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.html

@ -0,0 +1,56 @@
<!--
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.
-->
<ng-container [formGroup]="entityCountWidgetConfigForm">
<tb-datasources
[configMode]="basicMode"
hideDatasourcesMode
hideDatasourceLabel
hideDataKeys
displayDatasourceFilterForBasicMode
formControlName="datasources">
</tb-datasources>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.appearance</div>
<tb-count-widget-settings alarmElseEntity="false" formControlName="settings"></tb-count-widget-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="backgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

98
ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.ts

@ -0,0 +1,98 @@
///
/// Copyright © 2016-2023 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
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 { DatasourceType, 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 { UtilsService } from '@core/services/utils.service';
import { countDefaultSettings, CountWidgetSettings } from '@home/components/widget/lib/count/count-widget.models';
@Component({
selector: 'tb-entity-count-basic-config',
templateUrl: './entity-count-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class EntityCountBasicConfigComponent extends BasicWidgetConfigComponent {
entityCountWidgetConfigForm: UntypedFormGroup;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private utils: UtilsService,
private fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.entityCountWidgetConfigForm;
}
protected setupDefaults(configData: WidgetConfigComponentData) {
let datasources = configData.config.datasources;
if (!datasources || !datasources.length) {
datasources = [{}];
configData.config.datasources = datasources;
}
datasources[0].type = DatasourceType.entityCount;
datasources[0].dataKeys = [this.utils.createKey({name: 'count'}, DataKeyType.count)];
}
protected onConfigSet(configData: WidgetConfigComponentData) {
const settings: CountWidgetSettings = {...countDefaultSettings(false), ...(configData.config.settings || {})};
this.entityCountWidgetConfigForm = this.fb.group({
datasources: [configData.config.datasources, []],
settings: [settings, []],
backgroundColor: [configData.config.backgroundColor, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
actions: [configData.config.actions || {}, []]
});
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
this.widgetConfig.config.datasources = config.datasources;
this.widgetConfig.config.settings = {...(this.widgetConfig.config.settings || {}), ...config.settings};
this.widgetConfig.config.backgroundColor = config.backgroundColor;
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.borderRadius = config.borderRadius;
this.widgetConfig.config.actions = config.actions;
return this.widgetConfig;
}
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');
}
}

6
ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html

@ -26,7 +26,7 @@
</mat-form-field>
<section fxLayout="column" [ngSwitch]="datasourceFormGroup.get('type').value">
<ng-template [ngSwitchCase]="datasourceType.function">
<mat-form-field fxFlex>
<mat-form-field *ngIf="!hideDatasourceLabel" fxFlex>
<mat-label translate>datasource.label</mat-label>
<input matInput
formControlName="name">
@ -54,7 +54,7 @@
formControlName="entityAliasId"
[callbacks]="entityAliasSelectCallbacks">
</tb-entity-alias-select>
<mat-form-field *ngIf="[datasourceType.entityCount, datasourceType.alarmCount].includes(datasourceFormGroup.get('type').value)"
<mat-form-field *ngIf="!hideDatasourceLabel && [datasourceType.entityCount, datasourceType.alarmCount].includes(datasourceFormGroup.get('type').value)"
fxFlex>
<input matInput
placeholder="{{ 'datasource.label' | translate }}"
@ -95,7 +95,7 @@
</tb-data-keys>
</section>
<tb-filter-select
*ngIf="!basicMode && ![datasourceType.function, datasourceType.alarmCount].includes(datasourceFormGroup.get('type').value)"
*ngIf="(!basicMode || displayDatasourceFilterForBasicMode) && ![datasourceType.function, datasourceType.alarmCount].includes(datasourceFormGroup.get('type').value)"
[showLabel]="true"
[aliasController]="aliasController"
formControlName="filterId"

8
ui-ngx/src/app/modules/home/components/widget/config/datasource.component.ts

@ -123,6 +123,14 @@ export class DatasourceComponent implements ControlValueAccessor, OnInit, Valida
return this.widgetConfigComponent.widget;
}
public get hideDatasourceLabel(): boolean {
return this.datasourcesComponent?.hideDatasourceLabel;
}
public get displayDatasourceFilterForBasicMode(): boolean {
return this.datasourcesComponent?.displayDatasourceFilterForBasicMode;
}
public get hideDataKeyLabel(): boolean {
return this.datasourcesComponent?.hideDataKeyLabel;
}

2
ui-ngx/src/app/modules/home/components/widget/config/datasources.component.html

@ -22,7 +22,7 @@
<div fxFlex fxLayout="row" fxLayoutAlign="center center" *ngIf="timeseriesKeyError">
<mat-error >{{ 'widget-config.timeseries-key-error' | translate }}</mat-error>
</div>
<tb-toggle-select *ngIf="basicMode" [ngModel]="datasourcesMode" (ngModelChange)="datasourcesModeChange($event)"
<tb-toggle-select *ngIf="basicMode && !hideDatasourcesMode" [ngModel]="datasourcesMode" (ngModelChange)="datasourcesModeChange($event)"
[ngModelOptions]="{ standalone: true }">
<tb-toggle-option [value]="datasourceType.device">{{ 'device.device' | translate }}</tb-toggle-option>
<tb-toggle-option [value]="datasourceType.entity">{{ 'entity.entity-alias' | translate }}</tb-toggle-option>

15
ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts

@ -93,6 +93,18 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid
@Input()
disabled: boolean;
@Input()
@coerceBoolean()
hideDatasourcesMode = false;
@Input()
@coerceBoolean()
hideDatasourceLabel = false;
@Input()
@coerceBoolean()
displayDatasourceFilterForBasicMode = false;
@Input()
@coerceBoolean()
hideDataKeyLabel = false;
@ -285,7 +297,8 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid
if (datasources && datasources.length) {
datasourcesMode = datasources[0].type;
}
if (datasourcesMode !== DatasourceType.device && datasourcesMode !== DatasourceType.entity) {
if (!this.hideDatasourcesMode
&& datasourcesMode !== DatasourceType.device && datasourcesMode !== DatasourceType.entity) {
datasourcesMode = DatasourceType.device;
}
return datasourcesMode;

0
ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html → ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.html

0
ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.scss → ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.scss

2
ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts → ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts

@ -149,7 +149,7 @@ interface AlarmWidgetActionDescriptor extends TableCellButtonActionDescriptor {
@Component({
selector: 'tb-alarms-table-widget',
templateUrl: './alarms-table-widget.component.html',
styleUrls: ['./alarms-table-widget.component.scss', './table-widget.scss']
styleUrls: ['./alarms-table-widget.component.scss', './../table-widget.scss']
})
export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, OnDestroy, AfterViewInit {

37
ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.html

@ -0,0 +1,37 @@
<!--
Copyright © 2016-2023 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div class="tb-count-panel" [class.tb-count-pointer]="showChevron" (click)="cardClick($event)">
<div class="tb-count-panel-column">
<ng-container *ngTemplateOutlet="widgetTitlePanel"></ng-container>
<div class="tb-count-panel-row">
<div class="tb-count-icon-panel" *ngIf="showIconBackground || showIcon"
[style]="{minWidth: iconBackgroundSize, minHeight: iconBackgroundSize}">
<div *ngIf="showIconBackground" class="tb-count-icon-background-panel">
<div [style]="iconBackgroundStyle" [style.background-color]="iconBackgroundColor.color"></div>
</div>
<tb-icon *ngIf="showIcon" [style]="iconStyle" [style.color]="iconColor.color">{{ icon }}</tb-icon>
</div>
<div class="tb-count-label-value-panel" [class.tb-count-layout-row]="layout === countCardLayout.row">
<div *ngIf="showLabel" [style]="labelStyle" [style.color]="labelColor.color">{{ label }}</div>
<div *ngIf="layout === countCardLayout.row" style="flex: 1;"></div>
<div [style]="valueStyle" [style.color]="valueColor.color">{{ valueText }}</div>
</div>
</div>
</div>
<tb-icon *ngIf="showChevron" [style]="chevronStyle">chevron_right</tb-icon>
</div>

80
ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.scss

@ -0,0 +1,80 @@
/**
* 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-count-panel {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
padding: 12px;
&.tb-count-pointer {
cursor: pointer;
}
.tb-count-panel-column {
flex: 1;
display: flex;
flex-direction: column;
gap: 12px;
}
.tb-count-panel-row {
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
}
.tb-count-icon-panel {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.mat-icon {
z-index: 1;
}
}
.tb-count-icon-background-panel {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.tb-count-label-value-panel {
flex: 1;
display: flex;
flex-direction: column;
place-content: flex-start space-around;
align-items: flex-start;
gap: 0;
&.tb-count-layout-row {
flex-direction: row;
align-items: center;
}
}
}
}
:host ::ng-deep {
.tb-count-panel {
.tb-widget-title {
padding: 0;
}
}
}

148
ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.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 { ChangeDetectorRef, Component, Input, OnInit, TemplateRef } from '@angular/core';
import { WidgetContext } from '@home/models/widget-component.models';
import { formatValue } from '@core/utils';
import {
ColorProcessor,
ComponentStyle,
getSingleTsValue,
iconStyle,
textStyle
} from '@shared/models/widget-settings.models';
import { WidgetComponent } from '@home/components/widget/widget.component';
import {
CountCardLayout,
countDefaultSettings,
CountWidgetSettings
} from '@home/components/widget/lib/count/count-widget.models';
import { coerceBoolean } from '@shared/decorators/coercion';
@Component({
selector: 'tb-count-widget',
templateUrl: './count-widget.component.html',
styleUrls: ['./count-widget.component.scss']
})
export class CountWidgetComponent implements OnInit {
settings: CountWidgetSettings;
countCardLayout = CountCardLayout;
@Input()
ctx: WidgetContext;
@Input()
widgetTitlePanel: TemplateRef<any>;
@coerceBoolean()
@Input()
alarmElseEntity: boolean;
layout: CountCardLayout;
showLabel = true;
label: string;
labelStyle: ComponentStyle = {};
labelColor: ColorProcessor;
showIcon = true;
icon = '';
iconStyle: ComponentStyle = {};
iconColor: ColorProcessor;
showIconBackground = true;
iconBackgroundSize: string;
iconBackgroundStyle: ComponentStyle = {};
iconBackgroundColor: ColorProcessor;
valueText = 'N/A';
valueStyle: ComponentStyle = {};
valueColor: ColorProcessor;
showChevron = false;
chevronStyle: ComponentStyle = {};
constructor(private widgetComponent: WidgetComponent,
private cd: ChangeDetectorRef) {
}
ngOnInit(): void {
this.ctx.$scope.countWidget = this;
this.settings = {...countDefaultSettings(this.alarmElseEntity), ...this.ctx.settings};
this.layout = this.settings.layout;
this.showLabel = this.settings.showLabel;
this.label = this.settings.label;
this.labelStyle = textStyle(this.settings.labelFont, '0.4px');
this.labelColor = ColorProcessor.fromSettings(this.settings.labelColor);
this.showIcon = this.settings.showIcon;
this.icon = this.settings.icon;
this.iconStyle = iconStyle(this.settings.iconSize, this.settings.iconSizeUnit);
this.iconColor = ColorProcessor.fromSettings(this.settings.iconColor);
this.showIconBackground = this.settings.showIconBackground;
if (this.showIconBackground) {
this.iconBackgroundSize = this.settings.iconBackgroundSize + this.settings.iconBackgroundSizeUnit;
} else {
this.iconBackgroundSize = this.settings.iconSize + this.settings.iconSizeUnit;
}
this.iconBackgroundStyle = {
width: this.iconBackgroundSize,
height: this.iconBackgroundSize,
borderRadius: '4px'
};
this.iconBackgroundColor = ColorProcessor.fromSettings(this.settings.iconBackgroundColor);
this.valueStyle = textStyle(this.settings.valueFont, '0.1px');
this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor);
this.showChevron = this.settings.showChevron;
this.chevronStyle = iconStyle(this.settings.chevronSize, this.settings.chevronSizeUnit);
this.chevronStyle.color = this.settings.chevronColor;
}
public onInit() {
}
public onDataUpdated() {
const tsValue = getSingleTsValue(this.ctx.data);
let value: any;
if (tsValue) {
value = tsValue[1];
this.valueText = formatValue(value, 0);
} else {
this.valueText = 'N/A';
}
this.labelColor.update(value);
this.iconColor.update(value);
this.iconBackgroundColor.update(value);
this.valueColor.update(value);
this.cd.detectChanges();
}
public cardClick($event: Event) {
const descriptors = this.ctx.actionsApi.getActionDescriptors('cardClick');
if (descriptors.length) {
$event.stopPropagation();
const descriptor = descriptors[0];
this.ctx.actionsApi.handleWidgetAction($event, descriptor);
}
}
}

122
ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.models.ts

@ -0,0 +1,122 @@
///
/// 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 {
ColorSettings,
ColorType,
constantColor,
cssUnit,
defaultColorFunction,
Font
} from '@shared/models/widget-settings.models';
export enum CountCardLayout {
column = 'column',
row = 'row'
}
export const countCardLayouts = Object.keys(CountCardLayout) as CountCardLayout[];
export const countCardLayoutTranslations = new Map<CountCardLayout, string>(
[
[CountCardLayout.column, 'widgets.count.layout-column'],
[CountCardLayout.row, 'widgets.count.layout-row']
]
);
export const alarmCountCardLayoutImages = new Map<CountCardLayout, string>(
[
[CountCardLayout.column, 'assets/widget/alarm-count/column-layout.svg'],
[CountCardLayout.row, 'assets/widget/alarm-count/row-layout.svg']
]
);
export const entityCountCardLayoutImages = new Map<CountCardLayout, string>(
[
[CountCardLayout.column, 'assets/widget/entity-count/column-layout.svg'],
[CountCardLayout.row, 'assets/widget/entity-count/row-layout.svg']
]
);
export interface CountWidgetSettings {
layout: CountCardLayout;
showLabel: boolean;
label: string;
labelFont: Font;
labelColor: ColorSettings;
showIcon: boolean;
icon: string;
iconSize: number;
iconSizeUnit: cssUnit;
iconColor: ColorSettings;
showIconBackground: boolean;
iconBackgroundSize: number;
iconBackgroundSizeUnit: cssUnit;
iconBackgroundColor: ColorSettings;
valueFont: Font;
valueColor: ColorSettings;
showChevron: boolean;
chevronSize: number;
chevronSizeUnit: cssUnit;
chevronColor: string;
}
export const countDefaultSettings = (alarmElseEntity: boolean): CountWidgetSettings => ({
layout: CountCardLayout.column,
showLabel: true,
label: alarmElseEntity ? 'Total' : 'Devices',
labelFont: {
family: 'Roboto',
size: 12,
sizeUnit: 'px',
style: 'normal',
weight: '400',
lineHeight: '16px'
},
labelColor: constantColor('rgba(0, 0, 0, 0.54)'),
showIcon: true,
icon: alarmElseEntity ? 'warning' : 'devices',
iconSize: 20,
iconSizeUnit: 'px',
iconColor: constantColor('rgba(255, 255, 255, 1)'),
showIconBackground: true,
iconBackgroundSize: 36,
iconBackgroundSizeUnit: 'px',
iconBackgroundColor: alarmElseEntity
? {
color: 'rgba(0, 105, 92, 1)',
type: ColorType.range,
rangeList: [
{from: 0, to: 0, color: 'rgba(0, 105, 92, 1)'},
{from: 1, color: 'rgba(209, 39, 48, 1)'}
],
colorFunction: defaultColorFunction
}
: constantColor('rgba(241, 141, 23, 1)'),
valueFont: {
family: 'Roboto',
size: 20,
sizeUnit: 'px',
style: 'normal',
weight: '500',
lineHeight: '24px'
},
valueColor: constantColor('rgba(0, 0, 0, 0.87)'),
showChevron: false,
chevronSize: 24,
chevronSizeUnit: 'px',
chevronColor: 'rgba(0, 0, 0, 0.38)'
});

0
ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.html → ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.html

0
ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.scss → ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.scss

2
ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.ts → ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.ts

@ -64,7 +64,7 @@ import {
NodeRelationQueryFunction,
NodesSortFunction,
NodeTextFunction
} from '@home/components/widget/lib/entities-hierarchy-widget.models';
} from '@home/components/widget/lib/entity/entities-hierarchy-widget.models';
import { EntityRelationsQuery } from '@shared/models/relation.models';
import { AliasFilterType, RelationsQueryFilter } from '@shared/models/alias.models';
import { EntityFilter } from '@shared/models/query/query.models';

0
ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.models.ts → ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.models.ts

0
ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html → ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.html

0
ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.scss → ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.scss

2
ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts → ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts

@ -121,7 +121,7 @@ interface EntitiesTableWidgetSettings extends TableWidgetSettings {
@Component({
selector: 'tb-entities-table-widget',
templateUrl: './entities-table-widget.component.html',
styleUrls: ['./entities-table-widget.component.scss', './table-widget.scss']
styleUrls: ['./entities-table-widget.component.scss', './../table-widget.scss']
})
export class EntitiesTableWidgetComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy {

23
ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.html

@ -0,0 +1,23 @@
<!--
Copyright © 2016-2023 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ng-container [formGroup]="alarmCountWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.alarm-count.alarm-count-card-style</div>
<tb-count-widget-settings alarmElseEntity="true" formControlName="alarmCountSettings"></tb-count-widget-settings>
</div>
</ng-container>

62
ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.ts

@ -0,0 +1,62 @@
///
/// Copyright © 2016-2023 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component } from '@angular/core';
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { countDefaultSettings } from '@home/components/widget/lib/count/count-widget.models';
@Component({
selector: 'tb-alarm-count-widget-settings',
templateUrl: './alarm-count-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class AlarmCountWidgetSettingsComponent extends WidgetSettingsComponent {
alarmCountWidgetSettingsForm: UntypedFormGroup;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
}
protected settingsForm(): UntypedFormGroup {
return this.alarmCountWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {...countDefaultSettings(true)};
}
protected onSettingsSet(settings: WidgetSettings) {
this.alarmCountWidgetSettingsForm = this.fb.group({
alarmCountSettings: [settings.alarmCountSettings, []],
});
}
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
return {
alarmCountSettings: settings
};
}
protected prepareOutputSettings(settings: any): WidgetSettings {
return settings.alarmCountSettings;
}
}

1
ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts

@ -53,6 +53,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent
allowAcknowledgment: true,
allowClear: true,
allowAssign: true,
displayActivity: true,
displayPagination: true,
defaultPageSize: 10,
defaultSortOrder: '-createdTime',

103
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.html

@ -0,0 +1,103 @@
<!--
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.
-->
<ng-container [formGroup]="countWidgetConfigForm">
<tb-image-cards-select rowHeight="{{ '3:1' }}"
[cols]="2"
[colsLtMd]="1"
label="{{ 'widgets.count.layout' | translate }}" formControlName="layout">
<tb-image-cards-select-option *ngFor="let layout of countCardLayouts"
[value]="layout"
[image]="countCardLayoutImageMap.get(layout)">
{{ countCardLayoutTranslationMap.get(layout) | translate }}
</tb-image-cards-select-option>
</tb-image-cards-select>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showLabel">
{{ 'widgets.count.label' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="label" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="labelFont"
[previewText]="countWidgetConfigForm.get('label').value">
</tb-font-settings>
<tb-color-settings formControlName="labelColor">
</tb-color-settings>
</div>
</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showIcon">
{{ 'widgets.count.icon' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="flex number" subscriptSizing="dynamic">
<input matInput type="number" min="0" formControlName="iconSize" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-css-unit-select fxFlex formControlName="iconSizeUnit"></tb-css-unit-select>
<tb-material-icon-select asBoxInput
iconClearButton
[color]="countWidgetConfigForm.get('iconColor').value?.color"
[backgroundColor]="countWidgetConfigForm.get('iconBackgroundColor').enabled
? countWidgetConfigForm.get('iconBackgroundColor').value?.color
: ''"
formControlName="icon">
</tb-material-icon-select>
<tb-color-settings formControlName="iconColor">
</tb-color-settings>
</div>
</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showIconBackground">
{{ 'widgets.count.icon-background' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="flex number" subscriptSizing="dynamic">
<input matInput type="number" min="0" formControlName="iconBackgroundSize" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-css-unit-select fxFlex formControlName="iconBackgroundSizeUnit"></tb-css-unit-select>
<tb-color-settings formControlName="iconBackgroundColor">
</tb-color-settings>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.count.value</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="valueFont"
previewText="10">
</tb-font-settings>
<tb-color-settings formControlName="valueColor">
</tb-color-settings>
</div>
</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showChevron">
{{ 'widgets.count.chevron' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="flex number" subscriptSizing="dynamic">
<input matInput type="number" min="0" formControlName="chevronSize" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-css-unit-select fxFlex formControlName="chevronSizeUnit"></tb-css-unit-select>
<tb-color-input asBoxInput
colorClearButton
formControlName="chevronColor">
</tb-color-input>
</div>
</div>
</ng-container>

201
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts

@ -0,0 +1,201 @@
///
/// 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 {
AbstractControl,
ControlValueAccessor,
NG_VALUE_ACCESSOR,
UntypedFormBuilder,
UntypedFormGroup,
Validators
} from '@angular/forms';
import {Store} from '@ngrx/store';
import {AppState} from '@core/core.state';
import {
alarmCountCardLayoutImages,
CountCardLayout,
countCardLayouts,
countCardLayoutTranslations,
CountWidgetSettings, entityCountCardLayoutImages
} from '@home/components/widget/lib/count/count-widget.models';
import {PageComponent} from '@shared/components/page.component';
import {Component, forwardRef, Input, OnInit} from '@angular/core';
import { coerceBoolean } from '@shared/decorators/coercion';
import {
valueCardLayoutImages,
valueCardLayoutTranslations
} from '@home/components/widget/lib/cards/value-card-widget.models';
@Component({
selector: 'tb-count-widget-settings',
templateUrl: './count-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CountWidgetSettingsComponent),
multi: true
}
]
})
export class CountWidgetSettingsComponent extends PageComponent implements OnInit, ControlValueAccessor {
@Input()
disabled: boolean;
@coerceBoolean()
@Input()
alarmElseEntity: boolean;
private propagateChange = null;
countCardLayouts = countCardLayouts;
countCardLayoutTranslationMap = countCardLayoutTranslations;
countCardLayoutImageMap: Map<CountCardLayout, string>;
countWidgetConfigForm: UntypedFormGroup;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
}
ngOnInit(): void {
this.countCardLayoutImageMap = this.alarmElseEntity ? alarmCountCardLayoutImages : entityCountCardLayoutImages;
this.countWidgetConfigForm = this.fb.group({
layout: [null, []],
showLabel: [null, []],
label: [null, []],
labelFont: [null, []],
labelColor: [null, []],
showIcon: [null, []],
iconSize: [null, [Validators.min(0)]],
iconSizeUnit: [null, []],
icon: [null, []],
iconColor: [null, []],
showIconBackground: [null, []],
iconBackgroundSize: [null, [Validators.min(0)]],
iconBackgroundSizeUnit: [null, []],
iconBackgroundColor: [null, []],
valueFont: [null, []],
valueColor: [null, []],
showChevron: [null, []],
chevronSize: [null, [Validators.min(0)]],
chevronSizeUnit: [null, []],
chevronColor: [null, []],
});
this.countWidgetConfigForm.valueChanges.subscribe(() => {
this.updateModel();
});
for (const trigger of ['showLabel', 'showIcon', 'showIconBackground', 'showChevron']) {
const path = trigger.split('.');
let control: AbstractControl = this.countWidgetConfigForm;
for (const part of path) {
control = this.countWidgetConfigForm.get(part);
}
control.valueChanges.subscribe(() => {
this.updateValidators();
});
}
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.countWidgetConfigForm.disable({emitEvent: false});
} else {
this.countWidgetConfigForm.enable({emitEvent: false});
this.updateValidators();
}
}
writeValue(value: CountWidgetSettings): void {
this.countWidgetConfigForm.patchValue(
value, {emitEvent: false}
);
this.updateValidators();
}
private updateModel() {
const value: CountWidgetSettings = this.countWidgetConfigForm.value;
this.propagateChange(value);
}
protected updateValidators() {
const showLabel: boolean = this.countWidgetConfigForm.get('showLabel').value;
const showIcon: boolean = this.countWidgetConfigForm.get('showIcon').value;
const showIconBackground: boolean = this.countWidgetConfigForm.get('showIconBackground').value;
const showChevron: boolean = this.countWidgetConfigForm.get('showChevron').value;
if (showLabel) {
this.countWidgetConfigForm.get('label').enable({emitEvent: false});
this.countWidgetConfigForm.get('labelFont').enable({emitEvent: false});
this.countWidgetConfigForm.get('labelColor').enable({emitEvent: false});
} else {
this.countWidgetConfigForm.get('label').disable({emitEvent: false});
this.countWidgetConfigForm.get('labelFont').disable({emitEvent: false});
this.countWidgetConfigForm.get('labelColor').disable({emitEvent: false});
}
if (showIcon) {
this.countWidgetConfigForm.get('iconSize').enable({emitEvent: false});
this.countWidgetConfigForm.get('iconSizeUnit').enable({emitEvent: false});
this.countWidgetConfigForm.get('icon').enable({emitEvent: false});
this.countWidgetConfigForm.get('iconColor').enable({emitEvent: false});
} else {
this.countWidgetConfigForm.get('iconSize').disable({emitEvent: false});
this.countWidgetConfigForm.get('iconSizeUnit').disable({emitEvent: false});
this.countWidgetConfigForm.get('icon').disable({emitEvent: false});
this.countWidgetConfigForm.get('iconColor').disable({emitEvent: false});
}
if (showIconBackground) {
this.countWidgetConfigForm.get('iconBackgroundSize').enable({emitEvent: false});
this.countWidgetConfigForm.get('iconBackgroundSizeUnit').enable({emitEvent: false});
this.countWidgetConfigForm.get('iconBackgroundColor').enable({emitEvent: false});
} else {
this.countWidgetConfigForm.get('iconBackgroundSize').disable({emitEvent: false});
this.countWidgetConfigForm.get('iconBackgroundSizeUnit').disable({emitEvent: false});
this.countWidgetConfigForm.get('iconBackgroundColor').disable({emitEvent: false});
}
if (showChevron) {
this.countWidgetConfigForm.get('chevronSize').enable({emitEvent: false});
this.countWidgetConfigForm.get('chevronSizeUnit').enable({emitEvent: false});
this.countWidgetConfigForm.get('chevronColor').enable({emitEvent: false});
} else {
this.countWidgetConfigForm.get('chevronSize').disable({emitEvent: false});
this.countWidgetConfigForm.get('chevronSizeUnit').disable({emitEvent: false});
this.countWidgetConfigForm.get('chevronColor').disable({emitEvent: false});
}
}
protected readonly valueCardLayoutTranslations = valueCardLayoutTranslations;
protected readonly valueCardLayoutImages = valueCardLayoutImages;
}

9
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts

@ -40,6 +40,9 @@ import { BackgroundSettingsComponent } from '@home/components/widget/lib/setting
import {
BackgroundSettingsPanelComponent
} from '@home/components/widget/lib/settings/common/background-settings-panel.component';
import {
CountWidgetSettingsComponent
} from "@home/components/widget/lib/settings/common/count-widget-settings.component";
@NgModule({
declarations: [
@ -56,7 +59,8 @@ import {
BackgroundSettingsPanelComponent,
ValueSourceComponent,
LegendConfigComponent,
WidgetFontComponent
WidgetFontComponent,
CountWidgetSettingsComponent
],
imports: [
CommonModule,
@ -77,7 +81,8 @@ import {
BackgroundSettingsPanelComponent,
ValueSourceComponent,
LegendConfigComponent,
WidgetFontComponent
WidgetFontComponent,
CountWidgetSettingsComponent
]
})
export class WidgetSettingsCommonModule {

0
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.html → ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.html

0
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.ts → ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.ts

0
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html → ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.html

0
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.ts → ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.ts

0
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html → ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.html

0
ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts → ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.ts

23
ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.html

@ -0,0 +1,23 @@
<!--
Copyright © 2016-2023 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ng-container [formGroup]="entityCountWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.entity-count.entity-count-card-style</div>
<tb-count-widget-settings alarmElseEntity="false" formControlName="entityCountSettings"></tb-count-widget-settings>
</div>
</ng-container>

62
ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.ts

@ -0,0 +1,62 @@
///
/// Copyright © 2016-2023 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component } from '@angular/core';
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { countDefaultSettings } from '@home/components/widget/lib/count/count-widget.models';
@Component({
selector: 'tb-entity-count-widget-settings',
templateUrl: './entity-count-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class EntityCountWidgetSettingsComponent extends WidgetSettingsComponent {
entityCountWidgetSettingsForm: UntypedFormGroup;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
}
protected settingsForm(): UntypedFormGroup {
return this.entityCountWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return {...countDefaultSettings(false)};
}
protected onSettingsSet(settings: WidgetSettings) {
this.entityCountWidgetSettingsForm = this.fb.group({
entityCountSettings: [settings.entityCountSettings, []],
});
}
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
return {
entityCountSettings: settings
};
}
protected prepareOutputSettings(settings: any): WidgetSettings {
return settings.entityCountSettings;
}
}

24
ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts

@ -42,16 +42,16 @@ import {
} from '@home/components/widget/lib/settings/cards/dashboard-state-widget-settings.component';
import {
EntitiesHierarchyWidgetSettingsComponent
} from '@home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component';
} from '@home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component';
import {
HtmlCardWidgetSettingsComponent
} from '@home/components/widget/lib/settings/cards/html-card-widget-settings.component';
import {
EntitiesTableWidgetSettingsComponent
} from '@home/components/widget/lib/settings/cards/entities-table-widget-settings.component';
} from '@home/components/widget/lib/settings/entity/entities-table-widget-settings.component';
import {
EntitiesTableKeySettingsComponent
} from '@home/components/widget/lib/settings/cards/entities-table-key-settings.component';
} from '@home/components/widget/lib/settings/entity/entities-table-key-settings.component';
import {
AlarmsTableWidgetSettingsComponent
} from '@home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component';
@ -279,6 +279,12 @@ import {
import {
AggregatedValueCardWidgetSettingsComponent
} from '@home/components/widget/lib/settings/cards/aggregated-value-card-widget-settings.component';
import {
AlarmCountWidgetSettingsComponent
} from '@home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component';
import {
EntityCountWidgetSettingsComponent
} from '@home/components/widget/lib/settings/entity/entity-count-widget-settings.component';
@NgModule({
declarations: [
@ -382,7 +388,9 @@ import {
QuickLinksWidgetSettingsComponent,
ValueCardWidgetSettingsComponent,
AggregatedValueCardKeySettingsComponent,
AggregatedValueCardWidgetSettingsComponent
AggregatedValueCardWidgetSettingsComponent,
AlarmCountWidgetSettingsComponent,
EntityCountWidgetSettingsComponent
],
imports: [
CommonModule,
@ -491,7 +499,9 @@ import {
QuickLinksWidgetSettingsComponent,
ValueCardWidgetSettingsComponent,
AggregatedValueCardKeySettingsComponent,
AggregatedValueCardWidgetSettingsComponent
AggregatedValueCardWidgetSettingsComponent,
AlarmCountWidgetSettingsComponent,
EntityCountWidgetSettingsComponent
]
})
export class WidgetSettingsModule {
@ -565,5 +575,7 @@ export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsCo
'tb-quick-links-widget-settings': QuickLinksWidgetSettingsComponent,
'tb-value-card-widget-settings': ValueCardWidgetSettingsComponent,
'tb-aggregated-value-card-key-settings': AggregatedValueCardKeySettingsComponent,
'tb-aggregated-value-card-widget-settings': AggregatedValueCardWidgetSettingsComponent
'tb-aggregated-value-card-widget-settings': AggregatedValueCardWidgetSettingsComponent,
'tb-alarm-count-widget-settings': AlarmCountWidgetSettingsComponent,
'tb-entity-count-widget-settings': EntityCountWidgetSettingsComponent
};

3
ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts

@ -549,6 +549,9 @@ export class WidgetComponentService {
if (isUndefined(result.typeParameters.embedTitlePanel)) {
result.typeParameters.embedTitlePanel = false;
}
if (isUndefined(result.typeParameters.hideDataSettings)) {
result.typeParameters.hideDataSettings = false;
}
if (isFunction(widgetTypeInstance.actionSources)) {
result.actionSources = widgetTypeInstance.actionSources();
} else {

13
ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts

@ -17,12 +17,12 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@app/shared/shared.module';
import { EntitiesTableWidgetComponent } from '@home/components/widget/lib/entities-table-widget.component';
import { EntitiesTableWidgetComponent } from '@home/components/widget/lib/entity/entities-table-widget.component';
import { DisplayColumnsPanelComponent } from '@home/components/widget/lib/display-columns-panel.component';
import { AlarmsTableWidgetComponent } from '@home/components/widget/lib/alarms-table-widget.component';
import { AlarmsTableWidgetComponent } from '@home/components/widget/lib/alarm/alarms-table-widget.component';
import { SharedHomeComponentsModule } from '@home/components/shared-home-components.module';
import { TimeseriesTableWidgetComponent } from '@home/components/widget/lib/timeseries-table-widget.component';
import { EntitiesHierarchyWidgetComponent } from '@home/components/widget/lib/entities-hierarchy-widget.component';
import { EntitiesHierarchyWidgetComponent } from '@home/components/widget/lib/entity/entities-hierarchy-widget.component';
import { RpcWidgetsModule } from '@home/components/widget/lib/rpc/rpc-widgets.module';
import {
DateRangeNavigatorPanelComponent,
@ -56,6 +56,7 @@ import { ValueCardWidgetComponent } from '@home/components/widget/lib/cards/valu
import {
AggregatedValueCardWidgetComponent
} from '@home/components/widget/lib/cards/aggregated-value-card-widget.component';
import { CountWidgetComponent } from '@home/components/widget/lib/count/count-widget.component';
@NgModule({
declarations:
@ -88,7 +89,8 @@ import {
GatewayConfigurationComponent,
GatewayRemoteConfigurationDialogComponent,
ValueCardWidgetComponent,
AggregatedValueCardWidgetComponent
AggregatedValueCardWidgetComponent,
CountWidgetComponent
],
imports: [
CommonModule,
@ -125,7 +127,8 @@ import {
GatewayConfigurationComponent,
GatewayRemoteConfigurationDialogComponent,
ValueCardWidgetComponent,
AggregatedValueCardWidgetComponent
AggregatedValueCardWidgetComponent,
CountWidgetComponent
],
providers: [
{provide: WIDGET_COMPONENTS_MODULE_TOKEN, useValue: WidgetComponentsModule }

2
ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts

@ -721,7 +721,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
}
public get displayAppearanceDataSettings(): boolean {
return this.displayUnitsConfig || this.displayNoDataDisplayMessageConfig;
return !this.modelValue?.typeParameters?.hideDataSettings && (this.displayUnitsConfig || this.displayNoDataDisplayMessageConfig);
}
public get displayUnitsConfig(): boolean {

3
ui-ngx/src/app/shared/components/material-icon-select.component.html

@ -32,7 +32,8 @@
<button type="button"
mat-stroked-button
class="tb-box-button"
[ngStyle]="color && !disabled ? { color: color } : {}"
[style.color]="color && !disabled ? color : ''"
[style.background-color]="backgroundColor && !disabled ? backgroundColor : ''"
[disabled]="disabled"
#matButton
(click)="openIconPopup($event, matButton)">

3
ui-ngx/src/app/shared/components/material-icon-select.component.ts

@ -51,6 +51,9 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit
@Input()
color: string;
@Input()
backgroundColor: string;
@Input()
disabled: boolean;

26
ui-ngx/src/app/shared/models/widget-settings.models.ts

@ -20,6 +20,8 @@ import { Injector } from '@angular/core';
import { DatePipe } from '@angular/common';
import { DateAgoPipe } from '@shared/pipe/date-ago.pipe';
import { TranslateService } from '@ngx-translate/core';
import { AlarmFilterConfig } from '@shared/models/query/query.models';
import { AlarmSearchStatus } from '@shared/models/alarm.models';
export type ComponentStyle = {[klass: string]: any};
@ -111,13 +113,15 @@ export const defaultTimewindowStyle: TimewindowStyle = {
export const constantColor = (color: string): ColorSettings => ({
type: ColorType.constant,
color,
colorFunction: 'var temperature = value;\n' +
colorFunction: defaultColorFunction
});
export const defaultColorFunction = 'var temperature = value;\n' +
'if (typeof temperature !== undefined) {\n' +
' var percent = (temperature + 60)/120 * 100;\n' +
' return tinycolor.mix(\'blue\', \'red\', percent).toHexString();\n' +
'}\n' +
'return \'blue\';'
});
'return \'blue\';';
export const cssSizeToStrSize = (size?: number, unit?: cssUnit): string => (isDefinedAndNotNull(size) ? size + '' : '0') + (unit || 'px');
@ -422,6 +426,22 @@ export const getDataKey = (datasources?: Datasource[]): DataKey => {
return null;
};
export const getAlarmFilterConfig = (datasources?: Datasource[]): AlarmFilterConfig => {
if (datasources && datasources.length) {
const config = datasources[0].alarmFilterConfig;
if (config) {
return config;
}
}
return { statusList: [ AlarmSearchStatus.ACTIVE ] };
};
export const setAlarmFilterConfig = (config: AlarmFilterConfig, datasources?: Datasource[]): void => {
if (datasources && datasources.length) {
datasources[0].alarmFilterConfig = config;
}
};
export const getLabel = (datasources?: Datasource[]): string => {
const dataKey = getDataKey(datasources);
if (dataKey) {

1
ui-ngx/src/app/shared/models/widget.models.ts

@ -179,6 +179,7 @@ export interface WidgetTypeParameters {
previewWidth?: string;
previewHeight?: string;
embedTitlePanel?: boolean;
hideDataSettings?: boolean;
}
export interface WidgetControllerDescriptor {

19
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -6084,6 +6084,22 @@
"aggregation": "Aggregation",
"aggregated-value-card-style": "Aggregated value card style"
},
"alarm-count": {
"alarm-count-card-style": "Alarm count card style"
},
"entity-count": {
"entity-count-card-style": "Entity count card style"
},
"count": {
"layout": "Layout",
"layout-column": "Column",
"layout-row": "Row",
"label": "Label",
"icon": "Icon",
"icon-background": "Icon background",
"value": "Value",
"chevron": "Chevron"
},
"table": {
"common-table-settings": "Common Table Settings",
"enable-search": "Enable search",
@ -6403,7 +6419,8 @@
"element-click": "On HTML element click",
"pie-slice-click": "On slice click",
"row-double-click": "On row double click",
"action-button-click": "Action button click"
"action-button-click": "Action button click",
"card-click": "On card click"
}
},
"paginator" : {

21
ui-ngx/src/assets/widget/alarm-count/column-layout.svg

@ -0,0 +1,21 @@
<svg width="214" height="75" viewBox="0 0 214 75" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_2638_340594)">
<path d="M8.5 8C8.5 5.79086 10.2909 4 12.5 4H201.5C203.709 4 205.5 5.79086 205.5 8V59C205.5 61.2091 203.709 63 201.5 63H12.5C10.2909 63 8.5 61.2091 8.5 59V8Z" fill="white"/>
<rect x="20.5" y="15.5" width="36" height="36" rx="4" fill="#00695C"/>
<path d="M30.9701 41.4999H46.0301C47.5701 41.4999 48.5301 39.8299 47.7601 38.4999L40.2301 25.4899C39.4601 24.1599 37.5401 24.1599 36.7701 25.4899L29.2401 38.4999C28.4701 39.8299 29.4301 41.4999 30.9701 41.4999ZM38.5001 34.4999C37.9501 34.4999 37.5001 34.0499 37.5001 33.4999V31.4999C37.5001 30.9499 37.9501 30.4999 38.5001 30.4999C39.0501 30.4999 39.5001 30.9499 39.5001 31.4999V33.4999C39.5001 34.0499 39.0501 34.4999 38.5001 34.4999ZM39.5001 38.4999H37.5001V36.4999H39.5001V38.4999Z" fill="white"/>
<path d="M72.6426 16.9688V25.5H71.5293V16.9688H72.6426ZM75.3848 16.9688V17.8945H68.793V16.9688H75.3848ZM76.0133 22.4004V22.2656C76.0133 21.8086 76.0797 21.3848 76.2125 20.9941C76.3453 20.5996 76.5367 20.2578 76.7867 19.9688C77.0367 19.6758 77.3395 19.4492 77.6949 19.2891C78.0504 19.125 78.4488 19.043 78.8902 19.043C79.3355 19.043 79.7359 19.125 80.0914 19.2891C80.4508 19.4492 80.7555 19.6758 81.0055 19.9688C81.2594 20.2578 81.4527 20.5996 81.5855 20.9941C81.7184 21.3848 81.7848 21.8086 81.7848 22.2656V22.4004C81.7848 22.8574 81.7184 23.2812 81.5855 23.6719C81.4527 24.0625 81.2594 24.4043 81.0055 24.6973C80.7555 24.9863 80.4527 25.2129 80.0973 25.377C79.7457 25.5371 79.3473 25.6172 78.902 25.6172C78.4566 25.6172 78.0563 25.5371 77.7008 25.377C77.3453 25.2129 77.0406 24.9863 76.7867 24.6973C76.5367 24.4043 76.3453 24.0625 76.2125 23.6719C76.0797 23.2812 76.0133 22.8574 76.0133 22.4004ZM77.0973 22.2656V22.4004C77.0973 22.7168 77.1344 23.0156 77.2086 23.2969C77.2828 23.5742 77.3941 23.8203 77.5426 24.0352C77.6949 24.25 77.8844 24.4199 78.1109 24.5449C78.3375 24.666 78.6012 24.7266 78.902 24.7266C79.1988 24.7266 79.4586 24.666 79.6813 24.5449C79.9078 24.4199 80.0953 24.25 80.2438 24.0352C80.3922 23.8203 80.5035 23.5742 80.5777 23.2969C80.6559 23.0156 80.6949 22.7168 80.6949 22.4004V22.2656C80.6949 21.9531 80.6559 21.6582 80.5777 21.3809C80.5035 21.0996 80.3902 20.8516 80.2379 20.6367C80.0895 20.418 79.902 20.2461 79.6754 20.1211C79.4527 19.9961 79.191 19.9336 78.8902 19.9336C78.5934 19.9336 78.3316 19.9961 78.1051 20.1211C77.8824 20.2461 77.6949 20.418 77.5426 20.6367C77.3941 20.8516 77.2828 21.0996 77.2086 21.3809C77.1344 21.6582 77.0973 21.9531 77.0973 22.2656ZM86.1984 19.1602V19.9922H82.7707V19.1602H86.1984ZM83.9309 17.6191H85.0148V23.9297C85.0148 24.1445 85.048 24.3066 85.1145 24.416C85.1809 24.5254 85.2668 24.5977 85.3723 24.6328C85.4777 24.668 85.591 24.6855 85.7121 24.6855C85.802 24.6855 85.8957 24.6777 85.9934 24.6621C86.0949 24.6426 86.1711 24.627 86.2219 24.6152L86.2277 25.5C86.1418 25.5273 86.0285 25.5527 85.8879 25.5762C85.7512 25.6035 85.5852 25.6172 85.3898 25.6172C85.1242 25.6172 84.8801 25.5645 84.6574 25.459C84.4348 25.3535 84.257 25.1777 84.1242 24.9316C83.9953 24.6816 83.9309 24.3457 83.9309 23.9238V17.6191ZM91.6082 24.416V21.1523C91.6082 20.9023 91.5574 20.6855 91.4559 20.502C91.3582 20.3145 91.2098 20.1699 91.0105 20.0684C90.8113 19.9668 90.5652 19.916 90.2723 19.916C89.9988 19.916 89.7586 19.9629 89.5516 20.0566C89.3484 20.1504 89.1883 20.2734 89.0711 20.4258C88.9578 20.5781 88.9012 20.7422 88.9012 20.918H87.8172C87.8172 20.6914 87.8758 20.4668 87.993 20.2441C88.1102 20.0215 88.2781 19.8203 88.4969 19.6406C88.7195 19.457 88.9852 19.3125 89.2938 19.207C89.6063 19.0977 89.9539 19.043 90.3367 19.043C90.7977 19.043 91.2039 19.1211 91.5555 19.2773C91.9109 19.4336 92.1883 19.6699 92.3875 19.9863C92.5906 20.2988 92.6922 20.6914 92.6922 21.1641V24.1172C92.6922 24.3281 92.7098 24.5527 92.7449 24.791C92.784 25.0293 92.8406 25.2344 92.9148 25.4062V25.5H91.784C91.7293 25.375 91.6863 25.209 91.6551 25.002C91.6238 24.791 91.6082 24.5957 91.6082 24.416ZM91.7957 21.6562L91.8074 22.418H90.7117C90.4031 22.418 90.1277 22.4434 89.8855 22.4941C89.6434 22.541 89.4402 22.6133 89.2762 22.7109C89.1121 22.8086 88.9871 22.9316 88.9012 23.0801C88.8152 23.2246 88.7723 23.3945 88.7723 23.5898C88.7723 23.7891 88.8172 23.9707 88.907 24.1348C88.9969 24.2988 89.1316 24.4297 89.3113 24.5273C89.4949 24.6211 89.7195 24.668 89.9852 24.668C90.3172 24.668 90.6102 24.5977 90.8641 24.457C91.118 24.3164 91.3191 24.1445 91.4676 23.9414C91.6199 23.7383 91.702 23.541 91.7137 23.3496L92.1766 23.8711C92.1492 24.0352 92.075 24.2168 91.9539 24.416C91.8328 24.6152 91.6707 24.8066 91.4676 24.9902C91.2684 25.1699 91.0301 25.3203 90.7527 25.4414C90.4793 25.5586 90.1707 25.6172 89.827 25.6172C89.3973 25.6172 89.0203 25.5332 88.6961 25.3652C88.3758 25.1973 88.1258 24.9727 87.9461 24.6914C87.7703 24.4062 87.6824 24.0879 87.6824 23.7363C87.6824 23.3965 87.7488 23.0977 87.8816 22.8398C88.0145 22.5781 88.2059 22.3613 88.4559 22.1895C88.7059 22.0137 89.0066 21.8809 89.3582 21.791C89.7098 21.7012 90.1023 21.6562 90.5359 21.6562H91.7957ZM95.975 16.5V25.5H94.8852V16.5H95.975Z" fill="black" fill-opacity="0.54"/>
<path d="M78.8418 40.1992V42.5234C78.8418 43.6367 78.7311 44.5872 78.5098 45.375C78.2949 46.1562 77.9824 46.791 77.5723 47.2793C77.1621 47.7676 76.6706 48.1257 76.0977 48.3535C75.5312 48.5814 74.8965 48.6953 74.1934 48.6953C73.6335 48.6953 73.1126 48.6237 72.6309 48.4805C72.1556 48.3372 71.7259 48.1126 71.3418 47.8066C70.9577 47.5007 70.6289 47.1068 70.3555 46.625C70.0885 46.1367 69.8802 45.554 69.7305 44.877C69.5872 44.1999 69.5156 43.4154 69.5156 42.5234V40.1992C69.5156 39.0794 69.6263 38.1354 69.8477 37.3672C70.069 36.5924 70.3848 35.9642 70.7949 35.4824C71.2051 34.9941 71.6934 34.6393 72.2598 34.418C72.8327 34.1966 73.4707 34.0859 74.1738 34.0859C74.7402 34.0859 75.2611 34.1576 75.7363 34.3008C76.2181 34.4375 76.6478 34.6556 77.0254 34.9551C77.4095 35.2546 77.735 35.6452 78.002 36.127C78.2754 36.6022 78.4837 37.1784 78.627 37.8555C78.7702 38.526 78.8418 39.3073 78.8418 40.1992ZM76.4883 42.8555V39.8477C76.4883 39.2812 76.4557 38.7832 76.3906 38.3535C76.3255 37.9173 76.2279 37.5495 76.0977 37.25C75.974 36.944 75.8177 36.6966 75.6289 36.5078C75.4401 36.3125 75.2253 36.1725 74.9844 36.0879C74.7435 35.9967 74.4733 35.9512 74.1738 35.9512C73.8092 35.9512 73.4837 36.0228 73.1973 36.166C72.9108 36.3027 72.6699 36.5241 72.4746 36.8301C72.2793 37.1361 72.1296 37.5397 72.0254 38.041C71.9277 38.5358 71.8789 39.138 71.8789 39.8477V42.8555C71.8789 43.4284 71.9115 43.9329 71.9766 44.3691C72.0417 44.8053 72.1393 45.1797 72.2695 45.4922C72.3997 45.7982 72.556 46.0521 72.7383 46.2539C72.9271 46.4492 73.1419 46.5924 73.3828 46.6836C73.6302 46.7747 73.9004 46.8203 74.1934 46.8203C74.5645 46.8203 74.8932 46.7487 75.1797 46.6055C75.4661 46.4622 75.707 46.2344 75.9023 45.9219C76.0977 45.6029 76.2441 45.1895 76.3418 44.6816C76.4395 44.1738 76.4883 43.5651 76.4883 42.8555Z" fill="black" fill-opacity="0.87"/>
</g>
<defs>
<filter id="filter0_d_2638_340594" x="0.5" y="0" width="213" height="75" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="4"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2638_340594"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2638_340594" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.5 KiB

21
ui-ngx/src/assets/widget/alarm-count/row-layout.svg

@ -0,0 +1,21 @@
<svg width="214" height="75" viewBox="0 0 214 75" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_2638_340580)">
<path d="M8.5 8C8.5 5.79086 10.2909 4 12.5 4H201.5C203.709 4 205.5 5.79086 205.5 8V59C205.5 61.2091 203.709 63 201.5 63H12.5C10.2909 63 8.5 61.2091 8.5 59V8Z" fill="white"/>
<rect x="20.5" y="15.5" width="36" height="36" rx="4" fill="#00695C"/>
<path d="M30.9701 41.4999H46.0301C47.5701 41.4999 48.5301 39.8299 47.7601 38.4999L40.2301 25.4899C39.4601 24.1599 37.5401 24.1599 36.7701 25.4899L29.2401 38.4999C28.4701 39.8299 29.4301 41.4999 30.9701 41.4999ZM38.5001 34.4999C37.9501 34.4999 37.5001 34.0499 37.5001 33.4999V31.4999C37.5001 30.9499 37.9501 30.4999 38.5001 30.4999C39.0501 30.4999 39.5001 30.9499 39.5001 31.4999V33.4999C39.5001 34.0499 39.0501 34.4999 38.5001 34.4999ZM39.5001 38.4999H37.5001V36.4999H39.5001V38.4999Z" fill="white"/>
<path d="M72.6426 28.9688V37.5H71.5293V28.9688H72.6426ZM75.3848 28.9688V29.8945H68.793V28.9688H75.3848ZM76.0133 34.4004V34.2656C76.0133 33.8086 76.0797 33.3848 76.2125 32.9941C76.3453 32.5996 76.5367 32.2578 76.7867 31.9688C77.0367 31.6758 77.3395 31.4492 77.6949 31.2891C78.0504 31.125 78.4488 31.043 78.8902 31.043C79.3355 31.043 79.7359 31.125 80.0914 31.2891C80.4508 31.4492 80.7555 31.6758 81.0055 31.9688C81.2594 32.2578 81.4527 32.5996 81.5855 32.9941C81.7184 33.3848 81.7848 33.8086 81.7848 34.2656V34.4004C81.7848 34.8574 81.7184 35.2812 81.5855 35.6719C81.4527 36.0625 81.2594 36.4043 81.0055 36.6973C80.7555 36.9863 80.4527 37.2129 80.0973 37.377C79.7457 37.5371 79.3473 37.6172 78.902 37.6172C78.4566 37.6172 78.0563 37.5371 77.7008 37.377C77.3453 37.2129 77.0406 36.9863 76.7867 36.6973C76.5367 36.4043 76.3453 36.0625 76.2125 35.6719C76.0797 35.2812 76.0133 34.8574 76.0133 34.4004ZM77.0973 34.2656V34.4004C77.0973 34.7168 77.1344 35.0156 77.2086 35.2969C77.2828 35.5742 77.3941 35.8203 77.5426 36.0352C77.6949 36.25 77.8844 36.4199 78.1109 36.5449C78.3375 36.666 78.6012 36.7266 78.902 36.7266C79.1988 36.7266 79.4586 36.666 79.6813 36.5449C79.9078 36.4199 80.0953 36.25 80.2438 36.0352C80.3922 35.8203 80.5035 35.5742 80.5777 35.2969C80.6559 35.0156 80.6949 34.7168 80.6949 34.4004V34.2656C80.6949 33.9531 80.6559 33.6582 80.5777 33.3809C80.5035 33.0996 80.3902 32.8516 80.2379 32.6367C80.0895 32.418 79.902 32.2461 79.6754 32.1211C79.4527 31.9961 79.191 31.9336 78.8902 31.9336C78.5934 31.9336 78.3316 31.9961 78.1051 32.1211C77.8824 32.2461 77.6949 32.418 77.5426 32.6367C77.3941 32.8516 77.2828 33.0996 77.2086 33.3809C77.1344 33.6582 77.0973 33.9531 77.0973 34.2656ZM86.1984 31.1602V31.9922H82.7707V31.1602H86.1984ZM83.9309 29.6191H85.0148V35.9297C85.0148 36.1445 85.048 36.3066 85.1145 36.416C85.1809 36.5254 85.2668 36.5977 85.3723 36.6328C85.4777 36.668 85.591 36.6855 85.7121 36.6855C85.802 36.6855 85.8957 36.6777 85.9934 36.6621C86.0949 36.6426 86.1711 36.627 86.2219 36.6152L86.2277 37.5C86.1418 37.5273 86.0285 37.5527 85.8879 37.5762C85.7512 37.6035 85.5852 37.6172 85.3898 37.6172C85.1242 37.6172 84.8801 37.5645 84.6574 37.459C84.4348 37.3535 84.257 37.1777 84.1242 36.9316C83.9953 36.6816 83.9309 36.3457 83.9309 35.9238V29.6191ZM91.6082 36.416V33.1523C91.6082 32.9023 91.5574 32.6855 91.4559 32.502C91.3582 32.3145 91.2098 32.1699 91.0105 32.0684C90.8113 31.9668 90.5652 31.916 90.2723 31.916C89.9988 31.916 89.7586 31.9629 89.5516 32.0566C89.3484 32.1504 89.1883 32.2734 89.0711 32.4258C88.9578 32.5781 88.9012 32.7422 88.9012 32.918H87.8172C87.8172 32.6914 87.8758 32.4668 87.993 32.2441C88.1102 32.0215 88.2781 31.8203 88.4969 31.6406C88.7195 31.457 88.9852 31.3125 89.2938 31.207C89.6063 31.0977 89.9539 31.043 90.3367 31.043C90.7977 31.043 91.2039 31.1211 91.5555 31.2773C91.9109 31.4336 92.1883 31.6699 92.3875 31.9863C92.5906 32.2988 92.6922 32.6914 92.6922 33.1641V36.1172C92.6922 36.3281 92.7098 36.5527 92.7449 36.791C92.784 37.0293 92.8406 37.2344 92.9148 37.4062V37.5H91.784C91.7293 37.375 91.6863 37.209 91.6551 37.002C91.6238 36.791 91.6082 36.5957 91.6082 36.416ZM91.7957 33.6562L91.8074 34.418H90.7117C90.4031 34.418 90.1277 34.4434 89.8855 34.4941C89.6434 34.541 89.4402 34.6133 89.2762 34.7109C89.1121 34.8086 88.9871 34.9316 88.9012 35.0801C88.8152 35.2246 88.7723 35.3945 88.7723 35.5898C88.7723 35.7891 88.8172 35.9707 88.907 36.1348C88.9969 36.2988 89.1316 36.4297 89.3113 36.5273C89.4949 36.6211 89.7195 36.668 89.9852 36.668C90.3172 36.668 90.6102 36.5977 90.8641 36.457C91.118 36.3164 91.3191 36.1445 91.4676 35.9414C91.6199 35.7383 91.702 35.541 91.7137 35.3496L92.1766 35.8711C92.1492 36.0352 92.075 36.2168 91.9539 36.416C91.8328 36.6152 91.6707 36.8066 91.4676 36.9902C91.2684 37.1699 91.0301 37.3203 90.7527 37.4414C90.4793 37.5586 90.1707 37.6172 89.827 37.6172C89.3973 37.6172 89.0203 37.5332 88.6961 37.3652C88.3758 37.1973 88.1258 36.9727 87.9461 36.6914C87.7703 36.4062 87.6824 36.0879 87.6824 35.7363C87.6824 35.3965 87.7488 35.0977 87.8816 34.8398C88.0145 34.5781 88.2059 34.3613 88.4559 34.1895C88.7059 34.0137 89.0066 33.8809 89.3582 33.791C89.7098 33.7012 90.1023 33.6562 90.5359 33.6562H91.7957ZM95.975 28.5V37.5H94.8852V28.5H95.975Z" fill="black" fill-opacity="0.54"/>
<path d="M191.842 32.1992V34.5234C191.842 35.6367 191.731 36.5872 191.51 37.375C191.295 38.1562 190.982 38.791 190.572 39.2793C190.162 39.7676 189.671 40.1257 189.098 40.3535C188.531 40.5814 187.896 40.6953 187.193 40.6953C186.633 40.6953 186.113 40.6237 185.631 40.4805C185.156 40.3372 184.726 40.1126 184.342 39.8066C183.958 39.5007 183.629 39.1068 183.355 38.625C183.089 38.1367 182.88 37.554 182.73 36.877C182.587 36.1999 182.516 35.4154 182.516 34.5234V32.1992C182.516 31.0794 182.626 30.1354 182.848 29.3672C183.069 28.5924 183.385 27.9642 183.795 27.4824C184.205 26.9941 184.693 26.6393 185.26 26.418C185.833 26.1966 186.471 26.0859 187.174 26.0859C187.74 26.0859 188.261 26.1576 188.736 26.3008C189.218 26.4375 189.648 26.6556 190.025 26.9551C190.41 27.2546 190.735 27.6452 191.002 28.127C191.275 28.6022 191.484 29.1784 191.627 29.8555C191.77 30.526 191.842 31.3073 191.842 32.1992ZM189.488 34.8555V31.8477C189.488 31.2812 189.456 30.7832 189.391 30.3535C189.326 29.9173 189.228 29.5495 189.098 29.25C188.974 28.944 188.818 28.6966 188.629 28.5078C188.44 28.3125 188.225 28.1725 187.984 28.0879C187.743 27.9967 187.473 27.9512 187.174 27.9512C186.809 27.9512 186.484 28.0228 186.197 28.166C185.911 28.3027 185.67 28.5241 185.475 28.8301C185.279 29.1361 185.13 29.5397 185.025 30.041C184.928 30.5358 184.879 31.138 184.879 31.8477V34.8555C184.879 35.4284 184.911 35.9329 184.977 36.3691C185.042 36.8053 185.139 37.1797 185.27 37.4922C185.4 37.7982 185.556 38.0521 185.738 38.2539C185.927 38.4492 186.142 38.5924 186.383 38.6836C186.63 38.7747 186.9 38.8203 187.193 38.8203C187.564 38.8203 187.893 38.7487 188.18 38.6055C188.466 38.4622 188.707 38.2344 188.902 37.9219C189.098 37.6029 189.244 37.1895 189.342 36.6816C189.439 36.1738 189.488 35.5651 189.488 34.8555Z" fill="black" fill-opacity="0.87"/>
</g>
<defs>
<filter id="filter0_d_2638_340580" x="0.5" y="0" width="213" height="75" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="4"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2638_340580"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2638_340580" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.5 KiB

21
ui-ngx/src/assets/widget/entity-count/column-layout.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

21
ui-ngx/src/assets/widget/entity-count/row-layout.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

Loading…
Cancel
Save