From 1bd9b8d287a237ab35397aa329b082556424382c Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Fri, 16 Jan 2026 15:01:18 +0200 Subject: [PATCH] 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.",