Changed Security block for REST Connector
This commit is contained in:
parent
c4e5ab65ee
commit
580f3b5b3c
@ -0,0 +1,65 @@
|
||||
<!--
|
||||
|
||||
Copyright © 2016-2024 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.
|
||||
|
||||
-->
|
||||
<div class="tb-form-row space-between same-padding tb-flex column" [formGroup]="securityFormGroup">
|
||||
<div class="tb-flex row space-between align-center no-gap fill-width">
|
||||
<div class="fields-label" translate>gateway.security</div>
|
||||
<tb-toggle-select formControlName="type" appearance="fill">
|
||||
<tb-toggle-option *ngFor="let type of securityTypes" [value]="type">
|
||||
{{ SecurityTypeTranslationsMap.get(type) | translate }}
|
||||
</tb-toggle-option>
|
||||
</tb-toggle-select>
|
||||
</div>
|
||||
<ng-container *ngIf="securityFormGroup.get('type').value === BrokerSecurityType.BASIC">
|
||||
<div class="tb-form-row space-between tb-flex fill-width">
|
||||
<div class="fixed-title-width" translate>gateway.username</div>
|
||||
<div class="tb-flex no-gap">
|
||||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
|
||||
<input matInput name="value" formControlName="username" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="('gateway.username-required') | translate"
|
||||
*ngIf="securityFormGroup.get('username').hasError('required') && securityFormGroup.get('username').touched"
|
||||
class="tb-error">
|
||||
warning
|
||||
</mat-icon>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tb-form-row space-between tb-flex fill-width">
|
||||
<div class="fixed-title-width" translate>gateway.password</div>
|
||||
<div class="tb-flex no-gap">
|
||||
<mat-form-field class="tb-flex no-gap" appearance="outline" subscriptSizing="dynamic">
|
||||
<input matInput type="password" name="value" formControlName="password" placeholder="{{ 'gateway.set' | translate }}"/>
|
||||
<mat-icon matSuffix
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="tb-error-tooltip"
|
||||
[matTooltip]="('gateway.password-required') | translate"
|
||||
*ngIf="securityFormGroup.get('password').hasError('required')
|
||||
&& securityFormGroup.get('password').touched"
|
||||
class="tb-error">
|
||||
warning
|
||||
</mat-icon>
|
||||
<div [class.hide-toggle]="securityFormGroup.get('password').hasError('required')" class="tb-flex no-gap align-center fill-height" matSuffix>
|
||||
<tb-toggle-password class="tb-flex align-center fill-height"></tb-toggle-password>
|
||||
</div>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright © 2016-2024 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 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.fields-label {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.hide-toggle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
///
|
||||
/// Copyright © 2016-2024 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 {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
forwardRef,
|
||||
OnDestroy,
|
||||
} from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
FormBuilder,
|
||||
NG_VALIDATORS,
|
||||
NG_VALUE_ACCESSOR,
|
||||
UntypedFormGroup,
|
||||
ValidationErrors,
|
||||
Validator,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import {
|
||||
noLeadTrailSpacesRegex,
|
||||
RestSecurityType,
|
||||
RestSecurityTypeTranslationsMap
|
||||
} from '@home/components/widget/lib/gateway/gateway-widget.models';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-rest-connector-security',
|
||||
templateUrl: './rest-connector-security.component.html',
|
||||
styleUrls: ['./rest-connector-security.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => RestConnectorSecurityComponent),
|
||||
multi: true
|
||||
},
|
||||
{
|
||||
provide: NG_VALIDATORS,
|
||||
useExisting: forwardRef(() => RestConnectorSecurityComponent),
|
||||
multi: true
|
||||
}
|
||||
],
|
||||
standalone: true,
|
||||
imports: [
|
||||
SharedModule,
|
||||
CommonModule,
|
||||
]
|
||||
})
|
||||
export class RestConnectorSecurityComponent implements ControlValueAccessor, Validator, OnDestroy {
|
||||
BrokerSecurityType = RestSecurityType;
|
||||
securityTypes: RestSecurityType[] = Object.values(RestSecurityType);
|
||||
SecurityTypeTranslationsMap = RestSecurityTypeTranslationsMap;
|
||||
securityFormGroup: UntypedFormGroup;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
private propagateChange = (_: any) => {};
|
||||
|
||||
constructor(private fb: FormBuilder) {
|
||||
this.securityFormGroup = this.fb.group({
|
||||
type: [RestSecurityType.ANONYMOUS, []],
|
||||
username: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||
password: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||
});
|
||||
this.observeSecurityForm();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.propagateChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: any): void {}
|
||||
|
||||
writeValue(deviceInfo: any): void {
|
||||
if (!deviceInfo.type) {
|
||||
deviceInfo.type = RestSecurityType.ANONYMOUS;
|
||||
}
|
||||
this.securityFormGroup.reset(deviceInfo);
|
||||
this.updateView(deviceInfo);
|
||||
}
|
||||
|
||||
validate(): ValidationErrors | null {
|
||||
return this.securityFormGroup.valid ? null : {
|
||||
securityForm: { valid: false }
|
||||
};
|
||||
}
|
||||
|
||||
updateView(value: any): void {
|
||||
this.propagateChange(value);
|
||||
}
|
||||
|
||||
private updateValidators(type: RestSecurityType): void {
|
||||
if (type === RestSecurityType.BASIC) {
|
||||
this.securityFormGroup.get('username').enable({emitEvent: false});
|
||||
this.securityFormGroup.get('password').enable({emitEvent: false});
|
||||
} else {
|
||||
this.securityFormGroup.get('username').disable({emitEvent: false});
|
||||
this.securityFormGroup.get('password').disable({emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
private observeSecurityForm(): void {
|
||||
this.securityFormGroup.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(value => this.updateView(value));
|
||||
|
||||
this.securityFormGroup.get('type').valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(type => this.updateValidators(type));
|
||||
}
|
||||
}
|
||||
@ -368,38 +368,7 @@
|
||||
{{ 'gateway.rpc.add-header' | translate }}
|
||||
</button>
|
||||
</fieldset>
|
||||
<fieldset class="fields border" fxLayout="column" fxLayoutGap="10px" formArrayName="security">
|
||||
<span class="fields-label">{{ 'gateway.rpc.security' | translate }}</span>
|
||||
<div class="border" fxLayout="column" fxLayoutGap="10px" *ngIf="getFormArrayControls('security').length">
|
||||
<div fxLayout="row" fxLayoutGap="10px" fxLayoutAlign="center center">
|
||||
<span fxFlex class="title">{{ 'gateway.rpc.security-name' | translate }}</span>
|
||||
<span fxFlex class="title">{{ 'gateway.rpc.value' | translate }}</span>
|
||||
<span fxFlex="30px"></span>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div fxFlex fxLayout="row" fxLayoutGap="10px" fxLayoutAlign="center center"
|
||||
*ngFor="let control of getFormArrayControls('security'); let i = index">
|
||||
<ng-container [formGroupName]="i">
|
||||
<mat-form-field appearance="outline" fxFlex>
|
||||
<input matInput formControlName="securityName"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" fxFlex>
|
||||
<input matInput formControlName="value" placeholder="anonymous"/>
|
||||
</mat-form-field>
|
||||
<mat-icon style="cursor:pointer;"
|
||||
fxFlex="30px"
|
||||
(click)="removeHTTPSecurity(i)"
|
||||
matTooltip="{{ 'gateway.rpc.remove' | translate }}">delete
|
||||
</mat-icon>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<button mat-raised-button
|
||||
fxFlexAlign="start"
|
||||
(click)="addHTTPSecurity()">
|
||||
{{ 'gateway.rpc.add-security' | translate }}
|
||||
</button>
|
||||
</fieldset>
|
||||
<tb-rest-connector-security [formControl]="commandForm.get('security')"></tb-rest-connector-security>
|
||||
</ng-template>
|
||||
<ng-template [ngSwitchCase]="ConnectorType.REQUEST">
|
||||
<mat-form-field>
|
||||
|
||||
@ -114,17 +114,12 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, ControlValue
|
||||
this.commandForm = this.connectorParamsFormGroupByType(this.connectorType);
|
||||
this.commandForm.valueChanges.subscribe(value => {
|
||||
const httpHeaders = {};
|
||||
const security = {};
|
||||
switch (this.connectorType) {
|
||||
case ConnectorType.REST:
|
||||
value.httpHeaders.forEach(data => {
|
||||
httpHeaders[data.headerName] = data.value;
|
||||
})
|
||||
value.httpHeaders = httpHeaders;
|
||||
value.security.forEach(data => {
|
||||
security[data.securityName] = data.value;
|
||||
})
|
||||
value.security = security;
|
||||
break;
|
||||
case ConnectorType.REQUEST:
|
||||
value.httpHeaders.forEach(data => {
|
||||
@ -252,7 +247,7 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, ControlValue
|
||||
tries: [null, [Validators.required, Validators.min(1), Validators.pattern(this.numbersOnlyPattern)]],
|
||||
valueExpression: [null, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||
httpHeaders: this.fb.array([]),
|
||||
security: this.fb.array([])
|
||||
security: [{}, [Validators.required]]
|
||||
})
|
||||
break;
|
||||
case ConnectorType.REQUEST:
|
||||
@ -312,22 +307,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, ControlValue
|
||||
oidsFA.removeAt(index);
|
||||
}
|
||||
|
||||
addHTTPSecurity(value: { securityName: string, value: string } = {securityName: null, value: null}) {
|
||||
const securityFA = this.commandForm.get('security') as FormArray;
|
||||
const formGroup = this.fb.group({
|
||||
securityName: [value.securityName, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]],
|
||||
value: [value.value, [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]]
|
||||
})
|
||||
if (securityFA) {
|
||||
securityFA.push(formGroup, {emitEvent: false});
|
||||
}
|
||||
}
|
||||
|
||||
removeHTTPSecurity(index: number) {
|
||||
const oidsFA = this.commandForm.get('security') as FormArray;
|
||||
oidsFA.removeAt(index);
|
||||
}
|
||||
|
||||
getFormArrayControls(path: string) {
|
||||
return (this.commandForm.get(path) as FormArray).controls as FormControl[];
|
||||
}
|
||||
@ -402,11 +381,6 @@ export class GatewayServiceRPCConnectorComponent implements OnInit, ControlValue
|
||||
break;
|
||||
case ConnectorType.REST:
|
||||
this.clearFromArrayByName("httpHeaders");
|
||||
this.clearFromArrayByName("security");
|
||||
value.security && Object.entries(value.security).forEach(securityHeader => {
|
||||
this.addHTTPSecurity({securityName: securityHeader[0], value: securityHeader[1] as string})
|
||||
})
|
||||
delete value.security;
|
||||
value.httpHeaders && Object.entries(value.httpHeaders).forEach(httpHeader => {
|
||||
this.addHTTPHeader({headerName: httpHeader[0], value: httpHeader[1] as string})
|
||||
})
|
||||
|
||||
@ -360,6 +360,18 @@ export const BrokerSecurityTypeTranslationsMap = new Map<BrokerSecurityType, str
|
||||
]
|
||||
);
|
||||
|
||||
export enum RestSecurityType {
|
||||
ANONYMOUS = 'anonymous',
|
||||
BASIC = 'basic',
|
||||
}
|
||||
|
||||
export const RestSecurityTypeTranslationsMap = new Map<RestSecurityType, string>(
|
||||
[
|
||||
[RestSecurityType.ANONYMOUS, 'gateway.broker.security-types.anonymous'],
|
||||
[RestSecurityType.BASIC, 'gateway.broker.security-types.basic'],
|
||||
]
|
||||
);
|
||||
|
||||
export const MqttVersions = [
|
||||
{ name: 3.1, value: 3 },
|
||||
{ name: 3.11, value: 4 },
|
||||
|
||||
@ -100,6 +100,7 @@ import { BarChartWidgetComponent } from '@home/components/widget/lib/chart/bar-c
|
||||
import { PolarAreaWidgetComponent } from '@home/components/widget/lib/chart/polar-area-widget.component';
|
||||
import { RadarChartWidgetComponent } from '@home/components/widget/lib/chart/radar-chart-widget.component';
|
||||
import { MobileAppQrcodeWidgetComponent } from '@home/components/widget/lib/mobile-app-qrcode-widget.component';
|
||||
import { RestConnectorSecurityComponent } from '@home/components/widget/lib/gateway/connectors-configuration/rest-connector-secuirity/rest-connector-security.component';
|
||||
|
||||
@NgModule({
|
||||
declarations:
|
||||
@ -168,13 +169,14 @@ import { MobileAppQrcodeWidgetComponent } from '@home/components/widget/lib/mobi
|
||||
PolarAreaWidgetComponent,
|
||||
RadarChartWidgetComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
RpcWidgetsModule,
|
||||
HomePageWidgetsModule,
|
||||
SharedHomeComponentsModule
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
RpcWidgetsModule,
|
||||
HomePageWidgetsModule,
|
||||
SharedHomeComponentsModule,
|
||||
RestConnectorSecurityComponent
|
||||
],
|
||||
exports: [
|
||||
EntitiesTableWidgetComponent,
|
||||
AlarmsTableWidgetComponent,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user