From 4e42f0a33fa8806e93393c19fbc5fe9838aed7ee Mon Sep 17 00:00:00 2001 From: mpetrov Date: Thu, 13 Mar 2025 17:53:21 +0200 Subject: [PATCH 01/30] Added md help files for REST connector --- .../en_US/widget/lib/gateway/rest-json_fn.md | 53 +++++++++++++++++++ .../en_US/widget/lib/gateway/rest-url_fn.md | 53 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md new file mode 100644 index 0000000000..9b3012c00d --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md @@ -0,0 +1,53 @@ +### JSON Path: + +The expression field is used to extract data from the HTTP response message. + +JSONPath expressions specify the items within a JSON structure (which could be an object, array, or nested combination of both) that you want to access. These expressions can select elements from JSON data on specific criteria. Here's a basic overview of how JSONPath expressions are structured: + +- `$`: The root element of the JSON document; +- `.`: Child operator used to select child elements. For example, $.store.book ; +- `[]`: Child operator used to select child elements. $['store']['book'] accesses the book array within a store object; + +### Examples: + +For example, if we want to extract the device name from the following message, we can use the expression below: + +HTTP response message: + +```json +{ + "sensorModelInfo": { + "sensorName": "AM-123", + "sensorType": "myDeviceType" + }, + "data": { + "temp": 12.2, + "hum": 56, + "status": "ok" + } +} +``` + +Expression: + +`${sensorModelInfo.sensorName}` + +Converted data: + +`AM-123` + +If we want to extract all data from the message above, we can use the following expression: + +`${data}` + +Converted data: + +`{"temp": 12.2, "hum": 56, "status": "ok"}` + +Or if we want to extract specific data (for example “temperature”), you can use the following expression: + +`${data.temp}` + +And as a converted data we will get: + +`12.2` diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md new file mode 100644 index 0000000000..eccb52b96e --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md @@ -0,0 +1,53 @@ +## Request URL expression + +JSONPath expression uses for creating url address to send a message. + +JSONPath expressions specify the items within a JSON structure (which could be an object, array, or nested combination of both) that you want to access. These expressions can select elements from JSON data on specific criteria. Here's a basic overview of how JSONPath expressions are structured: + +- `$`: The root element of the JSON document; +- `.`: Child operator used to select child elements. For example, $.store.book ; +- `[]`: Child operator used to select child elements. $['store']['book'] accesses the book array within a store object; + +### Examples: + +For example, if we want to extract the device name from the following message, we can use the expression below: + +HTTP response message: + +```json +{ + "sensorModelInfo": { + "sensorName": "AM-123", + "sensorType": "myDeviceType" + }, + "data": { + "temp": 12.2, + "hum": 56, + "status": "ok" + } +} +``` + +Expression: + +`${sensorModelInfo.sensorName}` + +Converted data: + +`AM-123` + +If we want to extract all data from the message above, we can use the following expression: + +`${data}` + +Converted data: + +`{"temp": 12.2, "hum": 56, "status": "ok"}` + +Or if we want to extract specific data (for example “temperature”), you can use the following expression: + +`${data.temp}` + +And as a converted data we will get: + +`12.2` From 3061cc17bb18e73746ece4959d0a12e1de402c6d Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 18 Mar 2025 18:21:12 +0200 Subject: [PATCH 02/30] Updated md files --- .../en_US/widget/lib/gateway/rest-json_fn.md | 15 ++++++++------- .../en_US/widget/lib/gateway/rest-url_fn.md | 17 +++++++++-------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md index 9b3012c00d..14e0a86d6a 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md @@ -1,6 +1,7 @@ -### JSON Path: +### Expressions +#### JSON Path -The expression field is used to extract data from the HTTP response message. +The expression field is used to specify the path for extracting data from an HTTP response message. JSONPath expressions specify the items within a JSON structure (which could be an object, array, or nested combination of both) that you want to access. These expressions can select elements from JSON data on specific criteria. Here's a basic overview of how JSONPath expressions are structured: @@ -8,7 +9,7 @@ JSONPath expressions specify the items within a JSON structure (which could be a - `.`: Child operator used to select child elements. For example, $.store.book ; - `[]`: Child operator used to select child elements. $['store']['book'] accesses the book array within a store object; -### Examples: +#### Examples For example, if we want to extract the device name from the following message, we can use the expression below: @@ -28,7 +29,7 @@ HTTP response message: } ``` -Expression: +JSON Path Expression `${sensorModelInfo.sensorName}` @@ -36,7 +37,7 @@ Converted data: `AM-123` -If we want to extract all data from the message above, we can use the following expression: +For extracting all data from the message above, use: `${data}` @@ -44,10 +45,10 @@ Converted data: `{"temp": 12.2, "hum": 56, "status": "ok"}` -Or if we want to extract specific data (for example “temperature”), you can use the following expression: +For extracting a specific value, such as the temperature, use: `${data.temp}` -And as a converted data we will get: +Converted data: `12.2` diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md index eccb52b96e..33ff4e6172 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md @@ -1,14 +1,15 @@ -## Request URL expression +### Expressions +#### Request URL -JSONPath expression uses for creating url address to send a message. +JSONPath expressions are used to construct URL addresses for sending messages. -JSONPath expressions specify the items within a JSON structure (which could be an object, array, or nested combination of both) that you want to access. These expressions can select elements from JSON data on specific criteria. Here's a basic overview of how JSONPath expressions are structured: +JSONPath expressions specify items within a JSON structure (objects, arrays, or a nested combination) that you wish to access. These expressions can select elements from JSON data on specific criteria. Here's a basic overview of how JSONPath expressions are structured: - `$`: The root element of the JSON document; - `.`: Child operator used to select child elements. For example, $.store.book ; - `[]`: Child operator used to select child elements. $['store']['book'] accesses the book array within a store object; -### Examples: +#### Examples For example, if we want to extract the device name from the following message, we can use the expression below: @@ -28,7 +29,7 @@ HTTP response message: } ``` -Expression: +Url Expression: `${sensorModelInfo.sensorName}` @@ -36,7 +37,7 @@ Converted data: `AM-123` -If we want to extract all data from the message above, we can use the following expression: +For extracting all data from the message above, use: `${data}` @@ -44,10 +45,10 @@ Converted data: `{"temp": 12.2, "hum": 56, "status": "ok"}` -Or if we want to extract specific data (for example “temperature”), you can use the following expression: +For extracting specific data (e.g., "temperature"), use: `${data.temp}` -And as a converted data we will get: +Converted data: `12.2` From 9ff052e9c06bf3f33ad328382ec27a9838e259ea Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 18 Mar 2025 18:25:51 +0200 Subject: [PATCH 03/30] Updated md files --- .../src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md | 4 ++-- .../src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md index 14e0a86d6a..fe41a2c610 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md @@ -37,7 +37,7 @@ Converted data: `AM-123` -For extracting all data from the message above, use: +To extract all data from the message above, use: `${data}` @@ -45,7 +45,7 @@ Converted data: `{"temp": 12.2, "hum": 56, "status": "ok"}` -For extracting a specific value, such as the temperature, use: +To extract a specific value, such as the temperature, use: `${data.temp}` diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md index 33ff4e6172..a30deb6203 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md @@ -37,7 +37,7 @@ Converted data: `AM-123` -For extracting all data from the message above, use: +To extract all data from the message above, use: `${data}` @@ -45,7 +45,7 @@ Converted data: `{"temp": 12.2, "hum": 56, "status": "ok"}` -For extracting specific data (e.g., "temperature"), use: +To extract specific data (e.g., "temperature"), use: `${data.temp}` From 46c9547f98b84a11c85bd6a94d037c2bb9e0b908 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 19 Mar 2025 09:40:37 +0200 Subject: [PATCH 04/30] UI: Fixed label for digits and add default value for major ticks --- .../config/basic/gauge/analog-gauge-basic-config.component.html | 2 +- .../settings/gauge/analogue-gauge-widget-settings.component.ts | 2 +- ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.html index a08aefb103..d4246c51ca 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/gauge/analog-gauge-basic-config.component.html @@ -73,7 +73,7 @@
-
widget-config.decimals-suffix
+
widget-config.digits-suffix
Date: Wed, 19 Mar 2025 12:04:34 +0200 Subject: [PATCH 05/30] UI: Add new predefined example when created action place map item --- .../common/action/custom-action.models.ts | 12 +++ .../action/place-map-item-sample-html.raw | 82 +++++++++++++++++ .../action/place-map-item-sample-js.raw | 89 +++++++++++++++++++ .../common/action/widget-action.component.ts | 5 +- .../entity/entity-type-select.component.html | 4 +- .../entity/entity-type-select.component.ts | 4 + 6 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-html.raw create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts index 1b63e97ad6..40f1a6c819 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts @@ -22,6 +22,8 @@ import { deepClone, isDefined, isUndefined } from '@core/utils'; import customSampleJs from './custom-sample-js.raw'; import customSampleCss from './custom-sample-css.raw'; import customSampleHtml from './custom-sample-html.raw'; +import placeMapItemSampleHtml from './place-map-item-sample-html.raw'; +import placeMapItemSampleJs from './place-map-item-sample-js.raw'; const customActionCompletions: TbEditorCompletions = { ...{ @@ -96,5 +98,15 @@ export const toCustomAction = (action: WidgetAction): CustomActionDescriptor => return result; }; +export const toPlaceMapItemAction = (action: WidgetAction): CustomActionDescriptor => { + const result: CustomActionDescriptor = { + customHtml: action?.customHtml ?? placeMapItemSampleHtml, + customCss: action?.customCss ?? '', + customFunction: action?.customFunction ?? placeMapItemSampleJs + }; + result.customResources = isDefined(action?.customResources) ? deepClone(action.customResources) : []; + return result; +}; + export const CustomActionEditorCompleter = new TbEditorCompleter(customActionCompletions); export const CustomPrettyActionEditorCompleter = new TbEditorCompleter(customPrettyActionCompletions); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-html.raw b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-html.raw new file mode 100644 index 0000000000..bb36a39986 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-html.raw @@ -0,0 +1,82 @@ + + + + +
+ +

Add entity

+ + +
+ + +
+
+
+ + Entity Name + + + Entity name is required. + + + + Entity Label + + +
+
+ + + +
+
+
+ + Address + + + + Owner + + +
+
+
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw new file mode 100644 index 0000000000..cb8c23faee --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw @@ -0,0 +1,89 @@ +/*========================================================================*/ +/*========================= Add entity example =========================*/ +/*========================================================================*/ + +let $injector = widgetContext.$scope.$injector; +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); +let assetService = $injector.get(widgetContext.servicesMap.get('assetService')); +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); + +openAddEntityDialog(); + +function openAddEntityDialog() { + customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe(); +} + +function AddEntityDialogController(instance) { + let vm = instance; + + vm.allowedEntityTypes = ['ASSET', 'DEVICE']; + + vm.addEntityFormGroup = vm.fb.group({ + entityName: ['', [vm.validators.required]], + entityType: ['DEVICE'], + entityLabel: [null], + type: ['', [vm.validators.required]], + attributes: vm.fb.group({ + address: [null], + owner: [null] + }) + }); + + vm.cancel = function() { + vm.dialogRef.close(null); + }; + + vm.save = function() { + vm.addEntityFormGroup.markAsPristine(); + saveEntityObservable().pipe( + widgetContext.rxjs.switchMap((entity) => saveAttributes(entity.id)) + ).subscribe(() => { + widgetContext.updateAliases(); + vm.dialogRef.close(null); + }); + }; + + function saveEntityObservable() { + const formValues = vm.addEntityFormGroup.value; + let entity = { + name: formValues.entityName, + type: formValues.type, + label: formValues.entityLabel + }; + if (formValues.entityType == 'ASSET') { + return assetService.saveAsset(entity); + } else if (formValues.entityType == 'DEVICE') { + return deviceService.saveDevice(entity); + } + } + + function saveAttributes(entityId) { + let attributes = vm.addEntityFormGroup.get('attributes').value; + let attributesArray = getMapItemLocationAttributes(); + for (let key in attributes) { + if(attributes[key] !== null) { + attributesArray.push({key: key, value: attributes[key]}); + } + } + if (attributesArray.length > 0) { + return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray); + } + return widgetContext.rxjs.of([]); + } + + function getMapItemLocationAttributes() { + const attributes = []; + const mapItemType = $event.shape; + if (mapItemType === 'Marker') { + const mapType = widgetContext.mapInstance.type(); + attributes.push({key: mapType === 'image' ? 'xPos' : 'latitude', value: additionalParams.coordinates.x}); + attributes.push({key: mapType === 'image' ? 'yPos' : 'longitude', value: additionalParams.coordinates.y}); + } else if (mapItemType === 'Rectangle' || mapItemType === 'Polygon') { + attributes.push({key: 'perimeter', value: additionalParams.coordinates}); + } else if (mapItemType === 'Circle') { + attributes.push({key: 'circle', value: additionalParams.coordinates}); + } + return attributes; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts index 932c0e52c3..bd0fe36910 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts @@ -48,7 +48,8 @@ import { TranslateService } from '@ngx-translate/core'; import { PopoverPlacement, PopoverPlacements } from '@shared/components/popover.models'; import { CustomActionEditorCompleter, - toCustomAction + toCustomAction, + toPlaceMapItemAction } from '@home/components/widget/lib/settings/common/action/custom-action.models'; import { coerceBoolean } from '@shared/decorators/coercion'; @@ -336,7 +337,7 @@ export class WidgetActionComponent implements ControlValueAccessor, OnInit, Vali ); this.actionTypeFormGroup.addControl( 'customAction', - this.fb.control(toCustomAction(action), [Validators.required]) + this.fb.control(toPlaceMapItemAction(action), [Validators.required]) ); break; } diff --git a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.html b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.html index c85fc4eb21..b21734cfdd 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.html @@ -15,9 +15,9 @@ limitations under the License. --> - + {{ 'entity.type' | translate }} - + {{ displayEntityTypeFn(type) }} diff --git a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts index 773222dcec..82b3fcf572 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts @@ -32,6 +32,7 @@ import { AliasEntityType, EntityType, entityTypeTranslations } from '@app/shared import { EntityService } from '@core/http/entity.service'; import { coerceBoolean } from '@shared/decorators/coercion'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { MatFormFieldAppearance } from '@angular/material/form-field'; @Component({ selector: 'tb-entity-type-select', @@ -69,6 +70,9 @@ export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit, @Input() disabled: boolean; + @Input() + appearance: MatFormFieldAppearance = 'fill'; + @Input() additionEntityTypes: {[key in string]: string} = {}; From 3b925df445da22512171d29ee8ee4673acf92829 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Wed, 19 Mar 2025 14:22:53 +0200 Subject: [PATCH 06/30] Updated md files --- .../en_US/widget/lib/gateway/rest-json_fn.md | 52 +++++++++--------- .../en_US/widget/lib/gateway/rest-url_fn.md | 54 ------------------- 2 files changed, 24 insertions(+), 82 deletions(-) delete mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md index fe41a2c610..32143694df 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-json_fn.md @@ -1,9 +1,11 @@ ### Expressions #### JSON Path -The expression field is used to specify the path for extracting data from an HTTP response message. +The expression field is used to specify the path for extracting data from an incoming HTTP request body. -JSONPath expressions specify the items within a JSON structure (which could be an object, array, or nested combination of both) that you want to access. These expressions can select elements from JSON data on specific criteria. Here's a basic overview of how JSONPath expressions are structured: +JSONPath expressions specifies the items within a JSON structure (which could be an object, array, or nested combination of both) that you want to access. +These expressions can select elements from JSON data on specific criteria. +Basic overview of how JSONPath expressions are structured: - `$`: The root element of the JSON document; - `.`: Child operator used to select child elements. For example, $.store.book ; @@ -11,9 +13,7 @@ JSONPath expressions specify the items within a JSON structure (which could be a #### Examples -For example, if we want to extract the device name from the following message, we can use the expression below: - -HTTP response message: +Incoming request body: ```json { @@ -25,30 +25,26 @@ HTTP response message: "temp": 12.2, "hum": 56, "status": "ok" - } + }, + "rxInfo": [ + { + "rssi": 50, + "snr": 3 + }, + { + "rssi": 22, + "snr": 1 + } + ] } ``` +
-JSON Path Expression - -`${sensorModelInfo.sensorName}` - -Converted data: - -`AM-123` - -To extract all data from the message above, use: - -`${data}` - -Converted data: - -`{"temp": 12.2, "hum": 56, "status": "ok"}` - -To extract a specific value, such as the temperature, use: - -`${data.temp}` - -Converted data: +Examples below shows on how to extract values from incoming request body. -`12.2` +| JSON Path Expression | Extracted data | +|---------------------------------|---------------------------------------------| +| `${sensorModelInfo.sensorName}` | `AM-123` | +| `${data}` | `{"temp": 12.2, "hum": 56, "status": "ok"}` | +| `${$.data.temp}` | `12.2` | +| `${$.rxInfo[0].rssi}` | `50` | diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md deleted file mode 100644 index a30deb6203..0000000000 --- a/ui-ngx/src/assets/help/en_US/widget/lib/gateway/rest-url_fn.md +++ /dev/null @@ -1,54 +0,0 @@ -### Expressions -#### Request URL - -JSONPath expressions are used to construct URL addresses for sending messages. - -JSONPath expressions specify items within a JSON structure (objects, arrays, or a nested combination) that you wish to access. These expressions can select elements from JSON data on specific criteria. Here's a basic overview of how JSONPath expressions are structured: - -- `$`: The root element of the JSON document; -- `.`: Child operator used to select child elements. For example, $.store.book ; -- `[]`: Child operator used to select child elements. $['store']['book'] accesses the book array within a store object; - -#### Examples - -For example, if we want to extract the device name from the following message, we can use the expression below: - -HTTP response message: - -```json -{ - "sensorModelInfo": { - "sensorName": "AM-123", - "sensorType": "myDeviceType" - }, - "data": { - "temp": 12.2, - "hum": 56, - "status": "ok" - } -} -``` - -Url Expression: - -`${sensorModelInfo.sensorName}` - -Converted data: - -`AM-123` - -To extract all data from the message above, use: - -`${data}` - -Converted data: - -`{"temp": 12.2, "hum": 56, "status": "ok"}` - -To extract specific data (e.g., "temperature"), use: - -`${data.temp}` - -Converted data: - -`12.2` From 82bb007aaf909a346142f657b0559e4868433f7a Mon Sep 17 00:00:00 2001 From: mpetrov Date: Wed, 19 Mar 2025 15:43:20 +0200 Subject: [PATCH 07/30] Fixed import of current tenant shows error --- .../calculated-fields-table-config.ts | 21 +++++++++++++++++-- ...lated-field-arguments-table.component.html | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 1cf44966fc..37dc5d69e7 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -37,6 +37,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { CalculatedFieldsService } from '@core/http/calculated-fields.service'; import { catchError, filter, switchMap, tap } from 'rxjs/operators'; import { + ArgumentEntityType, ArgumentType, CalculatedField, CalculatedFieldEventArguments, @@ -60,7 +61,7 @@ import { DatePipe } from '@angular/common'; export class CalculatedFieldsTableConfig extends EntityTableConfig { readonly calculatedFieldsDebugPerTenantLimitsConfiguration = - getCurrentAuthState(this.store)['calculatedFieldsDebugPerTenantLimitsConfiguration'] || '1:1'; + getCurrentAuthState(this.store)['calculatedFieldsDebugPerTenantLimitsConfiguration']; readonly maxDebugModeDuration = getCurrentAuthState(this.store).maxDebugModeDurationMinutes * MINUTE; readonly tenantId = getCurrentAuthUser(this.store).tenantId; additionalDebugActionConfig = { @@ -252,7 +253,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig this.getCalculatedFieldDialog(calculatedField, 'action.add')), + switchMap(calculatedField => this.getCalculatedFieldDialog(this.updateImportedCalculatedField(calculatedField), 'action.add', true)), filter(Boolean), switchMap(calculatedField => this.calculatedFieldsService.saveCalculatedField(calculatedField)), filter(Boolean), @@ -261,6 +262,22 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig this.updateData()); } + private updateImportedCalculatedField(calculatedField: CalculatedField): CalculatedField { + return { + ...calculatedField, + configuration: { + ...calculatedField.configuration, + arguments: Object.keys(calculatedField.configuration.arguments).reduce((acc, key) => { + const arg = calculatedField.configuration.arguments[key]; + acc[key] = arg.refEntityId?.entityType === ArgumentEntityType.Tenant + ? { ...arg, refEntityId: { id: this.tenantId, entityType: ArgumentEntityType.Tenant } } + : arg; + return acc; + }, {}) + } + } + } + private onDebugConfigChanged(id: string, debugSettings: EntityDebugSettings): void { this.calculatedFieldsService.getCalculatedFieldById(id).pipe( switchMap(field => this.calculatedFieldsService.saveCalculatedField({ ...field, debugSettings })), diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html index abb34cb502..39cd4b757c 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html @@ -58,7 +58,7 @@
- @if (argument.refEntityId?.id) { + @if (argument.refEntityId?.id && argument.refEntityId?.entityType !== ArgumentEntityType.Tenant) { {{ entityNameMap.get(argument.refEntityId.id) ?? '' }} From 47232a629bf79ef1b7a47c80696bc7bd1ed81473 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Wed, 19 Mar 2025 17:20:01 +0200 Subject: [PATCH 08/30] refactoring --- .../calculated-fields-table-config.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 37dc5d69e7..cc4a100b2b 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -263,18 +263,17 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig { + const arg = calculatedField.configuration.arguments[key]; + acc[key] = arg.refEntityId?.entityType === ArgumentEntityType.Tenant + ? { ...arg, refEntityId: { id: this.tenantId, entityType: ArgumentEntityType.Tenant } } + : arg; + return acc; + }, {}); + return { ...calculatedField, - configuration: { - ...calculatedField.configuration, - arguments: Object.keys(calculatedField.configuration.arguments).reduce((acc, key) => { - const arg = calculatedField.configuration.arguments[key]; - acc[key] = arg.refEntityId?.entityType === ArgumentEntityType.Tenant - ? { ...arg, refEntityId: { id: this.tenantId, entityType: ArgumentEntityType.Tenant } } - : arg; - return acc; - }, {}) - } + configuration: { ...calculatedField.configuration, arguments: updatedArguments } } } From 1cc03d63e2582938729bf0b7e47adfb48c0432ae Mon Sep 17 00:00:00 2001 From: mpetrov Date: Wed, 19 Mar 2025 17:33:11 +0200 Subject: [PATCH 09/30] refactoring --- .../calculated-fields/calculated-fields-table-config.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index cc4a100b2b..69c0a35fb5 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -263,7 +263,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig { + calculatedField.configuration.arguments = Object.keys(calculatedField.configuration.arguments).reduce((acc, key) => { const arg = calculatedField.configuration.arguments[key]; acc[key] = arg.refEntityId?.entityType === ArgumentEntityType.Tenant ? { ...arg, refEntityId: { id: this.tenantId, entityType: ArgumentEntityType.Tenant } } @@ -271,10 +271,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig Date: Thu, 20 Mar 2025 15:16:35 +0200 Subject: [PATCH 10/30] UI: Add map widgets helps --- .../map/map-data-layer-dialog.component.html | 6 +++-- .../common/map/map-settings.component.html | 4 ++-- .../widget/action/custom_additional_params.md | 23 ++++++++++++++++++- .../assets/locale/locale.constant-en_US.json | 4 ++++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html index 803cdd01f1..cc2d3ab031 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html @@ -430,7 +430,7 @@ }
-
{{ 'widgets.maps.data-layer.groups' | translate }}
+
{{ 'widgets.maps.data-layer.groups' | translate }}
- {{ 'widgets.maps.data-layer.enable-snapping' | translate }} + + {{ 'widgets.maps.data-layer.enable-snapping' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-settings.component.html index 38a5d13922..b8d9515564 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-settings.component.html @@ -36,7 +36,7 @@
-
+
{{ 'widgets.maps.overlays.overlays' | translate }}
-
+
{{ 'widgets.maps.data-layer.additional-datasources' | translate }}
formattedTs (a string value of formatted timestamp) and
timeseries values for each column declared in widget datasource configuration. - + +
  • Map widgets - additionalParams: FormattedData: +
      +
    • additionalParams: FormattedData - An object associated with a data layer (markers, polygons, circles) or with a specific data point of a route (for trips data layers).
      + It contains basic entity properties (ex. entityId, entityName) and provides access to additional attributes and timeseries defined in datasource of the data layer configuration. +
    • +
    +
  • +
  • Map widgets (Action type: Place map item) - additionalParams: {coordinates: Coordinates; layer: L.Layer}: +
      +
    • coordinates: Coordinates - Represents geographical coordinates of the placed map item. The actual format of this parameter depends on the type of the selected map item: +
        +
      • Marker: {x: number; y: number}, where x represents latitude, and y represents longitude.
      • +
      • Polygon, Rectangle: TbPolygonRawCoordinates contains an array of points defining the shape boundaries.
      • +
      • Circle: TbCircleData contains center coordinates and radius information.
      • +
      + Note: The coordinates will be automatically converted according to the selected map type. +
    • +
    • layer: L.Layer - The Leaflet map layer instance (e.g., marker, polygon, circle) associated with the placed map item. This object provides access to layer properties and methods defined in Leaflet's API. +
    • +
    +
  • Entities hierarchy widget (On node selected) - additionalParams: { nodeCtx: HierarchyNodeContext }:
    • nodeCtx: HierarchyNodeContext - An 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 61bdb48b7c..c294b0210a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -7976,6 +7976,7 @@ }, "overlays": { "overlays": "Overlays", + "overlays-hint": "Configure datasources, appearance, behavior, editing options, and grouping for map entities", "trips": "Trips", "markers": "Markers", "polygons": "Polygons", @@ -7985,6 +7986,7 @@ "source": "Source", "additional-data-keys": "Additional data keys", "additional-datasources": "Additional datasources", + "additional-datasources-hint": "Datasource for accessing attributes or telemetry from entities not displayed on the map, usable in map overlay functions.", "data-keys": "Data keys", "add-datasource": "Add datasource", "no-datasources": "No datasources configured", @@ -7993,6 +7995,7 @@ "on-click": "On click", "on-click-hint": "Action invoked when user clicks on the map item.", "groups": "Groups", + "groups-hint": "List of group names assigned to this datasource. Used to toggle visibility of datasource items on the map.", "color": "Color", "fill-color": "Fill color", "stroke": "Stroke", @@ -8030,6 +8033,7 @@ "edit-instruments": "Instruments", "persist-location-attribute-scope": "Scope of the attribute to persist location", "enable-snapping": "Enable snapping to other vertices for precision drawing", + "enable-snapping-hint": "Automatically aligns new points with existing shapes to make drawing easier and more accurate.", "drag-drop-mode": "Drag-drop mode", "trip": { "no-trips": "No trips configured", From 71eaef8dbaa75b92e35b7ec2cf9690a0b4e0fc0d Mon Sep 17 00:00:00 2001 From: Vladyslav Prykhodko Date: Fri, 21 Mar 2025 09:50:24 +0200 Subject: [PATCH 11/30] UI: Limit table content height in map layers with scroll on overflow --- .../widget/lib/settings/common/map/map-layers.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layers.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layers.component.html index 1f0c930802..9ce010c309 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layers.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layers.component.html @@ -23,7 +23,7 @@
      widgets.maps.layer.layer
  • -
    From 28019cc5ad4fa77a841b43f98859dde6c4a89b22 Mon Sep 17 00:00:00 2001 From: Vladyslav Prykhodko Date: Fri, 21 Mar 2025 13:06:34 +0200 Subject: [PATCH 12/30] UI: Disable close on outside click for parameter popovers --- .../home/components/vc/entity-version-diff.component.ts | 2 +- .../home/components/vc/entity-versions-table.component.ts | 8 ++++---- .../common/action/get-value-action-settings.component.ts | 2 +- .../common/action/set-value-action-settings.component.ts | 2 +- .../common/action/widget-action-settings.component.ts | 2 +- .../common/auto-date-format-settings.component.ts | 2 +- .../lib/settings/common/background-settings.component.ts | 5 +++-- .../common/button/widget-button-custom-style.component.ts | 2 +- .../button/widget-button-toggle-custom-style.component.ts | 2 +- .../time-series-chart-axis-settings-button.component.ts | 2 +- .../time-series-chart-threshold-settings.component.ts | 2 +- .../chart/time-series-chart-y-axis-row.component.ts | 2 +- .../lib/settings/common/color-range-settings.component.ts | 2 +- .../lib/settings/common/color-settings.component.ts | 2 +- .../lib/settings/common/date-format-select.component.ts | 4 ++-- .../dynamic-form/dynamic-form-property-row.component.ts | 2 +- .../widget/lib/settings/common/font-settings.component.ts | 2 +- .../common/map/data-layer-color-settings.component.ts | 2 +- .../lib/settings/common/map/map-layer-row.component.ts | 2 +- .../common/map/map-tooltip-tag-actions.component.ts | 2 +- .../common/map/marker-image-settings.component.ts | 2 +- ui-ngx/src/app/shared/components/js-func.component.ts | 2 +- 22 files changed, 28 insertions(+), 27 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts index 88d4079916..1908b5e1fa 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts @@ -305,7 +305,7 @@ export class EntityVersionDiffComponent extends PageComponent implements OnInit, this.popoverService.hidePopover(trigger); } else { const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', true, null, + this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', false, null, { versionName: this.versionName, versionId: this.versionId, diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts index 5ccadcd4cb..2a6d5c5962 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts @@ -212,7 +212,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni this.popoverService.hidePopover(trigger); } else { const createVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityVersionCreateComponent, 'leftTop', true, null, + this.viewContainerRef, EntityVersionCreateComponent, 'leftTop', false, null, { branch: this.branch, entityId: this.entityId, @@ -244,7 +244,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni this.popoverService.hidePopover(trigger); } else { const complexCreateVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ComplexVersionCreateComponent, 'leftTop', true, null, + this.viewContainerRef, ComplexVersionCreateComponent, 'leftTop', false, null, { branch: this.branch, onClose: (result: VersionCreationResult | null, branch: string | null) => { @@ -296,7 +296,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni this.popoverService.hidePopover(trigger); } else { const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', true, null, + this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', false, null, { versionName: entityVersion.name, versionId: entityVersion.id, @@ -323,7 +323,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni this.popoverService.hidePopover(trigger); } else { const restoreEntitiesVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ComplexVersionLoadComponent, 'leftTop', true, null, + this.viewContainerRef, ComplexVersionLoadComponent, 'leftTop', false, null, { versionName: entityVersion.name, versionId: entityVersion.id, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings.component.ts index 00cea43192..5b95ef5f13 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings.component.ts @@ -142,7 +142,7 @@ export class GetValueActionSettingsComponent implements OnInit, ControlValueAcce }; const getValueSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, this.viewContainerRef, GetValueActionSettingsPanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], true, null, + ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings.component.ts index 08345bb148..e446e6f5b3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings.component.ts @@ -125,7 +125,7 @@ export class SetValueActionSettingsComponent implements OnInit, ControlValueAcce }; const setValueSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, this.viewContainerRef, SetValueActionSettingsPanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], true, null, + ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action-settings.component.ts index 7731df6407..51583f71fb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action-settings.component.ts @@ -123,7 +123,7 @@ export class WidgetActionSettingsComponent implements OnInit, ControlValueAccess }; const widgetActionSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, this.viewContainerRef, WidgetActionSettingsPanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], true, null, + ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings.component.ts index ae4158e3ed..1d776bcb70 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings.component.ts @@ -83,7 +83,7 @@ export class AutoDateFormatSettingsComponent implements OnInit, ControlValueAcce defaultValues: this.defaultValues }; const autoDateFormatSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, AutoDateFormatSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, AutoDateFormatSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts index c25bd1c8fb..cadf5fb07a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts @@ -37,9 +37,10 @@ import { TbPopoverService } from '@shared/components/popover.service'; import { BackgroundSettingsPanelComponent } from '@home/components/widget/lib/settings/common/background-settings-panel.component'; -import { Observable, of } from 'rxjs'; +import { Observable, of, pipe } from 'rxjs'; import { ImagePipe } from '@shared/pipe/image.pipe'; import { DomSanitizer } from '@angular/platform-browser'; +import { tap } from 'rxjs/operators'; @Component({ selector: 'tb-background-settings', @@ -110,7 +111,7 @@ export class BackgroundSettingsComponent implements OnInit, ControlValueAccessor backgroundSettings: this.modelValue }; const backgroundSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, BackgroundSettingsPanelComponent, ['left'], true, null, + this.viewContainerRef, BackgroundSettingsPanelComponent, ['left'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style.component.ts index 5e4e049055..5db91fb1bb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style.component.ts @@ -133,7 +133,7 @@ export class WidgetButtonCustomStyleComponent implements OnInit, OnChanges, Cont }; const widgetButtonCustomStylePanelPopover = this.popoverService.displayPopover(trigger, this.renderer, this.viewContainerRef, WidgetButtonCustomStylePanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], true, null, + ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style.component.ts index 3e31420747..b2a78ff961 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style.component.ts @@ -137,7 +137,7 @@ export class WidgetButtonToggleCustomStyleComponent implements OnInit, OnChanges }; const widgetButtonCustomStylePanelPopover = this.popoverService.displayPopover(trigger, this.renderer, this.viewContainerRef, WidgetButtonToggleCustomStylePanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], true, null, + ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts index 25ce5238ef..2f2067f3a8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts @@ -92,7 +92,7 @@ export class TimeSeriesChartAxisSettingsButtonComponent implements OnInit, Contr advanced: this.advanced }; const axisSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, TimeSeriesChartAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, TimeSeriesChartAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts index abb40594d6..e3ff513e0f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts @@ -108,7 +108,7 @@ export class TimeSeriesChartThresholdSettingsComponent implements OnInit, Contro yAxisIds: this.yAxisIds }; const thresholdSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, TimeSeriesChartThresholdSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, TimeSeriesChartThresholdSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts index 425e436102..69cbc29a25 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts @@ -158,7 +158,7 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O advanced: this.advanced }; const yAxisSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, TimeSeriesChartAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, TimeSeriesChartAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-range-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-range-settings.component.ts index 10f574a9d4..431fac44da 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-range-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-range-settings.component.ts @@ -126,7 +126,7 @@ export class ColorRangeSettingsComponent implements OnInit, ControlValueAccessor settingsComponents: this.colorSettingsComponentService.getOtherColorSettingsComponents(this) }; const colorRangeSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ColorRangePanelComponent, 'left', true, null, + this.viewContainerRef, ColorRangePanelComponent, 'left', false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts index 484d46fa38..133fa11bd4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts @@ -171,7 +171,7 @@ export class ColorSettingsComponent implements OnInit, ControlValueAccessor, OnD maxValue: this.maxValue }; const colorSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ColorSettingsPanelComponent, 'left', true, null, + this.viewContainerRef, ColorSettingsPanelComponent, 'left', false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts index 3a626b528b..92aef0ba29 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts @@ -166,7 +166,7 @@ export class DateFormatSelectComponent implements OnInit, ControlValueAccessor { dateFormat: deepClone(this.modelValue) }; const dateFormatSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, DateFormatSettingsPanelComponent, 'top', true, null, + this.viewContainerRef, DateFormatSettingsPanelComponent, 'top', false, null, ctx, {}, {}, {}, true); @@ -192,7 +192,7 @@ export class DateFormatSelectComponent implements OnInit, ControlValueAccessor { defaultAutoDateFormatSettings, this.modelValue.autoDateFormatSettings) }; const autoDateFormatSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, AutoDateFormatSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, AutoDateFormatSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-row.component.ts index 96526da502..79c2254a7d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-row.component.ts @@ -175,7 +175,7 @@ export class DynamicFormPropertyRowComponent implements ControlValueAccessor, On property: deepClone(this.modelValue) }; const dynamicFormPropertyPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, DynamicFormPropertyPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, DynamicFormPropertyPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts index 9534dd3a3b..25addab5ea 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts @@ -110,7 +110,7 @@ export class FontSettingsComponent implements OnInit, ControlValueAccessor { } } const fontSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, FontSettingsPanelComponent, 'left', true, null, + this.viewContainerRef, FontSettingsPanelComponent, 'left', false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-color-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-color-settings.component.ts index 5f56bd85c3..8c94ed2c80 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-color-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-color-settings.component.ts @@ -106,7 +106,7 @@ export class DataLayerColorSettingsComponent implements ControlValueAccessor { helpId: this.helpId }; const colorSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, DataLayerColorSettingsPanelComponent, 'left', true, null, + this.viewContainerRef, DataLayerColorSettingsPanelComponent, 'left', false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts index 392c9f9565..d7d4f78433 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts @@ -184,7 +184,7 @@ export class MapLayerRowComponent implements ControlValueAccessor, OnInit { mapLayerSettings: deepClone(this.modelValue) }; const mapLayerSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, MapLayerSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, MapLayerSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-tooltip-tag-actions.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-tooltip-tag-actions.component.ts index ba52e41b84..6cf5791406 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-tooltip-tag-actions.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-tooltip-tag-actions.component.ts @@ -162,7 +162,7 @@ export class MapTooltipTagActionsComponent implements ControlValueAccessor, OnIn }; const widgetActionSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, this.viewContainerRef, WidgetActionSettingsPanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], true, null, + ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-image-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-image-settings.component.ts index 21600392df..2d8feb817f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-image-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-image-settings.component.ts @@ -80,7 +80,7 @@ export class MarkerImageSettingsComponent implements ControlValueAccessor { markerImageSettings: this.modelValue, }; const markerImageSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, MarkerImageSettingsPanelComponent, 'left', true, null, + this.viewContainerRef, MarkerImageSettingsPanelComponent, 'left', false, null, ctx, {}, {}, {}, true); diff --git a/ui-ngx/src/app/shared/components/js-func.component.ts b/ui-ngx/src/app/shared/components/js-func.component.ts index 5568e6779d..e436f79157 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.ts +++ b/ui-ngx/src/app/shared/components/js-func.component.ts @@ -522,7 +522,7 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal modules: deepClone(this.modules) }; const modulesPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, JsFuncModulesComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, + this.viewContainerRef, JsFuncModulesComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, ctx, {}, {}, {}, true); From e97b1d2c2b293a8d9b4a47c5b7279ec14cb99a5c Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 21 Mar 2025 17:35:14 +0200 Subject: [PATCH 13/30] UI: Fixed init js-func component --- ui-ngx/src/app/shared/components/js-func.component.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/shared/components/js-func.component.ts b/ui-ngx/src/app/shared/components/js-func.component.ts index 5568e6779d..4026b54984 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.ts +++ b/ui-ngx/src/app/shared/components/js-func.component.ts @@ -336,7 +336,7 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal } private updatedScriptLanguage() { - this.jsEditor.session.setMode(`ace/mode/${ScriptLanguage.TBEL === this.scriptLanguage ? 'tbel' : 'javascript'}`); + this.jsEditor?.session?.setMode(`ace/mode/${ScriptLanguage.TBEL === this.scriptLanguage ? 'tbel' : 'javascript'}`); } validateOnSubmit(): Observable { @@ -582,7 +582,7 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal private updateHighlightRules(): void { // @ts-ignore - if (!!this.jsEditor.session.$mode) { + if (!!this.jsEditor?.session?.$mode) { // @ts-ignore const newMode = new this.jsEditor.session.$mode.constructor(); newMode.$highlightRules = new newMode.HighlightRules(); @@ -598,7 +598,7 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal if (this.scriptLanguage === ScriptLanguage.TBEL) { newMode.$highlightRules.$rules.start = [...tbelUtilsFuncHighlightRules, ...newMode.$highlightRules.$rules.start]; } - const identifierRule = newMode.$highlightRules.$rules.no_regex.find(rule => rule.token?.includes('identifier')); + const identifierRule = newMode.$highlightRules.$rules.no_regex.find(rule => Array.isArray(rule.token) && rule.token.includes('identifier')); if (identifierRule && identifierRule.next === 'no_regex') { identifierRule.next = 'start'; } @@ -609,7 +609,7 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal private updateJsWorkerGlobals() { // @ts-ignore - if (!!this.jsEditor.session.$worker) { + if (!!this.jsEditor?.session?.$worker) { const jsWorkerOptions = { undef: !this.disableUndefinedCheck, unused: true, @@ -638,6 +638,9 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal } updateCompleters() { + if (!this.jsEditor) { + return; + } let modulesCompleterObservable: Observable; if (this.withModules) { modulesCompleterObservable = loadModulesCompleter(this.http, this.modules); From 22d584317bfefdedd94781906c1d4c26f4146618 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 21 Mar 2025 18:43:48 +0200 Subject: [PATCH 14/30] UI: Fix analoque gauges bug on resize. --- .../home/components/widget/lib/analogue-gauge.models.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts index 93b2a6b6e5..110d6b34a0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/analogue-gauge.models.ts @@ -107,7 +107,9 @@ export abstract class TbBaseGauge { } resize() { - this.gauge.update({width: this.ctx.width, height: this.ctx.height} as GenericOptions); + if (this.ctx.width > 0 && this.ctx.height > 0) { + this.gauge.update({width: this.ctx.width, height: this.ctx.height} as GenericOptions); + } } destroy() { From b0758135777634a99438be470077f6b80ea17f24 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 24 Mar 2025 10:17:48 +0200 Subject: [PATCH 15/30] UI: Fixed click area for SCADA symbols --- .../src/main/data/json/system/scada_symbols/apartments-hp.svg | 2 +- .../data/json/system/scada_symbols/bottom-light-bulb-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/conical-tank.svg | 2 +- .../src/main/data/json/system/scada_symbols/consumers-hp.svg | 2 +- .../json/system/scada_symbols/dynamic-horizontal-scale-hp.svg | 2 +- .../json/system/scada_symbols/dynamic-vertical-scale-hp.svg | 2 +- .../system/scada_symbols/electrical-distribution-board-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/filter-hp.svg | 2 +- .../json/system/scada_symbols/four-rate-energy-meter-hp.svg | 2 +- .../main/data/json/system/scada_symbols/gas-preventer-hp.svg | 2 +- .../main/data/json/system/scada_symbols/heat-exchanger-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/heat-pump-hp.svg | 2 +- .../main/data/json/system/scada_symbols/horizontal-tank-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/house-hp.svg | 2 +- .../json/system/scada_symbols/industrial-fuel-generator-hp.svg | 2 +- .../json/system/scada_symbols/large-horizontal-separator-hp.svg | 2 +- .../main/data/json/system/scada_symbols/large-inverter-hp.svg | 2 +- .../json/system/scada_symbols/large-stand-cylindrical-tank.svg | 2 +- .../json/system/scada_symbols/large-stand-vertical-tank.svg | 2 +- .../json/system/scada_symbols/large-vertical-separator-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/leak-sensor.svg | 2 +- .../data/json/system/scada_symbols/low-voltage-tower-hp.svg | 2 +- application/src/main/data/json/system/scada_symbols/meter.svg | 2 +- .../src/main/data/json/system/scada_symbols/oil-pump-hp.svg | 2 +- application/src/main/data/json/system/scada_symbols/pool-hp.svg | 2 +- application/src/main/data/json/system/scada_symbols/pool.svg | 2 +- .../src/main/data/json/system/scada_symbols/power-socket-hp.svg | 2 +- .../data/json/system/scada_symbols/short-vertical-tank-hp.svg | 2 +- .../json/system/scada_symbols/simple-horizontal-scale-hp.svg | 2 +- .../data/json/system/scada_symbols/simple-vertical-scale-hp.svg | 2 +- .../data/json/system/scada_symbols/small-cylindrical-tank.svg | 2 +- .../scada_symbols/small-horizontal-separator-connector-hp.svg | 2 +- .../main/data/json/system/scada_symbols/small-left-meter.svg | 2 +- .../scada_symbols/small-vertical-separator-connector-hp.svg | 2 +- .../json/system/scada_symbols/small-vertical-separator-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/spherical-tank.svg | 2 +- .../data/json/system/scada_symbols/stand-cylindrical-tank.svg | 2 +- .../json/system/scada_symbols/stand-vertical-short-tank.svg | 2 +- .../main/data/json/system/scada_symbols/top-light-bulb-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/turbine-hp.svg | 2 +- .../scada_symbols/vertical-energy-system-controller-hp.svg | 2 +- .../main/data/json/system/scada_symbols/vertical-tank-hp.svg | 2 +- .../data/json/system/scada_symbols/voltage-stabilizer-hp.svg | 2 +- .../data/json/system/scada_symbols/wind-turbine-cluster-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/wind-turbine-hp.svg | 2 +- 45 files changed, 45 insertions(+), 45 deletions(-) diff --git a/application/src/main/data/json/system/scada_symbols/apartments-hp.svg b/application/src/main/data/json/system/scada_symbols/apartments-hp.svg index 9e2c965f79..97ac492626 100644 --- a/application/src/main/data/json/system/scada_symbols/apartments-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/apartments-hp.svg @@ -330,7 +330,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/bottom-light-bulb-hp.svg b/application/src/main/data/json/system/scada_symbols/bottom-light-bulb-hp.svg index 4f0603b904..db107240a0 100644 --- a/application/src/main/data/json/system/scada_symbols/bottom-light-bulb-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/bottom-light-bulb-hp.svg @@ -332,7 +332,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/conical-tank.svg b/application/src/main/data/json/system/scada_symbols/conical-tank.svg index 7ae8f41934..6b37adc52e 100644 --- a/application/src/main/data/json/system/scada_symbols/conical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/conical-tank.svg @@ -371,7 +371,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/consumers-hp.svg b/application/src/main/data/json/system/scada_symbols/consumers-hp.svg index e4005d7ae2..8333d6bf55 100644 --- a/application/src/main/data/json/system/scada_symbols/consumers-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/consumers-hp.svg @@ -332,7 +332,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/dynamic-horizontal-scale-hp.svg b/application/src/main/data/json/system/scada_symbols/dynamic-horizontal-scale-hp.svg index e782b07609..b3506ae54f 100644 --- a/application/src/main/data/json/system/scada_symbols/dynamic-horizontal-scale-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/dynamic-horizontal-scale-hp.svg @@ -791,5 +791,5 @@ - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/dynamic-vertical-scale-hp.svg b/application/src/main/data/json/system/scada_symbols/dynamic-vertical-scale-hp.svg index 960abed340..3c52dae1c3 100644 --- a/application/src/main/data/json/system/scada_symbols/dynamic-vertical-scale-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/dynamic-vertical-scale-hp.svg @@ -791,5 +791,5 @@ 26 - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/electrical-distribution-board-hp.svg b/application/src/main/data/json/system/scada_symbols/electrical-distribution-board-hp.svg index 0fcfe4dde0..6e4175c6d7 100644 --- a/application/src/main/data/json/system/scada_symbols/electrical-distribution-board-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/electrical-distribution-board-hp.svg @@ -318,7 +318,7 @@ }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/filter-hp.svg b/application/src/main/data/json/system/scada_symbols/filter-hp.svg index 58ff3951e5..1f4516723e 100644 --- a/application/src/main/data/json/system/scada_symbols/filter-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/filter-hp.svg @@ -273,7 +273,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/four-rate-energy-meter-hp.svg b/application/src/main/data/json/system/scada_symbols/four-rate-energy-meter-hp.svg index de4fb13836..bba67e5fe3 100644 --- a/application/src/main/data/json/system/scada_symbols/four-rate-energy-meter-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/four-rate-energy-meter-hp.svg @@ -862,7 +862,7 @@ } ] }]]> -T1T2T3Export000223000223000223000223kWh +T1T2T3Export000223000223000223000223kWh diff --git a/application/src/main/data/json/system/scada_symbols/gas-preventer-hp.svg b/application/src/main/data/json/system/scada_symbols/gas-preventer-hp.svg index ea5a479eda..487b5e54d9 100644 --- a/application/src/main/data/json/system/scada_symbols/gas-preventer-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/gas-preventer-hp.svg @@ -347,7 +347,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/heat-exchanger-hp.svg b/application/src/main/data/json/system/scada_symbols/heat-exchanger-hp.svg index 797220ea96..c1c3d4647e 100644 --- a/application/src/main/data/json/system/scada_symbols/heat-exchanger-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/heat-exchanger-hp.svg @@ -349,7 +349,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/heat-pump-hp.svg b/application/src/main/data/json/system/scada_symbols/heat-pump-hp.svg index 1d7babc3b0..eed54682cd 100644 --- a/application/src/main/data/json/system/scada_symbols/heat-pump-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/heat-pump-hp.svg @@ -587,7 +587,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg b/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg index 18f194684b..bb6f5e55a9 100644 --- a/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg @@ -502,7 +502,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/house-hp.svg b/application/src/main/data/json/system/scada_symbols/house-hp.svg index d95c47bb8b..e3556d4d9a 100644 --- a/application/src/main/data/json/system/scada_symbols/house-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/house-hp.svg @@ -335,7 +335,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/industrial-fuel-generator-hp.svg b/application/src/main/data/json/system/scada_symbols/industrial-fuel-generator-hp.svg index 2b7a476a92..e0ee85b8cf 100644 --- a/application/src/main/data/json/system/scada_symbols/industrial-fuel-generator-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/industrial-fuel-generator-hp.svg @@ -344,7 +344,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/large-horizontal-separator-hp.svg b/application/src/main/data/json/system/scada_symbols/large-horizontal-separator-hp.svg index 79f6745a73..8179549c54 100644 --- a/application/src/main/data/json/system/scada_symbols/large-horizontal-separator-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/large-horizontal-separator-hp.svg @@ -336,7 +336,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/large-inverter-hp.svg b/application/src/main/data/json/system/scada_symbols/large-inverter-hp.svg index 11bc5da0a6..bf18d64040 100644 --- a/application/src/main/data/json/system/scada_symbols/large-inverter-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/large-inverter-hp.svg @@ -564,7 +564,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg index 11bd47916f..09c0e2a9e1 100644 --- a/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg @@ -565,7 +565,7 @@ 1660 gal - + diff --git a/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg index d9c05bde40..be8b1207a0 100644 --- a/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg @@ -569,7 +569,7 @@ 1660 gal - + diff --git a/application/src/main/data/json/system/scada_symbols/large-vertical-separator-hp.svg b/application/src/main/data/json/system/scada_symbols/large-vertical-separator-hp.svg index 99ff420530..1951b741bf 100644 --- a/application/src/main/data/json/system/scada_symbols/large-vertical-separator-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/large-vertical-separator-hp.svg @@ -336,7 +336,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/leak-sensor.svg b/application/src/main/data/json/system/scada_symbols/leak-sensor.svg index 0fce8be608..813116a1f5 100644 --- a/application/src/main/data/json/system/scada_symbols/leak-sensor.svg +++ b/application/src/main/data/json/system/scada_symbols/leak-sensor.svg @@ -135,7 +135,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/low-voltage-tower-hp.svg b/application/src/main/data/json/system/scada_symbols/low-voltage-tower-hp.svg index 812e616433..002bd9cfae 100644 --- a/application/src/main/data/json/system/scada_symbols/low-voltage-tower-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/low-voltage-tower-hp.svg @@ -264,7 +264,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/meter.svg b/application/src/main/data/json/system/scada_symbols/meter.svg index 02b2833133..d5fa9f7cd7 100644 --- a/application/src/main/data/json/system/scada_symbols/meter.svg +++ b/application/src/main/data/json/system/scada_symbols/meter.svg @@ -713,7 +713,7 @@ 37% - + diff --git a/application/src/main/data/json/system/scada_symbols/oil-pump-hp.svg b/application/src/main/data/json/system/scada_symbols/oil-pump-hp.svg index e7dfa8f0c8..b1ff6ea2c0 100644 --- a/application/src/main/data/json/system/scada_symbols/oil-pump-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/oil-pump-hp.svg @@ -343,7 +343,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/pool-hp.svg b/application/src/main/data/json/system/scada_symbols/pool-hp.svg index 925ea8906a..0ce78af7d9 100644 --- a/application/src/main/data/json/system/scada_symbols/pool-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/pool-hp.svg @@ -501,7 +501,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/pool.svg b/application/src/main/data/json/system/scada_symbols/pool.svg index f5d0bd7ad7..6f8b12737c 100644 --- a/application/src/main/data/json/system/scada_symbols/pool.svg +++ b/application/src/main/data/json/system/scada_symbols/pool.svg @@ -292,7 +292,7 @@ 1660 gal - + diff --git a/application/src/main/data/json/system/scada_symbols/power-socket-hp.svg b/application/src/main/data/json/system/scada_symbols/power-socket-hp.svg index 5524b3bb14..2331242475 100644 --- a/application/src/main/data/json/system/scada_symbols/power-socket-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/power-socket-hp.svg @@ -357,7 +357,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg b/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg index 046c5c5802..cd15a16577 100644 --- a/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg @@ -502,7 +502,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/simple-horizontal-scale-hp.svg b/application/src/main/data/json/system/scada_symbols/simple-horizontal-scale-hp.svg index 26cee5cd30..1b91a0cd4a 100644 --- a/application/src/main/data/json/system/scada_symbols/simple-horizontal-scale-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/simple-horizontal-scale-hp.svg @@ -719,5 +719,5 @@ - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/simple-vertical-scale-hp.svg b/application/src/main/data/json/system/scada_symbols/simple-vertical-scale-hp.svg index fa0c0fc4d1..7b8e7299b8 100644 --- a/application/src/main/data/json/system/scada_symbols/simple-vertical-scale-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/simple-vertical-scale-hp.svg @@ -719,5 +719,5 @@ 26 - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg index d4ddda1895..1d6785d0c1 100644 --- a/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg @@ -537,7 +537,7 @@ 1660 gal - + diff --git a/application/src/main/data/json/system/scada_symbols/small-horizontal-separator-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/small-horizontal-separator-connector-hp.svg index dedc4dc81e..abb6d9b4ab 100644 --- a/application/src/main/data/json/system/scada_symbols/small-horizontal-separator-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/small-horizontal-separator-connector-hp.svg @@ -328,7 +328,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/small-left-meter.svg b/application/src/main/data/json/system/scada_symbols/small-left-meter.svg index a480412366..129006ffd7 100644 --- a/application/src/main/data/json/system/scada_symbols/small-left-meter.svg +++ b/application/src/main/data/json/system/scada_symbols/small-left-meter.svg @@ -713,5 +713,5 @@ 37% - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/small-vertical-separator-connector-hp.svg b/application/src/main/data/json/system/scada_symbols/small-vertical-separator-connector-hp.svg index b248996612..e9cc074cb6 100644 --- a/application/src/main/data/json/system/scada_symbols/small-vertical-separator-connector-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/small-vertical-separator-connector-hp.svg @@ -328,7 +328,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/small-vertical-separator-hp.svg b/application/src/main/data/json/system/scada_symbols/small-vertical-separator-hp.svg index 25aec080b3..0c7455e534 100644 --- a/application/src/main/data/json/system/scada_symbols/small-vertical-separator-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/small-vertical-separator-hp.svg @@ -328,7 +328,7 @@ } ] }]]> - + diff --git a/application/src/main/data/json/system/scada_symbols/spherical-tank.svg b/application/src/main/data/json/system/scada_symbols/spherical-tank.svg index cba49c63e0..f5d679fa96 100644 --- a/application/src/main/data/json/system/scada_symbols/spherical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/spherical-tank.svg @@ -572,7 +572,7 @@ 1660 gal - + diff --git a/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg index a78060dfaf..f5b8e8a892 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg @@ -567,7 +567,7 @@ 1660 gal - + diff --git a/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg index 96df175589..0d56901bfe 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg @@ -1364,5 +1364,5 @@ - + \ No newline at end of file diff --git a/application/src/main/data/json/system/scada_symbols/top-light-bulb-hp.svg b/application/src/main/data/json/system/scada_symbols/top-light-bulb-hp.svg index ed6855884a..fb419bac2a 100644 --- a/application/src/main/data/json/system/scada_symbols/top-light-bulb-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/top-light-bulb-hp.svg @@ -332,7 +332,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/turbine-hp.svg b/application/src/main/data/json/system/scada_symbols/turbine-hp.svg index d798b09477..2e0e176cfd 100644 --- a/application/src/main/data/json/system/scada_symbols/turbine-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/turbine-hp.svg @@ -363,7 +363,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/vertical-energy-system-controller-hp.svg b/application/src/main/data/json/system/scada_symbols/vertical-energy-system-controller-hp.svg index cebe949c36..6da68556a2 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-energy-system-controller-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-energy-system-controller-hp.svg @@ -364,7 +364,7 @@ } ] }]]> -Connected +Connected diff --git a/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg b/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg index 491fb4477e..9dee6cc2af 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg @@ -502,7 +502,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/voltage-stabilizer-hp.svg b/application/src/main/data/json/system/scada_symbols/voltage-stabilizer-hp.svg index aafc2af5a0..2ccad581d4 100644 --- a/application/src/main/data/json/system/scada_symbols/voltage-stabilizer-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/voltage-stabilizer-hp.svg @@ -570,7 +570,7 @@ } ] }]]> -220230inout +220230inout diff --git a/application/src/main/data/json/system/scada_symbols/wind-turbine-cluster-hp.svg b/application/src/main/data/json/system/scada_symbols/wind-turbine-cluster-hp.svg index 74855dd35a..dc8af28f59 100644 --- a/application/src/main/data/json/system/scada_symbols/wind-turbine-cluster-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/wind-turbine-cluster-hp.svg @@ -356,7 +356,7 @@ - + diff --git a/application/src/main/data/json/system/scada_symbols/wind-turbine-hp.svg b/application/src/main/data/json/system/scada_symbols/wind-turbine-hp.svg index a4282c16e7..b2c65988da 100644 --- a/application/src/main/data/json/system/scada_symbols/wind-turbine-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/wind-turbine-hp.svg @@ -346,7 +346,7 @@ - + From 4d18579daf06fe50c2a1636de71ac91ba547164f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 24 Mar 2025 11:11:14 +0200 Subject: [PATCH 16/30] UI: Add new help place map item; improved map hint and additionalParams map description --- ...custom-action-pretty-editor.component.html | 4 +- .../custom-action-pretty-editor.component.ts | 40 ++++---- ...ction-pretty-resources-tabs.component.html | 2 +- ...-action-pretty-resources-tabs.component.ts | 18 ++-- .../action/widget-action.component.html | 3 +- .../entity/entity-type-select.component.ts | 25 +---- .../widget/action/custom_additional_params.md | 16 +--- .../place_map_item/create_dialog_html.md | 87 +++++++++++++++++ .../action/place_map_item/create_dialog_js.md | 94 +++++++++++++++++++ .../place_map_item/place_map_item_action.md | 66 +++++++++++++ .../assets/locale/locale.constant-en_US.json | 2 +- 11 files changed, 288 insertions(+), 69 deletions(-) create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/place_map_item/create_dialog_html.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/place_map_item/create_dialog_js.md create mode 100644 ui-ngx/src/assets/help/en_US/widget/action/place_map_item/place_map_item_action.md diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-editor.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-editor.component.html index 0d53bc6c44..abcc4ad7af 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-editor.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-editor.component.html @@ -37,6 +37,7 @@
    @@ -44,6 +45,7 @@
    @@ -58,7 +60,7 @@ [validationArgs]="[]" [editorCompleter]="customPrettyActionEditorCompleter" functionTitle="{{ 'widget-action.custom-pretty-function' | translate }}" - helpId="widget/action/custom_pretty_action_fn"> + [helpId]="helpId">
    diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-editor.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-editor.component.ts index 2e177eb918..77f835a668 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-editor.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-editor.component.ts @@ -14,28 +14,22 @@ /// limitations under the License. /// -// eslint-disable-next-line @typescript-eslint/triple-slash-reference -/// - import { AfterViewInit, Component, ElementRef, forwardRef, Input, - OnDestroy, - OnInit, QueryList, ViewChildren, ViewEncapsulation } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { PageComponent } from '@shared/components/page.component'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; import { combineLatest } from 'rxjs'; -import { CustomActionDescriptor } from '@shared/models/widget.models'; -import { CustomPrettyActionEditorCompleter } from '@home/components/widget/lib/settings/common/action/custom-action.models'; +import { CustomActionDescriptor, WidgetActionType } from '@shared/models/widget.models'; +import { + CustomPrettyActionEditorCompleter +} from '@home/components/widget/lib/settings/common/action/custom-action.models'; @Component({ selector: 'tb-custom-action-pretty-editor', @@ -50,7 +44,7 @@ import { CustomPrettyActionEditorCompleter } from '@home/components/widget/lib/s ], encapsulation: ViewEncapsulation.None }) -export class CustomActionPrettyEditorComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy, ControlValueAccessor { +export class CustomActionPrettyEditorComponent implements AfterViewInit, ControlValueAccessor { @Input() disabled: boolean; @@ -58,6 +52,17 @@ export class CustomActionPrettyEditorComponent extends PageComponent implements fullscreen = false; + helpId= 'widget/action/custom_pretty_action_fn'; + + @Input() + set widgetActionType(type: WidgetActionType) { + if (type === WidgetActionType.placeMapItem) { + this.helpId = 'widget/action/place_map_item/place_map_item_action'; + } else { + this.helpId = 'widget/action/custom_pretty_action_fn'; + } + } + @ViewChildren('leftPanel') leftPanelElmRef: QueryList>; @@ -68,15 +73,11 @@ export class CustomActionPrettyEditorComponent extends PageComponent implements private propagateChange = (_: any) => {}; - constructor(protected store: Store) { - super(store); - } - - ngOnInit(): void { + constructor() { } ngAfterViewInit(): void { - combineLatest(this.leftPanelElmRef.changes, this.rightPanelElmRef.changes).subscribe(() => { + combineLatest([this.leftPanelElmRef.changes, this.rightPanelElmRef.changes]).subscribe(() => { if (this.leftPanelElmRef.length && this.rightPanelElmRef.length) { this.initSplitLayout(this.leftPanelElmRef.first.nativeElement, this.rightPanelElmRef.first.nativeElement); @@ -92,14 +93,11 @@ export class CustomActionPrettyEditorComponent extends PageComponent implements }); } - ngOnDestroy(): void { - } - registerOnChange(fn: any): void { this.propagateChange = fn; } - registerOnTouched(fn: any): void { + registerOnTouched(_fn: any): void { } setDisabledState(isDisabled: boolean): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-resources-tabs.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-resources-tabs.component.html index 9f351345c1..0852e7cc0d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-resources-tabs.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-resources-tabs.component.html @@ -101,7 +101,7 @@ [validationArgs]="[]" [editorCompleter]="customPrettyActionEditorCompleter" functionTitle="{{ 'widget-action.custom-pretty-function' | translate }}" - helpId="widget/action/custom_pretty_action_fn"> + [helpId]="helpId"> diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-resources-tabs.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-resources-tabs.component.ts index 5c65e23b58..367f90d160 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-resources-tabs.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action-pretty-resources-tabs.component.ts @@ -27,16 +27,15 @@ import { ViewChild, ViewEncapsulation } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; import { PageComponent } from '@shared/components/page.component'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; import { CustomActionDescriptor } from '@shared/models/widget.models'; import { Ace } from 'ace-builds'; import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; -import { CustomPrettyActionEditorCompleter } from '@home/components/widget/lib/settings/common/action/custom-action.models'; +import { + CustomPrettyActionEditorCompleter +} from '@home/components/widget/lib/settings/common/action/custom-action.models'; import { Observable } from 'rxjs/internal/Observable'; -import { forkJoin, from } from 'rxjs'; +import { forkJoin } from 'rxjs'; import { map, tap } from 'rxjs/operators'; import { getAce } from '@shared/models/ace/ace.models'; import { beautifyCss, beautifyHtml } from '@shared/models/beautify.models'; @@ -55,6 +54,9 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl @Input() hasCustomFunction: boolean; + @Input() + helpId: string; + @Output() actionUpdated: EventEmitter = new EventEmitter(); @@ -76,10 +78,8 @@ export class CustomActionPrettyResourcesTabsComponent extends PageComponent impl customPrettyActionEditorCompleter = CustomPrettyActionEditorCompleter; - constructor(protected store: Store, - private translate: TranslateService, - private raf: RafService) { - super(store); + constructor(private raf: RafService) { + super(); } ngOnInit(): void { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.html index ca2405b8b4..c4c90067dd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.html @@ -274,7 +274,8 @@ || widgetActionFormGroup.get('type').value === widgetActionType.placeMapItem ? widgetActionFormGroup.get('type').value : ''"> + [widgetActionType]="widgetActionFormGroup.get('type').value" + formControlName="customAction"> diff --git a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts index 82b3fcf572..ce599a0c08 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts @@ -14,19 +14,8 @@ /// limitations under the License. /// -import { - AfterViewInit, - Component, - DestroyRef, - forwardRef, - Input, - OnChanges, - OnInit, - SimpleChanges -} from '@angular/core'; +import { Component, DestroyRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { Store } from '@ngrx/store'; -import { AppState } from '@app/core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { AliasEntityType, EntityType, entityTypeTranslations } from '@app/shared/models/entity-type.models'; import { EntityService } from '@core/http/entity.service'; @@ -44,7 +33,7 @@ import { MatFormFieldAppearance } from '@angular/material/form-field'; multi: true }] }) -export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit, AfterViewInit, OnChanges { +export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit, OnChanges { entityTypeFormGroup: UntypedFormGroup; @@ -71,17 +60,16 @@ export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit, disabled: boolean; @Input() - appearance: MatFormFieldAppearance = 'fill'; + additionEntityTypes: {[key in string]: string} = {}; @Input() - additionEntityTypes: {[key in string]: string} = {}; + appearance: MatFormFieldAppearance = 'fill'; entityTypes: Array; private propagateChange = (v: any) => { }; - constructor(private store: Store, - private entityService: EntityService, + constructor(private entityService: EntityService, public translate: TranslateService, private fb: UntypedFormBuilder, private destroyRef: DestroyRef) { @@ -140,9 +128,6 @@ export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit, } } - ngAfterViewInit(): void { - } - setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (this.disabled) { diff --git a/ui-ngx/src/assets/help/en_US/widget/action/custom_additional_params.md b/ui-ngx/src/assets/help/en_US/widget/action/custom_additional_params.md index 35e5992b9f..704e25b7f1 100644 --- a/ui-ngx/src/assets/help/en_US/widget/action/custom_additional_params.md +++ b/ui-ngx/src/assets/help/en_US/widget/action/custom_additional_params.md @@ -32,27 +32,13 @@ An optional key/value object holding additional entity parameters depending on w -
  • Map widgets - additionalParams: FormattedData: +
  • Map widgets (On marker/polygon/circle click or Tag action) - additionalParams: FormattedData:
    • additionalParams: FormattedData - An object associated with a data layer (markers, polygons, circles) or with a specific data point of a route (for trips data layers).
      It contains basic entity properties (ex. entityId, entityName) and provides access to additional attributes and timeseries defined in datasource of the data layer configuration.
  • -
  • Map widgets (Action type: Place map item) - additionalParams: {coordinates: Coordinates; layer: L.Layer}: -
      -
    • coordinates: Coordinates - Represents geographical coordinates of the placed map item. The actual format of this parameter depends on the type of the selected map item: -
        -
      • Marker: {x: number; y: number}, where x represents latitude, and y represents longitude.
      • -
      • Polygon, Rectangle: TbPolygonRawCoordinates contains an array of points defining the shape boundaries.
      • -
      • Circle: TbCircleData contains center coordinates and radius information.
      • -
      - Note: The coordinates will be automatically converted according to the selected map type. -
    • -
    • layer: L.Layer - The Leaflet map layer instance (e.g., marker, polygon, circle) associated with the placed map item. This object provides access to layer properties and methods defined in Leaflet's API. -
    • -
    -
  • Entities hierarchy widget (On node selected) - additionalParams: { nodeCtx: HierarchyNodeContext }:
    • nodeCtx: HierarchyNodeContext - An diff --git a/ui-ngx/src/assets/help/en_US/widget/action/place_map_item/create_dialog_html.md b/ui-ngx/src/assets/help/en_US/widget/action/place_map_item/create_dialog_html.md new file mode 100644 index 0000000000..c3a58747e8 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/place_map_item/create_dialog_html.md @@ -0,0 +1,87 @@ +#### HTML template of dialog to create a device or an asset + +```html +{:code-style="max-height: 400px;"} +
      + +

      Add entity

      + + +
      + + +
      +
      +
      + + Entity Name + + + Entity name is required. + + + + Entity Label + + +
      +
      + + + +
      +
      +
      + + Address + + + + Owner + + +
      +
      +
      +
      + + +
      +
      +{:copy-code} +``` + +
      +
      diff --git a/ui-ngx/src/assets/help/en_US/widget/action/place_map_item/create_dialog_js.md b/ui-ngx/src/assets/help/en_US/widget/action/place_map_item/create_dialog_js.md new file mode 100644 index 0000000000..bc8823c777 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/place_map_item/create_dialog_js.md @@ -0,0 +1,94 @@ +#### Function displaying dialog to create a device or an asset + +```javascript +{:code-style="max-height: 400px;"} +let $injector = widgetContext.$scope.$injector; +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog')); +let assetService = $injector.get(widgetContext.servicesMap.get('assetService')); +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService')); +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService')); + +openAddEntityDialog(); + +function openAddEntityDialog() { + customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe(); +} + +function AddEntityDialogController(instance) { + let vm = instance; + + vm.allowedEntityTypes = ['ASSET', 'DEVICE']; + + vm.addEntityFormGroup = vm.fb.group({ + entityName: ['', [vm.validators.required]], + entityType: ['DEVICE'], + entityLabel: [null], + type: ['', [vm.validators.required]], + attributes: vm.fb.group({ + address: [null], + owner: [null] + }) + }); + + vm.cancel = function() { + vm.dialogRef.close(null); + }; + + vm.save = function() { + vm.addEntityFormGroup.markAsPristine(); + saveEntityObservable().pipe( + widgetContext.rxjs.switchMap((entity) => saveAttributes(entity.id)) + ).subscribe(() => { + widgetContext.updateAliases(); + vm.dialogRef.close(null); + }); + }; + + function saveEntityObservable() { + const formValues = vm.addEntityFormGroup.value; + let entity = { + name: formValues.entityName, + type: formValues.type, + label: formValues.entityLabel + }; + if (formValues.entityType == 'ASSET') { + return assetService.saveAsset(entity); + } else if (formValues.entityType == 'DEVICE') { + return deviceService.saveDevice(entity); + } + } + + function saveAttributes(entityId) { + let attributes = vm.addEntityFormGroup.get('attributes').value; + let attributesArray = getMapItemLocationAttributes(); + for (let key in attributes) { + if(attributes[key] !== null) { + attributesArray.push({key: key, value: attributes[key]}); + } + } + if (attributesArray.length > 0) { + return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray); + } + return widgetContext.rxjs.of([]); + } + + function getMapItemLocationAttributes() { + const attributes = []; + const mapItemType = $event.shape; + if (mapItemType === 'Marker') { + const mapType = widgetContext.mapInstance.type(); + attributes.push({key: mapType === 'image' ? 'xPos' : 'latitude', value: additionalParams.coordinates.x}); + attributes.push({key: mapType === 'image' ? 'yPos' : 'longitude', value: additionalParams.coordinates.y}); + } else if (mapItemType === 'Rectangle' || mapItemType === 'Polygon') { + attributes.push({key: 'perimeter', value: additionalParams.coordinates}); + } else if (mapItemType === 'Circle') { + attributes.push({key: 'circle', value: additionalParams.coordinates}); + } + return attributes; + } +} +{:copy-code} +``` + +
      +
      diff --git a/ui-ngx/src/assets/help/en_US/widget/action/place_map_item/place_map_item_action.md b/ui-ngx/src/assets/help/en_US/widget/action/place_map_item/place_map_item_action.md new file mode 100644 index 0000000000..131a674099 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/action/place_map_item/place_map_item_action.md @@ -0,0 +1,66 @@ +#### Place map item function + +
      +
      + +*function ($event, widgetContext, entityId, entityName, htmlTemplate, additionalParams, entityLabel): void* + +A JavaScript function triggered after a map item is placed. Optionally uses an HTML template to render dialog. + +**Parameters:** + +
        +
      • $event: {shape: PM.SUPPORTED_SHAPES; layer: L.Layer} - Event payload containing the created shape type and its associated map layer. +
      • +
      • widgetContext: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
      • +
      • entityId: string - An optional string id of the target entity. +
      • +
      • entityName: string - An optional string name of the target entity. +
      • +
      • htmlTemplate: string - An optional HTML template string defined in HTML tab.
        Used to render custom dialog (see Examples for more details). +
      • +
      • additionalParams: {coordinates: Coordinates; layer: L.Layer}: +
          +
        • coordinates: Coordinates - Represents geographical coordinates of the placed map item. The actual format of this parameter depends on the type of the selected map item: +
            +
          • Marker: {x: number; y: number}, where x represents latitude, and y represents longitude.
          • +
          • Polygon, Rectangle: TbPolygonRawCoordinates contains an array of points defining the shape boundaries.
          • +
          • Circle: TbCircleData contains center coordinates and radius information.
          • +
          + Note: The coordinates will be automatically converted according to the selected map type. +
        • +
        • layer: L.Layer - The Leaflet map layer instance (e.g., marker, polygon, circle) associated with the placed map item. This object provides access to layer properties and methods defined in Leaflet's API. +
        • +
        +
      • +
      • entityLabel: string - An optional string label of the target entity. +
      • +
      + +
      + +##### Examples + +###### Display dialog to create a device or an asset + +
      + +
      +
      + +
      + +
      +
      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 c294b0210a..9cb2070cd2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -7995,7 +7995,7 @@ "on-click": "On click", "on-click-hint": "Action invoked when user clicks on the map item.", "groups": "Groups", - "groups-hint": "List of group names assigned to this datasource. Used to toggle visibility of datasource items on the map.", + "groups-hint": "List of group names assigned to the overlay, used to toggle its visibility on the map.", "color": "Color", "fill-color": "Fill color", "stroke": "Stroke", From 55e6cddb9faef21c116d713355bd97aa1758a771 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Mon, 24 Mar 2025 11:32:45 +0200 Subject: [PATCH 17/30] fixed timeouts when linked telemetry list is empty --- .../CalculatedFieldManagerMessageProcessor.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java index 0990365748..bf441f1a35 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java @@ -367,6 +367,10 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware log.debug("Received linked telemetry msg from entity [{}]", sourceEntityId); var proto = msg.getProto(); var linksList = proto.getLinksList(); + if (linksList.isEmpty()) { + log.debug("[{}] No new linked telemetry to process for CF.", msg.getTenantId()); + msg.getCallback().onSuccess(); + } for (var linkProto : linksList) { var link = fromProto(linkProto); var targetEntityId = link.entityId(); From 5ecbae229a378b828d58e37b590546cd2c56c612 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Mon, 24 Mar 2025 12:03:14 +0200 Subject: [PATCH 18/30] updated log msg --- .../calculatedField/CalculatedFieldManagerMessageProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java index bf441f1a35..e109e83e4d 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java @@ -368,7 +368,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware var proto = msg.getProto(); var linksList = proto.getLinksList(); if (linksList.isEmpty()) { - log.debug("[{}] No new linked telemetry to process for CF.", msg.getTenantId()); + log.debug("[{}] No CF links to process new telemetry.", msg.getTenantId()); msg.getCallback().onSuccess(); } for (var linkProto : linksList) { From 64b85e67715a59ecd7f1b3e1fa3f35cd2c9e9800 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Mon, 24 Mar 2025 12:32:17 +0200 Subject: [PATCH 19/30] fix for calback when ctx is not initialized --- .../calculatedField/CalculatedFieldEntityMessageProcessor.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java index 4e15dba120..93214e4403 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java @@ -302,6 +302,8 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM systemContext.persistCalculatedFieldDebugEvent(tenantId, ctx.getCfId(), entityId, state.getArguments(), tbMsgId, tbMsgType, JacksonUtil.writeValueAsString(calculationResult.getResult()), null); } } + } else { + callback.onSuccess(); } } catch (Exception e) { throw CalculatedFieldException.builder().ctx(ctx).eventEntity(entityId).msgId(tbMsgId).msgType(tbMsgType).arguments(state.getArguments()).cause(e).build(); From df9f61c1af3b0c220c543102b3b3570f314d6a87 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 24 Mar 2025 17:15:52 +0200 Subject: [PATCH 20/30] UI: Refactoring popover service. Add single config --- .../components/color-input.component.ts | 23 ++-- .../shared/components/popover.component.ts | 10 +- .../app/shared/components/popover.models.ts | 38 ++++++ .../app/shared/components/popover.service.ts | 122 +++++++++++++----- 4 files changed, 151 insertions(+), 42 deletions(-) diff --git a/ui-ngx/src/app/shared/components/color-input.component.ts b/ui-ngx/src/app/shared/components/color-input.component.ts index 00ef7059d7..d0dc7235f7 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.ts +++ b/ui-ngx/src/app/shared/components/color-input.component.ts @@ -196,14 +196,21 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const colorPickerPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ColorPickerPanelComponent, ['left'], true, null, - { - color: this.colorFormGroup.get('color').value, - colorClearButton: this.colorClearButton, - colorCancelButton: true - }, - {}, {}, {}, false, () => {}, {padding: '12px 4px 12px 12px'}); + const colorPickerPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + hostView: this.viewContainerRef, + componentType: ColorPickerPanelComponent, + preferredPlacement: ['left'], + context: { + color: this.colorFormGroup.get('color').value, + colorClearButton: this.colorClearButton, + colorCancelButton: true + }, + showCloseButton: false, + popoverContentStyle: {padding: '12px 4px 12px 12px'}, + isModal: true + }) colorPickerPopover.tbComponentRef.instance.popover = colorPickerPopover; colorPickerPopover.tbComponentRef.instance.colorSelected.subscribe((color) => { colorPickerPopover.hide(); diff --git a/ui-ngx/src/app/shared/components/popover.component.ts b/ui-ngx/src/app/shared/components/popover.component.ts index 21cf4a83c5..4344b32fd7 100644 --- a/ui-ngx/src/app/shared/components/popover.component.ts +++ b/ui-ngx/src/app/shared/components/popover.component.ts @@ -311,6 +311,7 @@ export class TbPopoverDirective implements OnChanges, OnDestroy, AfterViewInit { #overlay="cdkConnectedOverlay" cdkConnectedOverlay [cdkConnectedOverlayHasBackdrop]="hasBackdrop" + [cdkConnectedOverlayBackdropClass]="backdropClass" [cdkConnectedOverlayOrigin]="origin" [cdkConnectedOverlayPositions]="positions" [cdkConnectedOverlayScrollStrategy]="scrollStrategy" @@ -382,6 +383,7 @@ export class TbPopoverComponent implements OnDestroy, OnInit { tbMouseLeaveDelay?: number; tbHideOnClickOutside = true; tbShowCloseButton = true; + tbModal = false; tbAnimationState = 'active'; @@ -461,7 +463,11 @@ export class TbPopoverComponent implements OnDestroy, OnInit { } get hasBackdrop(): boolean { - return this.tbTrigger === 'click' ? this.tbBackdrop : false; + return this.tbModal || (this.tbTrigger === 'click' && this.tbBackdrop); + } + + get backdropClass(): string { + return this.tbModal ? 'tb-popover-overlay-backdrop' : ''; } preferredPlacement: PopoverPlacement = 'top'; @@ -634,7 +640,7 @@ export class TbPopoverComponent implements OnDestroy, OnInit { } onClickOutside(event: MouseEvent): void { - if (this.tbHideOnClickOutside && !this.origin.elementRef.nativeElement.contains(event.target) && this.tbTrigger !== null) { + if (!this.tbModal && this.tbHideOnClickOutside && !this.origin.elementRef.nativeElement.contains(event.target) && this.tbTrigger !== null) { if (!this.isTopOverlay(event.target as Element)) { this.hide(); } diff --git a/ui-ngx/src/app/shared/components/popover.models.ts b/ui-ngx/src/app/shared/components/popover.models.ts index 15db9b1f93..9fb01d1f3d 100644 --- a/ui-ngx/src/app/shared/components/popover.models.ts +++ b/ui-ngx/src/app/shared/components/popover.models.ts @@ -18,6 +18,7 @@ import { animate, AnimationTriggerMetadata, style, transition, trigger } from '@ import { ConnectedOverlayPositionChange } from '@angular/cdk/overlay'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { POSITION_MAP } from '@shared/models/overlay.models'; +import { ComponentRef, Injector, Renderer2, Type, ViewContainerRef } from '@angular/core'; export const popoverMotion: AnimationTriggerMetadata = trigger('popoverMotion', [ transition('void => active', [ @@ -88,3 +89,40 @@ export interface PopoverWithTrigger { trigger: Element; popoverComponent: TbPopoverComponent; } + +export interface DisplayPopoverConfig extends Omit, 'componentRef'>{ + hostView: ViewContainerRef; +} + +export interface DisplayPopoverWithComponentRefConfig { + componentRef: ComponentRef + trigger: Element; + renderer: Renderer2; + componentType: Type; + preferredPlacement?: PopoverPreferredPlacement; + hideOnClickOutside?: boolean; + injector?: Injector; + context?: any; + overlayStyle?: any; + popoverStyle?: any; + style?: any, + showCloseButton?: boolean; + visibleFn?: (visible: boolean) => void; + popoverContentStyle?: any; + isModal?: boolean; +} + +export const defaultPopoverConfig: DisplayPopoverWithComponentRefConfig = { + componentRef: undefined, + trigger: undefined, + renderer: undefined, + componentType: undefined, + preferredPlacement: 'top', + hideOnClickOutside: true, + overlayStyle: {}, + popoverStyle: {}, + showCloseButton: true, + visibleFn: () => {}, + popoverContentStyle: {}, + isModal: false +}; diff --git a/ui-ngx/src/app/shared/components/popover.service.ts b/ui-ngx/src/app/shared/components/popover.service.ts index ce1288651c..15a18fb2fc 100644 --- a/ui-ngx/src/app/shared/components/popover.service.ts +++ b/ui-ngx/src/app/shared/components/popover.service.ts @@ -24,12 +24,19 @@ import { Type, ViewContainerRef } from '@angular/core'; -import { PopoverPreferredPlacement, PopoverWithTrigger } from '@shared/components/popover.models'; +import { + defaultPopoverConfig, + DisplayPopoverConfig, + DisplayPopoverWithComponentRefConfig, + PopoverPreferredPlacement, + PopoverWithTrigger +} from '@shared/components/popover.models'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { ComponentType } from '@angular/cdk/portal'; import { HELP_MARKDOWN_COMPONENT_TOKEN } from '@shared/components/tokens'; import { CdkOverlayOrigin } from '@angular/cdk/overlay'; import { Observable } from 'rxjs'; +import { mergeDeep } from '@core/utils'; @Injectable() export class TbPopoverService { @@ -58,57 +65,108 @@ export class TbPopoverService { return hostView.createComponent(TbPopoverComponent); } + displayPopover(config: DisplayPopoverConfig): TbPopoverComponent; displayPopover(trigger: Element, renderer: Renderer2, hostView: ViewContainerRef, - componentType: Type, preferredPlacement: PopoverPreferredPlacement = 'top', - hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, - popoverStyle: any = {}, style?: any, - showCloseButton = true, visibleFn: (visible: boolean) => void = () => {}, - popoverContentStyle: any = {}): TbPopoverComponent { - const componentRef = this.createPopoverRef(hostView); - return this.displayPopoverWithComponentRef(componentRef, trigger, renderer, componentType, preferredPlacement, hideOnClickOutside, - injector, context, overlayStyle, popoverStyle, style, showCloseButton, visibleFn, popoverContentStyle); + componentType: Type, preferredPlacement: PopoverPreferredPlacement, + hideOnClickOutside: boolean, injector?: Injector, context?: any, overlayStyle?: any, + popoverStyle?: any, style?: any, + showCloseButton?: boolean, visibleFn?: (visible: boolean) => void, + popoverContentStyle?: any): TbPopoverComponent; + displayPopover(config: Element | DisplayPopoverConfig, renderer?: Renderer2, hostView?: ViewContainerRef, + componentType?: Type, preferredPlacement?: PopoverPreferredPlacement, + hideOnClickOutside?: boolean, injector?: Injector, context?: any, overlayStyle?: any, + popoverStyle?: any, style?: any, + showCloseButton?: boolean, visibleFn?: (visible: boolean) => void, + popoverContentStyle?: any): TbPopoverComponent { + if (!(config instanceof Element) && 'trigger' in config && 'renderer' in config && 'componentType' in config) { + const componentRef = this.createPopoverRef(config.hostView); + return this.displayPopoverWithComponentRef({ ...config, componentRef }) + } else if (config instanceof Element) { + const componentRef = this.createPopoverRef(hostView); + return this.displayPopoverWithComponentRef(componentRef, config, renderer, componentType, preferredPlacement, hideOnClickOutside, + injector, context, overlayStyle, popoverStyle, style, showCloseButton, visibleFn, popoverContentStyle); + } else { + throw new Error("Invalid configuration provided for displayPopover"); + } } + displayPopoverWithComponentRef(config: DisplayPopoverWithComponentRefConfig): TbPopoverComponent; displayPopoverWithComponentRef(componentRef: ComponentRef, trigger: Element, renderer: Renderer2, - componentType: Type, preferredPlacement: PopoverPreferredPlacement = 'top', - hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, - popoverStyle: any = {}, style?: any, showCloseButton = true, - visibleFn: (visible: boolean) => void = () => {}, + componentType: Type, preferredPlacement: PopoverPreferredPlacement, + hideOnClickOutside: boolean, injector?: Injector, context?: any, overlayStyle?: any, + popoverStyle?: any, style?: any, showCloseButton?: boolean, + visibleFn?: (visible: boolean) => void, popoverContentStyle?: any): TbPopoverComponent; + displayPopoverWithComponentRef(config: ComponentRef | DisplayPopoverWithComponentRefConfig, + trigger?: Element, renderer?: Renderer2, componentType?: Type, + preferredPlacement?: PopoverPreferredPlacement, hideOnClickOutside?: boolean, + injector?: Injector, context?: any, overlayStyle?: any, + popoverStyle?: any, style?: any, showCloseButton?: boolean, + visibleFn?: (visible: boolean) => void, popoverContentStyle: any = {}): TbPopoverComponent { - const component = componentRef.instance; + let popoverConfig: DisplayPopoverWithComponentRefConfig; + if (!(config instanceof ComponentRef) && 'trigger' in config && 'renderer' in config && 'componentType' in config) { + popoverConfig = config; + } else if(config instanceof ComponentRef) { + popoverConfig = { + componentRef: config, + trigger, + renderer, + componentType, + preferredPlacement, + hideOnClickOutside, + injector, + context, + overlayStyle, + popoverStyle, + style, + showCloseButton, + visibleFn, + popoverContentStyle + } + } else { + throw new Error("Invalid configuration provided for displayPopoverWithComponentRef"); + } + popoverConfig = mergeDeep({} as any, defaultPopoverConfig, popoverConfig); + return this._displayPopoverWithComponentRef(popoverConfig); + } + + + private _displayPopoverWithComponentRef(conf: DisplayPopoverWithComponentRefConfig): TbPopoverComponent { + const component = conf.componentRef.instance; this.popoverWithTriggers.push({ - trigger, + trigger: conf.trigger, popoverComponent: component }); - renderer.removeChild( - renderer.parentNode(trigger), - componentRef.location.nativeElement + conf.renderer.removeChild( + conf.renderer.parentNode(conf.trigger), + conf.componentRef.location.nativeElement ); - const originElementRef = new ElementRef(trigger); + const originElementRef = new ElementRef(conf.trigger); component.setOverlayOrigin(new CdkOverlayOrigin(originElementRef)); - component.tbPlacement = preferredPlacement; - component.tbComponent = componentType; - component.tbComponentInjector = injector; - component.tbComponentContext = context; - component.tbOverlayStyle = overlayStyle; - component.tbPopoverInnerStyle = popoverStyle; - component.tbPopoverInnerContentStyle = popoverContentStyle; - component.tbComponentStyle = style; - component.tbHideOnClickOutside = hideOnClickOutside; - component.tbShowCloseButton = showCloseButton; + component.tbPlacement = conf.preferredPlacement; + component.tbComponent = conf.componentType; + component.tbComponentInjector = conf.injector; + component.tbComponentContext = conf.context; + component.tbOverlayStyle = conf.overlayStyle; + component.tbModal = conf.isModal; + component.tbPopoverInnerStyle = conf.popoverStyle; + component.tbPopoverInnerContentStyle = conf.popoverContentStyle; + component.tbComponentStyle = conf.style; + component.tbHideOnClickOutside = conf.hideOnClickOutside; + component.tbShowCloseButton = conf.showCloseButton; component.tbVisibleChange.subscribe((visible: boolean) => { if (!visible) { - componentRef.destroy(); + conf.componentRef.destroy(); } }); component.tbDestroy.subscribe(() => { this.removePopoverByComponent(component); }); component.tbHideStart.subscribe(() => { - visibleFn(false); + conf.visibleFn(false); }); component.show(); - visibleFn(true); + conf.visibleFn(true); return component; } From d6739538854ac9e029560c1687320870b183f06b Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 24 Mar 2025 17:59:53 +0200 Subject: [PATCH 21/30] UI: Refactoring popover to use isModal setting --- .../debug/entity-debug-settings.service.ts | 14 ++-- .../vc/entity-types-version-load.component.ts | 15 +++- .../vc/entity-version-diff.component.ts | 15 +++- .../vc/entity-versions-table.component.ts | 81 +++++++++++++------ .../config/timewindow-style.component.ts | 14 ++-- .../get-value-action-settings.component.ts | 36 +++++---- .../set-value-action-settings.component.ts | 30 +++---- .../widget-action-settings.component.ts | 28 ++++--- .../auto-date-format-settings.component.ts | 21 ++--- .../common/background-settings.component.ts | 19 +++-- .../widget-button-custom-style.component.ts | 28 ++++--- ...et-button-toggle-custom-style.component.ts | 30 +++---- ...es-chart-axis-settings-button.component.ts | 25 +++--- ...ries-chart-threshold-settings.component.ts | 20 +++-- .../time-series-chart-y-axis-row.component.ts | 25 +++--- .../common/color-range-settings.component.ts | 21 ++--- .../common/color-settings.component.ts | 35 ++++---- .../common/date-format-select.component.ts | 39 +++++---- .../dynamic-form-property-row.component.ts | 25 +++--- .../common/font-settings.component.ts | 14 ++-- .../common/key/data-keys.component.ts | 16 ++-- .../data-layer-color-settings.component.ts | 29 ++++--- .../common/map/map-layer-row.component.ts | 19 +++-- .../map/map-tooltip-tag-actions.component.ts | 32 ++++---- .../map/marker-image-settings.component.ts | 19 +++-- .../map/marker-shape-settings.component.ts | 25 +++--- .../applications/mobile-app.component.ts | 16 ++-- .../layout/mobile-page-item-row.component.ts | 31 ++++--- .../scada-symbol-behavior-row.component.ts | 27 ++++--- .../scada-symbol-metadata-tag.component.ts | 28 ++++--- .../pages/widget/widget-editor.component.ts | 14 ++-- .../shared/components/js-func.component.ts | 19 +++-- .../timewindow-config-dialog.component.ts | 32 +++++--- .../components/time/timezone.component.ts | 15 ++-- 34 files changed, 511 insertions(+), 346 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts index 873d8f0f3f..cb982b9650 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts @@ -37,14 +37,18 @@ export class EntityDebugSettingsService { if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const debugStrategyPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityDebugSettingsPanelComponent, 'bottom', true, null, - { + const debugStrategyPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: EntityDebugSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'bottom', + context: { ...panelConfig.debugSettings, ...panelConfig.debugConfig, }, - {}, - {}, {}, true); + isModal: true, + }); debugStrategyPopover.tbComponentRef.instance.onSettingsApplied.subscribe(settings => { panelConfig.onSettingsAppliedFn(settings); debugStrategyPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-types-version-load.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-types-version-load.component.ts index f06abaf3a8..903712aac8 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-types-version-load.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-types-version-load.component.ts @@ -232,16 +232,23 @@ export class EntityTypesVersionLoadComponent extends PageComponent implements On if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const removeOtherEntitiesConfirmPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, RemoveOtherEntitiesConfirmComponent, 'bottom', true, null, - { + const removeOtherEntitiesConfirmPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: RemoveOtherEntitiesConfirmComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'bottom', + context: { onClose: (result: boolean | null) => { removeOtherEntitiesConfirmPopover.hide(); if (result) { entityTypeControl.get('config').get('removeOtherEntities').patchValue(true, {emitEvent: true}); } } - }, {}, {}, {}, false); + }, + showCloseButton: false, + isModal: true + }); } } } diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts index 1908b5e1fa..19dc945d65 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts @@ -304,9 +304,13 @@ export class EntityVersionDiffComponent extends PageComponent implements OnInit, if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', false, null, - { + const restoreVersionPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: EntityVersionRestoreComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'leftTop', + context: { versionName: this.versionName, versionId: this.versionId, externalEntityId: this.externalEntityId, @@ -317,7 +321,10 @@ export class EntityVersionDiffComponent extends PageComponent implements OnInit, this.versionRestored.emit(); } } - }, {}, {}, {}, false); + }, + showCloseButton: false, + isModal: true + }); restoreVersionPopover.tbComponentRef.instance.popoverComponent = restoreVersionPopover; } } diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts index 2a6d5c5962..fe9af56e4b 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts @@ -211,9 +211,13 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const createVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityVersionCreateComponent, 'leftTop', false, null, - { + const createVersionPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: EntityVersionCreateComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'leftTop', + context: { branch: this.branch, entityId: this.entityId, entityName: this.entityName, @@ -229,8 +233,11 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni } } }, - {maxHeight: '100vh', height: '100%', padding: '10px'}, - {width: '400px', minWidth: '100%', maxWidth: '100%'}, {}, false); + showCloseButton: false, + overlayStyle: {maxHeight: '100vh', height: '100%', padding: '10px'}, + popoverStyle: {width: '400px', minWidth: '100%', maxWidth: '100%'}, + isModal: true + }); createVersionPopover.tbComponentRef.instance.popoverComponent = createVersionPopover; } } @@ -243,9 +250,13 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const complexCreateVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ComplexVersionCreateComponent, 'leftTop', false, null, - { + const complexCreateVersionPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: ComplexVersionCreateComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'leftTop', + context: { branch: this.branch, onClose: (result: VersionCreationResult | null, branch: string | null) => { complexCreateVersionPopover.hide(); @@ -258,8 +269,10 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni } } }, - {maxHeight: '90vh', height: '100%', padding: '10px'}, - {}, {}, false); + showCloseButton: false, + overlayStyle: {maxHeight: '90vh', height: '100%', padding: '10px'}, + isModal: true + }); complexCreateVersionPopover.tbComponentRef.instance.popoverComponent = complexCreateVersionPopover; } } @@ -272,14 +285,21 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const diffVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityVersionDiffComponent, 'leftTop', true, null, - { + const diffVersionPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: EntityVersionDiffComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'leftTop', + context: { versionName: entityVersion.name, versionId: entityVersion.id, entityId: this.entityId, externalEntityId: this.externalEntityIdValue - }, {}, {}, {}, false); + }, + showCloseButton: false, + isModal: true + }); diffVersionPopover.tbComponentRef.instance.popoverComponent = diffVersionPopover; diffVersionPopover.tbComponentRef.instance.versionRestored.subscribe(() => { this.versionRestored.emit(); @@ -295,9 +315,13 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', false, null, - { + const restoreVersionPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: EntityVersionRestoreComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'leftTop', + context: { versionName: entityVersion.name, versionId: entityVersion.id, externalEntityId: this.externalEntityIdValue, @@ -308,8 +332,11 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni } } }, - {maxHeight: '100vh', height: '100%', padding: '10px'}, - {width: '400px', minWidth: '100%', maxWidth: '100%'}, {}, false); + showCloseButton: false, + overlayStyle: {maxHeight: '100vh', height: '100%', padding: '10px'}, + popoverStyle: {width: '400px', minWidth: '100%', maxWidth: '100%'}, + isModal: true + }); restoreVersionPopover.tbComponentRef.instance.popoverComponent = restoreVersionPopover; } } @@ -322,17 +349,23 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const restoreEntitiesVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ComplexVersionLoadComponent, 'leftTop', false, null, - { + const restoreEntitiesVersionPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: ComplexVersionLoadComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'leftTop', + context: { versionName: entityVersion.name, versionId: entityVersion.id, onClose: (result: VersionLoadResult | null) => { restoreEntitiesVersionPopover.hide(); } }, - {maxHeight: '80vh', height: '100%', padding: '10px'}, - {}, {}, false); + showCloseButton: false, + overlayStyle: {maxHeight: '80vh', height: '100%', padding: '10px'}, + isModal: true + }); restoreEntitiesVersionPopover.tbComponentRef.instance.popoverComponent = restoreEntitiesVersionPopover; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.ts index 790535acbc..c9675caefa 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.ts @@ -80,11 +80,15 @@ export class TimewindowStyleComponent implements OnInit, ControlValueAccessor { timewindowStyle: this.modelValue, previewValue: this.previewValue }; - const timewindowStylePanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, TimewindowStylePanelComponent, 'left', true, null, - ctx, - {}, - {}, {}, true); + const timewindowStylePanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + hostView: this.viewContainerRef, + componentType: TimewindowStylePanelComponent, + preferredPlacement: 'left', + context: ctx, + isModal: true + }); timewindowStylePanelPopover.tbComponentRef.instance.popover = timewindowStylePanelPopover; timewindowStylePanelPopover.tbComponentRef.instance.timewindowStyleApplied.subscribe((timewindowStyle) => { timewindowStylePanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings.component.ts index 5b95ef5f13..7bdb17c06a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings.component.ts @@ -129,23 +129,25 @@ export class GetValueActionSettingsComponent implements OnInit, ControlValueAcce if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - getValueSettings: this.modelValue, - panelTitle: this.panelTitle, - valueType: this.valueType, - trueLabel: this.trueLabel, - falseLabel: this.falseLabel, - stateLabel: this.stateLabel, - aliasController: this.aliasController, - targetDevice: this.targetDevice, - widgetType: this.widgetType - }; - const getValueSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, GetValueActionSettingsPanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const getValueSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: GetValueActionSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], + context: { + getValueSettings: this.modelValue, + panelTitle: this.panelTitle, + valueType: this.valueType, + trueLabel: this.trueLabel, + falseLabel: this.falseLabel, + stateLabel: this.stateLabel, + aliasController: this.aliasController, + targetDevice: this.targetDevice, + widgetType: this.widgetType + }, + isModal: true + }); getValueSettingsPanelPopover.tbComponentRef.instance.popover = getValueSettingsPanelPopover; getValueSettingsPanelPopover.tbComponentRef.instance.getValueSettingsApplied.subscribe((getValueSettings) => { getValueSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings.component.ts index e446e6f5b3..cf90db33ed 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/set-value-action-settings.component.ts @@ -115,20 +115,22 @@ export class SetValueActionSettingsComponent implements OnInit, ControlValueAcce if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - setValueSettings: this.modelValue, - panelTitle: this.panelTitle, - valueType: this.valueType, - aliasController: this.aliasController, - targetDevice: this.targetDevice, - widgetType: this.widgetType - }; - const setValueSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, SetValueActionSettingsPanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const setValueSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: SetValueActionSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], + context: { + setValueSettings: this.modelValue, + panelTitle: this.panelTitle, + valueType: this.valueType, + aliasController: this.aliasController, + targetDevice: this.targetDevice, + widgetType: this.widgetType + }, + isModal: true + }); setValueSettingsPanelPopover.tbComponentRef.instance.popover = setValueSettingsPanelPopover; setValueSettingsPanelPopover.tbComponentRef.instance.setValueSettingsApplied.subscribe((setValueSettings) => { setValueSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action-settings.component.ts index 51583f71fb..de29366846 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action-settings.component.ts @@ -114,19 +114,21 @@ export class WidgetActionSettingsComponent implements OnInit, ControlValueAccess if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - widgetAction: this.modelValue, - panelTitle: this.panelTitle, - widgetType: this.widgetType, - callbacks: this.callbacks, - additionalWidgetActionTypes: this.additionalWidgetActionTypes - }; - const widgetActionSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, WidgetActionSettingsPanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const widgetActionSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: WidgetActionSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], + context: { + widgetAction: this.modelValue, + panelTitle: this.panelTitle, + widgetType: this.widgetType, + callbacks: this.callbacks, + additionalWidgetActionTypes: this.additionalWidgetActionTypes + }, + isModal: true + }); widgetActionSettingsPanelPopover.tbComponentRef.instance.widgetActionApplied.subscribe((widgetAction) => { widgetActionSettingsPanelPopover.hide(); this.modelValue = widgetAction; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings.component.ts index 1d776bcb70..f46bce6dd6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/auto-date-format-settings.component.ts @@ -78,15 +78,18 @@ export class AutoDateFormatSettingsComponent implements OnInit, ControlValueAcce if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - autoDateFormatSettings: deepClone(this.modelValue), - defaultValues: this.defaultValues - }; - const autoDateFormatSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, AutoDateFormatSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const autoDateFormatSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: AutoDateFormatSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: { + autoDateFormatSettings: deepClone(this.modelValue), + defaultValues: this.defaultValues + }, + isModal: true + }); autoDateFormatSettingsPanelPopover.tbComponentRef.instance.popover = autoDateFormatSettingsPanelPopover; autoDateFormatSettingsPanelPopover.tbComponentRef.instance.autoDateFormatSettingsApplied.subscribe((autoDateFormatSettings) => { autoDateFormatSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts index cadf5fb07a..a5ed2cf96a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts @@ -107,14 +107,17 @@ export class BackgroundSettingsComponent implements OnInit, ControlValueAccessor if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - backgroundSettings: this.modelValue - }; - const backgroundSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, BackgroundSettingsPanelComponent, ['left'], false, null, - ctx, - {}, - {}, {}, true); + const backgroundSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: BackgroundSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'left', + context: { + backgroundSettings: this.modelValue + }, + isModal: true + }); backgroundSettingsPanelPopover.tbComponentRef.instance.popover = backgroundSettingsPanelPopover; backgroundSettingsPanelPopover.tbComponentRef.instance.backgroundSettingsApplied.subscribe((backgroundSettings) => { backgroundSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style.component.ts index 5db91fb1bb..1cfc7a77cf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-custom-style.component.ts @@ -124,19 +124,21 @@ export class WidgetButtonCustomStyleComponent implements OnInit, OnChanges, Cont if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - appearance: this.appearance, - borderRadius: this.borderRadius, - autoScale: this.autoScale, - state: this.state, - customStyle: this.modelValue - }; - const widgetButtonCustomStylePanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, WidgetButtonCustomStylePanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const widgetButtonCustomStylePanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: WidgetButtonCustomStylePanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], + context: { + appearance: this.appearance, + borderRadius: this.borderRadius, + autoScale: this.autoScale, + state: this.state, + customStyle: this.modelValue + }, + isModal: true + }); widgetButtonCustomStylePanelPopover.tbComponentRef.instance.popover = widgetButtonCustomStylePanelPopover; widgetButtonCustomStylePanelPopover.tbComponentRef.instance.customStyleApplied.subscribe((customStyle) => { widgetButtonCustomStylePanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style.component.ts index b2a78ff961..1e0f19ea58 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/button/widget-button-toggle-custom-style.component.ts @@ -127,20 +127,22 @@ export class WidgetButtonToggleCustomStyleComponent implements OnInit, OnChanges if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - appearance: this.appearance, - borderRadius: this.borderRadius, - autoScale: this.autoScale, - state: this.state, - value: this.value, - customStyle: this.modelValue - }; - const widgetButtonCustomStylePanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, WidgetButtonToggleCustomStylePanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const widgetButtonCustomStylePanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: WidgetButtonToggleCustomStylePanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], + context: { + appearance: this.appearance, + borderRadius: this.borderRadius, + autoScale: this.autoScale, + state: this.state, + value: this.value, + customStyle: this.modelValue + }, + isModal: true + }); widgetButtonCustomStylePanelPopover.tbComponentRef.instance.popover = widgetButtonCustomStylePanelPopover; widgetButtonCustomStylePanelPopover.tbComponentRef.instance.customStyleApplied.subscribe((customStyle) => { widgetButtonCustomStylePanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts index 2f2067f3a8..016f213c0b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts @@ -85,17 +85,20 @@ export class TimeSeriesChartAxisSettingsButtonComponent implements OnInit, Contr if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - axisSettings: this.modelValue, - axisType: this.axisType, - panelTitle: this.panelTitle, - advanced: this.advanced - }; - const axisSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, TimeSeriesChartAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const axisSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: TimeSeriesChartAxisSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: { + axisSettings: this.modelValue, + axisType: this.axisType, + panelTitle: this.panelTitle, + advanced: this.advanced + }, + isModal: true + }); axisSettingsPanelPopover.tbComponentRef.instance.popover = axisSettingsPanelPopover; axisSettingsPanelPopover.tbComponentRef.instance.axisSettingsApplied.subscribe((axisSettings) => { axisSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts index e3ff513e0f..d39e4b48dd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts @@ -107,11 +107,21 @@ export class TimeSeriesChartThresholdSettingsComponent implements OnInit, Contro hideYAxis: this.hideYAxis, yAxisIds: this.yAxisIds }; - const thresholdSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, TimeSeriesChartThresholdSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const thresholdSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: TimeSeriesChartThresholdSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: { + thresholdSettings: deepClone(this.modelValue), + panelTitle: this.title, + widgetConfig: this.widgetConfig, + hideYAxis: this.hideYAxis, + yAxisIds: this.yAxisIds + }, + isModal: true + }); thresholdSettingsPanelPopover.tbComponentRef.instance.popover = thresholdSettingsPanelPopover; thresholdSettingsPanelPopover.tbComponentRef.instance.thresholdSettingsApplied.subscribe((thresholdSettings) => { thresholdSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts index 69cbc29a25..dec7148b30 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts @@ -151,17 +151,20 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - axisType: 'yAxis', - panelTitle: this.translate.instant('widgets.time-series-chart.axis.y-axis-settings'), - axisSettings: deepClone(this.modelValue), - advanced: this.advanced - }; - const yAxisSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, TimeSeriesChartAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const yAxisSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: TimeSeriesChartAxisSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: { + axisType: 'yAxis', + panelTitle: this.translate.instant('widgets.time-series-chart.axis.y-axis-settings'), + axisSettings: deepClone(this.modelValue), + advanced: this.advanced + }, + isModal: true + }); yAxisSettingsPanelPopover.tbComponentRef.instance.popover = yAxisSettingsPanelPopover; yAxisSettingsPanelPopover.tbComponentRef.instance.axisSettingsApplied.subscribe((yAxisSettings) => { yAxisSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-range-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-range-settings.component.ts index 431fac44da..23b1efbce9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-range-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-range-settings.component.ts @@ -121,15 +121,18 @@ export class ColorRangeSettingsComponent implements OnInit, ControlValueAccessor if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - colorRangeSettings: this.modelValue, - settingsComponents: this.colorSettingsComponentService.getOtherColorSettingsComponents(this) - }; - const colorRangeSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ColorRangePanelComponent, 'left', false, null, - ctx, - {}, - {}, {}, true); + const colorRangeSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: ColorRangePanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'left', + context: { + colorRangeSettings: this.modelValue, + settingsComponents: this.colorSettingsComponentService.getOtherColorSettingsComponents(this) + }, + isModal: true + }); colorRangeSettingsPanelPopover.tbComponentRef.instance.popover = colorRangeSettingsPanelPopover; colorRangeSettingsPanelPopover.tbComponentRef.instance.colorRangeApplied.subscribe((colorRangeSettings: Array) => { colorRangeSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts index 133fa11bd4..05c069cbf3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts @@ -159,22 +159,25 @@ export class ColorSettingsComponent implements OnInit, ControlValueAccessor, OnD if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - colorSettings: this.modelValue, - settingsComponents: this.colorSettingsComponentService.getOtherColorSettingsComponents(this), - aliasController: this.aliasController, - dataKeyCallbacks: this.dataKeyCallbacks, - datasource: this.datasource, - rangeAdvancedMode: this.rangeAdvancedMode, - gradientAdvancedMode: this.gradientAdvancedMode, - minValue: this.minValue, - maxValue: this.maxValue - }; - const colorSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ColorSettingsPanelComponent, 'left', false, null, - ctx, - {}, - {}, {}, true); + const colorSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: ColorSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'left', + context: { + colorSettings: this.modelValue, + settingsComponents: this.colorSettingsComponentService.getOtherColorSettingsComponents(this), + aliasController: this.aliasController, + dataKeyCallbacks: this.dataKeyCallbacks, + datasource: this.datasource, + rangeAdvancedMode: this.rangeAdvancedMode, + gradientAdvancedMode: this.gradientAdvancedMode, + minValue: this.minValue, + maxValue: this.maxValue + }, + isModal: true + }); colorSettingsPanelPopover.tbComponentRef.instance.popover = colorSettingsPanelPopover; colorSettingsPanelPopover.tbComponentRef.instance.colorSettingsApplied.subscribe((colorSettings) => { colorSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts index 92aef0ba29..847e869fe6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts @@ -162,14 +162,16 @@ export class DateFormatSelectComponent implements OnInit, ControlValueAccessor { if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - dateFormat: deepClone(this.modelValue) - }; - const dateFormatSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, DateFormatSettingsPanelComponent, 'top', false, null, - ctx, - {}, - {}, {}, true); + const dateFormatSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: DateFormatSettingsPanelComponent, + hostView: this.viewContainerRef, + context: { + dateFormat: deepClone(this.modelValue) + }, + isModal: true + }); dateFormatSettingsPanelPopover.tbComponentRef.instance.popover = dateFormatSettingsPanelPopover; dateFormatSettingsPanelPopover.tbComponentRef.instance.dateFormatApplied.subscribe((dateFormat) => { dateFormatSettingsPanelPopover.hide(); @@ -187,15 +189,18 @@ export class DateFormatSelectComponent implements OnInit, ControlValueAccessor { if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - autoDateFormatSettings: mergeDeep({} as AutoDateFormatSettings, - defaultAutoDateFormatSettings, this.modelValue.autoDateFormatSettings) - }; - const autoDateFormatSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, AutoDateFormatSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const autoDateFormatSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: AutoDateFormatSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: { + autoDateFormatSettings: mergeDeep({} as AutoDateFormatSettings, + defaultAutoDateFormatSettings, this.modelValue.autoDateFormatSettings) + }, + isModal: true + }); autoDateFormatSettingsPanelPopover.tbComponentRef.instance.popover = autoDateFormatSettingsPanelPopover; autoDateFormatSettingsPanelPopover.tbComponentRef.instance.autoDateFormatSettingsApplied.subscribe((autoDateFormatSettings) => { autoDateFormatSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-row.component.ts index 79c2254a7d..58d879ba79 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/dynamic-form/dynamic-form-property-row.component.ts @@ -168,17 +168,20 @@ export class DynamicFormPropertyRowComponent implements ControlValueAccessor, On if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - isAdd: add, - disabled: this.disabled, - booleanPropertyIds: this.booleanPropertyIds, - property: deepClone(this.modelValue) - }; - const dynamicFormPropertyPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, DynamicFormPropertyPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const dynamicFormPropertyPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: DynamicFormPropertyPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: { + isAdd: add, + disabled: this.disabled, + booleanPropertyIds: this.booleanPropertyIds, + property: deepClone(this.modelValue) + }, + isModal: true + }); dynamicFormPropertyPanelPopover.tbComponentRef.instance.popover = dynamicFormPropertyPanelPopover; dynamicFormPropertyPanelPopover.tbComponentRef.instance.propertySettingsApplied.subscribe((property) => { dynamicFormPropertyPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts index 25addab5ea..2675f9d1e6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts @@ -109,11 +109,15 @@ export class FontSettingsComponent implements OnInit, ControlValueAccessor { ctx.previewText = previewText; } } - const fontSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, FontSettingsPanelComponent, 'left', false, null, - ctx, - {}, - {}, {}, true); + const fontSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: FontSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'left', + context: ctx, + isModal: true + }); fontSettingsPanelPopover.tbComponentRef.instance.popover = fontSettingsPanelPopover; fontSettingsPanelPopover.tbComponentRef.instance.fontApplied.subscribe((font) => { fontSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/key/data-keys.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/key/data-keys.component.ts index e60d0298d9..a9be1fd352 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/key/data-keys.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/key/data-keys.component.ts @@ -565,14 +565,20 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const colorPickerPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ColorPickerPanelComponent, ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], true, null, - { + const colorPickerPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: ColorPickerPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], + context: { color: key.color, colorCancelButton: true }, - {}, - {}, {}, false, () => {}, {padding: '12px 4px 12px 12px'}); + showCloseButton: false, + popoverContentStyle: {padding: '12px 4px 12px 12px'}, + isModal: true + }); colorPickerPopover.tbComponentRef.instance.popover = colorPickerPopover; colorPickerPopover.tbComponentRef.instance.colorSelected.subscribe((color) => { colorPickerPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-color-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-color-settings.component.ts index 8c94ed2c80..ea5da11890 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-color-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/data-layer-color-settings.component.ts @@ -97,19 +97,22 @@ export class DataLayerColorSettingsComponent implements ControlValueAccessor { if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - colorSettings: this.modelValue, - context: this.context, - dsType: this.dsType, - dsEntityAliasId: this.dsEntityAliasId, - dsDeviceId: this.dsDeviceId, - helpId: this.helpId - }; - const colorSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, DataLayerColorSettingsPanelComponent, 'left', false, null, - ctx, - {}, - {}, {}, true); + const colorSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: DataLayerColorSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'left', + context: { + colorSettings: this.modelValue, + context: this.context, + dsType: this.dsType, + dsEntityAliasId: this.dsEntityAliasId, + dsDeviceId: this.dsDeviceId, + helpId: this.helpId + }, + isModal: true + }); colorSettingsPanelPopover.tbComponentRef.instance.popover = colorSettingsPanelPopover; colorSettingsPanelPopover.tbComponentRef.instance.colorSettingsApplied.subscribe((colorSettings) => { colorSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts index d7d4f78433..40a98b54cc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts @@ -180,14 +180,17 @@ export class MapLayerRowComponent implements ControlValueAccessor, OnInit { if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - mapLayerSettings: deepClone(this.modelValue) - }; - const mapLayerSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, MapLayerSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const mapLayerSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: MapLayerSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: { + mapLayerSettings: deepClone(this.modelValue) + }, + isModal: true + }); mapLayerSettingsPanelPopover.tbComponentRef.instance.popover = mapLayerSettingsPanelPopover; mapLayerSettingsPanelPopover.tbComponentRef.instance.mapLayerSettingsApplied.subscribe((layer) => { mapLayerSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-tooltip-tag-actions.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-tooltip-tag-actions.component.ts index 6cf5791406..26f17055b6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-tooltip-tag-actions.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-tooltip-tag-actions.component.ts @@ -151,21 +151,23 @@ export class MapTooltipTagActionsComponent implements ControlValueAccessor, OnIn } else { const title = this.translate.instant(isAdd ? 'widgets.maps.data-layer.add-tooltip-tag-action' : 'widgets.maps.data-layer.edit-tooltip-tag-action'); const applyTitle = this.translate.instant(isAdd ? 'action.add' : 'action.apply'); - const ctx: any = { - widgetAction: action, - withName: true, - actionNames, - panelTitle: title, - applyTitle, - widgetType: widgetType.latest, - callbacks: this.context.callbacks - }; - const widgetActionSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, WidgetActionSettingsPanelComponent, - ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const widgetActionSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: WidgetActionSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftTopOnly', 'leftOnly', 'leftBottomOnly'], + context: { + widgetAction: action, + withName: true, + actionNames, + panelTitle: title, + applyTitle, + widgetType: widgetType.latest, + callbacks: this.context.callbacks + }, + isModal: true + }); widgetActionSettingsPanelPopover.tbComponentRef.instance.widgetActionApplied.subscribe((widgetAction) => { widgetActionSettingsPanelPopover.hide(); callback(widgetAction); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-image-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-image-settings.component.ts index 2d8feb817f..eac0dc9121 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-image-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-image-settings.component.ts @@ -76,14 +76,17 @@ export class MarkerImageSettingsComponent implements ControlValueAccessor { if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - markerImageSettings: this.modelValue, - }; - const markerImageSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, MarkerImageSettingsPanelComponent, 'left', false, null, - ctx, - {}, - {}, {}, true); + const markerImageSettingsPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: MarkerImageSettingsPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'left', + context: { + markerImageSettings: this.modelValue, + }, + isModal: true + }); markerImageSettingsPanelPopover.tbComponentRef.instance.popover = markerImageSettingsPanelPopover; markerImageSettingsPanelPopover.tbComponentRef.instance.markerImageSettingsApplied.subscribe((markerImageSettings) => { markerImageSettingsPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts index 4400c5a151..bfb6c0c76d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts @@ -177,17 +177,20 @@ export class MarkerShapeSettingsComponent implements ControlValueAccessor, OnIni ); }); } else if (this.markerType === MarkerType.icon) { - const ctx: any = { - iconContainer: (this.modelValue as MarkerIconSettings).iconContainer, - icon: (this.modelValue as MarkerIconSettings).icon, - color: this.modelValue.color.color, - trip: this.trip - }; - const markerIconShapesPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, MarkerIconShapesComponent, 'left', true, null, - ctx, - {}, - {}, {}, true); + const markerIconShapesPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: MarkerIconShapesComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'left', + context: { + iconContainer: (this.modelValue as MarkerIconSettings).iconContainer, + icon: (this.modelValue as MarkerIconSettings).icon, + color: this.modelValue.color.color, + trip: this.trip + }, + isModal: true + }); markerIconShapesPopover.tbComponentRef.instance.popover = markerIconShapesPopover; markerIconShapesPopover.tbComponentRef.instance.markerIconSelected.subscribe((iconInfo) => { markerIconShapesPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/pages/mobile/applications/mobile-app.component.ts b/ui-ngx/src/app/modules/home/pages/mobile/applications/mobile-app.component.ts index bbd096bbaf..eceda5ac9a 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/applications/mobile-app.component.ts +++ b/ui-ngx/src/app/modules/home/pages/mobile/applications/mobile-app.component.ts @@ -166,11 +166,17 @@ export class MobileAppComponent extends EntityComponent { ? this.entityForm.get('versionInfo.latestVersionReleaseNotes').value : this.entityForm.get('versionInfo.minVersionReleaseNotes').value }; - const releaseNotesPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EditorPanelComponent, ['leftOnly', 'leftBottomOnly', 'leftTopOnly'], true, null, - ctx, - {}, - {}, {}, false, () => {}, {padding: '16px 24px'}); + const releaseNotesPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + hostView: this.viewContainerRef, + componentType: EditorPanelComponent, + preferredPlacement: ['leftOnly', 'leftBottomOnly', 'leftTopOnly'], + context: ctx, + showCloseButton: false, + popoverContentStyle: {padding: '16px 24px'}, + isModal: false + }); releaseNotesPanelPopover.tbComponentRef.instance.popover = releaseNotesPanelPopover; releaseNotesPanelPopover.tbComponentRef.instance.editorContentApplied.subscribe((releaseNotes) => { releaseNotesPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.ts b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.ts index 33be223815..9f4add3195 100644 --- a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.ts +++ b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/mobile-page-item-row.component.ts @@ -55,6 +55,7 @@ import { TbPopoverService } from '@shared/components/popover.service'; import { CustomMobilePagePanelComponent } from '@home/pages/mobile/bundes/layout/custom-mobile-page-panel.component'; import { DefaultMobilePagePanelComponent } from '@home/pages/mobile/bundes/layout/default-mobile-page-panel.component'; import { TranslateService } from '@ngx-translate/core'; +import { DisplayPopoverConfig } from '@shared/components/popover.models'; @Component({ selector: 'tb-mobile-menu-item-row', @@ -222,27 +223,31 @@ export class MobilePageItemRowComponent implements ControlValueAccessor, OnInit, if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - disabled: this.disabled, - pageItem: deepClone(this.modelValue) + const config: DisplayPopoverConfig = { + trigger, + renderer: this.renderer, + componentType: undefined, + hostView: this.viewContainerRef, + preferredPlacement: ['right', 'bottom', 'top'], + context: { + disabled: this.disabled, + pageItem: deepClone(this.modelValue) + }, + showCloseButton: false, + popoverContentStyle: {padding: '16px 24px'}, + isModal: true }; if (this.isDefaultMenuItem) { - const defaultMobilePagePanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, DefaultMobilePagePanelComponent, ['right', 'bottom', 'top'], true, null, - ctx, - {}, - {}, {}, false, () => {}, {padding: '16px 24px'}); + config.componentType = DefaultMobilePagePanelComponent; + const defaultMobilePagePanelPopover = this.popoverService.displayPopover(config); defaultMobilePagePanelPopover.tbComponentRef.instance.popover = defaultMobilePagePanelPopover; defaultMobilePagePanelPopover.tbComponentRef.instance.defaultMobilePageApplied.subscribe((menuItem) => { defaultMobilePagePanelPopover.hide(); this.afterPageEdit(menuItem); }); } else { - const customMobilePagePanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, CustomMobilePagePanelComponent, ['right', 'bottom', 'top'], true, null, - ctx, - {}, - {}, {}, false, () => {}, {padding: '16px 24px'}); + config.componentType = CustomMobilePagePanelComponent; + const customMobilePagePanelPopover = this.popoverService.displayPopover(config); customMobilePagePanelPopover.tbComponentRef.instance.popover = customMobilePagePanelPopover; customMobilePagePanelPopover.tbComponentRef.instance.customMobilePageApplied.subscribe((page) => { customMobilePagePanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts index 3b1db9a595..7cde50ef29 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-behavior-row.component.ts @@ -203,18 +203,21 @@ export class ScadaSymbolBehaviorRowComponent implements ControlValueAccessor, On if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - isAdd: add, - disabled: this.disabled, - aliasController: this.aliasController, - callbacks: this.callbacks, - behavior: deepClone(this.modelValue) - }; - const scadaSymbolBehaviorPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ScadaSymbolBehaviorPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, - ctx, - {}, - {}, {}, true); + const scadaSymbolBehaviorPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: ScadaSymbolBehaviorPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: { + isAdd: add, + disabled: this.disabled, + aliasController: this.aliasController, + callbacks: this.callbacks, + behavior: deepClone(this.modelValue) + }, + isModal: true + }); scadaSymbolBehaviorPanelPopover.tbComponentRef.instance.popover = scadaSymbolBehaviorPanelPopover; scadaSymbolBehaviorPanelPopover.tbComponentRef.instance.behaviorSettingsApplied.subscribe((behavior) => { scadaSymbolBehaviorPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.ts b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.ts index 95b49d47c2..339ac3a358 100644 --- a/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.ts +++ b/ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.ts @@ -158,19 +158,21 @@ export class ScadaSymbolMetadataTagComponent implements ControlValueAccessor, On tagFunctionControl = this.tagFormGroup.get('clickAction'); completer = this.clickActionFunctionCompleter; } - const ctx: any = { - tagFunction: tagFunctionControl.value, - tagFunctionType, - tag: this.tagFormGroup.get('tag').value, - completer, - disabled: this.disabled - }; - const scadaSymbolTagFunctionPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, ScadaSymbolMetadataTagFunctionPanelComponent, - ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, - ctx, - {}, - {}, {}, true); + const scadaSymbolTagFunctionPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: ScadaSymbolMetadataTagFunctionPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: { + tagFunction: tagFunctionControl.value, + tagFunctionType, + tag: this.tagFormGroup.get('tag').value, + completer, + disabled: this.disabled + }, + isModal: true + }); scadaSymbolTagFunctionPanelPopover.tbComponentRef.instance.popover = scadaSymbolTagFunctionPanelPopover; scadaSymbolTagFunctionPanelPopover.tbComponentRef.instance.tagFunctionApplied.subscribe((tagFunction) => { scadaSymbolTagFunctionPanelPopover.hide(); diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts index 6675425f32..93c411aabe 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts @@ -816,11 +816,15 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe const ctx: any = { modules: deepClone(this.controllerScriptModules) }; - const modulesPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, JsFuncModulesComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, - ctx, - {}, - {}, {}, true); + const modulesPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + hostView: this.viewContainerRef, + componentType: JsFuncModulesComponent, + preferredPlacement: ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], + context: ctx, + isModal: true + }); modulesPanelPopover.tbComponentRef.instance.popover = modulesPanelPopover; modulesPanelPopover.tbComponentRef.instance.modulesApplied.subscribe((modules) => { modulesPanelPopover.hide(); diff --git a/ui-ngx/src/app/shared/components/js-func.component.ts b/ui-ngx/src/app/shared/components/js-func.component.ts index c424df8242..435b0495ec 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.ts +++ b/ui-ngx/src/app/shared/components/js-func.component.ts @@ -518,14 +518,17 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const ctx: any = { - modules: deepClone(this.modules) - }; - const modulesPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, JsFuncModulesComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], false, null, - ctx, - {}, - {}, {}, true); + const modulesPanelPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: JsFuncModulesComponent, + hostView: this.viewContainerRef, + preferredPlacement: 'leftTop', + context: { + modules: deepClone(this.modules) + }, + isModal: true + }); modulesPanelPopover.tbComponentRef.instance.popover = modulesPanelPopover; modulesPanelPopover.tbComponentRef.instance.modulesApplied.subscribe((modules) => { modulesPanelPopover.hide(); diff --git a/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.ts b/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.ts index 68ec6bcdd9..1ad4dab88c 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.ts @@ -558,9 +558,13 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const aggregationConfigPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, AggregationOptionsConfigPanelComponent, ['left', 'leftTop', 'leftBottom'], true, null, - { + const aggregationConfigPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + hostView: this.viewContainerRef, + componentType: AggregationOptionsConfigPanelComponent, + preferredPlacement: ['left', 'leftTop', 'leftBottom'], + context: { allowedAggregationTypes: deepClone(this.timewindowForm.get('allowedAggTypes').value), onClose: (result: Array | null) => { aggregationConfigPopover.hide(); @@ -570,8 +574,10 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On } } }, - {maxHeight: '500px', height: '100%'}, - {}, {}, true, () => {}, {padding: 0}); + overlayStyle: {maxHeight: '500px', height: '100%'}, + popoverContentStyle: {padding: 0}, + isModal: true + }); aggregationConfigPopover.tbComponentRef.instance.popoverComponent = aggregationConfigPopover; } this.cd.detectChanges(); @@ -612,9 +618,13 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const intervalsConfigPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, IntervalOptionsConfigPanelComponent, ['left', 'leftTop', 'leftBottom'], true, null, - { + const intervalsConfigPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + hostView: this.viewContainerRef, + componentType: IntervalOptionsConfigPanelComponent, + preferredPlacement: ['left', 'leftTop', 'leftBottom'], + context: { aggregation: this.aggregation, allowedIntervals: deepClone(this.timewindowForm.get(allowedIntervalsControlName).value), aggIntervalsConfig: deepClone(this.timewindowForm.get(aggIntervalsConfigControlName).value), @@ -629,8 +639,10 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On } } }, - {maxHeight: '500px', height: '100%'}, - {}, {}, true, () => {}, {padding: 0}); + overlayStyle: {maxHeight: '500px', height: '100%'}, + popoverContentStyle: {padding: 0}, + isModal: true + }); intervalsConfigPopover.tbComponentRef.instance.popoverComponent = intervalsConfigPopover; } this.cd.detectChanges(); diff --git a/ui-ngx/src/app/shared/components/time/timezone.component.ts b/ui-ngx/src/app/shared/components/time/timezone.component.ts index 78a938f53f..34e2486106 100644 --- a/ui-ngx/src/app/shared/components/time/timezone.component.ts +++ b/ui-ngx/src/app/shared/components/time/timezone.component.ts @@ -155,9 +155,13 @@ export class TimezoneComponent implements ControlValueAccessor, OnInit { if (this.popoverService.hasPopover(trigger)) { this.popoverService.hidePopover(trigger); } else { - const timezoneSelectionPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, TimezonePanelComponent, ['bottomRight', 'leftBottom'], true, null, - { + const timezoneSelectionPopover = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + hostView: this.viewContainerRef, + componentType: TimezonePanelComponent, + preferredPlacement: ['bottomRight', 'leftBottom'], + context: { timezone: this.modelValue, userTimezoneByDefault: this.userTimezoneByDefaultValue, localBrowserTimezonePlaceholderOnEmpty: this.localBrowserTimezonePlaceholderOnEmptyValue, @@ -173,8 +177,9 @@ export class TimezoneComponent implements ControlValueAccessor, OnInit { } } }, - {}, - {}, {}, false); + showCloseButton: false, + isModal: true + }); timezoneSelectionPopover.tbComponentRef.instance.popoverComponent = timezoneSelectionPopover; } this.cd.detectChanges(); From 336d60268b818f5ecd5359a5fbb9afdd6ba6d93a Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 25 Mar 2025 10:56:32 +0200 Subject: [PATCH 22/30] UI: Refactoring popover model --- ui-ngx/src/app/shared/components/popover.models.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ui-ngx/src/app/shared/components/popover.models.ts b/ui-ngx/src/app/shared/components/popover.models.ts index 9fb01d1f3d..dc7e1f9ba7 100644 --- a/ui-ngx/src/app/shared/components/popover.models.ts +++ b/ui-ngx/src/app/shared/components/popover.models.ts @@ -112,11 +112,7 @@ export interface DisplayPopoverWithComponentRefConfig { isModal?: boolean; } -export const defaultPopoverConfig: DisplayPopoverWithComponentRefConfig = { - componentRef: undefined, - trigger: undefined, - renderer: undefined, - componentType: undefined, +export const defaultPopoverConfig: Partial> = { preferredPlacement: 'top', hideOnClickOutside: true, overlayStyle: {}, From 887c291deb71e26d8c743ed106afd626f3e34c84 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 25 Mar 2025 11:14:44 +0200 Subject: [PATCH 23/30] UI: Refactoring popover to use isModal setting --- .../calculated-field-arguments-table.component.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts index 945fc67ad4..512480279b 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts @@ -174,11 +174,15 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces entityHasError: this.entityNameErrorSet.has(argument.refEntityId?.id), usedArgumentNames: this.argumentsFormArray.value.map(({ argumentName }) => argumentName).filter(name => name !== argument.argumentName), }; - this.popoverComponent = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, CalculatedFieldArgumentPanelComponent, isDefined(index) ? 'left' : 'right', false, null, - ctx, - {}, - {}, {}, true); + this.popoverComponent = this.popoverService.displayPopover({ + trigger, + renderer: this.renderer, + componentType: CalculatedFieldArgumentPanelComponent, + hostView: this.viewContainerRef, + preferredPlacement: isDefined(index) ? 'left' : 'right', + context: ctx, + isModal: true + }); this.popoverComponent.tbComponentRef.instance.argumentsDataApplied.subscribe(({ value, index }) => { this.popoverComponent.hide(); const formGroup = this.fb.group(value); From f432ccc182c9fb7b1cbaac8e3b04db631bb51c7f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 25 Mar 2025 11:49:50 +0200 Subject: [PATCH 24/30] UI: Fixed not work decline settings in advanced map settings --- .../lib/settings/map/map-widget-settings.component.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-widget-settings.component.ts index 221f820d68..3dc10f34cf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/map-widget-settings.component.ts @@ -54,9 +54,17 @@ export class MapWidgetSettingsComponent extends WidgetSettingsComponent { return mergeDeepIgnoreArray({} as MapWidgetSettings, mapWidgetDefaultSettings); } + protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { + return { + mapSettings: settings, + background: settings.background, + padding: settings.padding + }; + } + protected onSettingsSet(settings: WidgetSettings) { this.mapWidgetSettingsForm = this.fb.group({ - mapSettings: [settings, []], + mapSettings: [settings.mapSettings, []], background: [settings.background, []], padding: [settings.padding, []] }); From 9d2c309d04a46ac3ca200718faef24239445e295 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 25 Mar 2025 11:53:53 +0200 Subject: [PATCH 25/30] Fix msa tests after docker service renaming --- .../java/org/thingsboard/server/msa/ContainerTestSuite.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java index 65def6a964..f2e721bdcb 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ContainerTestSuite.java @@ -188,8 +188,8 @@ public class ContainerTestSuite { .waitingFor("tb-vc-executor1", Wait.forLogMessage(TB_VC_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT)) .waitingFor("tb-vc-executor2", Wait.forLogMessage(TB_VC_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT)) .waitingFor("tb-js-executor", Wait.forLogMessage(TB_JS_EXECUTOR_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT)) - .waitingFor("tb-edqs-1", Wait.forLogMessage(TB_EDQS_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT)) - .waitingFor("tb-edqs-2", Wait.forLogMessage(TB_EDQS_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT)); + .waitingFor("tb-edqs1", Wait.forLogMessage(TB_EDQS_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT)) + .waitingFor("tb-edqs2", Wait.forLogMessage(TB_EDQS_LOG_REGEXP, 1).withStartupTimeout(CONTAINER_STARTUP_TIMEOUT)); testContainer.start(); setActive(true); } catch (Exception e) { From 73bd61c524981b28cdf2a0aacab12b4d7e75e6c3 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 25 Mar 2025 13:01:15 +0200 Subject: [PATCH 26/30] UI: Fixed close autocomplete in LWM2M list model; Minor refactoring --- .../lwm2m/lwm2m-object-list.component.html | 2 +- .../device/lwm2m/lwm2m-object-list.component.ts | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html index 706076e3ff..d05097bd5b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.html @@ -48,7 +48,7 @@
  • - {{ 'device-profile.lwm2m.no-objects-matching' | translate:{object: truncate.transform(searchText, true, 6, '...')} }} + {{ 'device-profile.lwm2m.no-objects-matching' | translate:{object: (searchText | truncate: true: 6: '...')} }} diff --git a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts index 7ea253cd9d..01e79fcadf 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-object-list.component.ts @@ -33,8 +33,8 @@ import { DeviceProfileService } from '@core/http/device-profile.service'; import { Direction } from '@shared/models/page/sort-order'; import { isDefined, isDefinedAndNotNull, isObject, isString } from '@core/utils'; import { PageLink } from '@shared/models/page/page-link'; -import { TruncatePipe } from '@shared/pipe/truncate.pipe'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; @Component({ selector: 'tb-profile-lwm2m-object-list', @@ -79,13 +79,12 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V @Output() removeList = new EventEmitter(); - @ViewChild('objectInput') objectInput: ElementRef; + @ViewChild('objectInput', {static: true}) objectInput: ElementRef; + @ViewChild('objectInput', {static: true, read: MatAutocompleteTrigger}) matAutocompleteTrigger: MatAutocompleteTrigger; - private propagateChange = (v: any) => { - } + private propagateChange: (value: any) => void = () => {}; - constructor(public truncate: TruncatePipe, - private deviceProfileService: DeviceProfileService, + constructor(private deviceProfileService: DeviceProfileService, private fb: UntypedFormBuilder) { this.lwm2mListFormGroup = this.fb.group({ objectsList: [this.objectsList], @@ -113,7 +112,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V this.propagateChange = fn; } - registerOnTouched(fn: any): void { + registerOnTouched(_fn: any): void { } ngOnInit() { @@ -140,6 +139,9 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V if (isDefined(this.objectInput)) { this.clear('', false); } + if (this.matAutocompleteTrigger.panelOpen) { + this.matAutocompleteTrigger.closePanel(); + } } else { this.lwm2mListFormGroup.enable({emitEvent: false}); } From dedf3db9287dcc2a4bf1c7e0ebb0b110eb7c5ab3 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 25 Mar 2025 13:55:11 +0200 Subject: [PATCH 27/30] UI: Minor fixes. --- .../widget/lib/chart/latest-chart.ts | 60 +++++++------- .../widget/lib/chart/time-series-chart.ts | 12 +-- .../home/models/dashboard-component.models.ts | 78 ++++++++++--------- 3 files changed, 78 insertions(+), 72 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts index 13e9dd7d5e..fad0d84632 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/latest-chart.ts @@ -223,40 +223,42 @@ export abstract class TbLatestChart { } protected updateSeriesData(initial = false) { - this.total = 0; - this.totalText = 'N/A'; - let hasValue = false; - for (const dataItem of this.dataItems) { - if (dataItem.enabled && dataItem.hasValue) { - hasValue = true; - this.total += dataItem.value; - } - if (this.settings.showLegend) { - const legendItem = this.legendItems.find(item => item.dataKey === dataItem.dataKey); - if (dataItem.hasValue) { - legendItem.hasValue = true; - legendItem.value = formatValue(dataItem.value, this.decimals, this.units, false); - } else { - legendItem.hasValue = false; - legendItem.value = '--'; + if (!this.latestChart.isDisposed()) { + this.total = 0; + this.totalText = 'N/A'; + let hasValue = false; + for (const dataItem of this.dataItems) { + if (dataItem.enabled && dataItem.hasValue) { + hasValue = true; + this.total += dataItem.value; + } + if (this.settings.showLegend) { + const legendItem = this.legendItems.find(item => item.dataKey === dataItem.dataKey); + if (dataItem.hasValue) { + legendItem.hasValue = true; + legendItem.value = formatValue(dataItem.value, this.decimals, this.units, false); + } else { + legendItem.hasValue = false; + legendItem.value = '--'; + } } } - } - if (this.settings.showTotal || this.settings.showLegend) { - if (hasValue) { - this.totalText = formatValue(this.total, this.decimals, this.units, false); - if (this.settings.showLegend && !this.settings.showTotal) { - this.legendItems[this.legendItems.length - 1].hasValue = true; - this.legendItems[this.legendItems.length - 1].value = this.totalText; + if (this.settings.showTotal || this.settings.showLegend) { + if (hasValue) { + this.totalText = formatValue(this.total, this.decimals, this.units, false); + if (this.settings.showLegend && !this.settings.showTotal) { + this.legendItems[this.legendItems.length - 1].hasValue = true; + this.legendItems[this.legendItems.length - 1].value = this.totalText; + } + } else if (this.settings.showLegend && !this.settings.showTotal) { + this.legendItems[this.legendItems.length - 1].hasValue = false; + this.legendItems[this.legendItems.length - 1].value = '--'; } - } else if (this.settings.showLegend && !this.settings.showTotal) { - this.legendItems[this.legendItems.length - 1].hasValue = false; - this.legendItems[this.legendItems.length - 1].value = '--'; } + this.doUpdateSeriesData(); + this.latestChart.setOption(this.latestChartOption); + this.afterUpdateSeriesData(initial); } - this.doUpdateSeriesData(); - this.latestChart.setOption(this.latestChartOption); - this.afterUpdateSeriesData(initial); } private drawChart() { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts index ad121a1eb0..2b4b52ccfb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts @@ -690,12 +690,14 @@ export class TbTimeSeriesChart { } private updateSeriesData(updateScale = false): void { - this.updateSeries(); - if (updateScale && this.updateYAxisScale(this.yAxisList)) { - this.timeSeriesChartOptions.yAxis = this.yAxisList.map(axis => axis.option); + if (!this.timeSeriesChart.isDisposed()) { + this.updateSeries(); + if (updateScale && this.updateYAxisScale(this.yAxisList)) { + this.timeSeriesChartOptions.yAxis = this.yAxisList.map(axis => axis.option); + } + this.timeSeriesChart.setOption(this.timeSeriesChartOptions); + this.updateAxes(); } - this.timeSeriesChart.setOption(this.timeSeriesChartOptions); - this.updateAxes(); } private updateSeries(): void { diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 458a1d1eeb..facb159af4 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -468,49 +468,51 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { const resizable = item.resize; - this.heightValue = resizable.height; - this.widthValue = resizable.width; - - const setItemHeight = resizable.setItemHeight.bind(resizable); - const setItemWidth = resizable.setItemWidth.bind(resizable); - resizable.setItemHeight = (height) => { - setItemHeight(height); - this.heightValue = height; - if (this.preserveAspectRatio) { - setItemWidth(height * this.aspectRatio); - } - }; - resizable.setItemWidth = (width) => { - setItemWidth(width); - this.widthValue = width; - if (this.preserveAspectRatio) { - setItemHeight(width / this.aspectRatio); - } - }; - - Object.defineProperty(resizable, 'height', { - get: () => this.heightValue, - set: v => { - if (this.heightValue !== v) { - if (this.preserveAspectRatio) { - this.widthValue = v * this.aspectRatio; + if (resizable) { + this.heightValue = resizable.height; + this.widthValue = resizable.width; + + const setItemHeight = resizable.setItemHeight.bind(resizable); + const setItemWidth = resizable.setItemWidth.bind(resizable); + resizable.setItemHeight = (height) => { + setItemHeight(height); + this.heightValue = height; + if (this.preserveAspectRatio) { + setItemWidth(height * this.aspectRatio); + } + }; + resizable.setItemWidth = (width) => { + setItemWidth(width); + this.widthValue = width; + if (this.preserveAspectRatio) { + setItemHeight(width / this.aspectRatio); + } + }; + + Object.defineProperty(resizable, 'height', { + get: () => this.heightValue, + set: v => { + if (this.heightValue !== v) { + if (this.preserveAspectRatio) { + this.widthValue = v * this.aspectRatio; + } + this.heightValue = v; } - this.heightValue = v; } - } - }); + }); - Object.defineProperty(resizable, 'width', { - get: () => this.widthValue, - set: v => { - if (this.widthValue !== v) { - if (this.preserveAspectRatio) { - this.heightValue = v / this.aspectRatio; + Object.defineProperty(resizable, 'width', { + get: () => this.widthValue, + set: v => { + if (this.widthValue !== v) { + if (this.preserveAspectRatio) { + this.heightValue = v / this.aspectRatio; + } + this.widthValue = v; } - this.widthValue = v; } - } - }); + }); + } this.preserveAspectRatioApplied = true; } } From ace521da5b04334bb8945b5e95b891f01236e0d0 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 25 Mar 2025 16:03:19 +0200 Subject: [PATCH 28/30] UI: New maps - prevent click event on marker drag. --- .../widget/lib/maps/data-layer/markers-data-layer.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/markers-data-layer.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/markers-data-layer.ts index 99cb5a9b7d..146ace1120 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/markers-data-layer.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/markers-data-layer.ts @@ -480,10 +480,14 @@ class TbMarkerDataLayerItem extends TbLatestDataLayerItem { + (this.marker.dragging as any)._draggable = { _moved: true }; + (this.marker.dragging as any)._enabled = true; this.moving = true; }); this.marker.on('pm:dragend', () => { this.saveMarkerLocation(); + delete (this.marker.dragging as any)._draggable; + delete (this.marker.dragging as any)._enabled; this.moving = false; }); } From 4b63d929c0ec4af7756a27c267112abfc24a11b8 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 25 Mar 2025 16:24:11 +0200 Subject: [PATCH 29/30] UI: Fix markdown widget change detection. --- .../home/components/widget/lib/markdown-widget.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts index 61f5073953..10d5f9b1a0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/markdown-widget.component.ts @@ -149,7 +149,7 @@ export class MarkdownWidgetComponent extends PageComponent implements OnInit { if (this.markdownText !== markdownText) { this.markdownText = this.utils.customTranslation(markdownText, markdownText); } - this.cd.markForCheck(); + this.cd.detectChanges(); } markdownClick($event: MouseEvent) { From f0f2b30269cd1c126c99025eb668e88a2b8a1bae Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 25 Mar 2025 17:16:26 +0200 Subject: [PATCH 30/30] UI: New maps - improve markers draggable mode. --- .../widget/lib/maps/data-layer/latest-map-data-layer.ts | 2 ++ .../components/widget/lib/maps/data-layer/markers-data-layer.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/latest-map-data-layer.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/latest-map-data-layer.ts index 3a537ba8e7..fb79611d71 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/latest-map-data-layer.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/data-layer/latest-map-data-layer.ts @@ -117,6 +117,7 @@ export abstract class TbLatestDataLayerItem { - (this.marker.dragging as any)._draggable = { _moved: true }; + (this.marker.dragging as any)._draggable = { _moved: true, off: (_args: any) => { return { disable: () => {}} } }; (this.marker.dragging as any)._enabled = true; this.moving = true; });