From 1bd9b8d287a237ab35397aa329b082556424382c Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Fri, 16 Jan 2026 15:01:18 +0200 Subject: [PATCH 1/2] Added component for query params --- .../common/common-rule-node-config.module.ts | 7 +- .../common/kv-list-config.component.ts | 89 +++++++++++++++++++ .../common/kv-map-config-old.component.ts | 6 +- .../rest-api-call-config.component.html | 9 +- .../assets/locale/locale.constant-en_US.json | 1 + 5 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/rule-node/common/kv-list-config.component.ts diff --git a/ui-ngx/src/app/modules/home/components/rule-node/common/common-rule-node-config.module.ts b/ui-ngx/src/app/modules/home/components/rule-node/common/common-rule-node-config.module.ts index c7d8ce2723..e21f0aa689 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/common/common-rule-node-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/rule-node/common/common-rule-node-config.module.ts @@ -34,6 +34,7 @@ import { SelectAttributesComponent } from './select-attributes.component'; import { AlarmStatusSelectComponent } from './alarm-status-select.component'; import { ExampleHintComponent } from './example-hint.component'; import { TimeUnitInputComponent } from './time-unit-input.component'; +import { KvListConfigComponent } from '@home/components/rule-node/common/kv-list-config.component'; @NgModule({ declarations: [ @@ -52,7 +53,8 @@ import { TimeUnitInputComponent } from './time-unit-input.component'; SelectAttributesComponent, AlarmStatusSelectComponent, ExampleHintComponent, - TimeUnitInputComponent + TimeUnitInputComponent, + KvListConfigComponent ], imports: [ CommonModule, @@ -75,7 +77,8 @@ import { TimeUnitInputComponent } from './time-unit-input.component'; SelectAttributesComponent, AlarmStatusSelectComponent, ExampleHintComponent, - TimeUnitInputComponent + TimeUnitInputComponent, + KvListConfigComponent ] }) diff --git a/ui-ngx/src/app/modules/home/components/rule-node/common/kv-list-config.component.ts b/ui-ngx/src/app/modules/home/components/rule-node/common/kv-list-config.component.ts new file mode 100644 index 0000000000..5284b88bce --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/rule-node/common/kv-list-config.component.ts @@ -0,0 +1,89 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { + AbstractControl, + ControlValueAccessor, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + Validator, + Validators +} from '@angular/forms'; +import { KvMapConfigOldComponent } from '@home/components/rule-node/common/kv-map-config-old.component'; + +@Component({ + selector: 'tb-kv-list-config', + templateUrl: './kv-map-config-old.component.html', + styleUrls: ['./kv-map-config-old.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => KvListConfigComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => KvListConfigComponent), + multi: true, + } + ] +}) +export class KvListConfigComponent extends KvMapConfigOldComponent implements ControlValueAccessor, OnInit, Validator{ + + @Input() keyProperty: string = 'key'; + + override writeValue(kvList: any): void { + const keyValsControls: Array = []; + if (Array.isArray(kvList) && kvList.length > 0) { + for (const property of kvList) { + keyValsControls.push(this.fb.group({ + key: [property[this.keyProperty], [Validators.required]], + value: [property.value, [Validators.required]] + })) + } + } + this.kvListFormGroup.setControl('keyVals', this.fb.array(keyValsControls), {emitEvent: false}); + } + + public override validate() { + const kvList: { key: string; value: string }[] = this.kvListFormGroup.get('keyVals').value; + if (!kvList.length && this.required) { + return { + kvMapRequired: true + }; + } + if (!this.kvListFormGroup.valid) { + return { + kvFieldsRequired: true + }; + } + return null; + } + + protected override updateModel() { + const kvList: { key: string; value: string }[] = this.kvListFormGroup.get('keyVals').value; + if (this.required && !kvList.length || !this.kvListFormGroup.valid) { + this.propagateChange(null); + } else { + const result = kvList.map(entry => ({ + [this.keyProperty]: entry.key, + value: entry.value + })); + this.propagateChange(result); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/rule-node/common/kv-map-config-old.component.ts b/ui-ngx/src/app/modules/home/components/rule-node/common/kv-map-config-old.component.ts index bd56212d4f..69fe1820eb 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/common/kv-map-config-old.component.ts +++ b/ui-ngx/src/app/modules/home/components/rule-node/common/kv-map-config-old.component.ts @@ -86,11 +86,11 @@ export class KvMapConfigOldComponent extends PageComponent implements ControlVal ngControl: NgControl; - private propagateChange = null; + public propagateChange = null; constructor(public translate: TranslateService, private injector: Injector, - private fb: FormBuilder, + protected fb: FormBuilder, private destroyRef: DestroyRef) { super(); } @@ -182,7 +182,7 @@ export class KvMapConfigOldComponent extends PageComponent implements ControlVal return null; } - private updateModel() { + protected updateModel() { const kvList: { key: string; value: string }[] = this.kvListFormGroup.get('keyVals').value; if (this.required && !kvList.length || !this.kvListFormGroup.valid) { this.propagateChange(null); diff --git a/ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html b/ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html index b265b997ac..7a30723f9e 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html +++ b/ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html @@ -19,7 +19,7 @@
Request URL
- rule-node-config.endpoint-url-pattern + rule-node-config.url {{ 'rule-node-config.endpoint-url-pattern-required' | translate }} @@ -32,14 +32,15 @@
- > - + emptyText="rule-node-config.query-params-empty" + keyProperty="name"> +
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 419eaf50ac..2ae1b4ff48 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5411,6 +5411,7 @@ "query-params-name-required": "Name is required", "query-params-value-required": "Value is required", "headers-empty": "No headers configured", + "url": "URL", "save-time-series": { "processing-settings": "Processing settings", "processing-settings-hint": "Define how incoming messages are processed. Basic processing settings allow you to select preconfigured strategies, while Advanced settings allow you to select individual processing strategies for each action.", From 07fd49c080944acdea5888b75d1cccb94eb72d41 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Fri, 16 Jan 2026 17:35:32 +0200 Subject: [PATCH 2/2] Moved to key name prop in Query params --- .../rule-node/common/kv-list-config.component.ts | 12 +++--------- .../external/rest-api-call-config.component.html | 3 +-- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/rule-node/common/kv-list-config.component.ts b/ui-ngx/src/app/modules/home/components/rule-node/common/kv-list-config.component.ts index 5284b88bce..fe913815cd 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/common/kv-list-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/rule-node/common/kv-list-config.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, OnInit } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -44,14 +44,12 @@ import { KvMapConfigOldComponent } from '@home/components/rule-node/common/kv-ma }) export class KvListConfigComponent extends KvMapConfigOldComponent implements ControlValueAccessor, OnInit, Validator{ - @Input() keyProperty: string = 'key'; - override writeValue(kvList: any): void { const keyValsControls: Array = []; if (Array.isArray(kvList) && kvList.length > 0) { for (const property of kvList) { keyValsControls.push(this.fb.group({ - key: [property[this.keyProperty], [Validators.required]], + key: [property.key, [Validators.required]], value: [property.value, [Validators.required]] })) } @@ -79,11 +77,7 @@ export class KvListConfigComponent extends KvMapConfigOldComponent implements Co if (this.required && !kvList.length || !this.kvListFormGroup.valid) { this.propagateChange(null); } else { - const result = kvList.map(entry => ({ - [this.keyProperty]: entry.key, - value: entry.value - })); - this.propagateChange(result); + this.propagateChange(kvList); } } } diff --git a/ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html b/ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html index 7a30723f9e..2f6840639c 100644 --- a/ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html +++ b/ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html @@ -38,8 +38,7 @@ keyRequiredText="rule-node-config.query-params-name-required" valText="rule-node-config.query-params-value" valRequiredText="rule-node-config.query-params-value-required" - emptyText="rule-node-config.query-params-empty" - keyProperty="name"> + emptyText="rule-node-config.query-params-empty">