diff --git a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json index 42cbd9b262..4ca5484223 100644 --- a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json @@ -2,12 +2,13 @@ "widgetsBundle": { "alias": "alarm_widgets", "title": "Alarm widgets", - "image": "data:image/png;base64,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", + "image": "data:image/png;base64,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", "description": "Visualization of alarms for devices, assets and other entities.", "externalId": null, "name": "Alarm widgets" }, "widgetTypeFqns": [ - "alarm_widgets.alarms_table" + "alarm_widgets.alarms_table", + "alarm_count" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/count_widgets.json b/application/src/main/data/json/system/widget_bundles/count_widgets.json new file mode 100644 index 0000000000..a40f33cd8e --- /dev/null +++ b/application/src/main/data/json/system/widget_bundles/count_widgets.json @@ -0,0 +1,14 @@ +{ + "widgetsBundle": { + "alias": "count_widgets", + "title": "Count widgets", + "image": "data:image/png;base64,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", + "description": "Cards to display the number of alarms or entities based on selected filter.", + "externalId": null, + "name": "Count widgets" + }, + "widgetTypeFqns": [ + "alarm_count", + "entity_count" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/entity_widgets.json b/application/src/main/data/json/system/widget_bundles/entity_widgets.json index 865d2e11ec..32ceedb4c1 100644 --- a/application/src/main/data/json/system/widget_bundles/entity_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/entity_widgets.json @@ -9,6 +9,7 @@ }, "widgetTypeFqns": [ "cards.entities_table", + "entity_count", "cards.entities_hierarchy" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/alarm_count.json b/application/src/main/data/json/system/widget_types/alarm_count.json new file mode 100644 index 0000000000..dd3b63e3ae --- /dev/null +++ b/application/src/main/data/json/system/widget_types/alarm_count.json @@ -0,0 +1,23 @@ +{ + "fqn": "alarm_count", + "name": "Alarm count", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAolBMVEXg4ODf39/g4OAAAADg4ODf39/////g4OD8/Pz+/v7RJzD29vb6+vr7+/v09PTt7e3z8/P4+Pjx8fHv7+/ok5fXQkqXl5chISHk5OTIyMi6urqpqamgoKDDw8P55OXurrI8PDzc3NyxsbF0dHRYWFjlhYrUND3V1dXroKT88fLR0dHzycvwu76QkJDieH7eY2pKSkovLy/219jieH1mZmbTND12Tj45AAAABnRSTlPvIL8Ar7DvmsykAAAEx0lEQVR42u2aiXLaMBBATdMuUmU5yEBJgEDanL3v//+1rpDI2khA087U63RfjGRJa4k3a5sMpjgZPCuGfef54KQYFGMFPUfVqPG8hifAGE+r3ufDo4piCE+CoYgwQ0S4ISLcEBFuiAg3RIQbIsINEeGGiHBDRLghItwQEW6ICDdEhBsiwg0R4YaIcENEuCEi3BARbogIN0SEGyLCDRHhhohwQ0S48X+IaDiKBibsiGit/hit/i06J0IatkRsaWPZxoZR3OIgheKYjUHbkoLj/jawOWOjsDQ3rUfTUXcIQ5c9IqhROlPlMf5lwm6saYx2KC4dJSg6BhsKzMZTBK3hSqV0XsQ6p9ic9EexximtMyJaOdMfDURjTnIiyrqe/d5fOauyIgb6ha4wJRmRsoKekRXRyvVPxKUiGkVGEFnfvswwXQMzRiiik4xYEpm+zHILDS4Wy8UFeE7jtfUK/i15Ea2seRB5uQeI0Bs/ew1mcWGw7kKkNjYrUj9aZP7m4o1Zzg1W512IOKVSEZUVufm+XyRu89dwOl/OmWQEdFbkHuD+gMgSNy+yNK+7EcllxLpUZEqXflbk3QIv+HdLc7FYvOlCxFkNuiWitc5dIx8AeU8iKSa8DHRBnd61NOREPoXm5wcRZmBGVJIRlRFZAawxKatbriK/efud+AtkisWkRyKZUwsVosjbKVMR91sZWQMyuW9c77vz1NAVlBGAY3etT9Dgcypy/mU2uz6DzsiLQCqyAs/NDXhWicjZ7Mt88fUaOoJOrWMZmQDEa2TDZFfk7uoO4GoGHUGf7PpIRlbQ4m32Yr+8hI4gETgi8g1arFKR8+uvl3fQFXT7PfKBOJ00uZlmRK5+zD5CJ1BGNBw+tfLALlezGjrgkZ8jKe18nAF8nGHRDfTf79+KzK7Pz7u+2J2Fg9fIbd5jCk2Wlyw+EA/etdbTnMfPNbQ56/5fFLVHpGf4jMDTEMl+r+VGvXqqsO8LOq1c1bPHCuWe736t6VdKdGXKVkbo3KpGJfQFbUeVs9mMqBJNxuPT8SnRbKS940MhcaOOXCgu9whoYTyw3nikIt7EOlONPNWorkeBUFe176lDGxuhDANYhMjQsymo8qMRf1gaQathSZ3bmCqO163p8LlufKybnlooosrSObMX95iBdOR4jHtEqEOPRIRyosLjfB/msLKhahYIFiECxzF486IOfPliU1Fo+ENiUSI0l2/EJeKiYeUQZ2NJK/mmRQ0EMiJqg03xevinwm4Thd1xI9R2YBtfKhqIsc3jFM2llI8uYwD2UMAGmlQhwSMRQVSfCBqpCOgNyuuEDaEq9oYOKg9BR+5O125ovTtCA1TRHKEH0EOnIqTixx8ARaXC2pcB5RsQ+o6zEwR4dLuNTZoqzrpdAFqRcS6gfJAIETUASIl2qBGrGA5JCNAOJKPUBiROQiHxXcBma8ydLpKIJMSc6WYrzkz7YY94eAeNYJonjEWzzHK0FwV20Nsh/T//FLBPiAg3RIQbIsINEeGGiHBDRLghItwQEW6ICDdEhBsiwg0R4YaIcENEuCEi3BARbogIN0SEGyLCDRHhhohwQ0S4ISLcGBZFz37Zn0cNi2djeALUL4pBUfc+J2qMGieD58O+UzwbnPwC9rQ9R9RHLAMAAAAASUVORK5CYII=", + "description": "Displays the number of alarms based on selected filter.", + "descriptor": { + "type": "latest", + "sizeX": 3.5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.countWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.countWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '220px',\n previewHeight: '100px',\n embedTitlePanel: true,\n hideDataSettings: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-alarm-count-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-alarm-count-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"count\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = Number((prevValue + Math.random() * 4 - 2).toFixed(0));\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"],\"assignedToCurrentUser\":false,\"assigneeId\":null}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"showLabel\":true,\"label\":\"Total\",\"labelFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.54)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":20,\"iconSizeUnit\":\"px\",\"icon\":\"warning\",\"iconColor\":{\"type\":\"constant\",\"color\":\"rgba(255, 255, 255, 1)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIconBackground\":true,\"iconBackgroundSize\":36,\"iconBackgroundSizeUnit\":\"px\",\"iconBackgroundColor\":{\"type\":\"range\",\"color\":\"rgba(0, 105, 92, 1)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"rgba(0, 105, 92, 1)\"},{\"from\":1,\"to\":null,\"color\":\"rgba(209, 39, 48, 1)\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":20,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"24px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showChevron\":false,\"chevronSize\":24,\"chevronSizeUnit\":\"px\",\"chevronColor\":\"rgba(0, 0, 0, 0.38)\",\"layout\":\"column\"},\"title\":\"Alarm count\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":null,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.54)\"}" + }, + "externalId": null +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/entity_count.json b/application/src/main/data/json/system/widget_types/entity_count.json new file mode 100644 index 0000000000..9efa02b2f6 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/entity_count.json @@ -0,0 +1,23 @@ +{ + "fqn": "entity_count", + "name": "Entity count", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays the number of entities based on selected filter.", + "descriptor": { + "type": "latest", + "sizeX": 3.5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.countWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.countWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '220px',\n previewHeight: '100px',\n embedTitlePanel: true,\n hideDataSettings: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-entity-count-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-entity-count-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"count\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"return 150;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"],\"assignedToCurrentUser\":false,\"assigneeId\":null}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"showLabel\":true,\"label\":\"Devices\",\"labelFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.54)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":20,\"iconSizeUnit\":\"px\",\"icon\":\"devices\",\"iconColor\":{\"type\":\"constant\",\"color\":\"rgba(255, 255, 255, 1)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIconBackground\":true,\"iconBackgroundSize\":36,\"iconBackgroundSizeUnit\":\"px\",\"iconBackgroundColor\":{\"type\":\"constant\",\"color\":\"rgb(241, 141, 23)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":20,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"24px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showChevron\":false,\"chevronSize\":24,\"chevronSizeUnit\":\"px\",\"chevronColor\":\"rgba(0, 0, 0, 0.38)\",\"layout\":\"column\"},\"title\":\"Entity count\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":null,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.54)\"}" + }, + "externalId": null +} \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 8530478c2a..4bb3645f20 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -523,6 +523,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { this.deleteSystemWidgetBundle("entity_widgets"); this.deleteSystemWidgetBundle("html_widgets"); this.deleteSystemWidgetBundle("tables"); + this.deleteSystemWidgetBundle("count_widgets"); installScripts.loadSystemWidgets(); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.html new file mode 100644 index 0000000000..d43a067e3d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.html @@ -0,0 +1,61 @@ + + +
+
+
alarm.filter
+ +
+ +
+
+
widget-config.appearance
+ +
+
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.ts new file mode 100644 index 0000000000..782d2d4547 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.ts @@ -0,0 +1,107 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DatasourceType, WidgetConfig, widgetType, } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { isUndefined } from '@core/utils'; +import { getAlarmFilterConfig, setAlarmFilterConfig } from '@shared/models/widget-settings.models'; +import { UtilsService } from '@core/services/utils.service'; +import { AlarmSearchStatus } from '@shared/models/alarm.models'; +import { + countDefaultSettings, + CountWidgetSettings +} from '@home/components/widget/lib/count/count-widget.models'; + +@Component({ + selector: 'tb-alarm-count-basic-config', + templateUrl: './alarm-count-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class AlarmCountBasicConfigComponent extends BasicWidgetConfigComponent { + + alarmSearchStatus = AlarmSearchStatus; + + alarmCountWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private utils: UtilsService, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.alarmCountWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + let datasources = configData.config.datasources; + if (!datasources || !datasources.length) { + datasources = [{}]; + configData.config.datasources = datasources; + } + datasources[0].type = DatasourceType.alarmCount; + datasources[0].alarmFilterConfig = {statusList: [AlarmSearchStatus.ACTIVE]}; + datasources[0].dataKeys = [this.utils.createKey({name: 'count'}, DataKeyType.count)]; + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: CountWidgetSettings = {...countDefaultSettings(true), ...(configData.config.settings || {})}; + this.alarmCountWidgetConfigForm = this.fb.group({ + alarmFilterConfig: [getAlarmFilterConfig(configData.config.datasources), []], + + settings: [settings, []], + + backgroundColor: [configData.config.backgroundColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + setAlarmFilterConfig(config.alarmFilterConfig, this.widgetConfig.config.datasources); + + this.widgetConfig.config.settings = {...(this.widgetConfig.config.settings || {}), ...config.settings}; + + this.widgetConfig.config.backgroundColor = config.backgroundColor; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html index e343ac9b81..d2d9fc5e8f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html @@ -49,7 +49,7 @@ formControlName="columns">
-
widget-config.card-appearance
+
widget-config.appearance
{{ 'widget-config.card-title' | translate }} @@ -85,6 +85,29 @@
+ +
+
widgets.table.table-buttons
+
+ + {{ 'widgets.table.display-alarm-activity' | translate }} + + + {{ 'widgets.table.display-alarm-details' | translate }} + + + {{ 'widgets.table.allow-alarms-assign' | translate }} + + + {{ 'widgets.table.allow-alarms-ack' | translate }} + + + {{ 'widgets.table.allow-alarms-clear' | translate }} + +
+
+
+
widget-config.card-appearance
widget-config.show-card-buttons
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts index 6c25585f76..4f61aea583 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts @@ -69,6 +69,13 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent showTitleIcon: [configData.config.showTitleIcon, []], titleIcon: [configData.config.titleIcon, []], iconColor: [configData.config.iconColor, []], + + displayActivity: [configData.config.settings?.displayActivity, []], + displayDetails: [configData.config.settings?.displayDetails, []], + allowAssign: [configData.config.settings?.allowAssign, []], + allowAcknowledgment: [configData.config.settings?.allowAcknowledgment, []], + allowClear: [configData.config.settings?.allowClear, []], + cardButtons: [this.getCardButtons(configData.config), []], color: [configData.config.color, []], backgroundColor: [configData.config.backgroundColor, []], @@ -84,7 +91,14 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent this.widgetConfig.config.actions = config.actions; this.widgetConfig.config.showTitle = config.showTitle; this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.widgetConfig.config.settings.alarmsTitle = config.title; + this.widgetConfig.config.settings.displayActivity = config.displayActivity; + this.widgetConfig.config.settings.displayDetails = config.displayDetails; + this.widgetConfig.config.settings.allowAssign = config.allowAssign; + this.widgetConfig.config.settings.allowAcknowledgment = config.allowAcknowledgment; + this.widgetConfig.config.settings.allowClear = config.allowClear; + this.widgetConfig.config.titleFont = config.titleFont; this.widgetConfig.config.titleColor = config.titleColor; this.widgetConfig.config.showTitleIcon = config.showTitleIcon; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 7c4168a786..69500d1c85 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -27,7 +27,7 @@ import { } from '@home/components/widget/config/basic/common/widget-actions-panel.component'; import { EntitiesTableBasicConfigComponent -} from '@home/components/widget/config/basic/cards/entities-table-basic-config.component'; +} from '@home/components/widget/config/basic/entity/entities-table-basic-config.component'; import { DataKeysPanelComponent } from '@home/components/widget/config/basic/common/data-keys-panel.component'; import { DataKeyRowComponent } from '@home/components/widget/config/basic/common/data-key-row.component'; import { @@ -49,6 +49,12 @@ import { import { AggregatedDataKeysPanelComponent } from '@home/components/widget/config/basic/cards/aggregated-data-keys-panel.component'; +import { + AlarmCountBasicConfigComponent +} from '@home/components/widget/config/basic/alarm/alarm-count-basic-config.component'; +import { + EntityCountBasicConfigComponent +} from '@home/components/widget/config/basic/entity/entity-count-basic-config.component'; @NgModule({ declarations: [ @@ -63,7 +69,9 @@ import { AggregatedDataKeyRowComponent, AggregatedDataKeysPanelComponent, DataKeyRowComponent, - DataKeysPanelComponent + DataKeysPanelComponent, + AlarmCountBasicConfigComponent, + EntityCountBasicConfigComponent ], imports: [ CommonModule, @@ -82,7 +90,9 @@ import { AggregatedDataKeyRowComponent, AggregatedDataKeysPanelComponent, DataKeyRowComponent, - DataKeysPanelComponent + DataKeysPanelComponent, + AlarmCountBasicConfigComponent, + EntityCountBasicConfigComponent ] }) export class BasicWidgetConfigModule { @@ -95,5 +105,7 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type + + + +
+
widget-config.appearance
+ +
+
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.ts new file mode 100644 index 0000000000..c18153ac50 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.ts @@ -0,0 +1,98 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DatasourceType, WidgetConfig, } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { isUndefined } from '@core/utils'; +import { UtilsService } from '@core/services/utils.service'; +import { countDefaultSettings, CountWidgetSettings } from '@home/components/widget/lib/count/count-widget.models'; + +@Component({ + selector: 'tb-entity-count-basic-config', + templateUrl: './entity-count-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class EntityCountBasicConfigComponent extends BasicWidgetConfigComponent { + + entityCountWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private utils: UtilsService, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.entityCountWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + let datasources = configData.config.datasources; + if (!datasources || !datasources.length) { + datasources = [{}]; + configData.config.datasources = datasources; + } + datasources[0].type = DatasourceType.entityCount; + datasources[0].dataKeys = [this.utils.createKey({name: 'count'}, DataKeyType.count)]; + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: CountWidgetSettings = {...countDefaultSettings(false), ...(configData.config.settings || {})}; + this.entityCountWidgetConfigForm = this.fb.group({ + datasources: [configData.config.datasources, []], + settings: [settings, []], + + backgroundColor: [configData.config.backgroundColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.datasources = config.datasources; + + this.widgetConfig.config.settings = {...(this.widgetConfig.config.settings || {}), ...config.settings}; + + this.widgetConfig.config.backgroundColor = config.backgroundColor; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html index 7f816e4593..a8c26dce3f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html @@ -26,7 +26,7 @@
- + datasource.label @@ -54,7 +54,7 @@ formControlName="entityAliasId" [callbacks]="entityAliasSelectCallbacks"> -
{{ 'widget-config.timeseries-key-error' | translate }}
- {{ 'device.device' | translate }} {{ 'entity.entity-alias' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts index adc7eb1019..849283f8d2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts @@ -93,6 +93,18 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid @Input() disabled: boolean; + @Input() + @coerceBoolean() + hideDatasourcesMode = false; + + @Input() + @coerceBoolean() + hideDatasourceLabel = false; + + @Input() + @coerceBoolean() + displayDatasourceFilterForBasicMode = false; + @Input() @coerceBoolean() hideDataKeyLabel = false; @@ -285,7 +297,8 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid if (datasources && datasources.length) { datasourcesMode = datasources[0].type; } - if (datasourcesMode !== DatasourceType.device && datasourcesMode !== DatasourceType.entity) { + if (!this.hideDatasourcesMode + && datasourcesMode !== DatasourceType.device && datasourcesMode !== DatasourceType.entity) { datasourcesMode = DatasourceType.device; } return datasourcesMode; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts similarity index 99% rename from ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts index 58c3804c19..034c131769 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts @@ -149,7 +149,7 @@ interface AlarmWidgetActionDescriptor extends TableCellButtonActionDescriptor { @Component({ selector: 'tb-alarms-table-widget', templateUrl: './alarms-table-widget.component.html', - styleUrls: ['./alarms-table-widget.component.scss', './table-widget.scss'] + styleUrls: ['./alarms-table-widget.component.scss', './../table-widget.scss'] }) export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, OnDestroy, AfterViewInit { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.html new file mode 100644 index 0000000000..e99863e1a9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.html @@ -0,0 +1,37 @@ + +
+
+ +
+
+
+
+
+ {{ icon }} +
+
+
{{ label }}
+
+
{{ valueText }}
+
+
+
+ chevron_right +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.scss new file mode 100644 index 0000000000..8deb211897 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.scss @@ -0,0 +1,80 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + .tb-count-panel { + width: 100%; + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + gap: 12px; + padding: 12px; + &.tb-count-pointer { + cursor: pointer; + } + .tb-count-panel-column { + flex: 1; + display: flex; + flex-direction: column; + gap: 12px; + } + .tb-count-panel-row { + flex: 1; + display: flex; + flex-direction: row; + align-items: center; + gap: 12px; + } + .tb-count-icon-panel { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .mat-icon { + z-index: 1; + } + } + .tb-count-icon-background-panel { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + .tb-count-label-value-panel { + flex: 1; + display: flex; + flex-direction: column; + place-content: flex-start space-around; + align-items: flex-start; + gap: 0; + &.tb-count-layout-row { + flex-direction: row; + align-items: center; + } + } + } +} + +:host ::ng-deep { + .tb-count-panel { + .tb-widget-title { + padding: 0; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts new file mode 100644 index 0000000000..8a8974c8bd --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts @@ -0,0 +1,148 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ChangeDetectorRef, Component, Input, OnInit, TemplateRef } from '@angular/core'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { formatValue } from '@core/utils'; +import { + ColorProcessor, + ComponentStyle, + getSingleTsValue, + iconStyle, + textStyle +} from '@shared/models/widget-settings.models'; +import { WidgetComponent } from '@home/components/widget/widget.component'; +import { + CountCardLayout, + countDefaultSettings, + CountWidgetSettings +} from '@home/components/widget/lib/count/count-widget.models'; +import { coerceBoolean } from '@shared/decorators/coercion'; + +@Component({ + selector: 'tb-count-widget', + templateUrl: './count-widget.component.html', + styleUrls: ['./count-widget.component.scss'] +}) +export class CountWidgetComponent implements OnInit { + + settings: CountWidgetSettings; + + countCardLayout = CountCardLayout; + + @Input() + ctx: WidgetContext; + + @Input() + widgetTitlePanel: TemplateRef; + + @coerceBoolean() + @Input() + alarmElseEntity: boolean; + + layout: CountCardLayout; + + showLabel = true; + label: string; + labelStyle: ComponentStyle = {}; + labelColor: ColorProcessor; + + showIcon = true; + icon = ''; + iconStyle: ComponentStyle = {}; + iconColor: ColorProcessor; + + showIconBackground = true; + iconBackgroundSize: string; + iconBackgroundStyle: ComponentStyle = {}; + iconBackgroundColor: ColorProcessor; + + valueText = 'N/A'; + valueStyle: ComponentStyle = {}; + valueColor: ColorProcessor; + + showChevron = false; + chevronStyle: ComponentStyle = {}; + + constructor(private widgetComponent: WidgetComponent, + private cd: ChangeDetectorRef) { + } + + ngOnInit(): void { + this.ctx.$scope.countWidget = this; + this.settings = {...countDefaultSettings(this.alarmElseEntity), ...this.ctx.settings}; + + this.layout = this.settings.layout; + + this.showLabel = this.settings.showLabel; + this.label = this.settings.label; + this.labelStyle = textStyle(this.settings.labelFont, '0.4px'); + this.labelColor = ColorProcessor.fromSettings(this.settings.labelColor); + + this.showIcon = this.settings.showIcon; + this.icon = this.settings.icon; + this.iconStyle = iconStyle(this.settings.iconSize, this.settings.iconSizeUnit); + this.iconColor = ColorProcessor.fromSettings(this.settings.iconColor); + + this.showIconBackground = this.settings.showIconBackground; + if (this.showIconBackground) { + this.iconBackgroundSize = this.settings.iconBackgroundSize + this.settings.iconBackgroundSizeUnit; + } else { + this.iconBackgroundSize = this.settings.iconSize + this.settings.iconSizeUnit; + } + this.iconBackgroundStyle = { + width: this.iconBackgroundSize, + height: this.iconBackgroundSize, + borderRadius: '4px' + }; + this.iconBackgroundColor = ColorProcessor.fromSettings(this.settings.iconBackgroundColor); + + this.valueStyle = textStyle(this.settings.valueFont, '0.1px'); + this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); + + this.showChevron = this.settings.showChevron; + this.chevronStyle = iconStyle(this.settings.chevronSize, this.settings.chevronSizeUnit); + this.chevronStyle.color = this.settings.chevronColor; + } + + public onInit() { + } + + public onDataUpdated() { + const tsValue = getSingleTsValue(this.ctx.data); + let value: any; + if (tsValue) { + value = tsValue[1]; + this.valueText = formatValue(value, 0); + } else { + this.valueText = 'N/A'; + } + this.labelColor.update(value); + this.iconColor.update(value); + this.iconBackgroundColor.update(value); + this.valueColor.update(value); + this.cd.detectChanges(); + } + + public cardClick($event: Event) { + const descriptors = this.ctx.actionsApi.getActionDescriptors('cardClick'); + if (descriptors.length) { + $event.stopPropagation(); + const descriptor = descriptors[0]; + this.ctx.actionsApi.handleWidgetAction($event, descriptor); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.models.ts new file mode 100644 index 0000000000..4a1b307f4b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.models.ts @@ -0,0 +1,122 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + ColorSettings, + ColorType, + constantColor, + cssUnit, + defaultColorFunction, + Font +} from '@shared/models/widget-settings.models'; + +export enum CountCardLayout { + column = 'column', + row = 'row' +} + +export const countCardLayouts = Object.keys(CountCardLayout) as CountCardLayout[]; + +export const countCardLayoutTranslations = new Map( + [ + [CountCardLayout.column, 'widgets.count.layout-column'], + [CountCardLayout.row, 'widgets.count.layout-row'] + ] +); + +export const alarmCountCardLayoutImages = new Map( + [ + [CountCardLayout.column, 'assets/widget/alarm-count/column-layout.svg'], + [CountCardLayout.row, 'assets/widget/alarm-count/row-layout.svg'] + ] +); + +export const entityCountCardLayoutImages = new Map( + [ + [CountCardLayout.column, 'assets/widget/entity-count/column-layout.svg'], + [CountCardLayout.row, 'assets/widget/entity-count/row-layout.svg'] + ] +); + +export interface CountWidgetSettings { + layout: CountCardLayout; + showLabel: boolean; + label: string; + labelFont: Font; + labelColor: ColorSettings; + showIcon: boolean; + icon: string; + iconSize: number; + iconSizeUnit: cssUnit; + iconColor: ColorSettings; + showIconBackground: boolean; + iconBackgroundSize: number; + iconBackgroundSizeUnit: cssUnit; + iconBackgroundColor: ColorSettings; + valueFont: Font; + valueColor: ColorSettings; + showChevron: boolean; + chevronSize: number; + chevronSizeUnit: cssUnit; + chevronColor: string; +} + +export const countDefaultSettings = (alarmElseEntity: boolean): CountWidgetSettings => ({ + layout: CountCardLayout.column, + showLabel: true, + label: alarmElseEntity ? 'Total' : 'Devices', + labelFont: { + family: 'Roboto', + size: 12, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '16px' + }, + labelColor: constantColor('rgba(0, 0, 0, 0.54)'), + showIcon: true, + icon: alarmElseEntity ? 'warning' : 'devices', + iconSize: 20, + iconSizeUnit: 'px', + iconColor: constantColor('rgba(255, 255, 255, 1)'), + showIconBackground: true, + iconBackgroundSize: 36, + iconBackgroundSizeUnit: 'px', + iconBackgroundColor: alarmElseEntity + ? { + color: 'rgba(0, 105, 92, 1)', + type: ColorType.range, + rangeList: [ + {from: 0, to: 0, color: 'rgba(0, 105, 92, 1)'}, + {from: 1, color: 'rgba(209, 39, 48, 1)'} + ], + colorFunction: defaultColorFunction + } + : constantColor('rgba(241, 141, 23, 1)'), + valueFont: { + family: 'Roboto', + size: 20, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '24px' + }, + valueColor: constantColor('rgba(0, 0, 0, 0.87)'), + showChevron: false, + chevronSize: 24, + chevronSizeUnit: 'px', + chevronColor: 'rgba(0, 0, 0, 0.38)' +}); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.ts similarity index 99% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.ts index 75ea8657d7..17e95601c1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.ts @@ -64,7 +64,7 @@ import { NodeRelationQueryFunction, NodesSortFunction, NodeTextFunction -} from '@home/components/widget/lib/entities-hierarchy-widget.models'; +} from '@home/components/widget/lib/entity/entities-hierarchy-widget.models'; import { EntityRelationsQuery } from '@shared/models/relation.models'; import { AliasFilterType, RelationsQueryFilter } from '@shared/models/alias.models'; import { EntityFilter } from '@shared/models/query/query.models'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.models.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.models.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.models.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts similarity index 99% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts index 1428b16f17..df71fce4f8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts @@ -121,7 +121,7 @@ interface EntitiesTableWidgetSettings extends TableWidgetSettings { @Component({ selector: 'tb-entities-table-widget', templateUrl: './entities-table-widget.component.html', - styleUrls: ['./entities-table-widget.component.scss', './table-widget.scss'] + styleUrls: ['./entities-table-widget.component.scss', './../table-widget.scss'] }) export class EntitiesTableWidgetComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.html new file mode 100644 index 0000000000..ab8e7635dd --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.html @@ -0,0 +1,23 @@ + + +
+
widgets.alarm-count.alarm-count-card-style
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.ts new file mode 100644 index 0000000000..6a36891c7e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.ts @@ -0,0 +1,62 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { countDefaultSettings } from '@home/components/widget/lib/count/count-widget.models'; + +@Component({ + selector: 'tb-alarm-count-widget-settings', + templateUrl: './alarm-count-widget-settings.component.html', + styleUrls: ['./../widget-settings.scss'] +}) +export class AlarmCountWidgetSettingsComponent extends WidgetSettingsComponent { + + alarmCountWidgetSettingsForm: UntypedFormGroup; + + constructor(protected store: Store, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.alarmCountWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...countDefaultSettings(true)}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.alarmCountWidgetSettingsForm = this.fb.group({ + alarmCountSettings: [settings.alarmCountSettings, []], + }); + } + + protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { + return { + alarmCountSettings: settings + }; + } + + protected prepareOutputSettings(settings: any): WidgetSettings { + return settings.alarmCountSettings; + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts index 223cf93e77..fff6e2c8fc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts @@ -53,6 +53,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent allowAcknowledgment: true, allowClear: true, allowAssign: true, + displayActivity: true, displayPagination: true, defaultPageSize: 10, defaultSortOrder: '-createdTime', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.html new file mode 100644 index 0000000000..e373acb8a5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.html @@ -0,0 +1,103 @@ + + + + + {{ countCardLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.count.label' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widgets.count.icon' | translate }} + +
+ + + + + + + + +
+
+
+ + {{ 'widgets.count.icon-background' | translate }} + +
+ + + + + + +
+
+
+
widgets.count.value
+
+ + + + +
+
+
+ + {{ 'widgets.count.chevron' | translate }} + +
+ + + + + + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts new file mode 100644 index 0000000000..2a37a46d5c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts @@ -0,0 +1,201 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + AbstractControl, + ControlValueAccessor, + NG_VALUE_ACCESSOR, + UntypedFormBuilder, + UntypedFormGroup, + Validators +} from '@angular/forms'; +import {Store} from '@ngrx/store'; +import {AppState} from '@core/core.state'; +import { + alarmCountCardLayoutImages, + CountCardLayout, + countCardLayouts, + countCardLayoutTranslations, + CountWidgetSettings, entityCountCardLayoutImages +} from '@home/components/widget/lib/count/count-widget.models'; +import {PageComponent} from '@shared/components/page.component'; +import {Component, forwardRef, Input, OnInit} from '@angular/core'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { + valueCardLayoutImages, + valueCardLayoutTranslations +} from '@home/components/widget/lib/cards/value-card-widget.models'; + +@Component({ + selector: 'tb-count-widget-settings', + templateUrl: './count-widget-settings.component.html', + styleUrls: ['./../widget-settings.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CountWidgetSettingsComponent), + multi: true + } + ] +}) +export class CountWidgetSettingsComponent extends PageComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + @coerceBoolean() + @Input() + alarmElseEntity: boolean; + + private propagateChange = null; + + countCardLayouts = countCardLayouts; + + countCardLayoutTranslationMap = countCardLayoutTranslations; + countCardLayoutImageMap: Map; + + countWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + private fb: UntypedFormBuilder) { + super(store); + } + + ngOnInit(): void { + this.countCardLayoutImageMap = this.alarmElseEntity ? alarmCountCardLayoutImages : entityCountCardLayoutImages; + this.countWidgetConfigForm = this.fb.group({ + layout: [null, []], + showLabel: [null, []], + label: [null, []], + labelFont: [null, []], + labelColor: [null, []], + + showIcon: [null, []], + iconSize: [null, [Validators.min(0)]], + iconSizeUnit: [null, []], + icon: [null, []], + iconColor: [null, []], + + showIconBackground: [null, []], + iconBackgroundSize: [null, [Validators.min(0)]], + iconBackgroundSizeUnit: [null, []], + iconBackgroundColor: [null, []], + + valueFont: [null, []], + valueColor: [null, []], + + showChevron: [null, []], + chevronSize: [null, [Validators.min(0)]], + chevronSizeUnit: [null, []], + chevronColor: [null, []], + }); + this.countWidgetConfigForm.valueChanges.subscribe(() => { + this.updateModel(); + }); + for (const trigger of ['showLabel', 'showIcon', 'showIconBackground', 'showChevron']) { + const path = trigger.split('.'); + let control: AbstractControl = this.countWidgetConfigForm; + for (const part of path) { + control = this.countWidgetConfigForm.get(part); + } + control.valueChanges.subscribe(() => { + this.updateValidators(); + }); + } + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (isDisabled) { + this.countWidgetConfigForm.disable({emitEvent: false}); + } else { + this.countWidgetConfigForm.enable({emitEvent: false}); + this.updateValidators(); + } + } + + writeValue(value: CountWidgetSettings): void { + this.countWidgetConfigForm.patchValue( + value, {emitEvent: false} + ); + this.updateValidators(); + } + + private updateModel() { + const value: CountWidgetSettings = this.countWidgetConfigForm.value; + this.propagateChange(value); + } + + protected updateValidators() { + const showLabel: boolean = this.countWidgetConfigForm.get('showLabel').value; + const showIcon: boolean = this.countWidgetConfigForm.get('showIcon').value; + const showIconBackground: boolean = this.countWidgetConfigForm.get('showIconBackground').value; + const showChevron: boolean = this.countWidgetConfigForm.get('showChevron').value; + + if (showLabel) { + this.countWidgetConfigForm.get('label').enable({emitEvent: false}); + this.countWidgetConfigForm.get('labelFont').enable({emitEvent: false}); + this.countWidgetConfigForm.get('labelColor').enable({emitEvent: false}); + } else { + this.countWidgetConfigForm.get('label').disable({emitEvent: false}); + this.countWidgetConfigForm.get('labelFont').disable({emitEvent: false}); + this.countWidgetConfigForm.get('labelColor').disable({emitEvent: false}); + } + + if (showIcon) { + this.countWidgetConfigForm.get('iconSize').enable({emitEvent: false}); + this.countWidgetConfigForm.get('iconSizeUnit').enable({emitEvent: false}); + this.countWidgetConfigForm.get('icon').enable({emitEvent: false}); + this.countWidgetConfigForm.get('iconColor').enable({emitEvent: false}); + } else { + this.countWidgetConfigForm.get('iconSize').disable({emitEvent: false}); + this.countWidgetConfigForm.get('iconSizeUnit').disable({emitEvent: false}); + this.countWidgetConfigForm.get('icon').disable({emitEvent: false}); + this.countWidgetConfigForm.get('iconColor').disable({emitEvent: false}); + } + + if (showIconBackground) { + this.countWidgetConfigForm.get('iconBackgroundSize').enable({emitEvent: false}); + this.countWidgetConfigForm.get('iconBackgroundSizeUnit').enable({emitEvent: false}); + this.countWidgetConfigForm.get('iconBackgroundColor').enable({emitEvent: false}); + } else { + this.countWidgetConfigForm.get('iconBackgroundSize').disable({emitEvent: false}); + this.countWidgetConfigForm.get('iconBackgroundSizeUnit').disable({emitEvent: false}); + this.countWidgetConfigForm.get('iconBackgroundColor').disable({emitEvent: false}); + } + + if (showChevron) { + this.countWidgetConfigForm.get('chevronSize').enable({emitEvent: false}); + this.countWidgetConfigForm.get('chevronSizeUnit').enable({emitEvent: false}); + this.countWidgetConfigForm.get('chevronColor').enable({emitEvent: false}); + } else { + this.countWidgetConfigForm.get('chevronSize').disable({emitEvent: false}); + this.countWidgetConfigForm.get('chevronSizeUnit').disable({emitEvent: false}); + this.countWidgetConfigForm.get('chevronColor').disable({emitEvent: false}); + } + } + + protected readonly valueCardLayoutTranslations = valueCardLayoutTranslations; + protected readonly valueCardLayoutImages = valueCardLayoutImages; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts index 6c383062ae..5a2a91b56b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts @@ -40,6 +40,9 @@ import { BackgroundSettingsComponent } from '@home/components/widget/lib/setting import { BackgroundSettingsPanelComponent } from '@home/components/widget/lib/settings/common/background-settings-panel.component'; +import { + CountWidgetSettingsComponent +} from "@home/components/widget/lib/settings/common/count-widget-settings.component"; @NgModule({ declarations: [ @@ -56,7 +59,8 @@ import { BackgroundSettingsPanelComponent, ValueSourceComponent, LegendConfigComponent, - WidgetFontComponent + WidgetFontComponent, + CountWidgetSettingsComponent ], imports: [ CommonModule, @@ -77,7 +81,8 @@ import { BackgroundSettingsPanelComponent, ValueSourceComponent, LegendConfigComponent, - WidgetFontComponent + WidgetFontComponent, + CountWidgetSettingsComponent ] }) export class WidgetSettingsCommonModule { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.html new file mode 100644 index 0000000000..e38fab6e27 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.html @@ -0,0 +1,23 @@ + + +
+
widgets.entity-count.entity-count-card-style
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.ts new file mode 100644 index 0000000000..348c893316 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.ts @@ -0,0 +1,62 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { countDefaultSettings } from '@home/components/widget/lib/count/count-widget.models'; + +@Component({ + selector: 'tb-entity-count-widget-settings', + templateUrl: './entity-count-widget-settings.component.html', + styleUrls: ['./../widget-settings.scss'] +}) +export class EntityCountWidgetSettingsComponent extends WidgetSettingsComponent { + + entityCountWidgetSettingsForm: UntypedFormGroup; + + constructor(protected store: Store, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.entityCountWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...countDefaultSettings(false)}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.entityCountWidgetSettingsForm = this.fb.group({ + entityCountSettings: [settings.entityCountSettings, []], + }); + } + + protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { + return { + entityCountSettings: settings + }; + } + + protected prepareOutputSettings(settings: any): WidgetSettings { + return settings.entityCountSettings; + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index e4ca0eb4d4..622f5a0c2a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -42,16 +42,16 @@ import { } from '@home/components/widget/lib/settings/cards/dashboard-state-widget-settings.component'; import { EntitiesHierarchyWidgetSettingsComponent -} from '@home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component'; +} from '@home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component'; import { HtmlCardWidgetSettingsComponent } from '@home/components/widget/lib/settings/cards/html-card-widget-settings.component'; import { EntitiesTableWidgetSettingsComponent -} from '@home/components/widget/lib/settings/cards/entities-table-widget-settings.component'; +} from '@home/components/widget/lib/settings/entity/entities-table-widget-settings.component'; import { EntitiesTableKeySettingsComponent -} from '@home/components/widget/lib/settings/cards/entities-table-key-settings.component'; +} from '@home/components/widget/lib/settings/entity/entities-table-key-settings.component'; import { AlarmsTableWidgetSettingsComponent } from '@home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component'; @@ -279,6 +279,12 @@ import { import { AggregatedValueCardWidgetSettingsComponent } from '@home/components/widget/lib/settings/cards/aggregated-value-card-widget-settings.component'; +import { + AlarmCountWidgetSettingsComponent +} from '@home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component'; +import { + EntityCountWidgetSettingsComponent +} from '@home/components/widget/lib/settings/entity/entity-count-widget-settings.component'; @NgModule({ declarations: [ @@ -382,7 +388,9 @@ import { QuickLinksWidgetSettingsComponent, ValueCardWidgetSettingsComponent, AggregatedValueCardKeySettingsComponent, - AggregatedValueCardWidgetSettingsComponent + AggregatedValueCardWidgetSettingsComponent, + AlarmCountWidgetSettingsComponent, + EntityCountWidgetSettingsComponent ], imports: [ CommonModule, @@ -491,7 +499,9 @@ import { QuickLinksWidgetSettingsComponent, ValueCardWidgetSettingsComponent, AggregatedValueCardKeySettingsComponent, - AggregatedValueCardWidgetSettingsComponent + AggregatedValueCardWidgetSettingsComponent, + AlarmCountWidgetSettingsComponent, + EntityCountWidgetSettingsComponent ] }) export class WidgetSettingsModule { @@ -565,5 +575,7 @@ export const widgetSettingsComponentsMap: {[key: string]: Type diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.ts b/ui-ngx/src/app/shared/components/material-icon-select.component.ts index 255aeb0668..a7af6eaa70 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.ts +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.ts @@ -51,6 +51,9 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit @Input() color: string; + @Input() + backgroundColor: string; + @Input() disabled: boolean; diff --git a/ui-ngx/src/app/shared/models/widget-settings.models.ts b/ui-ngx/src/app/shared/models/widget-settings.models.ts index 4bba815a37..2769a635e4 100644 --- a/ui-ngx/src/app/shared/models/widget-settings.models.ts +++ b/ui-ngx/src/app/shared/models/widget-settings.models.ts @@ -20,6 +20,8 @@ import { Injector } from '@angular/core'; import { DatePipe } from '@angular/common'; import { DateAgoPipe } from '@shared/pipe/date-ago.pipe'; import { TranslateService } from '@ngx-translate/core'; +import { AlarmFilterConfig } from '@shared/models/query/query.models'; +import { AlarmSearchStatus } from '@shared/models/alarm.models'; export type ComponentStyle = {[klass: string]: any}; @@ -111,13 +113,15 @@ export const defaultTimewindowStyle: TimewindowStyle = { export const constantColor = (color: string): ColorSettings => ({ type: ColorType.constant, color, - colorFunction: 'var temperature = value;\n' + + colorFunction: defaultColorFunction +}); + +export const defaultColorFunction = 'var temperature = value;\n' + 'if (typeof temperature !== undefined) {\n' + ' var percent = (temperature + 60)/120 * 100;\n' + ' return tinycolor.mix(\'blue\', \'red\', percent).toHexString();\n' + '}\n' + - 'return \'blue\';' -}); + 'return \'blue\';'; export const cssSizeToStrSize = (size?: number, unit?: cssUnit): string => (isDefinedAndNotNull(size) ? size + '' : '0') + (unit || 'px'); @@ -422,6 +426,22 @@ export const getDataKey = (datasources?: Datasource[]): DataKey => { return null; }; +export const getAlarmFilterConfig = (datasources?: Datasource[]): AlarmFilterConfig => { + if (datasources && datasources.length) { + const config = datasources[0].alarmFilterConfig; + if (config) { + return config; + } + } + return { statusList: [ AlarmSearchStatus.ACTIVE ] }; +}; + +export const setAlarmFilterConfig = (config: AlarmFilterConfig, datasources?: Datasource[]): void => { + if (datasources && datasources.length) { + datasources[0].alarmFilterConfig = config; + } +}; + export const getLabel = (datasources?: Datasource[]): string => { const dataKey = getDataKey(datasources); if (dataKey) { diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index c04eb6f7ec..a08d8837f5 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -179,6 +179,7 @@ export interface WidgetTypeParameters { previewWidth?: string; previewHeight?: string; embedTitlePanel?: boolean; + hideDataSettings?: boolean; } export interface WidgetControllerDescriptor { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 6ed0b5fde5..8a93e1bbfd 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -6084,6 +6084,22 @@ "aggregation": "Aggregation", "aggregated-value-card-style": "Aggregated value card style" }, + "alarm-count": { + "alarm-count-card-style": "Alarm count card style" + }, + "entity-count": { + "entity-count-card-style": "Entity count card style" + }, + "count": { + "layout": "Layout", + "layout-column": "Column", + "layout-row": "Row", + "label": "Label", + "icon": "Icon", + "icon-background": "Icon background", + "value": "Value", + "chevron": "Chevron" + }, "table": { "common-table-settings": "Common Table Settings", "enable-search": "Enable search", @@ -6403,7 +6419,8 @@ "element-click": "On HTML element click", "pie-slice-click": "On slice click", "row-double-click": "On row double click", - "action-button-click": "Action button click" + "action-button-click": "Action button click", + "card-click": "On card click" } }, "paginator" : { diff --git a/ui-ngx/src/assets/widget/alarm-count/column-layout.svg b/ui-ngx/src/assets/widget/alarm-count/column-layout.svg new file mode 100644 index 0000000000..d797417a65 --- /dev/null +++ b/ui-ngx/src/assets/widget/alarm-count/column-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/alarm-count/row-layout.svg b/ui-ngx/src/assets/widget/alarm-count/row-layout.svg new file mode 100644 index 0000000000..2519f5c411 --- /dev/null +++ b/ui-ngx/src/assets/widget/alarm-count/row-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/entity-count/column-layout.svg b/ui-ngx/src/assets/widget/entity-count/column-layout.svg new file mode 100644 index 0000000000..44cab51f33 --- /dev/null +++ b/ui-ngx/src/assets/widget/entity-count/column-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/entity-count/row-layout.svg b/ui-ngx/src/assets/widget/entity-count/row-layout.svg new file mode 100644 index 0000000000..06a5778426 --- /dev/null +++ b/ui-ngx/src/assets/widget/entity-count/row-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +