Browse Source

Merge branch 'master' into fx_bug_DateString_WithoutTz

pull/9778/head
nick 3 years ago
parent
commit
e1d421ed5e
  1. 10
      application/src/main/data/json/system/widget_bundles/air_quality.json
  2. 72
      application/src/main/data/json/system/widget_bundles/industial_widgets.json
  3. 32
      application/src/main/data/json/system/widget_types/flow_rate_card.json
  4. 32
      application/src/main/data/json/system/widget_types/flow_rate_card_with_background.json
  5. 35
      application/src/main/data/json/system/widget_types/flow_rate_chart_card.json
  6. 35
      application/src/main/data/json/system/widget_types/flow_rate_chart_card_with_background.json
  7. 33
      application/src/main/data/json/system/widget_types/flow_rate_gauge.json
  8. 32
      application/src/main/data/json/system/widget_types/flow_rate_progress_bar.json
  9. 32
      application/src/main/data/json/system/widget_types/flow_rate_progress_bar_with_background.json
  10. 35
      application/src/main/data/json/system/widget_types/flow_rate_range_chart.json
  11. 35
      application/src/main/data/json/system/widget_types/flow_rate_range_chart_with_background.json
  12. 34
      application/src/main/data/json/system/widget_types/fluid_pressure_card.json
  13. 34
      application/src/main/data/json/system/widget_types/fluid_pressure_card_with_background.json
  14. 37
      application/src/main/data/json/system/widget_types/fluid_pressure_chart_card.json
  15. 37
      application/src/main/data/json/system/widget_types/fluid_pressure_chart_card_with_background.json
  16. 35
      application/src/main/data/json/system/widget_types/fluid_pressure_gauge.json
  17. 34
      application/src/main/data/json/system/widget_types/fluid_pressure_progress_bar.json
  18. 34
      application/src/main/data/json/system/widget_types/fluid_pressure_progress_bar_with_background.json
  19. 37
      application/src/main/data/json/system/widget_types/fluid_pressure_range_chart.json
  20. 37
      application/src/main/data/json/system/widget_types/fluid_pressure_range_chart_with_background.json
  21. 32
      application/src/main/data/json/system/widget_types/fluid_temperature_card.json
  22. 32
      application/src/main/data/json/system/widget_types/fluid_temperature_card_with_background.json
  23. 35
      application/src/main/data/json/system/widget_types/fluid_temperature_chart_card.json
  24. 35
      application/src/main/data/json/system/widget_types/fluid_temperature_chart_card_with_background.json
  25. 33
      application/src/main/data/json/system/widget_types/fluid_temperature_gauge.json
  26. 32
      application/src/main/data/json/system/widget_types/fluid_temperature_progress_bar.json
  27. 32
      application/src/main/data/json/system/widget_types/fluid_temperature_progress_bar_with_background.json
  28. 35
      application/src/main/data/json/system/widget_types/fluid_temperature_range_chart.json
  29. 35
      application/src/main/data/json/system/widget_types/fluid_temperature_range_chart_with_background.json
  30. 32
      application/src/main/data/json/system/widget_types/horizontal_flow_rate_card.json
  31. 32
      application/src/main/data/json/system/widget_types/horizontal_flow_rate_card_with_background.json
  32. 34
      application/src/main/data/json/system/widget_types/horizontal_fluid_pressure_card.json
  33. 34
      application/src/main/data/json/system/widget_types/horizontal_fluid_pressure_card_with_background.json
  34. 32
      application/src/main/data/json/system/widget_types/horizontal_fluid_temperature_card.json
  35. 32
      application/src/main/data/json/system/widget_types/horizontal_fluid_temperature_card_with_background.json
  36. 32
      application/src/main/data/json/system/widget_types/horizontal_individual_allergy_index__iai__card.json
  37. 32
      application/src/main/data/json/system/widget_types/horizontal_individual_allergy_index__iai__card_with_background.json
  38. 32
      application/src/main/data/json/system/widget_types/horizontal_power_consumption_card.json
  39. 32
      application/src/main/data/json/system/widget_types/horizontal_power_consumption_card_with_background.json
  40. 33
      application/src/main/data/json/system/widget_types/horizontal_pump_vibration_card.json
  41. 33
      application/src/main/data/json/system/widget_types/horizontal_pump_vibration_card_with_background.json
  42. 24
      application/src/main/data/json/system/widget_types/individual_allergy_index__iai__card.json
  43. 24
      application/src/main/data/json/system/widget_types/individual_allergy_index__iai__card_with_background.json
  44. 35
      application/src/main/data/json/system/widget_types/individual_allergy_index__iai__chart_card.json
  45. 35
      application/src/main/data/json/system/widget_types/individual_allergy_index__iai__chart_card_with_background.json
  46. 32
      application/src/main/data/json/system/widget_types/power_consumption_card.json
  47. 32
      application/src/main/data/json/system/widget_types/power_consumption_card_with_background.json
  48. 35
      application/src/main/data/json/system/widget_types/power_consumption_chart_card.json
  49. 35
      application/src/main/data/json/system/widget_types/power_consumption_chart_card_with_background.json
  50. 35
      application/src/main/data/json/system/widget_types/power_consumption_range_chart.json
  51. 35
      application/src/main/data/json/system/widget_types/power_consumption_range_chart_with_background.json
  52. 33
      application/src/main/data/json/system/widget_types/pump_vibration_card.json
  53. 33
      application/src/main/data/json/system/widget_types/pump_vibration_card_with_background.json
  54. 36
      application/src/main/data/json/system/widget_types/pump_vibration_chart_card.json
  55. 36
      application/src/main/data/json/system/widget_types/pump_vibration_chart_card_with_background.json
  56. 36
      application/src/main/data/json/system/widget_types/pump_vibration_range_chart.json
  57. 36
      application/src/main/data/json/system/widget_types/pump_vibration_range_chart_with_background.json
  58. 35
      application/src/main/data/json/system/widget_types/simple_flow_rate_chart_card.json
  59. 35
      application/src/main/data/json/system/widget_types/simple_flow_rate_chart_card_with_background.json
  60. 37
      application/src/main/data/json/system/widget_types/simple_fluid_pressure_chart_card.json
  61. 37
      application/src/main/data/json/system/widget_types/simple_fluid_pressure_chart_card_with_background.json
  62. 35
      application/src/main/data/json/system/widget_types/simple_fluid_temperature_chart_card.json
  63. 35
      application/src/main/data/json/system/widget_types/simple_fluid_temperature_chart_card_with_background.json
  64. 35
      application/src/main/data/json/system/widget_types/simple_individual_allergy_index__iai__chart_card.json
  65. 35
      application/src/main/data/json/system/widget_types/simple_individual_allergy_index__iai__chart_card_with_background.json
  66. 35
      application/src/main/data/json/system/widget_types/simple_power_consumption_chart_card.json
  67. 35
      application/src/main/data/json/system/widget_types/simple_power_consumption_chart_card_with_background.json
  68. 36
      application/src/main/data/json/system/widget_types/simple_pump_vibration_chart_card.json
  69. 36
      application/src/main/data/json/system/widget_types/simple_pump_vibration_chart_card_with_background.json
  70. 3
      application/src/main/data/json/system/widget_types/speed_gauge.json
  71. 3
      application/src/main/data/json/system/widget_types/temperature_radial_gauge.json
  72. 2
      application/src/main/data/json/system/widget_types/thermometer_scale.json
  73. 2
      application/src/main/data/json/system/widget_types/update_location_timeseries.json
  74. 2
      application/src/main/data/json/system/widget_types/update_server_location_attribute.json
  75. 2
      application/src/main/data/json/system/widget_types/update_shared_location_attribute.json
  76. 2
      application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java
  77. 26
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js
  78. 4
      ui-ngx/src/app/core/api/alarm-data.service.ts
  79. 2
      ui-ngx/src/app/core/http/widget.service.ts
  80. 2
      ui-ngx/src/app/modules/home/components/alarm/alarm-comment.component.html
  81. 8
      ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts
  82. 11
      ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts
  83. 18
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts
  84. 11
      ui-ngx/src/app/modules/home/components/dashboard-page/states/manage-dashboard-states-dialog.component.html
  85. 83
      ui-ngx/src/app/modules/home/components/dashboard-page/states/manage-dashboard-states-dialog.component.ts
  86. 36
      ui-ngx/src/app/modules/home/components/entity/entities-table.component.html
  87. 5
      ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts
  88. 54
      ui-ngx/src/app/modules/home/components/entity/entity-filter.component.ts
  89. 2
      ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.html
  90. 2
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-duration-predicate-value.component.html
  91. 5
      ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.html
  92. 18
      ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.ts
  93. 5
      ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html
  94. 18
      ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.ts
  95. 2
      ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html
  96. 6
      ui-ngx/src/app/modules/home/components/rule-chain/rule-chain-autocomplete.component.html
  97. 8
      ui-ngx/src/app/modules/home/components/rule-chain/rule-chain-autocomplete.component.ts
  98. 2
      ui-ngx/src/app/modules/home/components/vc/version-control.scss
  99. 1
      ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.ts
  100. 2
      ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.html

10
application/src/main/data/json/system/widget_bundles/air_quality.json

@ -66,6 +66,14 @@
"volatile_organic_compounds_chart_card",
"volatile_organic_compounds_chart_card_with_background",
"simple_volatile_organic_compounds_chart_card",
"simple_volatile_organic_compounds_chart_card_with_background"
"simple_volatile_organic_compounds_chart_card_with_background",
"individual_allergy_index_card",
"individual_allergy_index_card_with_background",
"horizontal_individual_allergy_index_iai_card",
"horizontal_individual_allergy_index_iai_card_with_background",
"individual_allergy_index_iai_chart_card",
"individual_allergy_index_iai_chart_card_with_background",
"simple_individual_allergy_index_iai_chart_card",
"simple_individual_allergy_index_iai_chart_card_with_background2"
]
}

72
application/src/main/data/json/system/widget_bundles/industial_widgets.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/flow_rate_card.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/flow_rate_card_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/flow_rate_chart_card.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/flow_rate_chart_card_with_background.json

File diff suppressed because one or more lines are too long

33
application/src/main/data/json/system/widget_types/flow_rate_gauge.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/flow_rate_progress_bar.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/flow_rate_progress_bar_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/flow_rate_range_chart.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/flow_rate_range_chart_with_background.json

File diff suppressed because one or more lines are too long

34
application/src/main/data/json/system/widget_types/fluid_pressure_card.json

