Browse Source

Move REST API call rule node to new UI

pull/14540/head
Maksym Tsymbarov 8 months ago
parent
commit
4a03ed31ce
  1. 114
      ui-ngx/src/app/modules/home/components/rule-node/common/credentials-config.component.html
  2. 78
      ui-ngx/src/app/modules/home/components/rule-node/common/kv-map-config-old.component.html
  3. 4
      ui-ngx/src/app/modules/home/components/rule-node/common/kv-map-config-old.component.ts
  4. 227
      ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html
  5. 30
      ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.scss
  6. 28
      ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.ts
  7. 9
      ui-ngx/src/assets/locale/locale.constant-en_US.json

114
ui-ngx/src/app/modules/home/components/rule-node/common/credentials-config.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<section [formGroup]="credentialsConfigFormGroup" class="flex flex-col">
<mat-expansion-panel class="tb-credentials-config-panel-group" expanded="true">
<section [formGroup]="credentialsConfigFormGroup" class="tb-form-panel stroked">
<mat-expansion-panel class="tb-credentials-config-panel-group tb-settings" expanded="true">
<mat-expansion-panel-header>
<mat-panel-title translate>rule-node-config.credentials</mat-panel-title>
<mat-panel-description>
@ -24,7 +24,7 @@
</mat-panel-description>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<mat-form-field class="mat-block">
<mat-form-field class="mat-block" subscriptSizing="dynamic">
<mat-label translate>rule-node-config.credentials-type</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let credentialsType of allCredentialsTypes" [value]="credentialsType"
@ -36,60 +36,60 @@
{{ 'rule-node-config.credentials-type-required' | translate }}
</mat-error>
</mat-form-field>
<section class="flex flex-col" [ngSwitch]="credentialsConfigFormGroup.get('type').value">
<ng-template ngSwitchCase="anonymous">
</ng-template>
<ng-template ngSwitchCase="basic">
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.username</mat-label>
<input required matInput formControlName="username">
<mat-error *ngIf="credentialsConfigFormGroup.get('username').hasError('required')">
{{ 'rule-node-config.username-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.password</mat-label>
<input type="password" [required]="passwordFieldRequired" matInput formControlName="password" autocomplete="new-password">
<tb-toggle-password matSuffix></tb-toggle-password>
<mat-error *ngIf="credentialsConfigFormGroup.get('password').hasError('required')">
{{ 'rule-node-config.password-required' | translate }}
</mat-error>
</mat-form-field>
</ng-template>
<ng-template ngSwitchCase="cert.PEM">
<div class="tb-hint">{{ 'rule-node-config.credentials-pem-hint' | translate }}</div>
<tb-file-input formControlName="caCert"
inputId="caCertSelect"
[existingFileName]="credentialsConfigFormGroup.get('caCertFileName').value"
(fileNameChanged)="credentialsConfigFormGroup.get('caCertFileName').setValue($event)"
label="{{'rule-node-config.ca-cert' | translate}}"
noFileText="rule-node-config.no-file"
dropLabel="{{'rule-node-config.drop-file' | translate}}">
</tb-file-input>
<tb-file-input formControlName="cert"
inputId="CertSelect"
[existingFileName]="credentialsConfigFormGroup.get('certFileName').value"
(fileNameChanged)="credentialsConfigFormGroup.get('certFileName').setValue($event)"
label="{{'rule-node-config.cert' | translate}}"
noFileText="rule-node-config.no-file"
dropLabel="{{'rule-node-config.drop-file' | translate}}">
</tb-file-input>
<tb-file-input style="padding-bottom: 8px;"
formControlName="privateKey"
inputId="privateKeySelect"
[existingFileName]="credentialsConfigFormGroup.get('privateKeyFileName').value"
(fileNameChanged)="credentialsConfigFormGroup.get('privateKeyFileName').setValue($event)"
label="{{'rule-node-config.private-key' | translate}}"
noFileText="rule-node-config.no-file"
dropLabel="{{'rule-node-config.drop-file' | translate}}">
</tb-file-input>
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.private-key-password</mat-label>
<input type="password" matInput formControlName="password" autocomplete="new-password">
<tb-toggle-password matSuffix></tb-toggle-password>
</mat-form-field>
</ng-template>
</section>
@if (credentialsConfigFormGroup.get('type').value !== 'anonymous') {
<section class="flex flex-col" [ngSwitch]="credentialsConfigFormGroup.get('type').value">
<ng-template ngSwitchCase="basic">
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.username</mat-label>
<input required matInput formControlName="username">
<mat-error *ngIf="credentialsConfigFormGroup.get('username').hasError('required')">
{{ 'rule-node-config.username-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.password</mat-label>
<input type="password" [required]="passwordFieldRequired" matInput formControlName="password" autocomplete="new-password">
<tb-toggle-password matSuffix></tb-toggle-password>
<mat-error *ngIf="credentialsConfigFormGroup.get('password').hasError('required')">
{{ 'rule-node-config.password-required' | translate }}
</mat-error>
</mat-form-field>
</ng-template>
<ng-template ngSwitchCase="cert.PEM">
<div class="tb-form-hint tb-primary-fill mb-4">{{ 'rule-node-config.credentials-pem-hint' | translate }}</div>
<tb-file-input formControlName="caCert"
inputId="caCertSelect"
[existingFileName]="credentialsConfigFormGroup.get('caCertFileName').value"
(fileNameChanged)="credentialsConfigFormGroup.get('caCertFileName').setValue($event)"
label="{{'rule-node-config.ca-cert' | translate}}"
noFileText="rule-node-config.no-file"
dropLabel="{{'rule-node-config.drop-file' | translate}}">
</tb-file-input>
<tb-file-input formControlName="cert"
inputId="CertSelect"
[existingFileName]="credentialsConfigFormGroup.get('certFileName').value"
(fileNameChanged)="credentialsConfigFormGroup.get('certFileName').setValue($event)"
label="{{'rule-node-config.cert' | translate}}"
noFileText="rule-node-config.no-file"
dropLabel="{{'rule-node-config.drop-file' | translate}}">
</tb-file-input>
<tb-file-input style="padding-bottom: 8px;"
formControlName="privateKey"
inputId="privateKeySelect"
[existingFileName]="credentialsConfigFormGroup.get('privateKeyFileName').value"
(fileNameChanged)="credentialsConfigFormGroup.get('privateKeyFileName').setValue($event)"
label="{{'rule-node-config.private-key' | translate}}"
noFileText="rule-node-config.no-file"
dropLabel="{{'rule-node-config.drop-file' | translate}}">
</tb-file-input>
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.private-key-password</mat-label>
<input type="password" matInput formControlName="password" autocomplete="new-password">
<tb-toggle-password matSuffix></tb-toggle-password>
</mat-form-field>
</ng-template>
</section>
}
</ng-template>
</mat-expansion-panel>
</section>

78
ui-ngx/src/app/modules/home/components/rule-node/common/kv-map-config-old.component.html

@ -16,40 +16,52 @@
-->
<section class="tb-kv-map-config flex flex-col" [formGroup]="kvListFormGroup">
<div class="header flex flex-1 flex-row gap-2">
<span class="cell tb-required flex-1">{{ keyText | translate }}</span>
<span class="cell tb-required flex-1">{{ valText | translate }}</span>
<span [class.!hidden]="disabled" style="width: 52px;" innerHTML="&nbsp"></span>
</div>
<div class="body">
<div class="row flex flex-row items-center justify-start gap-2"
formArrayName="keyVals"
*ngFor="let keyValControl of keyValsFormArray().controls; let $index = index">
<mat-form-field class="cell mat-block flex-1">
<input [formControl]="keyValControl.get('key')" matInput required
placeholder="{{ keyText | translate }}"/>
<mat-error *ngIf="keyValControl.get('key').hasError('required')">
{{ keyRequiredText | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="cell mat-block flex-1">
<input [formControl]="keyValControl.get('value')" matInput required
placeholder="{{ valText | translate }}"/>
<mat-error *ngIf="keyValControl.get('value').hasError('required')">
{{ valRequiredText | translate }}
</mat-error>
</mat-form-field>
<button mat-icon-button color="primary"
[class.!hidden]="disabled"
type="button"
(click)="removeKeyVal($index)"
[disabled]="isLoading$ | async"
matTooltip="{{ 'rule-node-config.key-val.remove-entry' | translate }}"
matTooltipPosition="above">
<mat-icon>close</mat-icon>
</button>
@if (description) {
<div class="tb-form-hint tb-primary-fill mb-4" [innerHTML]="description | translate | safe: 'html'"></div>
}
@if (keyValsFormArray().controls.length || !emptyText) {
<div class="header flex flex-1 flex-row gap-2" >
<span class="cell tb-required flex-1">{{ keyText | translate }}</span>
<span class="cell tb-required flex-1">{{ valText | translate }}</span>
<span [class.!hidden]="disabled" style="width: 52px;" innerHTML="&nbsp"></span>
</div>
<div *ngIf="hintText" class="tb-hint" [innerHTML]="hintText | translate | safe: 'html'"></div>
}
<div class="body">
@for (keyValControl of keyValsFormArray().controls; track $index) {
<div class="row flex flex-row items-center justify-start gap-2"
formArrayName="keyVals">
<mat-form-field class="cell mat-block flex-1">
<input [formControl]="keyValControl.get('key')" matInput required
placeholder="{{ keyText | translate }}"/>
<mat-error *ngIf="keyValControl.get('key').hasError('required')">
{{ keyRequiredText | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="cell mat-block flex-1">
<input [formControl]="keyValControl.get('value')" matInput required
placeholder="{{ valText | translate }}"/>
<mat-error *ngIf="keyValControl.get('value').hasError('required')">
{{ valRequiredText | translate }}
</mat-error>
</mat-form-field>
<button mat-icon-button color="primary"
[class.!hidden]="disabled"
type="button"
(click)="removeKeyVal($index)"
[disabled]="isLoading$ | async"
matTooltip="{{ 'rule-node-config.key-val.remove-entry' | translate }}"
matTooltipPosition="above">
<mat-icon>close</mat-icon>
</button>
</div>
} @empty {
@if (emptyText) {
<div class="tb-prompt h-10 flex items-center justify-center">{{emptyText | translate}}</div>
}
}
@if (hintText) {
<div class="tb-hint" [innerHTML]="hintText | translate | safe: 'html'"></div>
}
</div>
<tb-error [error]="ngControl.hasError('kvMapRequired') || ngControl.hasError('uniqueKeyValuePair') ?
(ngControl.hasError('kvMapRequired') ? translate.instant(requiredText) :

4
ui-ngx/src/app/modules/home/components/rule-node/common/kv-map-config-old.component.ts

@ -67,6 +67,10 @@ export class KvMapConfigOldComponent extends PageComponent implements ControlVal
@Input() hintText: string;
@Input() description: string;
@Input() emptyText: string;
private requiredValue: boolean;
get required(): boolean {

227
ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.html

@ -15,15 +15,34 @@
limitations under the License.
-->
<section [formGroup]="restApiCallConfigForm" class="flex flex-col">
<mat-form-field class="mat-block" subscriptSizing="dynamic">
<mat-label translate>rule-node-config.endpoint-url-pattern</mat-label>
<input required matInput formControlName="restEndpointUrlPattern">
<mat-error *ngIf="restApiCallConfigForm.get('restEndpointUrlPattern').hasError('required')">
{{ 'rule-node-config.endpoint-url-pattern-required' | translate }}
</mat-error>
<mat-hint translate>rule-node-config.general-pattern-hint</mat-hint>
</mat-form-field>
<section [formGroup]="restApiCallConfigForm" class="flex flex-col gap-4">
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title">Request URL</div>
<mat-form-field class="mat-block" subscriptSizing="dynamic">
<mat-label translate>rule-node-config.endpoint-url-pattern</mat-label>
<input required matInput formControlName="restEndpointUrlPattern">
<mat-error *ngIf="restApiCallConfigForm.get('restEndpointUrlPattern').hasError('required')">
{{ 'rule-node-config.endpoint-url-pattern-required' | translate }}
</mat-error>
<mat-hint translate>rule-node-config.url-hint</mat-hint>
</mat-form-field>
<mat-expansion-panel class="tb-settings tb-form-panel stroked no-gap" [expanded]="isQueryParamsExpanded">
<mat-expansion-panel-header>
{{ 'rule-node-config.query-params' | translate }}
<div [tb-hint-tooltip-icon]="'rule-node-config.query-params-hint' | translate" tooltipPosition="above"></div>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-kv-map-config-old
formControlName="queryParams"
keyText="rule-node-config.query-params-name"
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">>
</tb-kv-map-config-old>
</ng-template>
</mat-expansion-panel>
</div>
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.request-method</mat-label>
<mat-select formControlName="requestMethod">
@ -32,99 +51,113 @@
</mat-option>
</mat-select>
</mat-form-field>
<mat-checkbox formControlName="enableProxy">
{{ 'rule-node-config.enable-proxy' | translate }}
</mat-checkbox>
<mat-checkbox *ngIf="!restApiCallConfigForm.get('enableProxy').value" formControlName="useSimpleClientHttpFactory">
{{ 'rule-node-config.use-simple-client-http-factory' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="parseToPlainText">
{{ 'rule-node-config.parse-to-plain-text' | translate }}
</mat-checkbox>
<div class="tb-hint" style="padding-bottom: 5px;" translate>rule-node-config.parse-to-plain-text-hint</div>
<mat-checkbox formControlName="ignoreRequestBody">
{{ 'rule-node-config.ignore-request-body' | translate }}
</mat-checkbox>
<div *ngIf="restApiCallConfigForm.get('enableProxy').value">
<mat-checkbox formControlName="useSystemProxyProperties">
{{ 'rule-node-config.use-system-proxy-properties' | translate }}
</mat-checkbox>
<div *ngIf="!restApiCallConfigForm.get('useSystemProxyProperties').value">
<div class="gt-sm:flex gt-sm:flex-row gt-sm:gap-2">
<mat-form-field class="mat-block gt-sm:max-w-10% gt-sm:flex-full">
<mat-label translate>rule-node-config.proxy-scheme</mat-label>
<mat-select formControlName="proxyScheme">
<mat-option *ngFor="let proxyScheme of proxySchemes" [value]="proxyScheme">
{{ proxyScheme }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="md-block gt-sm:max-w-50% gt-sm:flex-full">
<mat-label translate>rule-node-config.proxy-host</mat-label>
<input matInput required formControlName="proxyHost">
<mat-error *ngIf="restApiCallConfigForm.get('proxyHost').hasError('required')">
{{ 'rule-node-config.proxy-host-required' | translate }}
<div class="tb-form-panel stroked">
<mat-expansion-panel class="tb-settings" [expanded]="isHeadersExpanded">
<mat-expansion-panel-header>
{{ 'rule-node-config.headers' | translate }}
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<tb-kv-map-config-old
formControlName="headers"
keyText="rule-node-config.header"
keyRequiredText="rule-node-config.header-required"
valText="rule-node-config.value"
valRequiredText="rule-node-config.value-required"
description="rule-node-config.headers-hint"
emptyText="rule-node-config.headers-empty">
</tb-kv-map-config-old>
</ng-template>
</mat-expansion-panel>
</div>
<tb-credentials-config formControlName="credentials"></tb-credentials-config>
<div class="tb-form-panel stroked">
<mat-expansion-panel class="tb-settings">
<mat-expansion-panel-header>
{{ 'rule-node-config.advanced-settings' | translate }}
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-panel stroked column">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="enableProxy">
{{ 'rule-node-config.enable-proxy' | translate }}
</mat-slide-toggle>
<div *ngIf="restApiCallConfigForm.get('enableProxy').value" class="flex flex-col gap-4">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="useSystemProxyProperties">
{{ 'rule-node-config.use-system-proxy-properties' | translate }}
</mat-slide-toggle>
<div *ngIf="!restApiCallConfigForm.get('useSystemProxyProperties').value">
<div class="gt-sm:flex gt-sm:flex-row gt-sm:gap-2">
<mat-form-field class="md-block gt-sm:max-w-50% gt-sm:flex-full">
<mat-label translate>rule-node-config.proxy-host</mat-label>
<input matInput required formControlName="proxyHost">
<mat-error *ngIf="restApiCallConfigForm.get('proxyHost').hasError('required')">
{{ 'rule-node-config.proxy-host-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block gt-sm:max-w-50% gt-sm:flex-full">
<mat-label translate>rule-node-config.proxy-port</mat-label>
<input matInput required formControlName="proxyPort" type="number" step="1">
<mat-error *ngIf="restApiCallConfigForm.get('proxyPort').hasError('required')">
{{ 'rule-node-config.proxy-port-required' | translate }}
</mat-error>
<mat-error
*ngIf="restApiCallConfigForm.get('proxyPort').hasError('min') || restApiCallConfigForm.get('proxyPort').hasError('max')">
{{ 'rule-node-config.proxy-port-range' | translate }}
</mat-error>
</mat-form-field>
</div>
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.proxy-user</mat-label>
<input matInput formControlName="proxyUser">
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.proxy-password</mat-label>
<input matInput type="password" formControlName="proxyPassword">
<tb-toggle-password matSuffix></tb-toggle-password>
</mat-form-field>
</div>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="parseToPlainText">
<div [tb-hint-tooltip-icon]="'rule-node-config.parse-to-plain-text-hint' | translate" tooltipPosition="above">
{{ 'rule-node-config.parse-to-plain-text' | translate }}
</div>
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="ignoreRequestBody">
{{ 'rule-node-config.ignore-request-body' | translate }}
</mat-slide-toggle>
</div>
<mat-form-field *ngIf="restApiCallConfigForm.get('enableProxy').value" class="mat-block"
subscriptSizing="dynamic">
<mat-label translate>rule-node-config.read-timeout</mat-label>
<input type="text" min="0" [max]="IntLimit" inputmode="numeric" pattern="[0-9]*" matInput formControlName="readTimeoutMs">
<mat-hint translate>rule-node-config.read-timeout-hint</mat-hint>
<mat-error
*ngIf="restApiCallConfigForm.get('readTimeoutMs').hasError('max')">
{{ 'rule-node-config.int-range' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block gt-sm:max-w-40% gt-sm:flex-full">
<mat-label translate>rule-node-config.proxy-port</mat-label>
<input matInput required formControlName="proxyPort" type="number" step="1">
<mat-error *ngIf="restApiCallConfigForm.get('proxyPort').hasError('required')">
{{ 'rule-node-config.proxy-port-required' | translate }}
<mat-form-field class="mat-block" subscriptSizing="dynamic">
<mat-label translate>rule-node-config.max-parallel-requests-count</mat-label>
<input type="text" min="0" [max]="IntLimit" inputmode="numeric" pattern="[0-9]*" matInput formControlName="maxParallelRequestsCount">
<mat-hint translate>rule-node-config.max-parallel-requests-count-hint</mat-hint>
<mat-error
*ngIf="restApiCallConfigForm.get('maxParallelRequestsCount').hasError('max')">
{{ 'rule-node-config.int-range' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block" subscriptSizing="dynamic">
<mat-label translate>rule-node-config.max-response-size</mat-label>
<input type="text" min="1" [max]="MemoryBufferSizeInKbLimit" inputmode="numeric" pattern="[0-9]*" matInput formControlName="maxInMemoryBufferSizeInKb">
<mat-hint translate>rule-node-config.max-response-size-hint</mat-hint>
<mat-error
*ngIf="restApiCallConfigForm.get('proxyPort').hasError('min') || restApiCallConfigForm.get('proxyPort').hasError('max')">
{{ 'rule-node-config.proxy-port-range' | translate }}
*ngIf="restApiCallConfigForm.get('maxInMemoryBufferSizeInKb').hasError('min') || restApiCallConfigForm.get('maxInMemoryBufferSizeInKb').hasError('max')">
{{ 'rule-node-config.memory-buffer-size-range' | translate: { max: MemoryBufferSizeInKbLimit } }}
</mat-error>
</mat-form-field>
</div>
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.proxy-user</mat-label>
<input matInput formControlName="proxyUser">
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>rule-node-config.proxy-password</mat-label>
<input matInput formControlName="proxyPassword">
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<mat-form-field *ngIf="!restApiCallConfigForm.get('useSimpleClientHttpFactory').value || restApiCallConfigForm.get('enableProxy').value" class="mat-block"
subscriptSizing="dynamic">
<mat-label translate>rule-node-config.read-timeout</mat-label>
<input type="text" min="0" [max]="IntLimit" inputmode="numeric" pattern="[0-9]*" matInput formControlName="readTimeoutMs">
<mat-hint translate>rule-node-config.read-timeout-hint</mat-hint>
<mat-error
*ngIf="restApiCallConfigForm.get('readTimeoutMs').hasError('max')">
{{ 'rule-node-config.int-range' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block" subscriptSizing="dynamic">
<mat-label translate>rule-node-config.max-parallel-requests-count</mat-label>
<input type="text" min="0" [max]="IntLimit" inputmode="numeric" pattern="[0-9]*" matInput formControlName="maxParallelRequestsCount">
<mat-hint translate>rule-node-config.max-parallel-requests-count-hint</mat-hint>
<mat-error
*ngIf="restApiCallConfigForm.get('maxParallelRequestsCount').hasError('max')">
{{ 'rule-node-config.int-range' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block" subscriptSizing="dynamic">
<mat-label translate>rule-node-config.max-response-size</mat-label>
<input type="text" min="1" [max]="MemoryBufferSizeInKbLimit" inputmode="numeric" pattern="[0-9]*" matInput formControlName="maxInMemoryBufferSizeInKb">
<mat-hint translate>rule-node-config.max-response-size-hint</mat-hint>
<mat-error
*ngIf="restApiCallConfigForm.get('maxInMemoryBufferSizeInKb').hasError('min') || restApiCallConfigForm.get('maxInMemoryBufferSizeInKb').hasError('max')">
{{ 'rule-node-config.memory-buffer-size-range' | translate: { max: MemoryBufferSizeInKbLimit } }}
</mat-error>
</mat-form-field>
<label translate class="tb-title">rule-node-config.headers</label>
<div class="tb-hint" [innerHTML]="'rule-node-config.headers-hint' | translate | safe: 'html'"> </div>
<tb-kv-map-config-old
required="false"
formControlName="headers"
keyText="rule-node-config.header"
keyRequiredText="rule-node-config.header-required"
valText="rule-node-config.value"
valRequiredText="rule-node-config.value-required">
</tb-kv-map-config-old>
<tb-credentials-config formControlName="credentials" [disableCertPemCredentials]="restApiCallConfigForm.get('useSimpleClientHttpFactory').value"></tb-credentials-config>
</section>

30
ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.scss

@ -0,0 +1,30 @@
/**
* 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.
*/
:host ::ng-deep {
.mat-expansion-panel-content {
.mat-expansion-panel-body {
.tb-kv-map-config {
margin-bottom: 0;
.body {
.mdc-icon-button {
margin-bottom: 22px;
}
}
}
}
}
}

28
ui-ngx/src/app/modules/home/components/rule-node/external/rest-api-call-config.component.ts

@ -18,21 +18,24 @@ import { Component } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { RuleNodeConfiguration, RuleNodeConfigurationComponent } from '@app/shared/models/rule-node.models';
import { HttpRequestType, IntLimit } from '../rule-node-config.models';
import { isDefinedAndNotNull } from '@core/utils';
@Component({
selector: 'tb-external-node-rest-api-call-config',
templateUrl: './rest-api-call-config.component.html',
styleUrls: []
styleUrls: ['./rest-api-call-config.component.scss']
})
export class RestApiCallConfigComponent extends RuleNodeConfigurationComponent {
restApiCallConfigForm: UntypedFormGroup;
readonly proxySchemes: string[] = ['http', 'https'];
readonly httpRequestTypes = Object.keys(HttpRequestType);
readonly MemoryBufferSizeInKbLimit = 25000;
readonly IntLimit = IntLimit;
isHeadersExpanded = false;
isQueryParamsExpanded = false;
constructor(private fb: UntypedFormBuilder) {
super();
}
@ -45,12 +48,10 @@ export class RestApiCallConfigComponent extends RuleNodeConfigurationComponent {
this.restApiCallConfigForm = this.fb.group({
restEndpointUrlPattern: [configuration ? configuration.restEndpointUrlPattern : null, [Validators.required]],
requestMethod: [configuration ? configuration.requestMethod : null, [Validators.required]],
useSimpleClientHttpFactory: [configuration ? configuration.useSimpleClientHttpFactory : false, []],
parseToPlainText: [configuration ? configuration.parseToPlainText : false, []],
ignoreRequestBody: [configuration ? configuration.ignoreRequestBody : false, []],
enableProxy: [configuration ? configuration.enableProxy : false, []],
useSystemProxyProperties: [configuration ? configuration.enableProxy : false, []],
proxyScheme: [configuration ? configuration.proxyHost : null, []],
proxyHost: [configuration ? configuration.proxyHost : null, []],
proxyPort: [configuration ? configuration.proxyPort : null, []],
proxyUser: [configuration ? configuration.proxyUser :null, []],
@ -59,16 +60,22 @@ export class RestApiCallConfigComponent extends RuleNodeConfigurationComponent {
maxParallelRequestsCount: [configuration ? configuration.maxParallelRequestsCount : null, [Validators.min(0), Validators.max(IntLimit)]],
headers: [configuration ? configuration.headers : null, []],
credentials: [configuration ? configuration.credentials : null, []],
maxInMemoryBufferSizeInKb: [configuration ? configuration.maxInMemoryBufferSizeInKb : null, [Validators.min(1), Validators.max(this.MemoryBufferSizeInKbLimit)]]
maxInMemoryBufferSizeInKb: [configuration ? configuration.maxInMemoryBufferSizeInKb : null, [Validators.min(1), Validators.max(this.MemoryBufferSizeInKbLimit)]],
queryParams: [configuration ? configuration.queryParams : [], []],
});
}
protected validatorTriggers(): string[] {
return ['useSimpleClientHttpFactory', 'enableProxy', 'useSystemProxyProperties'];
return ['enableProxy', 'useSystemProxyProperties'];
}
protected prepareInputConfig(configuration: RuleNodeConfiguration): RuleNodeConfiguration {
this.isQueryParamsExpanded = configuration && isDefinedAndNotNull(configuration.queryParams) && !!Object.keys(configuration.queryParams).length;
this.isHeadersExpanded = configuration && isDefinedAndNotNull(configuration.headers) && !!Object.keys(configuration.headers).length;
return super.prepareInputConfig(configuration);
}
protected updateValidators(emitEvent: boolean) {
const useSimpleClientHttpFactory: boolean = this.restApiCallConfigForm.get('useSimpleClientHttpFactory').value;
const enableProxy: boolean = this.restApiCallConfigForm.get('enableProxy').value;
const useSystemProxyProperties: boolean = this.restApiCallConfigForm.get('useSystemProxyProperties').value;
@ -79,12 +86,7 @@ export class RestApiCallConfigComponent extends RuleNodeConfigurationComponent {
} else {
this.restApiCallConfigForm.get('proxyHost').setValidators([]);
this.restApiCallConfigForm.get('proxyPort').setValidators([]);
if (useSimpleClientHttpFactory) {
this.restApiCallConfigForm.get('readTimeoutMs').setValidators([]);
} else {
this.restApiCallConfigForm.get('readTimeoutMs').setValidators([Validators.min(0), Validators.max(IntLimit)]);
}
this.restApiCallConfigForm.get('readTimeoutMs').setValidators([Validators.min(0), Validators.max(IntLimit)]);
}
this.restApiCallConfigForm.get('readTimeoutMs').updateValueAndValidity({emitEvent});

9
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -5404,6 +5404,15 @@
"tell-failure-aws-lambda-hint": "Rule node forces failure of message processing if AWS Lambda function execution raises exception.",
"basic-mode": "Basic",
"advanced-mode": "Advanced",
"url-hint" : "Enter the request URL. Ensure special characters are percent-encoded.",
"query-params": "Query parameters",
"query-params-hint": "Additional query parameters to include in the request URL. Both names and values support templatization and are strictly (RFC 3986) encoded after template resolution.",
"query-params-empty": "No query parameters configured",
"query-params-name": "Name",
"query-params-value": "Value",
"query-params-name-required": "Name is required",
"query-params-value-required": "Value is required",
"headers-empty": "No headers configured",
"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.",

Loading…
Cancel
Save