Browse Source

UI: Added device provision to device profile

pull/3518/head
Vladyslav Prykhodko 6 years ago
parent
commit
e8d8382c74
  1. 7
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  2. 10
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html
  3. 20
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts
  4. 10
      ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html
  5. 4
      ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.ts
  6. 46
      ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html
  7. 140
      ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.ts
  8. 10
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts
  9. 24
      ui-ngx/src/app/shared/models/device.models.ts
  10. 12
      ui-ngx/src/assets/locale/locale.constant-en_US.json

7
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,

10
ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html

@ -93,6 +93,14 @@
</tb-device-profile-alarms>
</form>
</mat-step>
<mat-step [stepControl]="provisionConfigurationFormGroup">
<form [formGroup]="provisionConfigurationFormGroup" style="padding-bottom: 16px;">
<ng-template matStepLabel>{{'device-profile.device-provisioning' | translate }}</ng-template>
<tb-device-profile-provision-configuration
formControlName="provisionConfiguration">
</tb-device-profile-provision-configuration>
</form>
</mat-step>
</mat-horizontal-stepper>
</div>
<div mat-dialog-actions fxLayout="row wrap" fxLayoutAlign="space-between center">
@ -107,7 +115,7 @@
<button mat-raised-button
[disabled]="(isLoading$ | async) || selectedForm().invalid"
color="primary"
(click)="nextStep()">{{ (selectedIndex === 2 ? 'action.add' : 'action.continue') | translate }}</button>
(click)="nextStep()">{{ (selectedIndex === 3 ? 'action.add' : 'action.continue') | translate }}</button>
</div>
</div>
</div>

20
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<AppState>,
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) {

10
ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html

@ -51,5 +51,15 @@
formControlName="alarms">
</tb-device-profile-alarms>
</mat-expansion-panel>
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
<div translate>device-profile.device-provisioning</div>
</mat-panel-title>
</mat-expansion-panel-header>
<tb-device-profile-provision-configuration
formControlName="provisionConfiguration">
</tb-device-profile-provision-configuration>
</mat-expansion-panel>
</mat-accordion>
</div>

4
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() {

46
ui-ngx/src/app/modules/home/components/profile/device-profile-provision-configuration.component.html

@ -0,0 +1,46 @@
<!--
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.
-->
<div [formGroup]="provisionConfigurationFormGroup">
<mat-form-field class="mat-block">
<mat-label translate>device-profile.provision-strategy</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let type of deviceProvisionTypes" [value]="type">
{{deviceProvisionTypeTranslateMap.get(type) | translate}}
</mat-option>
</mat-select>
<mat-error *ngIf="provisionConfigurationFormGroup.get('type').hasError('required')">
{{ 'device-profile.provision-strategy-required' | translate }}
</mat-error>
</mat-form-field>
<section *ngIf="provisionConfigurationFormGroup.get('type').value !== deviceProvisionType.DISABLED" fxLayoutGap.gt-xs="8px" fxLayout="row" fxLayout.xs="column">
<mat-form-field fxFlex class="mat-block">
<mat-label translate>device-profile.provision-device-secret</mat-label>
<input matInput formControlName="provisionDeviceSecret" required/>
<mat-error *ngIf="provisionConfigurationFormGroup.get('provisionDeviceSecret').hasError('required')">
{{ 'device-profile.provision-device-secret-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>device-profile.provision-device-key</mat-label>
<input matInput formControlName="provisionDeviceKey" required/>
<mat-error *ngIf="provisionConfigurationFormGroup.get('provisionDeviceKey').hasError('required')">
{{ 'device-profile.provision-device-key-required' | translate }}
</mat-error>
</mat-form-field>
</section>
</div>

140
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);
}
}

10
ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts

@ -126,6 +126,10 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
}
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<DeviceProfile> {
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) {

24
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<DeviceTransportType, st
]
);
export const deviceProvisionTypeTranslationMap = new Map<DeviceProvisionType, string>(
[
[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<DeviceTransportType, DeviceConfigurationFormInfo>(
[
[
@ -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<DeviceProfileAlarm>;
provisionConfiguration?: DeviceProvisionConfiguration;
}
export interface DeviceProfile extends BaseData<DeviceProfileId> {
@ -229,6 +251,8 @@ export interface DeviceProfile extends BaseData<DeviceProfileId> {
default?: boolean;
type: DeviceProfileType;
transportType: DeviceTransportType;
provisionType: DeviceProvisionType;
provisionDeviceKey?: string;
defaultRuleChainId?: RuleChainId;
profileData: DeviceProfileData;
}

12
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"

Loading…
Cancel
Save