File diff suppressed because one or more lines are too long

34
application/src/main/data/json/system/widget_types/fluid_pressure_card_with_background.json

File diff suppressed because one or more lines are too long

37
application/src/main/data/json/system/widget_types/fluid_pressure_chart_card.json

File diff suppressed because one or more lines are too long

37
application/src/main/data/json/system/widget_types/fluid_pressure_chart_card_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/fluid_pressure_gauge.json

File diff suppressed because one or more lines are too long

34
application/src/main/data/json/system/widget_types/fluid_pressure_progress_bar.json

File diff suppressed because one or more lines are too long

34
application/src/main/data/json/system/widget_types/fluid_pressure_progress_bar_with_background.json

File diff suppressed because one or more lines are too long

37
application/src/main/data/json/system/widget_types/fluid_pressure_range_chart.json

File diff suppressed because one or more lines are too long

37
application/src/main/data/json/system/widget_types/fluid_pressure_range_chart_with_background.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/fluid_temperature_card.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/fluid_temperature_card_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/fluid_temperature_chart_card.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/fluid_temperature_chart_card_with_background.json

File diff suppressed because one or more lines are too long

33
application/src/main/data/json/system/widget_types/fluid_temperature_gauge.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/fluid_temperature_progress_bar.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/fluid_temperature_progress_bar_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/fluid_temperature_range_chart.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/fluid_temperature_range_chart_with_background.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/horizontal_flow_rate_card.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/horizontal_flow_rate_card_with_background.json

File diff suppressed because one or more lines are too long

34
application/src/main/data/json/system/widget_types/horizontal_fluid_pressure_card.json

File diff suppressed because one or more lines are too long

34
application/src/main/data/json/system/widget_types/horizontal_fluid_pressure_card_with_background.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/horizontal_fluid_temperature_card.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/horizontal_fluid_temperature_card_with_background.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/horizontal_individual_allergy_index__iai__card.json

@ -0,0 +1,32 @@
{
"fqn": "horizontal_individual_allergy_index_iai_card",
"name": "Horizontal individual allergy index (IAI) card",
"deprecated": false,
"image": "data:image/png;base64,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",
"description": "Indicates the concentration of airborne allergens, including pollen and mold spores, which can trigger allergic reactions in sensitive individuals.",
"descriptor": {
"type": "latest",
"sizeX": 5,
"sizeY": 1,
"resources": [],
"templateHtml": "<tb-value-card-widget \n [ctx]=\"ctx\"\n [widgetTitlePanel]=\"widgetTitlePanel\">\n</tb-value-card-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'IAI_level', label: 'IAI', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n",
"settingsSchema": "",
"dataKeySettingsSchema": "",
"settingsDirective": "tb-value-card-widget-settings",
"hasBasicMode": true,
"basicModeDirective": "tb-value-card-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"IAI\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 10 - 5;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 12) {\\n\\tvalue = 12;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:flower-pollen\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":2,\"color\":\"#3FA71A\"},{\"from\":2,\"to\":6,\"color\":\"#80C32C\"},{\"from\":6,\"to\":9,\"color\":\"#F36900\"},{\"from\":9,\"to\":null,\"color\":\"#D81838\"}],\"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\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":2,\"color\":\"#3FA71A\"},{\"from\":2,\"to\":6,\"color\":\"#80C32C\"},{\"from\":6,\"to\":9,\"color\":\"#F36900\"},{\"from\":9,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"IAI\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":null,\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}"
},
"externalId": null,
"tags": [
"weather",
"environment",
"air",
"aqi",
"pollution",
"emission",
"smog"
]
}

32
application/src/main/data/json/system/widget_types/horizontal_individual_allergy_index__iai__card_with_background.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/horizontal_power_consumption_card.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/horizontal_power_consumption_card_with_background.json

File diff suppressed because one or more lines are too long

33
application/src/main/data/json/system/widget_types/horizontal_pump_vibration_card.json

File diff suppressed because one or more lines are too long

33
application/src/main/data/json/system/widget_types/horizontal_pump_vibration_card_with_background.json

File diff suppressed because one or more lines are too long

24
application/src/main/data/json/system/widget_types/individual_allergy_index__iai__card.json

@ -0,0 +1,24 @@
{
"fqn": "individual_allergy_index_card",
"name": "Individual allergy index (IAI) card",
"deprecated": false,
"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAYAAABJ/yOpAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAxTSURBVHgB7d1fbFRVAsfxM0Asyp+OkJTaGgpEpPiPkqBtNjHrSgzrU4lCdpNdw+KL6Avsg/HFh90sL6wPBh80vFjJ+mKIiX1SNBiNm1j+GKpd/i2EloZiMVnotCUUAu3e34FTZqb3HmmZe6Z/vp9kmPb+naHnN+ece+69kzGRzs7OZZlMpiX6sSF6ZA0ws302MjLy1+XLl3dlbofjaGVlZXbhwoVm1qxZBpiphoeHzeDgoLl8+XJfFJK1c6JwvPvggw/acAAznSoIZSEKSjaXy7Woutg4f/58A+CO2xVGg21P0awCCt3ORJZkAB4EBPAgIIAHAQE8CAjgQUAADwICeBAQwIOAAB4EBPAgIIAHAQE8CAjgQUAADwICeBAQwIOAAB4EBPAgIIBHWQLSe+WU+eTEdnPyf1/Hzm//pdXO771y0gDlVJaAfNv9vg3H/s5dsfMP9nxs53/T/YEphePHj5tPP/3U9Pf3j5mn6W1tbYnrYGYLEpChGwMFvzfW/NksmVdvn+OsWdJs5zdUNRdM7xu6YCbiq6++Mm+++eaYgCgEmr5t27bEdTCzpR6Q1v++bXa1/ca0Xfh4dNqyyqfNtrX7TFPNK7HrNEXB0fz6xc+PTlOza/eRDWZvx6umVD766CN7/yMFJ64WAVIPSFf/YfucG+pJXEbNqT1HN9kQJOkdvNUf6bs2sVokjkLx8ssvm6amJvPee+8ZoNgck7ItT7SYk5e+HtNcyqfaRR139T2Slntu6RsmO7fW1j6loP7F+fPnzdatW82XX35pdu7caWsSbsGKfKnXINm5NbbJNHfOAvu7+iPFfQnNr4sKfmNtYZ9ER7Fc/0Xra7nqeatMKSggjz32mHn44YfNpk2bRqcB+VKvQYrtad9kA7JhxVu2wIv6Gvn9DVFzS/0XBWz7uv2mlFRzqHmlgLiOuGoOdcxVowBO8IAM3Ri8/XyrZlDTav/ZXVHfosdkK2rNb5e+bptRd458ZUypHTx40D6vXr16dJrCotDooT4JIMED8lrDvqjjfijqa2y0Ncnejq2jYdDvXR2HzZYnP7S1S7aixvY7Sm337t02BO+8887oNPU/GhoabC1CQOAEHyhUk0nhEA0YFo+RiDskrGZXKfocCxYssH0N0diHvPTSSwXLqIn1wgsvjNYu+etg5sp0dXWN1NXVmRB0OPdgVPi7codHm1Fxp5Oo1lDtoXl6bqx9xXsUDEjDuXPnwgVE4dD5VRP1h9W7x3TkgTQpIMGaWPkj6RNx8B7XByYiWCc9dy1+JH1VVCs8Fx25qp5Xbzvp30T9kh9jRtT7rvUYILRgNciqRWObR+qA/zFqOikcog78xkd32kHDYnULSzOCDoxHsIDoxMTiQ7bqfMcvWziirvV0qgkQWrCAqHaoX/S7gmlzZy+IXdadluJoPa0PhBYsIDp1pLijfjEaRY9TfMau1mujk44yCBeQi2M73m0X/jVmHEQddQ0gFvvxYvKp8EBaynoUSwOFe45utoOAlVETqm/oZ3Pq0oHY0fWhm/1mOhgcHDTXr183ixYtMiH09vaa6upqg4kJVoOs8YyEq/n1bfcH0eHdz2LDIfdyFOvzzz+3gz4TdebMGVMqp0+fNseOHUucf+nSJVuo75aW/e677xLfn947Jq6sR7GSzJ1TeNHSvR7Fcp/axTStuDC6aW55rasCqOfi5dwy+T+7fSVtt5gCoYdbxgUof9uaX7x/6e7uNkePHi14vfnbjVsnbr+Olte0/PdzN9uazoI1sXRkavu6L+wpJ+p36FwsjY7H3fpH4yM67V3nbN06+rV+zJGte6WC2N7ebps6CkBzc7MtFPrEVZNEhW79+vV2OVFBfPbZZ0fXVyFWodG0/J/37dtnli5dOhqUzZs32wJ24MABuy/97Jo87tNdyz7yyCNm5cqVo4Vdz1pey7j1tP385pL2o0dxLdHa2mruu+++xPeu5TVf29Rp/o8//rh9fzqR0733Z555xr4ety33GteuXWtmkuBn89bbkfM3bECWJJypq9F1zddyOvO31OGQxYsXmxdffNH+wd2ntJopKgwqMC4MjY2N9jk/HL9G23SBU2FT4VPhUuD0LJqn5bRd7U/NuPnz59sCr0KqZwVP4dBrUEH2Nc0c7U+FWe9N+yvm9qttar/u7GbtX8vr4fpH7v9D29L70QdKXE08nQW/HiSfAqA+R/55VhpFb0q4HVAp6Y+vJooKoqMCU1FRYU95d4VsItyntwqaa66o8Bcvo/34OutaT69DAROFejz7j6tFNE01ZnHHXfspfo3507SeHnpNvtppuin7rUd/v+Ite4FU86P/sM9/iR5pcIXNNX0UDn2SKhSOmlMDAwM2GCq4rnnl1s/nmh0S1z9x7XltRw/X/3DLuna9PskfeuihMeuL1tN+tIxea36Yk7hQuvdazPUxVHPlh1OBcX0ft38FUv9P7r3otRSHaLqbvWPHjr9ls1lTTuqE63ysNK4eFP2Re3p6bDNCD71f/fF/+uknO+/++++3v1dVVdkmh5a5efOmLZQuCD/88ENBmLSNU6dOmY6ODrvMAw88YGpra20z5OrVq3b6U089Zadpu1pW89yyamppuUOHDplMJmML5YoVK+w87V9XOGr/KphaRq9TlyXotRZT+PT6KysrzezZs83w8LCtnVwo81+31td+v//+e/se9aivr7fru/eu16LAaH/almowTVeoZlJAcrlc2AumZoKWlhbbMZ9qBUlNTl1FKTqgoFrrbmqs6Uz/J2Xtg0xH+uSdim101SDqm4hqnJkeDocaBEgQ9IpCYCoiIIAHAQE8CAjgQUAADwICeBAQwIOAAB4EBPAgIIAHAQE8CAjgQUAADwICeBAQwIOAAB4EBPAgIIAHAQE8CAjgQUAADwICeBAQwIMbxwWkG3UnfUHQROiu92nc+R53EJCA9J2M+iatUtF3qPD12OmiiRWQvqAUUwsBCaj4660x+RGQgK6VsP+BMAhIQNQgUw+d9ICGboz9rnd93dyGFW8ZTE7UIIH0XjkVO72Cw7STGgEJJK72EH3NNSYvAhJI37We2OnZinS+lxGlQUACSRoDYSR8ciMggSSdYqJv98XkRUACycUc4qX2mPw4zBvI1ZgaJL//oRpG/ZTeKycL5quGIUjlQ0ACycV00lXwu3KH7QmMCkZSM2xZ5dNmzZJm01DVbBAWXwMdyN///eSYaQrIeE5/1yHhLU+0cGg4EL4GOpCkI1jjvTZE29l9ZINp/6XVIAwCEkDSGMhE7T+7q6CvgvTQBwng12qKuqiPsaxyXdTkWmhH3FVTnOs/Ej33JG7vkxPbzfZ1+w3SRUACyM6tNasWP2/O5Y4UnHKiYGxcuTOxT6Gm1P6z/4w9TUUh0nw67umikx6YTlpU80i1w91cLqvl93a8GhsSHd3a8uSHBulQJ50aJLDqeavsYzzLN9b8KfZadh0iVnDUNEM66KRPAU01rySG4OSlrw3SQ0CmAI2XLEmodbgRRLoIyBRRTUDKgoBMEZyPVR4EBPDgKFbKkm43Ot7bhg5xy6CyICApS7rd6HjvZpJ00wdOXEwXTayUJRXgpAIfR7XHuWjMI44GC5EeApKy+kXrY6drkK8rodAX8529O55BR4wfAUmZ+hl1CZ/yraffTrwdkKPDuN92vx87b01VM6PoKSMgATy39PXY6Sr8e9o3J45lqIbZ+5+tiR10vvogfXTSA1A/QbVIXD/CXQSlppKW050W+4Z+NhevnPD2U1R70EFPH2fzBqJa4FZtce8XT+n0+dca9jF4mDIuuQ1IhXnLEx/awn0vdJcTbYdwhEFAAlKTaPu6L+xXp02Exk50/QdNq3BoYpWJ+h5d/YdNW8/HUX8j+fpyhUH9jYaqjQQjMDWxCMgkoP6JuwmDu8FD9bzVJltRQ1OqjLiicJJQCO6MiDMyPpnQBwE8CAjgQUAADwICeBAQwIOAAB4EBPAgIIAHAQE8CAjgQUAADwICeBAQwIOAAB4EBPAgIIAHAQE8CAjgQUAADwICeBAQwIOAAB4EBPAgIIAHAQE8CAjgQUAADwICeBAQwIOAAB4EBPAgIIAHAQE8CAjgQUAADwICeBAQwIOAAB4KSN/w8LABcIfLhALSPjAwYADcMTg4aEZGRlpnRf9s7Yv09/cbahLMdMpALpczly9f7ot+3ZHRxM7OzmWZTObd6MeNBpjZFIx2VRzLly/v+j8lGJwYwkWU7gAAAABJRU5ErkJggg==",
"description": "Indicates the concentration of airborne allergens, including pollen and mold spores, which can trigger allergic reactions in sensitive individuals.",
"descriptor": {
"type": "latest",
"sizeX": 3,
"sizeY": 3,
"resources": [],
"templateHtml": "<tb-value-card-widget \n [ctx]=\"ctx\"\n [widgetTitlePanel]=\"widgetTitlePanel\">\n</tb-value-card-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'IAI_level', label: 'IAI', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n",
"settingsSchema": "",
"dataKeySettingsSchema": "",
"settingsDirective": "tb-value-card-widget-settings",
"hasBasicMode": true,
"basicModeDirective": "tb-value-card-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"IAI\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 10 - 5;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 12) {\\n\\tvalue = 12;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:flower-pollen\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":2,\"color\":\"#3FA71A\"},{\"from\":2,\"to\":6,\"color\":\"#80C32C\"},{\"from\":6,\"to\":9,\"color\":\"#F36900\"},{\"from\":9,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":2,\"color\":\"#3FA71A\"},{\"from\":2,\"to\":6,\"color\":\"#80C32C\"},{\"from\":6,\"to\":9,\"color\":\"#F36900\"},{\"from\":9,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Individual allergy index card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":null,\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}"
},
"externalId": null,
"tags": null
}

24
application/src/main/data/json/system/widget_types/individual_allergy_index__iai__card_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/individual_allergy_index__iai__chart_card.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/individual_allergy_index__iai__chart_card_with_background.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/power_consumption_card.json

File diff suppressed because one or more lines are too long

32
application/src/main/data/json/system/widget_types/power_consumption_card_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/power_consumption_chart_card.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/power_consumption_chart_card_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/power_consumption_range_chart.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/power_consumption_range_chart_with_background.json

File diff suppressed because one or more lines are too long

33
application/src/main/data/json/system/widget_types/pump_vibration_card.json

File diff suppressed because one or more lines are too long

33
application/src/main/data/json/system/widget_types/pump_vibration_card_with_background.json

File diff suppressed because one or more lines are too long

36
application/src/main/data/json/system/widget_types/pump_vibration_chart_card.json

File diff suppressed because one or more lines are too long

36
application/src/main/data/json/system/widget_types/pump_vibration_chart_card_with_background.json

File diff suppressed because one or more lines are too long

36
application/src/main/data/json/system/widget_types/pump_vibration_range_chart.json

File diff suppressed because one or more lines are too long

36
application/src/main/data/json/system/widget_types/pump_vibration_range_chart_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/simple_flow_rate_chart_card.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/simple_flow_rate_chart_card_with_background.json

File diff suppressed because one or more lines are too long

37
application/src/main/data/json/system/widget_types/simple_fluid_pressure_chart_card.json

File diff suppressed because one or more lines are too long

37
application/src/main/data/json/system/widget_types/simple_fluid_pressure_chart_card_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/simple_fluid_temperature_chart_card.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/simple_fluid_temperature_chart_card_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/simple_individual_allergy_index__iai__chart_card.json

@ -0,0 +1,35 @@
{
"fqn": "simple_individual_allergy_index_iai_chart_card",
"name": "Simple individual allergy index (IAI) chart card",
"deprecated": false,
"image": "data:image/png;base64,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",
"description": "Displays the concentration of airborne allergens, including pollen and mold spores, which can trigger allergic reactions in sensitive individuals as a simplified chart. Optionally may display the corresponding latest concentration of allergens value.",
"descriptor": {
"type": "timeseries",
"sizeX": 4.5,
"sizeY": 2,
"resources": [],
"templateHtml": "<tb-value-chart-card-widget \n [ctx]=\"ctx\"\n [widgetTitlePanel]=\"widgetTitlePanel\">\n</tb-value-chart-card-widget>\n",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'IAI_level', label: 'IAI', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'IAI_level', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}",
"latestDataKeySettingsSchema": "{}",
"settingsDirective": "tb-value-chart-card-widget-settings",
"dataKeySettingsDirective": "",
"latestDataKeySettingsDirective": "",
"hasBasicMode": true,
"basicModeDirective": "tb-value-chart-card-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Air Quality Index\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 10 - 5;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 12) {\\n\\tvalue = 12;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 10 - 5;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 12) {\\n\\tvalue = 12;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":2,\"color\":\"#3FA71A\"},{\"from\":2,\"to\":6,\"color\":\"#80C32C\"},{\"from\":6,\"to\":9,\"color\":\"#F36900\"},{\"from\":9,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"IAI\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:flower-pollen\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":0,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":null,\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}"
},
"externalId": null,
"tags": [
"weather",
"environment",
"air",
"aqi",
"pollution",
"emission",
"smog"
]
}

35
application/src/main/data/json/system/widget_types/simple_individual_allergy_index__iai__chart_card_with_background.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/simple_power_consumption_chart_card.json

File diff suppressed because one or more lines are too long

35
application/src/main/data/json/system/widget_types/simple_power_consumption_chart_card_with_background.json

File diff suppressed because one or more lines are too long

36
application/src/main/data/json/system/widget_types/simple_pump_vibration_chart_card.json

File diff suppressed because one or more lines are too long

36
application/src/main/data/json/system/widget_types/simple_pump_vibration_chart_card_with_background.json

File diff suppressed because one or more lines are too long

3
application/src/main/data/json/system/widget_types/speed_gauge.json

@ -16,6 +16,7 @@
"settingsDirective": "tb-analogue-radial-gauge-widget-settings",
"hasBasicMode": true,
"basicModeDirective": "tb-radial-gauge-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 50 - 25;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 220) {\\n\\tvalue = 220;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":180,\"startAngle\":45,\"ticksAngle\":270,\"showBorder\":false,\"defaultColor\":\"#e65100\",\"needleCircleSize\":7,\"highlights\":[{\"from\":80,\"to\":120,\"color\":\"#fdd835\"},{\"color\":\"#e57373\",\"from\":120,\"to\":180}],\"showUnitTitle\":false,\"colorPlate\":\"#fff\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"minorTicks\":2,\"valueInt\":3,\"minValue\":0,\"valueDec\":0,\"highlightsWidth\":15,\"valueBox\":true,\"animation\":true,\"animationDuration\":1500,\"animationRule\":\"linear\",\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"colorNeedleShadowDown\":\"rgba(188, 143, 143, 0.78)\",\"units\":\"MPH\",\"majorTicksCount\":9,\"numbersFont\":{\"family\":\"Roboto\",\"size\":22,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#888\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":28,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"valueFont\":{\"size\":32,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\",\"family\":\"Segment7Standard\"},\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\"},\"title\":\"Speed gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\"}" },
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 50 - 25;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 220) {\\n\\tvalue = 220;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"startAngle\":45,\"ticksAngle\":270,\"needleCircleSize\":7,\"defaultColor\":\"#e65100\",\"minValue\":0,\"maxValue\":180,\"majorTicksCount\":9,\"colorMajorTicks\":\"#444\",\"minorTicks\":9,\"colorMinorTicks\":\"#666\",\"numbersFont\":{\"family\":\"Roboto\",\"size\":22,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"numbersColor\":\"#616161\",\"showUnitTitle\":false,\"unitTitle\":null,\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#888\"},\"titleColor\":\"#888\",\"unitsFont\":{\"family\":\"Roboto\",\"size\":28,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"unitsColor\":\"#616161\",\"valueBox\":true,\"valueInt\":3,\"valueFont\":{\"size\":32,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\",\"family\":\"Segment7Standard\"},\"valueColor\":\"#444\",\"valueColorShadow\":\"rgba(0, 0, 0, 0.49)\",\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\",\"showBorder\":false,\"colorPlate\":\"#fff\",\"colorNeedle\":null,\"colorNeedleEnd\":null,\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"colorNeedleShadowDown\":\"rgba(188, 143, 143, 0.78)\",\"highlightsWidth\":15,\"highlights\":[{\"from\":80,\"to\":120,\"color\":\"#fdd835\"},{\"color\":\"#e57373\",\"from\":120,\"to\":180}],\"animation\":true,\"animationDuration\":1500,\"animationRule\":\"linear\"},\"title\":\"Speed gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\",\"units\":\"mph\"}"
},
"externalId": null
}

