Commit ccb04f34a1dd5af8cfa8a30bfd10ad9a449b6c3c
Committed by
GitHub
Merge pull request #4871 from vvlladd28/improvement/device-credential/select-type
UI: Improvement device credentials
Showing
19 changed files
with
388 additions
and
200 deletions
ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.html
renamed from
ui-ngx/src/app/modules/home/components/device/security-config-lwm2m-server.component.html
ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m-server.component.ts
renamed from
ui-ngx/src/app/modules/home/components/device/security-config-lwm2m-server.component.ts
... | ... | @@ -39,24 +39,24 @@ import { takeUntil } from 'rxjs/operators'; |
39 | 39 | import { Subject } from 'rxjs'; |
40 | 40 | |
41 | 41 | @Component({ |
42 | - selector: 'tb-security-config-lwm2m-server', | |
43 | - templateUrl: './security-config-lwm2m-server.component.html', | |
42 | + selector: 'tb-device-credentials-lwm2m-server', | |
43 | + templateUrl: './device-credentials-lwm2m-server.component.html', | |
44 | 44 | styleUrls: [], |
45 | 45 | providers: [ |
46 | 46 | { |
47 | 47 | provide: NG_VALUE_ACCESSOR, |
48 | - useExisting: forwardRef(() => SecurityConfigLwm2mServerComponent), | |
48 | + useExisting: forwardRef(() => DeviceCredentialsLwm2mServerComponent), | |
49 | 49 | multi: true |
50 | 50 | }, |
51 | 51 | { |
52 | 52 | provide: NG_VALIDATORS, |
53 | - useExisting: forwardRef(() => SecurityConfigLwm2mServerComponent), | |
53 | + useExisting: forwardRef(() => DeviceCredentialsLwm2mServerComponent), | |
54 | 54 | multi: true |
55 | 55 | } |
56 | 56 | ] |
57 | 57 | }) |
58 | 58 | |
59 | -export class SecurityConfigLwm2mServerComponent implements OnDestroy, ControlValueAccessor, Validator { | |
59 | +export class DeviceCredentialsLwm2mServerComponent implements OnDestroy, ControlValueAccessor, Validator { | |
60 | 60 | |
61 | 61 | serverFormGroup: FormGroup; |
62 | 62 | securityConfigLwM2MType = Lwm2mSecurityType; | ... | ... |
ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.html
renamed from
ui-ngx/src/app/modules/home/components/device/security-config-lwm2m.component.html
... | ... | @@ -15,8 +15,8 @@ |
15 | 15 | limitations under the License. |
16 | 16 | |
17 | 17 | --> |
18 | -<mat-tab-group> | |
19 | - <mat-tab label="{{ 'device.lwm2m-security-config.client-tab' | translate }}" [formGroup]="lwm2mConfigFormGroup"> | |
18 | +<mat-tab-group [formGroup]="lwm2mConfigFormGroup"> | |
19 | + <mat-tab label="{{ 'device.lwm2m-security-config.client-tab' | translate }}"> | |
20 | 20 | <ng-container formGroupName="client"> |
21 | 21 | <mat-form-field class="mat-block"> |
22 | 22 | <mat-label translate>device.lwm2m-security-config.endpoint</mat-label> |
... | ... | @@ -79,7 +79,7 @@ |
79 | 79 | </mat-form-field> |
80 | 80 | </ng-container> |
81 | 81 | </mat-tab> |
82 | - <mat-tab label="{{ 'device.lwm2m-security-config.bootstrap-tab' | translate }}" [formGroup]="lwm2mConfigFormGroup"> | |
82 | + <mat-tab label="{{ 'device.lwm2m-security-config.bootstrap-tab' | translate }}"> | |
83 | 83 | <div style="padding: 2px;" formGroupName="bootstrap"> |
84 | 84 | <mat-accordion multi="true" class="mat-body-1"> |
85 | 85 | <mat-expansion-panel> |
... | ... | @@ -89,9 +89,9 @@ |
89 | 89 | </mat-panel-title> |
90 | 90 | </mat-expansion-panel-header> |
91 | 91 | <ng-template matExpansionPanelContent> |
92 | - <tb-security-config-lwm2m-server | |
92 | + <tb-device-credentials-lwm2m-server | |
93 | 93 | formControlName="bootstrapServer"> |
94 | - </tb-security-config-lwm2m-server> | |
94 | + </tb-device-credentials-lwm2m-server> | |
95 | 95 | </ng-template> |
96 | 96 | </mat-expansion-panel> |
97 | 97 | <mat-expansion-panel> |
... | ... | @@ -101,23 +101,12 @@ |
101 | 101 | </mat-panel-title> |
102 | 102 | </mat-expansion-panel-header> |
103 | 103 | <ng-template matExpansionPanelContent> |
104 | - <tb-security-config-lwm2m-server | |
104 | + <tb-device-credentials-lwm2m-server | |
105 | 105 | formControlName="lwm2mServer"> |
106 | - </tb-security-config-lwm2m-server> | |
106 | + </tb-device-credentials-lwm2m-server> | |
107 | 107 | </ng-template> |
108 | 108 | </mat-expansion-panel> |
109 | 109 | </mat-accordion> |
110 | 110 | </div> |
111 | 111 | </mat-tab> |
112 | - <mat-tab label="{{ 'device.lwm2m-security-config.config-json-tab' | translate }}"> | |
113 | - <ng-template matTabContent> | |
114 | - <tb-json-object-edit | |
115 | - [ngModel]="lwm2mConfigFormGroup.value" | |
116 | - label="{{ 'device.lwm2m-value' | translate }}" | |
117 | - readonly | |
118 | - [required]="true" | |
119 | - [fillHeight]="false"> | |
120 | - </tb-json-object-edit> | |
121 | - </ng-template> | |
122 | - </mat-tab> | |
123 | 112 | </mat-tab-group> | ... | ... |
ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.scss
renamed from
ui-ngx/src/app/modules/home/components/device/security-config-lwm2m.component.scss
ui-ngx/src/app/modules/home/components/device/device-credentials-lwm2m.component.ts
renamed from
ui-ngx/src/app/modules/home/components/device/security-config-lwm2m.component.ts
... | ... | @@ -40,24 +40,24 @@ import { takeUntil } from 'rxjs/operators'; |
40 | 40 | import { isDefinedAndNotNull } from '@core/utils'; |
41 | 41 | |
42 | 42 | @Component({ |
43 | - selector: 'tb-security-config-lwm2m', | |
44 | - templateUrl: './security-config-lwm2m.component.html', | |
45 | - styleUrls: ['./security-config-lwm2m.component.scss'], | |
43 | + selector: 'tb-device-credentials-lwm2m', | |
44 | + templateUrl: './device-credentials-lwm2m.component.html', | |
45 | + styleUrls: ['./device-credentials-lwm2m.component.scss'], | |
46 | 46 | providers: [ |
47 | 47 | { |
48 | 48 | provide: NG_VALUE_ACCESSOR, |
49 | - useExisting: forwardRef(() => SecurityConfigLwm2mComponent), | |
49 | + useExisting: forwardRef(() => DeviceCredentialsLwm2mComponent), | |
50 | 50 | multi: true |
51 | 51 | }, |
52 | 52 | { |
53 | 53 | provide: NG_VALIDATORS, |
54 | - useExisting: forwardRef(() => SecurityConfigLwm2mComponent), | |
54 | + useExisting: forwardRef(() => DeviceCredentialsLwm2mComponent), | |
55 | 55 | multi: true |
56 | 56 | } |
57 | 57 | ] |
58 | 58 | }) |
59 | 59 | |
60 | -export class SecurityConfigLwm2mComponent implements ControlValueAccessor, Validator, OnDestroy { | |
60 | +export class DeviceCredentialsLwm2mComponent implements ControlValueAccessor, Validator, OnDestroy { | |
61 | 61 | |
62 | 62 | lwm2mConfigFormGroup: FormGroup; |
63 | 63 | securityConfigLwM2MType = Lwm2mSecurityType; |
... | ... | @@ -89,6 +89,7 @@ export class SecurityConfigLwm2mComponent implements ControlValueAccessor, Valid |
89 | 89 | this.lwm2mConfigFormGroup.disable({emitEvent: false}); |
90 | 90 | } else { |
91 | 91 | this.lwm2mConfigFormGroup.enable({emitEvent: false}); |
92 | + this.securityConfigClientUpdateValidators(this.lwm2mConfigFormGroup.get('client.securityConfigClientMode').value); | |
92 | 93 | } |
93 | 94 | } |
94 | 95 | |
... | ... | @@ -126,21 +127,21 @@ export class SecurityConfigLwm2mComponent implements ControlValueAccessor, Valid |
126 | 127 | switch (mode) { |
127 | 128 | case Lwm2mSecurityType.NO_SEC: |
128 | 129 | this.setValidatorsNoSecX509(); |
129 | - this.lwm2mConfigFormGroup.get('client.cert').disable(); | |
130 | + this.lwm2mConfigFormGroup.get('client.cert').disable({emitEvent: false}); | |
130 | 131 | break; |
131 | 132 | case Lwm2mSecurityType.X509: |
132 | 133 | this.setValidatorsNoSecX509(); |
133 | - this.lwm2mConfigFormGroup.get('client.cert').enable(); | |
134 | + this.lwm2mConfigFormGroup.get('client.cert').enable({emitEvent: false}); | |
134 | 135 | break; |
135 | 136 | case Lwm2mSecurityType.PSK: |
136 | 137 | this.lenMaxKeyClient = LEN_MAX_PSK; |
137 | 138 | this.setValidatorsPskRpk(mode); |
138 | - this.lwm2mConfigFormGroup.get('client.identity').enable(); | |
139 | + this.lwm2mConfigFormGroup.get('client.identity').enable({emitEvent: false}); | |
139 | 140 | break; |
140 | 141 | case Lwm2mSecurityType.RPK: |
141 | 142 | this.lenMaxKeyClient = LEN_MAX_PUBLIC_KEY_RPK; |
142 | 143 | this.setValidatorsPskRpk(mode); |
143 | - this.lwm2mConfigFormGroup.get('client.identity').disable(); | |
144 | + this.lwm2mConfigFormGroup.get('client.identity').disable({emitEvent: false}); | |
144 | 145 | break; |
145 | 146 | } |
146 | 147 | this.lwm2mConfigFormGroup.get('client.identity').updateValueAndValidity({emitEvent: false}); | ... | ... |
ui-ngx/src/app/modules/home/components/device/device-credentials-mqtt-basic.component.html
0 → 100644
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2021 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<section [formGroup]="deviceCredentialsMqttFormGroup"> | |
19 | + <mat-form-field class="mat-block"> | |
20 | + <mat-label translate>device.client-id</mat-label> | |
21 | + <input matInput formControlName="clientId"> | |
22 | + <mat-error *ngIf="deviceCredentialsMqttFormGroup.get('clientId').hasError('pattern')"> | |
23 | + {{ 'device.client-id-pattern' | translate }} | |
24 | + </mat-error> | |
25 | + </mat-form-field> | |
26 | + <mat-form-field class="mat-block"> | |
27 | + <mat-label translate>device.user-name</mat-label> | |
28 | + <input matInput formControlName="userName" [required]="!!deviceCredentialsMqttFormGroup.get('password').value"> | |
29 | + <mat-error *ngIf="deviceCredentialsMqttFormGroup.get('userName').hasError('required')"> | |
30 | + {{ 'device.user-name-required' | translate }} | |
31 | + </mat-error> | |
32 | + </mat-form-field> | |
33 | + <mat-form-field class="mat-block"> | |
34 | + <mat-label translate>device.password</mat-label> | |
35 | + <input matInput formControlName="password" | |
36 | + autocomplete="new-password" | |
37 | + (ngModelChange)="passwordChanged()" | |
38 | + [type]="hidePassword ? 'password' : 'text'"> | |
39 | + <button mat-icon-button matSuffix type="button" | |
40 | + (click)="hidePassword = !hidePassword" | |
41 | + [attr.aria-pressed]="hidePassword"> | |
42 | + <mat-icon>{{hidePassword ? 'visibility_off' : 'visibility'}}</mat-icon> | |
43 | + </button> | |
44 | + </mat-form-field> | |
45 | + <tb-error style="margin-top: -12px; display: block;" | |
46 | + [error]="deviceCredentialsMqttFormGroup.hasError('atLeastOne') ? | |
47 | + ('device.client-id-or-user-name-necessary' | translate) : ''"></tb-error> | |
48 | +</section> | ... | ... |
1 | +/// | |
2 | +/// Copyright © 2016-2021 The Thingsboard Authors | |
3 | +/// | |
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | +/// you may not use this file except in compliance with the License. | |
6 | +/// You may obtain a copy of the License at | |
7 | +/// | |
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | |
9 | +/// | |
10 | +/// Unless required by applicable law or agreed to in writing, software | |
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | |
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | +/// See the License for the specific language governing permissions and | |
14 | +/// limitations under the License. | |
15 | +/// | |
16 | + | |
17 | +import { Component, forwardRef, Input, OnDestroy } from '@angular/core'; | |
18 | +import { | |
19 | + ControlValueAccessor, | |
20 | + FormBuilder, | |
21 | + FormGroup, | |
22 | + NG_VALIDATORS, | |
23 | + NG_VALUE_ACCESSOR, | |
24 | + ValidationErrors, | |
25 | + Validator, | |
26 | + ValidatorFn, | |
27 | + Validators | |
28 | +} from '@angular/forms'; | |
29 | +import { Subject } from 'rxjs'; | |
30 | +import { DeviceCredentialMQTTBasic } from '@shared/models/device.models'; | |
31 | +import { takeUntil } from 'rxjs/operators'; | |
32 | +import { isDefinedAndNotNull, isEmptyStr } from '@core/utils'; | |
33 | + | |
34 | +@Component({ | |
35 | + selector: 'tb-device-credentials-mqtt-basic', | |
36 | + templateUrl: './device-credentials-mqtt-basic.component.html', | |
37 | + providers: [ | |
38 | + { | |
39 | + provide: NG_VALUE_ACCESSOR, | |
40 | + useExisting: forwardRef(() => DeviceCredentialsMqttBasicComponent), | |
41 | + multi: true | |
42 | + }, | |
43 | + { | |
44 | + provide: NG_VALIDATORS, | |
45 | + useExisting: forwardRef(() => DeviceCredentialsMqttBasicComponent), | |
46 | + multi: true, | |
47 | + }], | |
48 | + styleUrls: [] | |
49 | +}) | |
50 | +export class DeviceCredentialsMqttBasicComponent implements ControlValueAccessor, Validator, OnDestroy { | |
51 | + | |
52 | + @Input() | |
53 | + disabled: boolean; | |
54 | + | |
55 | + deviceCredentialsMqttFormGroup: FormGroup; | |
56 | + | |
57 | + hidePassword = true; | |
58 | + | |
59 | + private destroy$ = new Subject(); | |
60 | + private propagateChange = (v: any) => {}; | |
61 | + | |
62 | + constructor(public fb: FormBuilder) { | |
63 | + this.deviceCredentialsMqttFormGroup = this.fb.group({ | |
64 | + clientId: [null, [Validators.pattern(/^[A-Za-z0-9]+$/)]], | |
65 | + userName: [null], | |
66 | + password: [null] | |
67 | + }, {validators: this.atLeastOne(Validators.required, ['clientId', 'userName'])}); | |
68 | + this.deviceCredentialsMqttFormGroup.valueChanges.pipe( | |
69 | + takeUntil(this.destroy$) | |
70 | + ).subscribe((value) => { | |
71 | + this.updateView(value); | |
72 | + }); | |
73 | + } | |
74 | + | |
75 | + ngOnDestroy(): void { | |
76 | + this.destroy$.next(); | |
77 | + this.destroy$.complete(); | |
78 | + } | |
79 | + | |
80 | + registerOnChange(fn: any): void { | |
81 | + this.propagateChange = fn; | |
82 | + } | |
83 | + | |
84 | + registerOnTouched(fn: any): void {} | |
85 | + | |
86 | + setDisabledState(isDisabled: boolean) { | |
87 | + this.disabled = isDisabled; | |
88 | + if (this.disabled) { | |
89 | + this.deviceCredentialsMqttFormGroup.disable({emitEvent: false}); | |
90 | + } else { | |
91 | + this.deviceCredentialsMqttFormGroup.enable({emitEvent: false}); | |
92 | + } | |
93 | + } | |
94 | + | |
95 | + validate(): ValidationErrors | null { | |
96 | + return this.deviceCredentialsMqttFormGroup.valid ? null : { | |
97 | + deviceCredentialsMqttBasic: false | |
98 | + }; | |
99 | + } | |
100 | + | |
101 | + writeValue(mqttBasic: string) { | |
102 | + if (isDefinedAndNotNull(mqttBasic) && !isEmptyStr(mqttBasic)) { | |
103 | + const value = JSON.parse(mqttBasic); | |
104 | + this.deviceCredentialsMqttFormGroup.patchValue(value, {emitEvent: false}); | |
105 | + } | |
106 | + } | |
107 | + | |
108 | + updateView(value: DeviceCredentialMQTTBasic) { | |
109 | + const formValue = JSON.stringify(value); | |
110 | + this.propagateChange(formValue); | |
111 | + } | |
112 | + | |
113 | + passwordChanged() { | |
114 | + const value = this.deviceCredentialsMqttFormGroup.get('password').value; | |
115 | + if (value !== '') { | |
116 | + this.deviceCredentialsMqttFormGroup.get('userName').setValidators([Validators.required]); | |
117 | + } else { | |
118 | + this.deviceCredentialsMqttFormGroup.get('userName').setValidators([]); | |
119 | + } | |
120 | + this.deviceCredentialsMqttFormGroup.get('userName').updateValueAndValidity({emitEvent: false}); | |
121 | + } | |
122 | + | |
123 | + private atLeastOne(validator: ValidatorFn, controls: string[] = null) { | |
124 | + return (group: FormGroup): ValidationErrors | null => { | |
125 | + if (!controls) { | |
126 | + controls = Object.keys(group.controls); | |
127 | + } | |
128 | + const hasAtLeastOne = group?.controls && controls.some(k => !validator(group.controls[k])); | |
129 | + | |
130 | + return hasAtLeastOne ? null : {atLeastOne: true}; | |
131 | + }; | |
132 | + } | |
133 | +} | ... | ... |
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 | |
17 | 17 | --> |
18 | 18 | <section [formGroup]="deviceCredentialsFormGroup"> |
19 | - <mat-form-field class="mat-block"> | |
19 | + <mat-form-field class="mat-block" [fxShow]="credentialsTypes?.length > 1"> | |
20 | 20 | <mat-label translate>device.credentials-type</mat-label> |
21 | 21 | <mat-select formControlName="credentialsType"> |
22 | 22 | <mat-option *ngFor="let credentialsType of credentialsTypes" [value]="credentialsType"> |
... | ... | @@ -24,58 +24,35 @@ |
24 | 24 | </mat-option> |
25 | 25 | </mat-select> |
26 | 26 | </mat-form-field> |
27 | - <mat-form-field *ngIf="deviceCredentialsFormGroup.get('credentialsType').value === deviceCredentialsType.ACCESS_TOKEN" | |
28 | - class="mat-block"> | |
29 | - <mat-label translate>device.access-token</mat-label> | |
30 | - <input matInput formControlName="credentialsId" required> | |
31 | - <mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsId').hasError('required')"> | |
32 | - {{ 'device.access-token-required' | translate }} | |
33 | - </mat-error> | |
34 | - <mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsId').hasError('pattern')"> | |
35 | - {{ 'device.access-token-invalid' | translate }} | |
36 | - </mat-error> | |
37 | - </mat-form-field> | |
38 | - <mat-form-field *ngIf="deviceCredentialsFormGroup.get('credentialsType').value === deviceCredentialsType.X509_CERTIFICATE" | |
39 | - class="mat-block"> | |
40 | - <mat-label translate>device.rsa-key</mat-label> | |
41 | - <textarea matInput formControlName="credentialsValue" cols="15" rows="5" required></textarea> | |
42 | - <mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsValue').hasError('required')"> | |
43 | - {{ 'device.rsa-key-required' | translate }} | |
44 | - </mat-error> | |
45 | - </mat-form-field> | |
46 | - <section *ngIf="deviceCredentialsFormGroup.get('credentialsType').value === deviceCredentialsType.MQTT_BASIC" formGroupName="credentialsBasic"> | |
47 | - <mat-form-field class="mat-block"> | |
48 | - <mat-label translate>device.client-id</mat-label> | |
49 | - <input matInput formControlName="clientId"> | |
50 | - <mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsBasic.clientId').hasError('pattern')"> | |
51 | - {{ 'device.client-id-pattern' | translate }} | |
52 | - </mat-error> | |
53 | - </mat-form-field> | |
54 | - <mat-form-field class="mat-block"> | |
55 | - <mat-label translate>device.user-name</mat-label> | |
56 | - <input matInput formControlName="userName" [required]="!!deviceCredentialsFormGroup.get('credentialsBasic.password').value"> | |
57 | - <mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsBasic.userName').hasError('required')"> | |
58 | - {{ 'device.user-name-required' | translate }} | |
59 | - </mat-error> | |
60 | - </mat-form-field> | |
61 | - <mat-form-field class="mat-block"> | |
62 | - <mat-label translate>device.password</mat-label> | |
63 | - <input matInput formControlName="password" | |
64 | - autocomplete="new-password" | |
65 | - (ngModelChange)="passwordChanged()" | |
66 | - [type]="hidePassword ? 'password' : 'text'"> | |
67 | - <button mat-icon-button matSuffix type="button" | |
68 | - (click)="hidePassword = !hidePassword" | |
69 | - [attr.aria-pressed]="hidePassword"> | |
70 | - <mat-icon>{{hidePassword ? 'visibility_off' : 'visibility'}}</mat-icon> | |
71 | - </button> | |
72 | - </mat-form-field> | |
73 | - <tb-error style="margin-top: -12px; display: block;" | |
74 | - [error]="deviceCredentialsFormGroup.get('credentialsBasic').hasError('atLeastOne') ? | |
75 | - ('device.client-id-or-user-name-necessary' | translate) : ''"></tb-error> | |
76 | - </section> | |
77 | - <div *ngIf="deviceCredentialsFormGroup.get('credentialsType').value === deviceCredentialsType.LWM2M_CREDENTIALS"> | |
78 | - <tb-security-config-lwm2m formControlName="credentialsValue"> | |
79 | - </tb-security-config-lwm2m> | |
27 | + <div [ngSwitch]="deviceCredentialsFormGroup.get('credentialsType').value"> | |
28 | + <ng-template [ngSwitchCase]="deviceCredentialsType.ACCESS_TOKEN"> | |
29 | + <mat-form-field class="mat-block"> | |
30 | + <mat-label translate>device.access-token</mat-label> | |
31 | + <input matInput formControlName="credentialsId" required> | |
32 | + <mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsId').hasError('required')"> | |
33 | + {{ 'device.access-token-required' | translate }} | |
34 | + </mat-error> | |
35 | + <mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsId').hasError('pattern')"> | |
36 | + {{ 'device.access-token-invalid' | translate }} | |
37 | + </mat-error> | |
38 | + </mat-form-field> | |
39 | + </ng-template> | |
40 | + <ng-template [ngSwitchCase]="deviceCredentialsType.X509_CERTIFICATE"> | |
41 | + <mat-form-field class="mat-block"> | |
42 | + <mat-label translate>device.rsa-key</mat-label> | |
43 | + <textarea matInput formControlName="credentialsValue" cols="15" rows="5" required></textarea> | |
44 | + <mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsValue').hasError('required')"> | |
45 | + {{ 'device.rsa-key-required' | translate }} | |
46 | + </mat-error> | |
47 | + </mat-form-field> | |
48 | + </ng-template> | |
49 | + <ng-template [ngSwitchCase]="deviceCredentialsType.MQTT_BASIC"> | |
50 | + <tb-device-credentials-mqtt-basic formControlName="credentialsValue"> | |
51 | + </tb-device-credentials-mqtt-basic> | |
52 | + </ng-template> | |
53 | + <ng-template [ngSwitchCase]="deviceCredentialsType.LWM2M_CREDENTIALS"> | |
54 | + <tb-device-credentials-lwm2m formControlName="credentialsValue"> | |
55 | + </tb-device-credentials-lwm2m> | |
56 | + </ng-template> | |
80 | 57 | </div> |
81 | 58 | </section> | ... | ... |
... | ... | @@ -22,16 +22,15 @@ import { |
22 | 22 | FormGroup, |
23 | 23 | NG_VALIDATORS, |
24 | 24 | NG_VALUE_ACCESSOR, |
25 | - ValidationErrors, | |
26 | 25 | Validator, |
27 | - ValidatorFn, | |
28 | 26 | Validators |
29 | 27 | } from '@angular/forms'; |
30 | 28 | import { |
31 | 29 | credentialTypeNames, |
32 | - DeviceCredentialMQTTBasic, | |
30 | + credentialTypesByTransportType, | |
33 | 31 | DeviceCredentials, |
34 | - DeviceCredentialsType | |
32 | + DeviceCredentialsType, | |
33 | + DeviceTransportType | |
35 | 34 | } from '@shared/models/device.models'; |
36 | 35 | import { Subject } from 'rxjs'; |
37 | 36 | import { takeUntil } from 'rxjs/operators'; |
... | ... | @@ -58,32 +57,40 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, |
58 | 57 | @Input() |
59 | 58 | disabled: boolean; |
60 | 59 | |
60 | + private deviceTransportTypeValue = DeviceTransportType.DEFAULT; | |
61 | + get deviceTransportType(): DeviceTransportType { | |
62 | + return this.deviceTransportTypeValue; | |
63 | + } | |
64 | + @Input() | |
65 | + set deviceTransportType(type: DeviceTransportType) { | |
66 | + if (type) { | |
67 | + this.deviceTransportTypeValue = type; | |
68 | + this.credentialsTypes = credentialTypesByTransportType.get(type); | |
69 | + const currentType = this.deviceCredentialsFormGroup.get('credentialsType').value; | |
70 | + if (!this.credentialsTypes.includes(currentType)) { | |
71 | + this.deviceCredentialsFormGroup.get('credentialsType').patchValue(this.credentialsTypes[0], {onlySelf: true}); | |
72 | + } | |
73 | + } | |
74 | + } | |
75 | + | |
61 | 76 | private destroy$ = new Subject(); |
62 | 77 | |
63 | 78 | deviceCredentialsFormGroup: FormGroup; |
64 | 79 | |
65 | 80 | deviceCredentialsType = DeviceCredentialsType; |
66 | 81 | |
67 | - credentialsTypes = Object.values(DeviceCredentialsType); | |
82 | + credentialsTypes = credentialTypesByTransportType.get(DeviceTransportType.DEFAULT); | |
68 | 83 | |
69 | 84 | credentialTypeNamesMap = credentialTypeNames; |
70 | 85 | |
71 | - hidePassword = true; | |
72 | - | |
73 | 86 | private propagateChange = (v: any) => {}; |
74 | 87 | |
75 | 88 | constructor(public fb: FormBuilder) { |
76 | 89 | this.deviceCredentialsFormGroup = this.fb.group({ |
77 | 90 | credentialsType: [DeviceCredentialsType.ACCESS_TOKEN], |
78 | 91 | credentialsId: [null], |
79 | - credentialsValue: [null], | |
80 | - credentialsBasic: this.fb.group({ | |
81 | - clientId: [null, [Validators.pattern(/^[A-Za-z0-9]+$/)]], | |
82 | - userName: [null], | |
83 | - password: [null] | |
84 | - }, {validators: this.atLeastOne(Validators.required, ['clientId', 'userName'])}) | |
92 | + credentialsValue: [null] | |
85 | 93 | }); |
86 | - this.deviceCredentialsFormGroup.get('credentialsBasic').disable(); | |
87 | 94 | this.deviceCredentialsFormGroup.valueChanges.pipe( |
88 | 95 | takeUntil(this.destroy$) |
89 | 96 | ).subscribe(() => { |
... | ... | @@ -109,18 +116,11 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, |
109 | 116 | |
110 | 117 | writeValue(value: DeviceCredentials | null): void { |
111 | 118 | if (isDefinedAndNotNull(value)) { |
112 | - let credentialsBasic = {clientId: null, userName: null, password: null}; | |
113 | - let credentialsValue = null; | |
114 | - if (value.credentialsType === DeviceCredentialsType.MQTT_BASIC) { | |
115 | - credentialsBasic = JSON.parse(value.credentialsValue) as DeviceCredentialMQTTBasic; | |
116 | - } else { | |
117 | - credentialsValue = value.credentialsValue; | |
118 | - } | |
119 | + const credentialsType = this.credentialsTypes.includes(value.credentialsType) ? value.credentialsType : this.credentialsTypes[0]; | |
119 | 120 | this.deviceCredentialsFormGroup.patchValue({ |
120 | - credentialsType: value.credentialsType, | |
121 | + credentialsType, | |
121 | 122 | credentialsId: value.credentialsId, |
122 | - credentialsValue, | |
123 | - credentialsBasic | |
123 | + credentialsValue: value.credentialsValue | |
124 | 124 | }, {emitEvent: false}); |
125 | 125 | this.updateValidators(); |
126 | 126 | } |
... | ... | @@ -128,10 +128,6 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, |
128 | 128 | |
129 | 129 | updateView() { |
130 | 130 | const deviceCredentialsValue = this.deviceCredentialsFormGroup.value; |
131 | - if (deviceCredentialsValue.credentialsType === DeviceCredentialsType.MQTT_BASIC) { | |
132 | - deviceCredentialsValue.credentialsValue = JSON.stringify(deviceCredentialsValue.credentialsBasic); | |
133 | - } | |
134 | - delete deviceCredentialsValue.credentialsBasic; | |
135 | 131 | this.propagateChange(deviceCredentialsValue); |
136 | 132 | } |
137 | 133 | |
... | ... | @@ -163,14 +159,12 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, |
163 | 159 | credentialsTypeChanged(): void { |
164 | 160 | this.deviceCredentialsFormGroup.patchValue({ |
165 | 161 | credentialsId: null, |
166 | - credentialsValue: null, | |
167 | - credentialsBasic: {clientId: '', userName: '', password: ''} | |
162 | + credentialsValue: null | |
168 | 163 | }); |
169 | 164 | this.updateValidators(); |
170 | 165 | } |
171 | 166 | |
172 | 167 | updateValidators(): void { |
173 | - this.hidePassword = true; | |
174 | 168 | const credentialsType = this.deviceCredentialsFormGroup.get('credentialsType').value as DeviceCredentialsType; |
175 | 169 | switch (credentialsType) { |
176 | 170 | case DeviceCredentialsType.ACCESS_TOKEN: |
... | ... | @@ -178,48 +172,13 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, |
178 | 172 | this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity({emitEvent: false}); |
179 | 173 | this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([]); |
180 | 174 | this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity({emitEvent: false}); |
181 | - this.deviceCredentialsFormGroup.get('credentialsBasic').disable({emitEvent: false}); | |
182 | 175 | break; |
183 | - case DeviceCredentialsType.X509_CERTIFICATE: | |
184 | - case DeviceCredentialsType.LWM2M_CREDENTIALS: | |
176 | + default: | |
185 | 177 | this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([Validators.required]); |
186 | 178 | this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity({emitEvent: false}); |
187 | 179 | this.deviceCredentialsFormGroup.get('credentialsId').setValidators([]); |
188 | 180 | this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity({emitEvent: false}); |
189 | - this.deviceCredentialsFormGroup.get('credentialsBasic').disable({emitEvent: false}); | |
190 | - break; | |
191 | - case DeviceCredentialsType.MQTT_BASIC: | |
192 | - this.deviceCredentialsFormGroup.get('credentialsBasic').enable({emitEvent: false}); | |
193 | - this.deviceCredentialsFormGroup.get('credentialsBasic').updateValueAndValidity({emitEvent: false}); | |
194 | - this.deviceCredentialsFormGroup.get('credentialsId').setValidators([]); | |
195 | - this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity({emitEvent: false}); | |
196 | - this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([]); | |
197 | - this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity({emitEvent: false}); | |
198 | 181 | break; |
199 | 182 | } |
200 | 183 | } |
201 | - | |
202 | - private atLeastOne(validator: ValidatorFn, controls: string[] = null) { | |
203 | - return (group: FormGroup): ValidationErrors | null => { | |
204 | - if (!controls) { | |
205 | - controls = Object.keys(group.controls); | |
206 | - } | |
207 | - const hasAtLeastOne = group?.controls && controls.some(k => !validator(group.controls[k])); | |
208 | - | |
209 | - return hasAtLeastOne ? null : {atLeastOne: true}; | |
210 | - }; | |
211 | - } | |
212 | - | |
213 | - passwordChanged() { | |
214 | - const value = this.deviceCredentialsFormGroup.get('credentialsBasic.password').value; | |
215 | - if (value !== '') { | |
216 | - this.deviceCredentialsFormGroup.get('credentialsBasic.userName').setValidators([Validators.required]); | |
217 | - } else { | |
218 | - this.deviceCredentialsFormGroup.get('credentialsBasic.userName').setValidators([]); | |
219 | - } | |
220 | - this.deviceCredentialsFormGroup.get('credentialsBasic.userName').updateValueAndValidity({ | |
221 | - emitEvent: false, | |
222 | - onlySelf: true | |
223 | - }); | |
224 | - } | |
225 | 184 | } | ... | ... |
1 | +/// | |
2 | +/// Copyright © 2016-2021 The Thingsboard Authors | |
3 | +/// | |
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | +/// you may not use this file except in compliance with the License. | |
6 | +/// You may obtain a copy of the License at | |
7 | +/// | |
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | |
9 | +/// | |
10 | +/// Unless required by applicable law or agreed to in writing, software | |
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | |
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | +/// See the License for the specific language governing permissions and | |
14 | +/// limitations under the License. | |
15 | +/// | |
16 | + | |
17 | +import { NgModule } from '@angular/core'; | |
18 | +import { CommonModule } from '@angular/common'; | |
19 | +import { SharedModule } from '@shared/shared.module'; | |
20 | +import { CopyDeviceCredentialsComponent } from './copy-device-credentials.component'; | |
21 | +import { DeviceCredentialsComponent } from './device-credentials.component'; | |
22 | +import { DeviceCredentialsLwm2mComponent } from './device-credentials-lwm2m.component'; | |
23 | +import { DeviceCredentialsLwm2mServerComponent } from './device-credentials-lwm2m-server.component'; | |
24 | +import { DeviceCredentialsMqttBasicComponent } from './device-credentials-mqtt-basic.component'; | |
25 | + | |
26 | +@NgModule({ | |
27 | + declarations: [ | |
28 | + CopyDeviceCredentialsComponent, | |
29 | + DeviceCredentialsComponent, | |
30 | + DeviceCredentialsLwm2mComponent, | |
31 | + DeviceCredentialsLwm2mServerComponent, | |
32 | + DeviceCredentialsMqttBasicComponent | |
33 | + ], | |
34 | + imports: [ | |
35 | + CommonModule, | |
36 | + SharedModule | |
37 | + ], | |
38 | + exports: [ | |
39 | + CopyDeviceCredentialsComponent, | |
40 | + DeviceCredentialsComponent, | |
41 | + DeviceCredentialsLwm2mComponent, | |
42 | + DeviceCredentialsLwm2mServerComponent, | |
43 | + DeviceCredentialsMqttBasicComponent | |
44 | + ] | |
45 | +}) | |
46 | +export class DeviceCredentialsModule { } | ... | ... |
... | ... | @@ -110,7 +110,6 @@ import { RuleChainAutocompleteComponent } from '@home/components/rule-chain/rule |
110 | 110 | import { DeviceProfileProvisionConfigurationComponent } from '@home/components/profile/device-profile-provision-configuration.component'; |
111 | 111 | import { AlarmScheduleComponent } from '@home/components/profile/alarm/alarm-schedule.component'; |
112 | 112 | import { DeviceWizardDialogComponent } from '@home/components/wizard/device-wizard-dialog.component'; |
113 | -import { DeviceCredentialsComponent } from '@home/components/device/device-credentials.component'; | |
114 | 113 | import { AlarmScheduleInfoComponent } from '@home/components/profile/alarm/alarm-schedule-info.component'; |
115 | 114 | import { AlarmScheduleDialogComponent } from '@home/components/profile/alarm/alarm-schedule-dialog.component'; |
116 | 115 | import { EditAlarmDetailsDialogComponent } from '@home/components/profile/alarm/edit-alarm-details-dialog.component'; |
... | ... | @@ -120,7 +119,6 @@ import { TenantProfileConfigurationComponent } from '@home/components/profile/te |
120 | 119 | import { SmsProviderConfigurationComponent } from '@home/components/sms/sms-provider-configuration.component'; |
121 | 120 | import { AwsSnsProviderConfigurationComponent } from '@home/components/sms/aws-sns-provider-configuration.component'; |
122 | 121 | import { TwilioSmsProviderConfigurationComponent } from '@home/components/sms/twilio-sms-provider-configuration.component'; |
123 | -import { CopyDeviceCredentialsComponent } from '@home/components/device/copy-device-credentials.component'; | |
124 | 122 | import { Lwm2mProfileComponentsModule } from '@home/components/profile/device/lwm2m/lwm2m-profile-components.module'; |
125 | 123 | import { DashboardPageComponent } from '@home/components/dashboard-page/dashboard-page.component'; |
126 | 124 | import { DashboardToolbarComponent } from '@home/components/dashboard-page/dashboard-toolbar.component'; |
... | ... | @@ -139,11 +137,10 @@ import { EdgeDownlinkTableComponent } from '@home/components/edge/edge-downlink- |
139 | 137 | import { EdgeDownlinkTableHeaderComponent } from '@home/components/edge/edge-downlink-table-header.component'; |
140 | 138 | import { DisplayWidgetTypesPanelComponent } from '@home/components/dashboard-page/widget-types-panel.component'; |
141 | 139 | import { AlarmDurationPredicateValueComponent } from '@home/components/profile/alarm/alarm-duration-predicate-value.component'; |
142 | -import { SecurityConfigLwm2mComponent } from '@home/components/device/security-config-lwm2m.component'; | |
143 | -import { SecurityConfigLwm2mServerComponent } from '@home/components/device/security-config-lwm2m-server.component'; | |
144 | 140 | import { DashboardImageDialogComponent } from '@home/components/dashboard-page/dashboard-image-dialog.component'; |
145 | 141 | import { WidgetContainerComponent } from '@home/components/widget/widget-container.component'; |
146 | 142 | import { SnmpDeviceProfileTransportModule } from '@home/components/profile/device/snpm/snmp-device-profile-transport.module'; |
143 | +import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module'; | |
147 | 144 | |
148 | 145 | @NgModule({ |
149 | 146 | declarations: |
... | ... | @@ -245,10 +242,6 @@ import { SnmpDeviceProfileTransportModule } from '@home/components/profile/devic |
245 | 242 | AlarmScheduleComponent, |
246 | 243 | AlarmDurationPredicateValueComponent, |
247 | 244 | DeviceWizardDialogComponent, |
248 | - DeviceCredentialsComponent, | |
249 | - CopyDeviceCredentialsComponent, | |
250 | - SecurityConfigLwm2mComponent, | |
251 | - SecurityConfigLwm2mServerComponent, | |
252 | 245 | AlarmScheduleDialogComponent, |
253 | 246 | EditAlarmDetailsDialogComponent, |
254 | 247 | SmsProviderConfigurationComponent, |
... | ... | @@ -274,7 +267,8 @@ import { SnmpDeviceProfileTransportModule } from '@home/components/profile/devic |
274 | 267 | SharedHomeComponentsModule, |
275 | 268 | Lwm2mProfileComponentsModule, |
276 | 269 | SnmpDeviceProfileTransportModule, |
277 | - StatesControllerModule | |
270 | + StatesControllerModule, | |
271 | + DeviceCredentialsModule | |
278 | 272 | ], |
279 | 273 | exports: [ |
280 | 274 | EntitiesTableComponent, |
... | ... | @@ -353,10 +347,6 @@ import { SnmpDeviceProfileTransportModule } from '@home/components/profile/devic |
353 | 347 | AddDeviceProfileDialogComponent, |
354 | 348 | RuleChainAutocompleteComponent, |
355 | 349 | DeviceWizardDialogComponent, |
356 | - DeviceCredentialsComponent, | |
357 | - CopyDeviceCredentialsComponent, | |
358 | - SecurityConfigLwm2mComponent, | |
359 | - SecurityConfigLwm2mServerComponent, | |
360 | 350 | AlarmScheduleInfoComponent, |
361 | 351 | AlarmScheduleComponent, |
362 | 352 | AlarmScheduleDialogComponent, | ... | ... |
... | ... | @@ -64,7 +64,8 @@ |
64 | 64 | [ngClass]="{invisible: deviceWizardFormGroup.get('addProfileType').value !== 0}" |
65 | 65 | [addNewProfile]="false" |
66 | 66 | [selectDefaultProfile]="true" |
67 | - [editProfileEnabled]="false"> | |
67 | + [editProfileEnabled]="false" | |
68 | + (deviceProfileChanged)="deviceProfileChanged($event)"> | |
68 | 69 | </tb-device-profile-autocomplete> |
69 | 70 | <mat-form-field fxFlex class="mat-block" |
70 | 71 | [ngClass]="{invisible: deviceWizardFormGroup.get('addProfileType').value !== 1}"> |
... | ... | @@ -154,6 +155,7 @@ |
154 | 155 | <mat-checkbox style="padding-bottom: 16px;" formControlName="setCredential">{{ 'device.wizard.add-credentials' | translate }}</mat-checkbox> |
155 | 156 | <tb-device-credentials |
156 | 157 | [fxShow]="credentialsFormGroup.get('setCredential').value" |
158 | + [deviceTransportType]="deviceTransportType" | |
157 | 159 | formControlName="credential"> |
158 | 160 | </tb-device-credentials> |
159 | 161 | </form> | ... | ... |
... | ... | @@ -25,6 +25,7 @@ import { |
25 | 25 | createDeviceProfileConfiguration, |
26 | 26 | createDeviceProfileTransportConfiguration, |
27 | 27 | DeviceProfile, |
28 | + DeviceProfileInfo, | |
28 | 29 | DeviceProfileType, |
29 | 30 | DeviceProvisionConfiguration, |
30 | 31 | DeviceProvisionType, |
... | ... | @@ -91,6 +92,7 @@ export class DeviceWizardDialogComponent extends |
91 | 92 | serviceType = ServiceType.TB_RULE_ENGINE; |
92 | 93 | |
93 | 94 | private subscriptions: Subscription[] = []; |
95 | + private currentDeviceProfileTransportType = DeviceTransportType.DEFAULT; | |
94 | 96 | |
95 | 97 | constructor(protected store: Store<AppState>, |
96 | 98 | protected router: Router, |
... | ... | @@ -265,6 +267,20 @@ export class DeviceWizardDialogComponent extends |
265 | 267 | } |
266 | 268 | } |
267 | 269 | |
270 | + get deviceTransportType(): DeviceTransportType { | |
271 | + if (this.deviceWizardFormGroup.get('addProfileType').value) { | |
272 | + return this.transportConfigFormGroup.get('transportType').value; | |
273 | + } else { | |
274 | + return this.currentDeviceProfileTransportType; | |
275 | + } | |
276 | + } | |
277 | + | |
278 | + deviceProfileChanged(deviceProfile: DeviceProfileInfo) { | |
279 | + if (deviceProfile) { | |
280 | + this.currentDeviceProfileTransportType = deviceProfile.transportType; | |
281 | + } | |
282 | + } | |
283 | + | |
268 | 284 | private createDeviceProfile(): Observable<EntityId> { |
269 | 285 | if (this.deviceWizardFormGroup.get('addProfileType').value) { |
270 | 286 | const deviceProvisionConfiguration: DeviceProvisionConfiguration = this.provisionConfigFormGroup.get('provisionConfiguration').value; | ... | ... |
... | ... | @@ -17,7 +17,7 @@ |
17 | 17 | --> |
18 | 18 | <form [formGroup]="deviceCredentialsFormGroup" (ngSubmit)="save()" style="min-width: 350px;"> |
19 | 19 | <mat-toolbar color="primary"> |
20 | - <h2 translate>device.device-credentials</h2> | |
20 | + <h2>{{ 'device.device-credentials' | translate }}</h2> | |
21 | 21 | <span fxFlex></span> |
22 | 22 | <button mat-icon-button |
23 | 23 | (click)="cancel()" |
... | ... | @@ -25,15 +25,26 @@ |
25 | 25 | <mat-icon class="material-icons">close</mat-icon> |
26 | 26 | </button> |
27 | 27 | </mat-toolbar> |
28 | - <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> | |
28 | + <mat-progress-bar color="warn" mode="indeterminate" *ngIf="(isLoading$ | async) && !loadingCredentials"> | |
29 | 29 | </mat-progress-bar> |
30 | - <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div> | |
30 | + <div style="height: 4px;" *ngIf="!(isLoading$ | async) || loadingCredentials"></div> | |
31 | 31 | <div mat-dialog-content> |
32 | - <fieldset [disabled]="(isLoading$ | async) || isReadOnly"> | |
33 | - <tb-device-credentials | |
34 | - formControlName="credential"> | |
35 | - </tb-device-credentials> | |
36 | - </fieldset> | |
32 | + <section *ngIf="!loadingCredentials; else loadCredentials"> | |
33 | + <fieldset [disabled]="(isLoading$ | async) || isReadOnly"> | |
34 | + <tb-device-credentials | |
35 | + [deviceTransportType]="deviceTransportType" | |
36 | + formControlName="credential"> | |
37 | + </tb-device-credentials> | |
38 | + </fieldset> | |
39 | + </section> | |
40 | + <ng-template #loadCredentials> | |
41 | + <div fxLayout="column" fxLayoutAlign="center center"> | |
42 | + <mat-spinner color="accent" diameter="65" strokeWidth="4" style="margin-bottom: 18px"></mat-spinner> | |
43 | + <span class="mat-subheading-2" style="margin-bottom: 0"> | |
44 | + {{ 'device.loading-device-credentials' | translate }} | |
45 | + </span> | |
46 | + </div> | |
47 | + </ng-template> | |
37 | 48 | </div> |
38 | 49 | <div mat-dialog-actions fxLayoutAlign="end center"> |
39 | 50 | <button mat-button color="primary" | ... | ... |
... | ... | @@ -21,13 +21,16 @@ import { Store } from '@ngrx/store'; |
21 | 21 | import { AppState } from '@core/core.state'; |
22 | 22 | import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm } from '@angular/forms'; |
23 | 23 | import { DeviceService } from '@core/http/device.service'; |
24 | -import { credentialTypeNames, DeviceCredentials, DeviceCredentialsType } from '@shared/models/device.models'; | |
24 | +import { DeviceCredentials, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; | |
25 | 25 | import { DialogComponent } from '@shared/components/dialog.component'; |
26 | 26 | import { Router } from '@angular/router'; |
27 | +import { DeviceProfileService } from '@core/http/device-profile.service'; | |
28 | +import { forkJoin } from 'rxjs'; | |
27 | 29 | |
28 | 30 | export interface DeviceCredentialsDialogData { |
29 | 31 | isReadOnly: boolean; |
30 | 32 | deviceId: string; |
33 | + deviceProfileId: string; | |
31 | 34 | } |
32 | 35 | |
33 | 36 | @Component({ |
... | ... | @@ -40,25 +43,18 @@ export class DeviceCredentialsDialogComponent extends |
40 | 43 | DialogComponent<DeviceCredentialsDialogComponent, DeviceCredentials> implements OnInit, ErrorStateMatcher { |
41 | 44 | |
42 | 45 | deviceCredentialsFormGroup: FormGroup; |
43 | - | |
46 | + deviceTransportType: DeviceTransportType; | |
44 | 47 | isReadOnly: boolean; |
48 | + loadingCredentials = true; | |
45 | 49 | |
46 | - deviceCredentials: DeviceCredentials; | |
47 | - | |
48 | - submitted = false; | |
49 | - | |
50 | - deviceCredentialsType = DeviceCredentialsType; | |
51 | - | |
52 | - credentialsTypes = Object.keys(DeviceCredentialsType); | |
53 | - | |
54 | - credentialTypeNamesMap = credentialTypeNames; | |
55 | - | |
56 | - hidePassword = true; | |
50 | + private deviceCredentials: DeviceCredentials; | |
51 | + private submitted = false; | |
57 | 52 | |
58 | 53 | constructor(protected store: Store<AppState>, |
59 | 54 | protected router: Router, |
60 | 55 | @Inject(MAT_DIALOG_DATA) public data: DeviceCredentialsDialogData, |
61 | 56 | private deviceService: DeviceService, |
57 | + private deviceProfileService: DeviceProfileService, | |
62 | 58 | @SkipSelf() private errorStateMatcher: ErrorStateMatcher, |
63 | 59 | public dialogRef: MatDialogRef<DeviceCredentialsDialogComponent, DeviceCredentials>, |
64 | 60 | public fb: FormBuilder) { |
... | ... | @@ -84,14 +80,17 @@ export class DeviceCredentialsDialogComponent extends |
84 | 80 | } |
85 | 81 | |
86 | 82 | loadDeviceCredentials() { |
87 | - this.deviceService.getDeviceCredentials(this.data.deviceId).subscribe( | |
88 | - (deviceCredentials) => { | |
89 | - this.deviceCredentials = deviceCredentials; | |
90 | - this.deviceCredentialsFormGroup.patchValue({ | |
91 | - credential: deviceCredentials | |
92 | - }, {emitEvent: false}); | |
93 | - } | |
94 | - ); | |
83 | + const task = []; | |
84 | + task.push(this.deviceService.getDeviceCredentials(this.data.deviceId)); | |
85 | + task.push(this.deviceProfileService.getDeviceProfileInfo(this.data.deviceProfileId)); | |
86 | + forkJoin(task).subscribe(([deviceCredentials, deviceProfile]: [DeviceCredentials, DeviceProfileInfo]) => { | |
87 | + this.deviceTransportType = deviceProfile.transportType; | |
88 | + this.deviceCredentials = deviceCredentials; | |
89 | + this.deviceCredentialsFormGroup.patchValue({ | |
90 | + credential: deviceCredentials | |
91 | + }, {emitEvent: false}); | |
92 | + this.loadingCredentials = false; | |
93 | + }); | |
95 | 94 | } |
96 | 95 | |
97 | 96 | cancel(): void { | ... | ... |
... | ... | @@ -33,6 +33,7 @@ import { MqttDeviceTransportConfigurationComponent } from './data/mqtt-device-tr |
33 | 33 | import { CoapDeviceTransportConfigurationComponent } from './data/coap-device-transport-configuration.component'; |
34 | 34 | import { Lwm2mDeviceTransportConfigurationComponent } from './data/lwm2m-device-transport-configuration.component'; |
35 | 35 | import { SnmpDeviceTransportConfigurationComponent } from './data/snmp-device-transport-configuration.component'; |
36 | +import { DeviceCredentialsModule } from '@home/components/device/device-credentials.module'; | |
36 | 37 | |
37 | 38 | @NgModule({ |
38 | 39 | declarations: [ |
... | ... | @@ -55,6 +56,7 @@ import { SnmpDeviceTransportConfigurationComponent } from './data/snmp-device-tr |
55 | 56 | SharedModule, |
56 | 57 | HomeComponentsModule, |
57 | 58 | HomeDialogsModule, |
59 | + DeviceCredentialsModule, | |
58 | 60 | DeviceRoutingModule |
59 | 61 | ] |
60 | 62 | }) | ... | ... |
... | ... | @@ -112,7 +112,8 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev |
112 | 112 | )); |
113 | 113 | }; |
114 | 114 | this.config.onEntityAction = action => this.onDeviceAction(action); |
115 | - this.config.detailsReadonly = () => (this.config.componentsData.deviceScope === 'customer_user' || this.config.componentsData.deviceScope === 'edge_customer_user'); | |
115 | + this.config.detailsReadonly = () => | |
116 | + (this.config.componentsData.deviceScope === 'customer_user' || this.config.componentsData.deviceScope === 'edge_customer_user'); | |
116 | 117 | |
117 | 118 | this.config.headerComponent = DeviceTableHeaderComponent; |
118 | 119 | |
... | ... | @@ -528,6 +529,7 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev |
528 | 529 | panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], |
529 | 530 | data: { |
530 | 531 | deviceId: device.id.id, |
532 | + deviceProfileId: device.deviceProfileId.id, | |
531 | 533 | isReadOnly: this.config.componentsData.deviceScope === 'customer_user' || this.config.componentsData.deviceScope === 'edge_customer_user' |
532 | 534 | } |
533 | 535 | }).afterClosed().subscribe(deviceCredentials => { | ... | ... |
... | ... | @@ -682,6 +682,20 @@ export const credentialTypeNames = new Map<DeviceCredentialsType, string>( |
682 | 682 | ] |
683 | 683 | ); |
684 | 684 | |
685 | +export const credentialTypesByTransportType = new Map<DeviceTransportType, DeviceCredentialsType[]>( | |
686 | + [ | |
687 | + [DeviceTransportType.DEFAULT, [ | |
688 | + DeviceCredentialsType.ACCESS_TOKEN, DeviceCredentialsType.X509_CERTIFICATE, DeviceCredentialsType.MQTT_BASIC | |
689 | + ]], | |
690 | + [DeviceTransportType.MQTT, [ | |
691 | + DeviceCredentialsType.ACCESS_TOKEN, DeviceCredentialsType.X509_CERTIFICATE, DeviceCredentialsType.MQTT_BASIC | |
692 | + ]], | |
693 | + [DeviceTransportType.COAP, [DeviceCredentialsType.ACCESS_TOKEN, DeviceCredentialsType.X509_CERTIFICATE]], | |
694 | + [DeviceTransportType.LWM2M, [DeviceCredentialsType.LWM2M_CREDENTIALS]], | |
695 | + [DeviceTransportType.SNMP, [DeviceCredentialsType.ACCESS_TOKEN]] | |
696 | + ] | |
697 | +); | |
698 | + | |
685 | 699 | export interface DeviceCredentials extends BaseData<DeviceCredentialsId> { |
686 | 700 | deviceId: DeviceId; |
687 | 701 | credentialsType: DeviceCredentialsType; | ... | ... |
... | ... | @@ -941,13 +941,13 @@ |
941 | 941 | "unassign-devices-title": "Are you sure you want to unassign { count, plural, 1 {1 device} other {# devices} }?", |
942 | 942 | "unassign-devices-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the customer.", |
943 | 943 | "device-credentials": "Device Credentials", |
944 | + "loading-device-credentials": "Loading device credentials...", | |
944 | 945 | "credentials-type": "Credentials type", |
945 | 946 | "access-token": "Access token", |
946 | 947 | "access-token-required": "Access token is required.", |
947 | 948 | "access-token-invalid": "Access token length must be from 1 to 20 characters.", |
948 | 949 | "rsa-key": "RSA public key", |
949 | 950 | "rsa-key-required": "RSA public key is required.", |
950 | - "lwm2m-value": "LwM2M Security config", | |
951 | 951 | "lwm2m-security-config": { |
952 | 952 | "identity": "Client Identity", |
953 | 953 | "identity-required": "Client Identity is required.", |
... | ... | @@ -971,7 +971,6 @@ |
971 | 971 | "client-secret-key-required": "Client Secret Key is required.", |
972 | 972 | "client-secret-key-pattern": "Client Secret Key must be hexadecimal format.", |
973 | 973 | "client-secret-key-length": "Client Secret Key must be {{ count }} characters.", |
974 | - "config-json-tab": "Json Client Security Config", | |
975 | 974 | "client-public-key": "Client public key", |
976 | 975 | "client-public-key-hint": "If client public key is empty, the trusted certificate will be used" |
977 | 976 | }, | ... | ... |