From e8d8382c74c7d76f7050618eae1f36cbff329bc6 Mon Sep 17 00:00:00 2001 From: Vladyslav Prykhodko Date: Sun, 4 Oct 2020 00:05:52 +0300 Subject: [PATCH] UI: Added device provision to device profile --- .../home/components/home-components.module.ts | 7 +- .../add-device-profile-dialog.component.html | 10 +- .../add-device-profile-dialog.component.ts | 20 ++- .../device-profile-data.component.html | 10 ++ .../profile/device-profile-data.component.ts | 4 +- ...ile-provision-configuration.component.html | 46 ++++++ ...ofile-provision-configuration.component.ts | 140 ++++++++++++++++++ .../profile/device-profile.component.ts | 10 +- ui-ngx/src/app/shared/models/device.models.ts | 24 +++ .../assets/locale/locale.constant-en_US.json | 12 +- 10 files changed, 275 insertions(+), 8 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html create mode 100644 ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index d583369016..5209dd3602 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -107,6 +107,7 @@ import { AlarmRuleKeyFiltersDialogComponent } from './profile/alarm/alarm-rule-k import { FilterTextComponent } from './filter/filter-text.component'; import { AddDeviceProfileDialogComponent } from './profile/add-device-profile-dialog.component'; import { RuleChainAutocompleteComponent } from './rule-chain/rule-chain-autocomplete.component'; +import { DeviceProfileProvisionConfigurationComponent } from "./profile/device-profile-provision-configuration.component"; @NgModule({ declarations: @@ -196,7 +197,8 @@ import { RuleChainAutocompleteComponent } from './rule-chain/rule-chain-autocomp DeviceProfileComponent, DeviceProfileDialogComponent, AddDeviceProfileDialogComponent, - RuleChainAutocompleteComponent + RuleChainAutocompleteComponent, + DeviceProfileProvisionConfigurationComponent ], imports: [ CommonModule, @@ -275,7 +277,8 @@ import { RuleChainAutocompleteComponent } from './rule-chain/rule-chain-autocomp DeviceProfileComponent, DeviceProfileDialogComponent, AddDeviceProfileDialogComponent, - RuleChainAutocompleteComponent + RuleChainAutocompleteComponent, + DeviceProfileProvisionConfigurationComponent ], providers: [ WidgetComponentService, diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html index d7f119a3b7..bda26153d1 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html @@ -93,6 +93,14 @@ + +
+ {{'device-profile.device-provisioning' | translate }} + + +
+
@@ -107,7 +115,7 @@ + (click)="nextStep()">{{ (selectedIndex === 3 ? 'action.add' : 'action.continue') | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts index 476c69488f..42edc3c613 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts @@ -77,6 +77,8 @@ export class AddDeviceProfileDialogComponent extends alarmRulesFormGroup: FormGroup; + provisionConfigurationFormGroup: FormGroup; + constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: AddDeviceProfileDialogData, @@ -111,6 +113,12 @@ export class AddDeviceProfileDialogComponent extends alarms: [null] } ); + + this.provisionConfigurationFormGroup = this.fb.group( + { + provisionConfiguration: [null] + } + ) } private deviceProfileTransportTypeChanged() { @@ -131,7 +139,7 @@ export class AddDeviceProfileDialogComponent extends } nextStep() { - if (this.selectedIndex < 2) { + if (this.selectedIndex < 3) { this.addDeviceProfileStepper.next(); } else { this.add(); @@ -146,6 +154,8 @@ export class AddDeviceProfileDialogComponent extends return this.transportConfigFormGroup; case 2: return this.alarmRulesFormGroup; + case 3: + return this.provisionConfigurationFormGroup; } } @@ -154,11 +164,17 @@ export class AddDeviceProfileDialogComponent extends name: this.deviceProfileDetailsFormGroup.get('name').value, type: this.deviceProfileDetailsFormGroup.get('type').value, transportType: this.transportConfigFormGroup.get('transportType').value, + provisionType: this.provisionConfigurationFormGroup.get('provisionConfiguration').value.type, + provisionDeviceKey: this.provisionConfigurationFormGroup.get('provisionConfiguration').value.provisionDeviceKey, description: this.deviceProfileDetailsFormGroup.get('description').value, profileData: { configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT), transportConfiguration: this.transportConfigFormGroup.get('transportConfiguration').value, - alarms: this.alarmRulesFormGroup.get('alarms').value + alarms: this.alarmRulesFormGroup.get('alarms').value, + provisionConfiguration: { + type: this.provisionConfigurationFormGroup.get('provisionConfiguration').value.type, + provisionDeviceSecret: this.provisionConfigurationFormGroup.get('provisionConfiguration').value.provisionDeviceSecret + } } }; if (this.deviceProfileDetailsFormGroup.get('defaultRuleChainId').value) { diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html index daae838285..eb4aef68eb 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html @@ -51,5 +51,15 @@ formControlName="alarms"> + + + +
device-profile.device-provisioning
+
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.ts index 7d7fc55057..5b7fd9b998 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.ts @@ -72,7 +72,8 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit this.deviceProfileDataFormGroup = this.fb.group({ configuration: [null, Validators.required], transportConfiguration: [null, Validators.required], - alarms: [null] + alarms: [null], + provisionConfiguration: [null] }); this.deviceProfileDataFormGroup.valueChanges.subscribe(() => { this.updateModel(); @@ -98,6 +99,7 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit this.deviceProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false}); this.deviceProfileDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false}); this.deviceProfileDataFormGroup.patchValue({alarms: value?.alarms}, {emitEvent: false}); + this.deviceProfileDataFormGroup.patchValue({provisionConfiguration: value?.provisionConfiguration}, {emitEvent: false}); } private updateModel() { diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html new file mode 100644 index 0000000000..46d15905d1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html @@ -0,0 +1,46 @@ + +
+ + device-profile.provision-strategy + + + {{deviceProvisionTypeTranslateMap.get(type) | translate}} + + + + {{ 'device-profile.provision-strategy-required' | translate }} + + +
+ + device-profile.provision-device-secret + + + {{ 'device-profile.provision-device-secret-required' | translate }} + + + + device-profile.provision-device-key + + + {{ 'device-profile.provision-device-key-required' | translate }} + + +
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts new file mode 100644 index 0000000000..f37d8bb2c6 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts @@ -0,0 +1,140 @@ +/// +/// Copyright © 2016-2020 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input, OnInit } from "@angular/core"; +import { + ControlValueAccessor, + FormBuilder, + FormControl, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, + Validators +} from "@angular/forms"; +import { coerceBooleanProperty } from "@angular/cdk/coercion"; +import { + DeviceProvisionConfiguration, + DeviceProvisionType, + deviceProvisionTypeTranslationMap +} from "@shared/models/device.models"; +import { isDefinedAndNotNull } from "@core/utils"; + +@Component({ + selector: 'tb-device-profile-provision-configuration', + templateUrl: './device-profile-provision-configuration.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DeviceProfileProvisionConfigurationComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => DeviceProfileProvisionConfigurationComponent), + multi: true, + } + ] +}) +export class DeviceProfileProvisionConfigurationComponent implements ControlValueAccessor, OnInit, Validator { + + provisionConfigurationFormGroup: FormGroup; + + deviceProvisionType = DeviceProvisionType; + deviceProvisionTypes = Object.keys(DeviceProvisionType); + deviceProvisionTypeTranslateMap = deviceProvisionTypeTranslationMap; + + private requiredValue: boolean; + get required(): boolean { + return this.requiredValue; + } + @Input() + set required(value: boolean) { + this.requiredValue = coerceBooleanProperty(value); + } + + @Input() + disabled: boolean; + + private propagateChange = (v: any) => { }; + + constructor(private fb: FormBuilder) { + } + + ngOnInit(): void { + this.provisionConfigurationFormGroup = this.fb.group({ + type: [DeviceProvisionType.DISABLED, Validators.required], + provisionDeviceSecret: [{value: null, disabled: true}, Validators.required], + provisionDeviceKey: [{value: null, disabled: true}, Validators.required] + }); + this.provisionConfigurationFormGroup.get('type').valueChanges.subscribe((type) => { + if(type === DeviceProvisionType.DISABLED) { + this.provisionConfigurationFormGroup.get('provisionDeviceSecret').disable({emitEvent: false}); + this.provisionConfigurationFormGroup.get('provisionDeviceSecret').patchValue(null,{emitEvent: false}); + this.provisionConfigurationFormGroup.get('provisionDeviceKey').disable({emitEvent: false}); + this.provisionConfigurationFormGroup.get('provisionDeviceKey').patchValue(null); + } else { + this.provisionConfigurationFormGroup.get('provisionDeviceSecret').enable({emitEvent: false}); + this.provisionConfigurationFormGroup.get('provisionDeviceKey').enable({emitEvent: false}); + } + }); + this.provisionConfigurationFormGroup.valueChanges.subscribe(() => { + this.updateModel(); + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + writeValue(value: DeviceProvisionConfiguration | null): void { + if(isDefinedAndNotNull(value)){ + this.provisionConfigurationFormGroup.patchValue(value, {emitEvent: false}); + } else { + this.provisionConfigurationFormGroup.patchValue({type: DeviceProvisionType.DISABLED}); + } + } + + setDisabledState(isDisabled: boolean){ + this.disabled = isDisabled; + if(this.disabled){ + this.provisionConfigurationFormGroup.disable(); + } else { + this.provisionConfigurationFormGroup.enable({emitEvent: false}); + } + } + + validate(c: FormControl): ValidationErrors | null { + return (this.provisionConfigurationFormGroup.valid) ? null : { + provisionConfiguration: { + valid: false, + }, + }; + } + + private updateModel(): void { + let deviceProvisionConfiguration: DeviceProvisionConfiguration = null; + if (this.provisionConfigurationFormGroup.valid) { + deviceProvisionConfiguration = this.provisionConfigurationFormGroup.getRawValue(); + } + this.propagateChange(deviceProvisionConfiguration); + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts index e3c441c8a2..9c5fc9b5a5 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts @@ -126,6 +126,10 @@ export class DeviceProfileComponent extends EntityComponent { } updateForm(entity: DeviceProfile) { + if(entity?.profileData?.provisionConfiguration) { + entity.profileData.provisionConfiguration.provisionDeviceKey = entity?.provisionDeviceKey; + } + this.entityForm.patchValue({name: entity.name}); this.entityForm.patchValue({type: entity.type}, {emitEvent: false}); this.entityForm.patchValue({transportType: entity.transportType}, {emitEvent: false}); @@ -138,7 +142,11 @@ export class DeviceProfileComponent extends EntityComponent { if (formValue.defaultRuleChainId) { formValue.defaultRuleChainId = new RuleChainId(formValue.defaultRuleChainId); } - return formValue; + formValue.provisionType = formValue.profileData.provisionConfiguration.type; + formValue.provisionDeviceKey = formValue.profileData.provisionConfiguration.provisionDeviceKey; + delete formValue.profileData.provisionConfiguration.provisionDeviceKey; + + return super.prepareFormValue(formValue); } onDeviceProfileIdCopied(event) { diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index fe92268b80..a0d91c908e 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -36,6 +36,12 @@ export enum DeviceTransportType { LWM2M = 'LWM2M' } +export enum DeviceProvisionType { + DISABLED = 'DISABLED', + ALLOW_CREATE_NEW_DEVICES = 'ALLOW_CREATE_NEW_DEVICES', + CHECK_PRE_PROVISIONED_DEVICES = 'CHECK_PRE_PROVISIONED_DEVICES' +} + export interface DeviceConfigurationFormInfo { hasProfileConfiguration: boolean; hasDeviceConfiguration: boolean; @@ -67,6 +73,15 @@ export const deviceTransportTypeTranslationMap = new Map( + [ + [DeviceProvisionType.DISABLED, 'device-profile.provision-strategy-disabled'], + [DeviceProvisionType.ALLOW_CREATE_NEW_DEVICES, 'device-profile.provision-strategy-created-new'], + [DeviceProvisionType.CHECK_PRE_PROVISIONED_DEVICES, 'device-profile.provision-strategy-check-pre-provisioned'] + ] +) + export const deviceTransportTypeConfigurationInfoMap = new Map( [ [ @@ -125,6 +140,12 @@ export interface DeviceProfileTransportConfiguration extends DeviceProfileTransp type: DeviceTransportType; } +export interface DeviceProvisionConfiguration { + type: DeviceProvisionType; + provisionDeviceSecret?: string; + provisionDeviceKey?: string; +} + export function createDeviceProfileConfiguration(type: DeviceProfileType): DeviceProfileConfiguration { let configuration: DeviceProfileConfiguration = null; if (type) { @@ -220,6 +241,7 @@ export interface DeviceProfileData { configuration: DeviceProfileConfiguration; transportConfiguration: DeviceProfileTransportConfiguration; alarms?: Array; + provisionConfiguration?: DeviceProvisionConfiguration; } export interface DeviceProfile extends BaseData { @@ -229,6 +251,8 @@ export interface DeviceProfile extends BaseData { default?: boolean; type: DeviceProfileType; transportType: DeviceTransportType; + provisionType: DeviceProvisionType; + provisionDeviceKey?: string; defaultRuleChainId?: RuleChainId; profileData: DeviceProfileData; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index c98a2d5c17..23d2fba8df 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -840,7 +840,17 @@ "alarm-details": "Alarm details", "alarm-rule-condition": "Alarm rule condition", "enter-alarm-rule-condition-prompt": "Please add alarm rule condition", - "edit-alarm-rule-condition": "Edit alarm rule condition" + "edit-alarm-rule-condition": "Edit alarm rule condition", + "device-provisioning": "Device provisioning", + "provision-strategy": "Provision strategy", + "provision-strategy-required": "Provision strategy is required.", + "provision-strategy-disabled": "Disabled", + "provision-strategy-created-new": "Allow create new devices", + "provision-strategy-check-pre-provisioned": "Check pre provisioned devices", + "provision-device-key": "Provision device key", + "provision-device-key-required": "Provision device key is required.", + "provision-device-secret": "Provision device secret", + "provision-device-secret-required": "Provision device secret is required." }, "dialog": { "close": "Close dialog"