3
application/src/main/data/json/system/widget_types/temperature_radial_gauge.json

@ -16,6 +16,7 @@
"settingsDirective": "tb-analogue-radial-gauge-widget-settings",
"hasBasicMode": true,
"basicModeDirective": "tb-radial-gauge-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":60,\"startAngle\":67.5,\"ticksAngle\":225,\"showBorder\":true,\"defaultColor\":\"#e65100\",\"needleCircleSize\":7,\"highlights\":[{\"from\":-60,\"to\":-50,\"color\":\"#42a5f5\"},{\"from\":-50,\"to\":-40,\"color\":\"rgba(66, 165, 245, 0.83)\"},{\"from\":-40,\"to\":-30,\"color\":\"rgba(66, 165, 245, 0.66)\"},{\"from\":-30,\"to\":-20,\"color\":\"rgba(66, 165, 245, 0.5)\"},{\"from\":-20,\"to\":-10,\"color\":\"rgba(66, 165, 245, 0.33)\"},{\"from\":-10,\"to\":0,\"color\":\"rgba(66, 165, 245, 0.16)\"},{\"from\":0,\"to\":10,\"color\":\"rgba(229, 115, 115, 0.16)\"},{\"from\":10,\"to\":20,\"color\":\"rgba(229, 115, 115, 0.33)\"},{\"from\":20,\"to\":30,\"color\":\"rgba(229, 115, 115, 0.5)\"},{\"from\":30,\"to\":40,\"color\":\"rgba(229, 115, 115, 0.66)\"},{\"from\":40,\"to\":50,\"color\":\"rgba(229, 115, 115, 0.83)\"},{\"from\":50,\"to\":60,\"color\":\"#e57373\"}],\"showUnitTitle\":true,\"colorPlate\":\"#cfd8dc\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"minorTicks\":2,\"valueInt\":3,\"valueDec\":1,\"highlightsWidth\":15,\"valueBox\":true,\"animation\":true,\"animationDuration\":1000,\"animationRule\":\"bounce\",\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"colorNeedleShadowDown\":\"rgba(188, 143, 143, 0.78)\",\"units\":\"°C\",\"majorTicksCount\":12,\"numbersFont\":{\"family\":\"Roboto\",\"size\":20,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":28,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"valueFont\":{\"family\":\"Segment7Standard\",\"size\":30,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\"},\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\",\"unitTitle\":\"Temperature\",\"minValue\":-60},\"title\":\"Temperature radial gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\"}" },
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"startAngle\":67.5,\"ticksAngle\":225,\"needleCircleSize\":7,\"defaultColor\":\"#e65100\",\"minValue\":-60,\"maxValue\":60,\"majorTicksCount\":12,\"colorMajorTicks\":\"#444\",\"minorTicks\":12,\"colorMinorTicks\":\"#666\",\"numbersFont\":{\"family\":\"Roboto\",\"size\":20,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"numbersColor\":\"#263238\",\"showUnitTitle\":true,\"unitTitle\":\"Temperature\",\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"titleColor\":\"#263238\",\"unitsFont\":{\"family\":\"Roboto\",\"size\":28,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"unitsColor\":\"#616161\",\"valueBox\":true,\"valueInt\":3,\"valueFont\":{\"family\":\"Segment7Standard\",\"size\":30,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\"},\"valueColor\":\"#444\",\"valueColorShadow\":\"rgba(0, 0, 0, 0.49)\",\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\",\"showBorder\":true,\"colorPlate\":\"#cfd8dc\",\"colorNeedle\":null,\"colorNeedleEnd\":null,\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"colorNeedleShadowDown\":\"rgba(188, 143, 143, 0.78)\",\"highlightsWidth\":15,\"highlights\":[{\"from\":-60,\"to\":-50,\"color\":\"#42a5f5\"},{\"from\":-50,\"to\":-40,\"color\":\"rgba(66, 165, 245, 0.83)\"},{\"from\":-40,\"to\":-30,\"color\":\"rgba(66, 165, 245, 0.66)\"},{\"from\":-30,\"to\":-20,\"color\":\"rgba(66, 165, 245, 0.5)\"},{\"from\":-20,\"to\":-10,\"color\":\"rgba(66, 165, 245, 0.33)\"},{\"from\":-10,\"to\":0,\"color\":\"rgba(66, 165, 245, 0.16)\"},{\"from\":0,\"to\":10,\"color\":\"rgba(229, 115, 115, 0.16)\"},{\"from\":10,\"to\":20,\"color\":\"rgba(229, 115, 115, 0.33)\"},{\"from\":20,\"to\":30,\"color\":\"rgba(229, 115, 115, 0.5)\"},{\"from\":30,\"to\":40,\"color\":\"rgba(229, 115, 115, 0.66)\"},{\"from\":40,\"to\":50,\"color\":\"rgba(229, 115, 115, 0.83)\"},{\"from\":50,\"to\":60,\"color\":\"#e57373\"}],\"animation\":true,\"animationDuration\":1000,\"animationRule\":\"bounce\"},\"title\":\"Temperature radial gauge\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\",\"units\":\"°C\"}"
},
"externalId": null
}

2
application/src/main/data/json/system/widget_types/thermometer_scale.json

@ -17,7 +17,7 @@
"settingsDirective": "tb-analogue-linear-gauge-widget-settings",
"hasBasicMode": true,
"basicModeDirective": "tb-thermometer-scale-gauge-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temp\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 30 - 15;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":100,\"defaultColor\":\"#e64a19\",\"barStrokeWidth\":2.5,\"colorBar\":\"rgba(255, 255, 255, 0.4)\",\"colorBarEnd\":\"rgba(221, 221, 221, 0.38)\",\"showUnitTitle\":true,\"minorTicks\":2,\"valueBox\":true,\"valueInt\":3,\"colorPlate\":\"#fff\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"colorNeedleShadowUp\":\"rgba(2,255,255,0.2)\",\"colorNeedleShadowDown\":\"rgba(188,143,143,0.45)\",\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\",\"highlightsWidth\":10,\"animation\":true,\"animationDuration\":1500,\"animationRule\":\"linear\",\"showBorder\":false,\"majorTicksCount\":8,\"numbersFont\":{\"family\":\"Arial\",\"size\":18,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#78909c\"},\"unitsFont\":{\"family\":\"Roboto\",\"size\":26,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#37474f\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":40,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#444\",\"shadowColor\":\"rgba(0,0,0,0.3)\"},\"minValue\":-60,\"highlights\":[{\"from\":-60,\"to\":-40,\"color\":\"#90caf9\"},{\"from\":-40,\"to\":-20,\"color\":\"rgba(144, 202, 249, 0.66)\"},{\"from\":-20,\"to\":0,\"color\":\"rgba(144, 202, 249, 0.33)\"},{\"from\":0,\"to\":20,\"color\":\"rgba(244, 67, 54, 0.2)\"},{\"from\":20,\"to\":40,\"color\":\"rgba(244, 67, 54, 0.4)\"},{\"from\":40,\"to\":60,\"color\":\"rgba(244, 67, 54, 0.6)\"},{\"from\":60,\"to\":80,\"color\":\"rgba(244, 67, 54, 0.8)\"},{\"from\":80,\"to\":100,\"color\":\"#f44336\"}],\"unitTitle\":\"Temperature\",\"units\":\"°C\",\"colorBarProgress\":\"#90caf9\",\"colorBarProgressEnd\":\"#f44336\",\"colorBarStroke\":\"#b0bec5\",\"valueDec\":1},\"title\":\"Thermometer scale\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\"}"
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temp\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 30 - 15;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"startAngle\":45,\"ticksAngle\":270,\"needleCircleSize\":10,\"defaultColor\":\"#e64a19\",\"minValue\":-60,\"maxValue\":100,\"majorTicksCount\":8,\"colorMajorTicks\":\"#444\",\"minorTicks\":8,\"colorMinorTicks\":\"#666\",\"numbersFont\":{\"family\":\"Arial\",\"size\":18,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#263238\"},\"numbersColor\":\"#263238\",\"showUnitTitle\":true,\"unitTitle\":\"Temperature\",\"titleFont\":{\"family\":\"Roboto\",\"size\":24,\"style\":\"normal\",\"weight\":\"normal\",\"color\":\"#78909c\"},\"titleColor\":\"#78909c\",\"unitsFont\":{\"family\":\"Roboto\",\"size\":26,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#37474f\"},\"unitsColor\":\"#37474f\",\"valueBox\":true,\"valueInt\":3,\"valueFont\":{\"family\":\"Roboto\",\"size\":40,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#444\",\"shadowColor\":\"rgba(0,0,0,0.3)\"},\"valueColor\":\"#444\",\"valueColorShadow\":\"rgba(0,0,0,0.3)\",\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\",\"showBorder\":false,\"colorPlate\":\"#fff\",\"colorNeedle\":null,\"colorNeedleEnd\":null,\"colorNeedleShadowUp\":\"rgba(2,255,255,0.2)\",\"colorNeedleShadowDown\":\"rgba(188,143,143,0.45)\",\"highlightsWidth\":10,\"highlights\":[{\"from\":-60,\"to\":-40,\"color\":\"#90caf9\"},{\"from\":-40,\"to\":-20,\"color\":\"rgba(144, 202, 249, 0.66)\"},{\"from\":-20,\"to\":0,\"color\":\"rgba(144, 202, 249, 0.33)\"},{\"from\":0,\"to\":20,\"color\":\"rgba(244, 67, 54, 0.2)\"},{\"from\":20,\"to\":40,\"color\":\"rgba(244, 67, 54, 0.4)\"},{\"from\":40,\"to\":60,\"color\":\"rgba(244, 67, 54, 0.6)\"},{\"from\":60,\"to\":80,\"color\":\"rgba(244, 67, 54, 0.8)\"},{\"from\":80,\"to\":100,\"color\":\"#f44336\"}],\"animation\":true,\"animationDuration\":1500,\"animationRule\":\"linear\",\"barStrokeWidth\":2.5,\"colorBarStroke\":\"#b0bec5\",\"colorBar\":\"rgba(255, 255, 255, 0.4)\",\"colorBarEnd\":\"rgba(221, 221, 221, 0.38)\",\"colorBarProgress\":\"#90caf9\",\"colorBarProgressEnd\":\"#f44336\"},\"title\":\"Thermometer scale\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"decimals\":0,\"noDataDisplayMessage\":\"\",\"configMode\":\"basic\",\"units\":\"°C\"}"
},
"externalId": null,
"tags": [

2
application/src/main/data/json/system/widget_types/update_location_timeseries.json

@ -15,7 +15,7 @@
"settingsSchema": "",
"dataKeySettingsSchema": "{}\n",
"settingsDirective": "tb-update-location-attribute-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update location timeseries\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"widgetTitle\":\"\",\"showResultMessage\":true,\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showGetLocation\":true,\"enableHighAccuracy\":false,\"showLabel\":true,\"latLabel\":\"\",\"lngLabel\":\"\",\"inputFieldsAlignment\":\"column\",\"isLatRequired\":true,\"isLngRequired\":true,\"requiredErrorMessage\":\"\"},\"title\":\"Update location timeseries\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
},
"externalId": null
}

2
application/src/main/data/json/system/widget_types/update_server_location_attribute.json

@ -15,7 +15,7 @@
"settingsSchema": "",
"dataKeySettingsSchema": "{}\n",
"settingsDirective": "tb-update-location-attribute-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update server location attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"widgetTitle\":\"\",\"showResultMessage\":true,\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showGetLocation\":true,\"enableHighAccuracy\":false,\"showLabel\":true,\"latLabel\":\"\",\"lngLabel\":\"\",\"inputFieldsAlignment\":\"column\",\"isLatRequired\":true,\"isLngRequired\":true,\"requiredErrorMessage\":\"\"},\"title\":\"Update server location attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
},
"externalId": null
}

2
application/src/main/data/json/system/widget_types/update_shared_location_attribute.json

@ -15,7 +15,7 @@
"settingsSchema": "",
"dataKeySettingsSchema": "{}\n",
"settingsDirective": "tb-update-location-attribute-widget-settings",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Update shared location attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"widgetTitle\":\"\",\"showResultMessage\":true,\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showGetLocation\":true,\"enableHighAccuracy\":false,\"showLabel\":true,\"latLabel\":\"\",\"lngLabel\":\"\",\"inputFieldsAlignment\":\"column\",\"isLatRequired\":true,\"isLngRequired\":true,\"requiredErrorMessage\":\"\"},\"title\":\"Update shared location attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
},
"externalId": null
}

2
application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java

@ -193,7 +193,7 @@ public class SwaggerConfiguration {
.defaultModelExpandDepth(1)
.defaultModelRendering(ModelRendering.EXAMPLE)
.displayRequestDuration(false)
.docExpansion(DocExpansion.NONE)
.docExpansion(DocExpansion.LIST)
.filter(false)
.maxDisplayedTags(null)
.operationsSorter(OperationsSorter.ALPHA)

26
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

File diff suppressed because one or more lines are too long

4
ui-ngx/src/app/core/api/alarm-data.service.ts

@ -16,7 +16,7 @@
import { SubscriptionTimewindow } from '@shared/models/time/time.models';
import { Datasource, DatasourceType } from '@shared/models/widget.models';
import { PageData } from '@shared/models/page/page-data';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { AlarmData, AlarmDataPageLink, KeyFilter } from '@shared/models/query/query.models';
import { Injectable } from '@angular/core';
import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service';
@ -26,6 +26,7 @@ import {
AlarmSubscriptionDataKey
} from '@core/api/alarm-data-subscription';
import { deepClone } from '@core/utils';
import { of } from 'rxjs';
export interface AlarmDataListener {
subscriptionTimewindow?: SubscriptionTimewindow;
@ -50,6 +51,7 @@ export class AlarmDataService {
const alarmSource = listener.alarmSource;
listener.alarmDataSubscriptionOptions = this.createAlarmSubscriptionOptions(listener, pageLink, keyFilters);
if (alarmSource.type === DatasourceType.entity && (!alarmSource.entityFilter || !pageLink)) {
listener.alarmsLoaded(emptyPageData<AlarmData>(), 0, 0);
return;
}
listener.subscription = new AlarmDataSubscription(listener, this.telemetryService);

2
ui-ngx/src/app/core/http/widget.service.ts

@ -144,7 +144,7 @@ export class WidgetService {
public exportBundleWidgetTypesDetails(widgetsBundleId: string,
config?: RequestConfig): Observable<Array<WidgetTypeDetails>> {
return this.http.get<Array<WidgetTypeDetails>>(`/api/widgetTypesDetails?widgetsBundleId=${widgetsBundleId}?inlineImages=true`,
return this.http.get<Array<WidgetTypeDetails>>(`/api/widgetTypesDetails?widgetsBundleId=${widgetsBundleId}&inlineImages=true`,
defaultHttpOptionsFromConfig(config));
}

2
ui-ngx/src/app/modules/home/components/alarm/alarm-comment.component.html

@ -36,7 +36,7 @@
(click)="changeSortDirection()"
[matTooltip]="getSortDirectionTooltipText()"
matTooltipPosition="above">
<mat-icon class="material-icons" [svgIcon]="getSortDirectionIcon()"></mat-icon>
<tb-icon class="material-icons">{{ getSortDirectionIcon() }}</tb-icon>
</button>
<button mat-icon-button
type="button"

8
ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts

@ -17,6 +17,7 @@
import {
CellActionDescriptorType,
DateEntityTableColumn,
EntityLinkTableColumn,
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
@ -59,7 +60,7 @@ import {
AlarmAssigneePanelData
} from '@home/components/alarm/alarm-assignee-panel.component';
import { ComponentPortal } from '@angular/cdk/portal';
import { isDefinedAndNotNull } from '@core/utils';
import { getEntityDetailsPageURL, isDefinedAndNotNull } from '@core/utils';
import { UtilsService } from '@core/services/utils.service';
import { AlarmFilterConfig } from '@shared/models/query/query.models';
import { EntityService } from '@core/http/entity.service';
@ -113,8 +114,9 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
this.columns.push(
new DateEntityTableColumn<AlarmInfo>('createdTime', 'alarm.created-time', this.datePipe, '150px'));
this.columns.push(
new EntityTableColumn<AlarmInfo>('originatorName', 'alarm.originator', '25%',
(entity) => entity.originatorName, entity => ({}), false));
new EntityLinkTableColumn<AlarmInfo>('originatorName', 'alarm.originator', '25%',
(entity) => entity.originatorName,
(entity) => getEntityDetailsPageURL(entity.originator.id, entity.originator.entityType as EntityType)));
this.columns.push(
new EntityTableColumn<AlarmInfo>('type', 'alarm.type', '25%',
entity => this.utilsService.customTranslation(entity.type, entity.type)));

11
ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts

@ -20,11 +20,11 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import {
FormGroupDirective,
NgForm,
UntypedFormBuilder,
UntypedFormControl,
UntypedFormGroup,
FormGroupDirective,
NgForm,
ValidatorFn,
Validators
} from '@angular/forms';
@ -36,6 +36,7 @@ import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { EntityService } from '@core/http/entity.service';
import { Observable } from 'rxjs';
import { isEmpty, isEqual } from '@core/utils';
export interface EntityAliasDialogData {
isAdd: boolean;
@ -141,6 +142,12 @@ export class EntityAliasDialogComponent extends DialogComponent<EntityAliasDialo
this.alias.alias = this.entityAliasFormGroup.get('alias').value.trim();
this.alias.filter = this.entityAliasFormGroup.get('filter').value;
this.alias.filter.resolveMultiple = this.entityAliasFormGroup.get('resolveMultiple').value;
if (!isEmpty(this.alias.filter?.filters)) {
this.alias.filter.filters = this.alias.filter.filters.filter((value, index, self) =>
self.findIndex(v => v.relationType === value.relationType && isEqual(v.entityTypes, value.entityTypes)) === index &&
(value.relationType || value.entityTypes.length)
);
}
if (this.alias.filter.type) {
this.validate().subscribe(() => {
if (this.isAdd) {

18
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts

@ -55,7 +55,7 @@ import {
} from '@app/shared/models/dashboard.models';
import { WINDOW } from '@core/services/window.service';
import { WindowMessage } from '@shared/models/window-message.model';
import { deepClone, guid, isDefined, isDefinedAndNotNull, isNotEmptyStr } from '@app/core/utils';
import { deepClone, guid, isDefined, isDefinedAndNotNull, isEqual, isNotEmptyStr } from '@app/core/utils';
import {
DashboardContext,
DashboardPageInitData,
@ -868,15 +868,21 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
$event.stopPropagation();
}
this.dialog.open<ManageDashboardStatesDialogComponent, ManageDashboardStatesDialogData,
{[id: string]: DashboardState }>(ManageDashboardStatesDialogComponent, {
{states: {[id: string]: DashboardState}; widgets: {[id: string]: Widget}}>(ManageDashboardStatesDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
states: deepClone(this.dashboard.configuration.states)
states: deepClone(this.dashboard.configuration.states),
widgets: deepClone(this.dashboard.configuration.widgets) as {[id: string]: Widget}
}
}).afterClosed().subscribe((states) => {
if (states) {
this.updateStates(states);
}).afterClosed().subscribe((result) => {
if (result) {
if (!isEqual(result.widgets, this.dashboard.configuration.widgets)) {
this.dashboard.configuration.widgets = result.widgets;
}
if (result.states) {
this.updateStates(result.states);
}
}
});
}

11
ui-ngx/src/app/modules/home/components/dashboard-page/states/manage-dashboard-states-dialog.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<form [formGroup]="statesFormGroup" (ngSubmit)="save()" style="min-width: 480px;">
<form [formGroup]="statesFormGroup" (ngSubmit)="save()" style="width: 750px;">
<mat-toolbar color="primary">
<h2 translate>dashboard.manage-states</h2>
<span fxFlex></span>
@ -96,7 +96,7 @@
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<mat-header-cell *matHeaderCellDef style="min-width: 80px; max-width: 80px; width: 80px">
<mat-header-cell *matHeaderCellDef style="min-width: 120px; max-width: 120px; width: 120px">
</mat-header-cell>
<mat-cell *matCellDef="let state">
<div fxFlex fxLayout="row">
@ -107,6 +107,13 @@
(click)="editState($event, state)">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button [disabled]="isLoading$ | async"
type="button"
matTooltip="{{ 'dashboard.duplicate-state-action' | translate }}"
matTooltipPosition="above"
(click)="duplicateState($event, state)">
<mat-icon>content_copy</mat-icon>
</button>
<button [fxShow]="!state.root" mat-icon-button [disabled]="isLoading$ | async"
type="button"
matTooltip="{{ 'dashboard.delete-state' | translate }}"

83
ui-ngx/src/app/modules/home/components/dashboard-page/states/manage-dashboard-states-dialog.component.ts

@ -19,7 +19,7 @@ import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, FormGroupDirective, NgForm } from '@angular/forms';
import { FormGroupDirective, NgForm, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component';
import { DashboardState } from '@app/shared/models/dashboard.models';
@ -35,14 +35,17 @@ import { fromEvent, merge } from 'rxjs';
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
import { DialogService } from '@core/services/dialog.service';
import { deepClone, isUndefined } from '@core/utils';
import { deepClone, isDefined } from '@core/utils';
import {
DashboardStateDialogComponent,
DashboardStateDialogData
} from '@home/components/dashboard-page/states/dashboard-state-dialog.component';
import { UtilsService } from '@core/services/utils.service';
import { Widget } from '@shared/models/widget.models';
export interface ManageDashboardStatesDialogData {
states: {[id: string]: DashboardState };
widgets: {[id: string]: Widget };
}
@Component({
@ -51,13 +54,14 @@ export interface ManageDashboardStatesDialogData {
providers: [{provide: ErrorStateMatcher, useExisting: ManageDashboardStatesDialogComponent}],
styleUrls: ['./manage-dashboard-states-dialog.component.scss']
})
export class ManageDashboardStatesDialogComponent extends
DialogComponent<ManageDashboardStatesDialogComponent, {[id: string]: DashboardState }>
export class ManageDashboardStatesDialogComponent
extends DialogComponent<ManageDashboardStatesDialogComponent, {states: {[id: string]: DashboardState}; widgets: {[id: string]: Widget}}>
implements OnInit, ErrorStateMatcher, AfterViewInit {
statesFormGroup: UntypedFormGroup;
states: {[id: string]: DashboardState };
widgets: {[id: string]: Widget};
displayedColumns: string[];
pageLink: PageLink;
@ -66,6 +70,8 @@ export class ManageDashboardStatesDialogComponent extends
submitted = false;
stateNames: Set<string> = new Set<string>();
@ViewChild('searchInput') searchInputField: ElementRef;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ -75,15 +81,19 @@ export class ManageDashboardStatesDialogComponent extends
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: ManageDashboardStatesDialogData,
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
public dialogRef: MatDialogRef<ManageDashboardStatesDialogComponent, {[id: string]: DashboardState }>,
public dialogRef: MatDialogRef<ManageDashboardStatesDialogComponent,
{states: {[id: string]: DashboardState}; widgets: {[id: string]: Widget}}>,
private fb: UntypedFormBuilder,
private translate: TranslateService,
private dialogs: DialogService,
private utils: UtilsService,
private dialog: MatDialog) {
super(store, router, dialogRef);
this.states = this.data.states;
this.widgets = this.data.widgets;
this.statesFormGroup = this.fb.group({});
Object.values(this.states).forEach(value => this.stateNames.add(value.name));
const sortOrder: SortOrder = { property: 'name', direction: Direction.ASC };
this.pageLink = new PageLink(5, 0, null, sortOrder);
@ -142,6 +152,7 @@ export class ManageDashboardStatesDialogComponent extends
this.translate.instant('action.yes')).subscribe(
(res) => {
if (res) {
this.stateNames.delete(state.name);
delete this.states[state.id];
this.onStatesUpdated();
}
@ -171,8 +182,10 @@ export class ManageDashboardStatesDialogComponent extends
}
const isAdd = state === null;
let prevStateId = null;
let prevStateName = '';
if (!isAdd) {
prevStateId = state.id;
prevStateName = state.name;
}
this.dialog.open<DashboardStateDialogComponent, DashboardStateDialogData,
DashboardStateInfo>(DashboardStateDialogComponent, {
@ -186,13 +199,13 @@ export class ManageDashboardStatesDialogComponent extends
}).afterClosed().subscribe(
(res) => {
if (res) {
this.saveState(res, prevStateId);
this.saveState(res, prevStateId, prevStateName);
}
}
);
}
saveState(state: DashboardStateInfo, prevStateId: string) {
saveState(state: DashboardStateInfo, prevStateId: string, prevStateName: string) {
const newState: DashboardState = {
name: state.name,
root: state.root,
@ -204,6 +217,10 @@ export class ManageDashboardStatesDialogComponent extends
} else {
this.states[state.id] = newState;
}
if (prevStateName && prevStateName !== state.name) {
this.stateNames.delete(prevStateName);
this.stateNames.add(state.name);
}
if (state.root) {
for (const id of Object.keys(this.states)) {
const otherState = this.states[id];
@ -228,6 +245,56 @@ export class ManageDashboardStatesDialogComponent extends
this.onStatesUpdated();
}
duplicateState($event: Event, state: DashboardStateInfo) {
const originalState = state;
const newStateName = this.getNextDuplicatedName(state.name);
if (newStateName) {
const duplicatedStates = deepClone(originalState);
const duplicatedWidgets = deepClone(this.widgets);
const mainWidgets = {};
const rightWidgets = {};
duplicatedStates.id = newStateName.toLowerCase().replace(/\W/g, '_');
duplicatedStates.name = newStateName;
duplicatedStates.root = false;
this.stateNames.add(duplicatedStates.name);
for (const [key, value] of Object.entries(duplicatedStates.layouts.main.widgets)) {
const guid = this.utils.guid();
mainWidgets[guid] = value;
duplicatedWidgets[guid] = this.widgets[key];
duplicatedWidgets[guid].id = guid;
}
duplicatedStates.layouts.main.widgets = mainWidgets;
if (isDefined(duplicatedStates.layouts?.right)) {
for (const [key, value] of Object.entries(duplicatedStates.layouts.right.widgets)) {
const guid = this.utils.guid();
rightWidgets[guid] = value;
duplicatedWidgets[guid] = this.widgets[key];
duplicatedWidgets[guid].id = guid;
}
duplicatedStates.layouts.right.widgets = rightWidgets;
}
this.states[duplicatedStates.id] = duplicatedStates;
this.widgets = duplicatedWidgets;
this.onStatesUpdated();
}
}
private getNextDuplicatedName(stateName: string): string {
const suffix = ` - ${this.translate.instant('action.copy')} `;
let counter = 0;
while (++counter < Number.MAX_SAFE_INTEGER) {
const newName = `${stateName}${suffix}${counter}`;
if (!this.stateNames.has(newName)) {
return newName;
}
}
return null;
}
private onStatesUpdated() {
this.statesFormGroup.markAsDirty();
this.updateData(true);
@ -245,6 +312,6 @@ export class ManageDashboardStatesDialogComponent extends
save(): void {
this.submitted = true;
this.dialogRef.close(this.states);
this.dialogRef.close({ states: this.states, widgets: this.widgets });
}
}

36
ui-ngx/src/app/modules/home/components/entity/entities-table.component.html

@ -60,7 +60,7 @@
(click)="entitiesTableConfig.addActionDescriptors[0].onAction($event)"
matTooltip="{{ entitiesTableConfig.addActionDescriptors[0].name }}"
matTooltipPosition="above">
<mat-icon>{{entitiesTableConfig.addActionDescriptors[0].icon}}</mat-icon>
<tb-icon>{{entitiesTableConfig.addActionDescriptors[0].icon}}</tb-icon>
</button>
<ng-template #addActionsMenu>
<button mat-icon-button [disabled]="isLoading$ | async"
@ -74,7 +74,7 @@
[disabled]="isLoading$ | async"
[fxShow]="actionDescriptor.isEnabled()"
(click)="actionDescriptor.onAction($event)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
<tb-icon matMenuItemIcon>{{actionDescriptor.icon}}</tb-icon>
<span>{{ actionDescriptor.name }}</span>
</button>
</mat-menu>
@ -132,7 +132,7 @@
matTooltip="{{ actionDescriptor.name }}"
matTooltipPosition="above"
(click)="actionDescriptor.onAction($event, dataSource.selection.selected)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
<tb-icon>{{actionDescriptor.icon}}</tb-icon>
</button>
</div>
</mat-toolbar>
@ -165,7 +165,12 @@
[matTooltip]="cellTooltip(entity, column, row)"
matTooltipPosition="above"
[ngStyle]="cellStyle(entity, column, row)">
<span [innerHTML]="cellContent(entity, column, row)"></span>
<ng-container *ngIf="column.type == 'link'; else defaultContent">
<a [routerLink]="column.entityURL(entity)" [innerHTML]="cellContent(entity, column, row)" (click)="$event.stopPropagation();"></a>
</ng-container>
<ng-template #defaultContent>
<span [innerHTML]="cellContent(entity, column, row)"></span>
</ng-template>
<ng-template [ngIf]="column.actionCell">
<ng-container [ngSwitch]="column.actionCell.type">
<ng-template [ngSwitchCase]="cellActionType.COPY_BUTTON">
@ -176,7 +181,7 @@
tooltipText="{{ column.actionCell.nameFunction ? column.actionCell.nameFunction(entity) : column.actionCell.name }}"
tooltipPosition="above"
[icon]="column.actionCell.icon"
[mdiIcon]="column.actionCell.mdiIcon" [style]="column.actionCell.style">
[style]="column.actionCell.style">
</tb-copy-button>
</ng-template>
<ng-template ngSwitchDefault>
@ -185,9 +190,9 @@
matTooltip="{{ column.actionCell.nameFunction ? column.actionCell.nameFunction(entity) : column.actionCell.name }}"
matTooltipPosition="above"
(click)="column.actionCell.onAction($event, entity)">
<mat-icon [svgIcon]="column.actionCell.mdiIcon" [ngStyle]="column.actionCell.style">
<tb-icon [ngStyle]="column.actionCell.style">
{{column.actionCell.icon}}
</mat-icon>
</tb-icon>
</button>
</ng-template>
</ng-container>
@ -203,8 +208,9 @@
matTooltip="{{ column.actionDescriptor.nameFunction ? column.actionDescriptor.nameFunction(entity) : column.actionDescriptor.name }}"
matTooltipPosition="above"
(click)="column.actionDescriptor.onAction($event, entity)">
<mat-icon [svgIcon]="column.actionDescriptor.mdiIcon" [ngStyle]="column.actionDescriptor.style">
{{column.actionDescriptor.icon}}</mat-icon>
<tb-icon [ngStyle]="column.actionDescriptor.style">
{{column.actionDescriptor.icon}}
</tb-icon>
</button>
</mat-cell>
</ng-container>
@ -223,9 +229,9 @@
matTooltip="{{ actionDescriptor.nameFunction ? actionDescriptor.nameFunction(entity) : actionDescriptor.name }}"
matTooltipPosition="above"
(click)="actionDescriptor.onAction($event, entity)">
<mat-icon svgIcon="{{ actionDescriptor.mdiIconFunction ? actionDescriptor.mdiIconFunction(entity) : actionDescriptor.mdiIcon }}"
[ngStyle]="actionDescriptor.style">
{{actionDescriptor.icon}}</mat-icon>
<tb-icon [ngStyle]="actionDescriptor.style">
{{actionDescriptor.iconFunction ? actionDescriptor.iconFunction(entity) : actionDescriptor.icon}}
</tb-icon>
</button>
</div>
<div fxHide [fxShow.lt-lg]="cellActionDescriptors.length !== 1" *ngIf="cellActionDescriptors.length">
@ -239,9 +245,9 @@
[disabled]="isLoading$ | async"
[fxShow]="actionDescriptor.isEnabled(entity)"
(click)="actionDescriptor.onAction($event, entity)">
<mat-icon svgIcon="{{ actionDescriptor.mdiIconFunction ? actionDescriptor.mdiIconFunction(entity) : actionDescriptor.mdiIcon }}"
[ngStyle]="actionDescriptor.style">
{{actionDescriptor.icon}}</mat-icon>
<tb-icon matMenuItemIcon [ngStyle]="actionDescriptor.style">
{{actionDescriptor.iconFunction ? actionDescriptor.iconFunction(entity) : actionDescriptor.icon}}
</tb-icon>
<span>{{ actionDescriptor.nameFunction ? actionDescriptor.nameFunction(entity) : actionDescriptor.name }}</span>
</button>
</mat-menu>

5
ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts

@ -48,6 +48,7 @@ import {
CellActionDescriptorType,
EntityActionTableColumn,
EntityColumn,
EntityLinkTableColumn,
EntityTableColumn,
EntityTableConfig,
GroupActionDescriptor,
@ -613,7 +614,7 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
columnsUpdated(resetData: boolean = false) {
this.entityColumns = this.entitiesTableConfig.columns.filter(
(column) => column instanceof EntityTableColumn)
(column) => column instanceof EntityTableColumn || column instanceof EntityLinkTableColumn)
.map(column => column as EntityTableColumn<BaseData<HasId>>);
this.actionColumns = this.entitiesTableConfig.columns.filter(
(column) => column instanceof EntityActionTableColumn)
@ -670,7 +671,7 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
}
cellContent(entity: BaseData<HasId>, column: EntityColumn<BaseData<HasId>>, row: number) {
if (column instanceof EntityTableColumn) {
if (column instanceof EntityTableColumn || column instanceof EntityLinkTableColumn) {
const col = this.entitiesTableConfig.columns.indexOf(column);
const index = row * this.entitiesTableConfig.columns.length + col;
let res = this.cellContentCache[index];

54
ui-ngx/src/app/modules/home/components/entity/entity-filter.component.ts

@ -14,13 +14,14 @@
/// limitations under the License.
///
import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Component, EventEmitter, forwardRef, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { AliasFilterType, aliasFilterTypeTranslationMap, EntityAliasFilter } from '@shared/models/alias.models';
import { AliasEntityType, EntityType } from '@shared/models/entity-type.models';
import { TranslateService } from '@ngx-translate/core';
import { EntityService } from '@core/http/entity.service';
import { EntitySearchDirection, entitySearchDirectionTranslations } from '@shared/models/relation.models';
import { Subject, Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'tb-entity-filter',
@ -34,7 +35,7 @@ import { EntitySearchDirection, entitySearchDirectionTranslations } from '@share
}
]
})
export class EntityFilterComponent implements ControlValueAccessor, OnInit {
export class EntityFilterComponent implements ControlValueAccessor, OnInit, OnDestroy {
@Input() disabled: boolean;
@ -44,8 +45,8 @@ export class EntityFilterComponent implements ControlValueAccessor, OnInit {
@Output() resolveMultipleChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
entityFilterFormGroup: UntypedFormGroup;
filterFormGroup: UntypedFormGroup;
entityFilterFormGroup: FormGroup;
filterFormGroup: FormGroup;
aliasFilterTypes: Array<AliasFilterType>;
@ -59,9 +60,11 @@ export class EntityFilterComponent implements ControlValueAccessor, OnInit {
private propagateChange = null;
constructor(private translate: TranslateService,
private entityService: EntityService,
private fb: UntypedFormBuilder) {
private destroy$ = new Subject<void>();
private subscriptions = new Subscription();
constructor(private entityService: EntityService,
private fb: FormBuilder) {
}
ngOnInit(): void {
@ -71,15 +74,25 @@ export class EntityFilterComponent implements ControlValueAccessor, OnInit {
this.entityFilterFormGroup = this.fb.group({
type: [null, [Validators.required]]
});
this.entityFilterFormGroup.get('type').valueChanges.subscribe((type: AliasFilterType) => {
this.entityFilterFormGroup.get('type').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((type: AliasFilterType) => {
this.filterTypeChanged(type);
});
this.entityFilterFormGroup.valueChanges.subscribe(() => {
this.entityFilterFormGroup.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(() => {
this.updateModel();
});
this.filterFormGroup = this.fb.group({});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
this.subscriptions.unsubscribe();
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
@ -105,6 +118,8 @@ export class EntityFilterComponent implements ControlValueAccessor, OnInit {
}
private updateFilterFormGroup(type: AliasFilterType, filter?: EntityAliasFilter) {
this.subscriptions.unsubscribe();
this.subscriptions = new Subscription();
switch (type) {
case AliasFilterType.singleEntity:
this.filterFormGroup = this.fb.group({
@ -114,8 +129,17 @@ export class EntityFilterComponent implements ControlValueAccessor, OnInit {
case AliasFilterType.entityList:
this.filterFormGroup = this.fb.group({
entityType: [filter ? filter.entityType : null, [Validators.required]],
entityList: [filter ? filter.entityList : [], [Validators.required]],
entityList: [{
value: filter ? filter.entityList : [],
disabled: !filter?.entityType
}, [Validators.required]],
});
const entityTypeSubscription = this.filterFormGroup.get('entityType').valueChanges.subscribe((entityType) => {
if (entityType && this.filterFormGroup.get('entityList').disabled) {
this.filterFormGroup.get('entityList').enable({emitEvent: false});
}
});
this.subscriptions.add(entityTypeSubscription);
break;
case AliasFilterType.entityName:
this.filterFormGroup = this.fb.group({
@ -175,10 +199,11 @@ export class EntityFilterComponent implements ControlValueAccessor, OnInit {
maxLevel: [filter ? filter.maxLevel : 1, []],
fetchLastLevelOnly: [filter ? filter.fetchLastLevelOnly : false, []]
});
this.filterFormGroup.get('rootStateEntity').valueChanges.subscribe((rootStateEntity: boolean) => {
const rootStateSubscription = this.filterFormGroup.get('rootStateEntity').valueChanges.subscribe((rootStateEntity: boolean) => {
this.filterFormGroup.get('rootEntity').setValidators(rootStateEntity ? [] : [Validators.required]);
this.filterFormGroup.get('rootEntity').updateValueAndValidity();
});
this.subscriptions.add(rootStateSubscription);
if (type === AliasFilterType.relationsQuery) {
this.filterFormGroup.addControl('filters',
this.fb.control(filter ? filter.filters : [], []));
@ -201,9 +226,10 @@ export class EntityFilterComponent implements ControlValueAccessor, OnInit {
}
break;
}
this.filterFormGroup.valueChanges.subscribe(() => {
const filterFormSubscription = this.filterFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
this.subscriptions.add(filterFormSubscription);
}
private filterTypeChanged(type: AliasFilterType) {

2
ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.html

@ -81,6 +81,6 @@
matTooltip="{{ (dynamicMode ? 'filter.switch-to-default-value' : 'filter.switch-to-dynamic-value') | translate }}"
matTooltipPosition="above"
(click)="dynamicMode = !dynamicMode">
<mat-icon class="tb-mat-20" [svgIcon]="dynamicMode ? 'mdi:numeric' : 'mdi:variable'"></mat-icon>
<tb-icon class="tb-mat-20">{{ dynamicMode ? 'mdi:numeric' : 'mdi:variable' }}</tb-icon>
</button>
</div>

2
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-duration-predicate-value.component.html

@ -71,6 +71,6 @@
matTooltip="{{ (dynamicMode ? 'filter.switch-to-default-value' : 'filter.switch-to-dynamic-value') | translate }}"
matTooltipPosition="above"
(click)="dynamicMode = !dynamicMode">
<mat-icon class="tb-mat-20" [svgIcon]="dynamicMode ? 'mdi:numeric' : 'mdi:variable'"></mat-icon>
<tb-icon class="tb-mat-20">{{ dynamicMode ? 'mdi:numeric' : 'mdi:variable' }}</tb-icon>
</button>
</div>

5
ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.html

@ -25,8 +25,9 @@
(keydown)="assetProfileEnter($event)"
(keypress)="assetProfileEnter($event)"
[matAutocomplete]="assetProfileAutocomplete"
[fxShow]="!showDetailsPageLink || !disabled || !selectAssetProfileFormGroup.get('assetProfile').value">
<a *ngIf="showDetailsPageLink && selectAssetProfileFormGroup.get('assetProfile').value && disabled" aria-label="Open asset profile" [routerLink]=assetProfileURL>
[fxShow]="!showDetailsPageLink || !useAssetProfileLink || !disabled || !selectAssetProfileFormGroup.get('assetProfile').value">
<a *ngIf="showDetailsPageLink && useAssetProfileLink && selectAssetProfileFormGroup.get('assetProfile').value && disabled"
aria-label="Open asset profile" [routerLink]=assetProfileURL>
{{ displayAssetProfileFn(selectAssetProfileFormGroup.get('assetProfile').value) }}
</a>
<button *ngIf="selectAssetProfileFormGroup.get('assetProfile').value && !disabled"

18
ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.ts

@ -25,7 +25,7 @@ import {
Output,
ViewChild
} from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { PageLink } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order';
@ -33,7 +33,6 @@ import { catchError, debounceTime, distinctUntilChanged, map, share, switchMap,
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { entityIdEquals } from '@shared/models/id/entity-id';
import { TruncatePipe } from '@shared//pipe/truncate.pipe';
import { ENTER } from '@angular/cdk/keycodes';
@ -47,6 +46,9 @@ import { AssetProfileService } from '@core/http/asset-profile.service';
import { AssetProfileDialogComponent, AssetProfileDialogData } from './asset-profile-dialog.component';
import { SubscriptSizing } from '@angular/material/form-field';
import { coerceBoolean } from '@shared/decorators/coercion';
import { AuthUser } from '@shared/models/user.model';
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum';
@Component({
selector: 'tb-asset-profile-autocomplete',
@ -110,6 +112,10 @@ export class AssetProfileAutocompleteComponent implements ControlValueAccessor,
searchText = '';
assetProfileURL: string;
useAssetProfileLink = true;
private authUser: AuthUser;
private dirty = false;
private ignoreClosedPanel = false;
@ -128,6 +134,10 @@ export class AssetProfileAutocompleteComponent implements ControlValueAccessor,
private fb: UntypedFormBuilder,
private zone: NgZone,
private dialog: MatDialog) {
this.authUser = getCurrentAuthUser(this.store);
if (this.authUser.authority === Authority.CUSTOMER_USER) {
this.useAssetProfileLink = false;
}
this.selectAssetProfileFormGroup = this.fb.group({
assetProfile: [null]
});
@ -226,7 +236,9 @@ export class AssetProfileAutocompleteComponent implements ControlValueAccessor,
this.assetProfileService.getAssetProfileInfo(value.id).subscribe(
(profile) => {
this.modelValue = new AssetProfileId(profile.id.id);
this.assetProfileURL = getEntityDetailsPageURL(this.modelValue.id, this.modelValue.entityType);
if (this.useAssetProfileLink) {
this.assetProfileURL = getEntityDetailsPageURL(this.modelValue.id, this.modelValue.entityType);
}
this.selectAssetProfileFormGroup.get('assetProfile').patchValue(profile, {emitEvent: false});
this.assetProfileChanged.emit(profile);
}

5
ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html

@ -25,8 +25,9 @@
(keydown)="deviceProfileEnter($event)"
(keypress)="deviceProfileEnter($event)"
[matAutocomplete]="deviceProfileAutocomplete"
[fxShow]="!showDetailsPageLink || !disabled || !selectDeviceProfileFormGroup.get('deviceProfile').value">
<a *ngIf="showDetailsPageLink && selectDeviceProfileFormGroup.get('deviceProfile').value && disabled" aria-label="Open device profile" [routerLink]=deviceProfileURL>
[fxShow]="!showDetailsPageLink || !useDeviceProfileLink || !disabled || !selectDeviceProfileFormGroup.get('deviceProfile').value">
<a *ngIf="showDetailsPageLink && useDeviceProfileLink && selectDeviceProfileFormGroup.get('deviceProfile').value && disabled"
aria-label="Open device profile" [routerLink]=deviceProfileURL>
{{ displayDeviceProfileFn(selectDeviceProfileFormGroup.get('deviceProfile').value) }}
</a>
<button *ngIf="selectDeviceProfileFormGroup.get('deviceProfile').value && !disabled"

18
ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.ts

@ -27,7 +27,7 @@ import {
SimpleChanges,
ViewChild
} from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { PageLink } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order';
@ -35,7 +35,6 @@ import { catchError, debounceTime, distinctUntilChanged, map, share, switchMap,
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { entityIdEquals } from '@shared/models/id/entity-id';
import { TruncatePipe } from '@shared//pipe/truncate.pipe';
import { ENTER } from '@angular/cdk/keycodes';
@ -50,6 +49,9 @@ import { emptyPageData } from '@shared/models/page/page-data';
import { getEntityDetailsPageURL } from '@core/utils';
import { SubscriptSizing } from '@angular/material/form-field';
import { coerceBoolean } from '@shared/decorators/coercion';
import { AuthUser } from '@shared/models/user.model';
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum';
@Component({
selector: 'tb-device-profile-autocomplete',
@ -119,6 +121,10 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
searchText = '';
deviceProfileURL: string;
useDeviceProfileLink = true;
private authUser: AuthUser;
private dirty = false;
private ignoreClosedPanel = false;
@ -139,6 +145,10 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
private fb: UntypedFormBuilder,
private zone: NgZone,
private dialog: MatDialog) {
this.authUser = getCurrentAuthUser(this.store);
if (this.authUser.authority === Authority.CUSTOMER_USER) {
this.useDeviceProfileLink = false;
}
this.selectDeviceProfileFormGroup = this.fb.group({
deviceProfile: [null]
});
@ -248,7 +258,9 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
this.deviceProfileService.getDeviceProfileInfo(value.id).subscribe(
(profile) => {
this.modelValue = new DeviceProfileId(profile.id.id);
this.deviceProfileURL = getEntityDetailsPageURL(this.modelValue.id, this.modelValue.entityType);
if (this.useDeviceProfileLink) {
this.deviceProfileURL = getEntityDetailsPageURL(this.modelValue.id, this.modelValue.entityType);
}
this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(profile, {emitEvent: false});
this.deviceProfileChanged.emit(profile);
}

2
ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html

@ -297,7 +297,7 @@
{{ 'tenant-profile.rule-engine-exceptions-ttl-days-required' | translate}}
</mat-error>
<mat-error *ngIf="defaultTenantProfileConfigurationFormGroup.get('ruleEngineExceptionsTtlDays').hasError('min')">
{{ 'tenant-profile.rule-engine-exceptions-ttl-days-days-range' | translate}}
{{ 'tenant-profile.rule-engine-exceptions-ttl-days-range' | translate}}
</mat-error>
<mat-hint></mat-hint>
</mat-form-field>

6
ui-ngx/src/app/modules/home/components/rule-chain/rule-chain-autocomplete.component.html

@ -22,7 +22,11 @@
formControlName="ruleChainId"
(focusin)="onFocus()"
[required]="required"
[matAutocomplete]="ruleChainAutocomplete">
[matAutocomplete]="ruleChainAutocomplete"
[fxShow]="!disabled || !selectRuleChainFormGroup.get('ruleChainId').value">
<a *ngIf="selectRuleChainFormGroup.get('ruleChainId').value && disabled" aria-label="Open device profile" [routerLink]=ruleChainURL>
{{ displayRuleChainFn(selectRuleChainFormGroup.get('ruleChainId').value) }}
</a>
<button *ngIf="selectRuleChainFormGroup.get('ruleChainId').value && !disabled"
type="button"
matSuffix mat-icon-button aria-label="Clear"

8
ui-ngx/src/app/modules/home/components/rule-chain/rule-chain-autocomplete.component.ts

@ -15,7 +15,7 @@
///
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { catchError, debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
@ -30,6 +30,7 @@ import { TruncatePipe } from '@shared/pipe/truncate.pipe';
import { RuleChainService } from '@core/http/rule-chain.service';
import { MatAutocompleteTrigger } from '@angular/material/autocomplete';
import { RuleChainType } from '@app/shared/models/rule-chain.models';
import { getEntityDetailsPageURL } from '@core/utils';
@Component({
selector: 'tb-rule-chain-autocomplete',
@ -74,6 +75,7 @@ export class RuleChainAutocompleteComponent implements ControlValueAccessor, OnI
filteredRuleChains: Observable<Array<BaseData<EntityId>>>;
searchText = '';
ruleChainURL: string;
private dirty = false;
@ -151,6 +153,10 @@ export class RuleChainAutocompleteComponent implements ControlValueAccessor, OnI
this.entityService.getEntity(targetEntityType, value, {ignoreLoading: true, ignoreErrors: true}).subscribe(
(entity) => {
this.modelValue = entity.id.id;
this.ruleChainURL = getEntityDetailsPageURL(this.modelValue,EntityType.RULE_CHAIN);
if (this.ruleChainType === RuleChainType.EDGE) {
this.ruleChainURL = '/edgeManagement' + this.ruleChainURL;
}
this.selectRuleChainFormGroup.get('ruleChainId').patchValue(entity, {emitEvent: false});
},
() => {

2
ui-ngx/src/app/modules/home/components/vc/version-control.scss

@ -15,8 +15,10 @@
*/
:host {
.vc-result-message {
max-width: 65vw;
padding: 0 8px;
text-align: center;
word-wrap: break-word;
&:first-child {
padding-top: 48px;
}

1
ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.ts

@ -108,6 +108,7 @@ export class GaugeBasicConfigComponent extends BasicWidgetConfigComponent {
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.borderRadius = config.borderRadius;
this.widgetConfig.config.backgroundColor = config.backgroundColor;
this.widgetConfig.config.settings.showUnitTitle = config.showUnitTitle;

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

@ -148,7 +148,7 @@
<button mat-menu-item *ngIf="actionDescriptor.icon"
[disabled]="(isLoading$ | async) || !actionEnabled(alarm, actionDescriptor)"
(click)="onActionButtonClick($event, alarm, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
<tb-icon matMenuItemIcon>{{actionDescriptor.icon}}</tb-icon>
<span>{{ actionDescriptor.displayName }}</span>
</button>
</ng-container>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save