Commit 3adbb481a17e23d10cd9688f96226d16f95598f1
1 parent
0759c135
UI: Device profile transport configuration
Showing
14 changed files
with
402 additions
and
12 deletions
@@ -181,8 +181,10 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -181,8 +181,10 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
181 | switch (deviceProfile.getTransportType()){ | 181 | switch (deviceProfile.getTransportType()){ |
182 | case DEFAULT: | 182 | case DEFAULT: |
183 | deviceData.setTransportConfiguration(new DefaultDeviceTransportConfiguration()); | 183 | deviceData.setTransportConfiguration(new DefaultDeviceTransportConfiguration()); |
184 | + break; | ||
184 | case MQTT: | 185 | case MQTT: |
185 | deviceData.setTransportConfiguration(new MqttDeviceTransportConfiguration()); | 186 | deviceData.setTransportConfiguration(new MqttDeviceTransportConfiguration()); |
187 | + break; | ||
186 | case LWM2M: | 188 | case LWM2M: |
187 | deviceData.setTransportConfiguration(new Lwm2mDeviceTransportConfiguration()); | 189 | deviceData.setTransportConfiguration(new Lwm2mDeviceTransportConfiguration()); |
188 | break; | 190 | break; |
@@ -92,6 +92,8 @@ import { DefaultDeviceProfileConfigurationComponent } from './profile/device/def | @@ -92,6 +92,8 @@ import { DefaultDeviceProfileConfigurationComponent } from './profile/device/def | ||
92 | import { DeviceProfileConfigurationComponent } from './profile/device/device-profile-configuration.component'; | 92 | import { DeviceProfileConfigurationComponent } from './profile/device/device-profile-configuration.component'; |
93 | import { DeviceProfileDataComponent } from './profile/device-profile-data.component'; | 93 | import { DeviceProfileDataComponent } from './profile/device-profile-data.component'; |
94 | import { DeviceProfileComponent } from './profile/device-profile.component'; | 94 | import { DeviceProfileComponent } from './profile/device-profile.component'; |
95 | +import { DefaultDeviceProfileTransportConfigurationComponent } from './profile/device/default-device-profile-transport-configuration.component'; | ||
96 | +import { DeviceProfileTransportConfigurationComponent } from './profile/device/device-profile-transport-configuration.component'; | ||
95 | 97 | ||
96 | @NgModule({ | 98 | @NgModule({ |
97 | declarations: | 99 | declarations: |
@@ -165,6 +167,8 @@ import { DeviceProfileComponent } from './profile/device-profile.component'; | @@ -165,6 +167,8 @@ import { DeviceProfileComponent } from './profile/device-profile.component'; | ||
165 | TenantProfileDialogComponent, | 167 | TenantProfileDialogComponent, |
166 | DefaultDeviceProfileConfigurationComponent, | 168 | DefaultDeviceProfileConfigurationComponent, |
167 | DeviceProfileConfigurationComponent, | 169 | DeviceProfileConfigurationComponent, |
170 | + DefaultDeviceProfileTransportConfigurationComponent, | ||
171 | + DeviceProfileTransportConfigurationComponent, | ||
168 | DeviceProfileDataComponent, | 172 | DeviceProfileDataComponent, |
169 | DeviceProfileComponent | 173 | DeviceProfileComponent |
170 | ], | 174 | ], |
@@ -229,6 +233,8 @@ import { DeviceProfileComponent } from './profile/device-profile.component'; | @@ -229,6 +233,8 @@ import { DeviceProfileComponent } from './profile/device-profile.component'; | ||
229 | TenantProfileDialogComponent, | 233 | TenantProfileDialogComponent, |
230 | DefaultDeviceProfileConfigurationComponent, | 234 | DefaultDeviceProfileConfigurationComponent, |
231 | DeviceProfileConfigurationComponent, | 235 | DeviceProfileConfigurationComponent, |
236 | + DefaultDeviceProfileTransportConfigurationComponent, | ||
237 | + DeviceProfileTransportConfigurationComponent, | ||
232 | DeviceProfileDataComponent, | 238 | DeviceProfileDataComponent, |
233 | DeviceProfileComponent | 239 | DeviceProfileComponent |
234 | ], | 240 | ], |
@@ -34,7 +34,10 @@ | @@ -34,7 +34,10 @@ | ||
34 | <div translate>device-profile.transport-configuration</div> | 34 | <div translate>device-profile.transport-configuration</div> |
35 | </mat-panel-title> | 35 | </mat-panel-title> |
36 | </mat-expansion-panel-header> | 36 | </mat-expansion-panel-header> |
37 | - TODO | 37 | + <tb-device-profile-transport-configuration |
38 | + formControlName="transportConfiguration" | ||
39 | + required> | ||
40 | + </tb-device-profile-transport-configuration> | ||
38 | </mat-expansion-panel> | 41 | </mat-expansion-panel> |
39 | </mat-accordion> | 42 | </mat-accordion> |
40 | </div> | 43 | </div> |
@@ -62,7 +62,8 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit | @@ -62,7 +62,8 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit | ||
62 | 62 | ||
63 | ngOnInit() { | 63 | ngOnInit() { |
64 | this.deviceProfileDataFormGroup = this.fb.group({ | 64 | this.deviceProfileDataFormGroup = this.fb.group({ |
65 | - configuration: [null, Validators.required] | 65 | + configuration: [null, Validators.required], |
66 | + transportConfiguration: [null, Validators.required] | ||
66 | }); | 67 | }); |
67 | this.deviceProfileDataFormGroup.valueChanges.subscribe(() => { | 68 | this.deviceProfileDataFormGroup.valueChanges.subscribe(() => { |
68 | this.updateModel(); | 69 | this.updateModel(); |
@@ -80,6 +81,7 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit | @@ -80,6 +81,7 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit | ||
80 | 81 | ||
81 | writeValue(value: DeviceProfileData | null): void { | 82 | writeValue(value: DeviceProfileData | null): void { |
82 | this.deviceProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false}); | 83 | this.deviceProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false}); |
84 | + this.deviceProfileDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false}); | ||
83 | } | 85 | } |
84 | 86 | ||
85 | private updateModel() { | 87 | private updateModel() { |
@@ -65,6 +65,17 @@ | @@ -65,6 +65,17 @@ | ||
65 | {{ 'device-profile.type-required' | translate }} | 65 | {{ 'device-profile.type-required' | translate }} |
66 | </mat-error> | 66 | </mat-error> |
67 | </mat-form-field> | 67 | </mat-form-field> |
68 | + <mat-form-field class="mat-block"> | ||
69 | + <mat-label translate>device-profile.transport-type</mat-label> | ||
70 | + <mat-select formControlName="transportType" required> | ||
71 | + <mat-option *ngFor="let type of deviceTransportTypes" [value]="type"> | ||
72 | + {{deviceTransportTypeTranslations.get(type) | translate}} | ||
73 | + </mat-option> | ||
74 | + </mat-select> | ||
75 | + <mat-error *ngIf="entityForm.get('transportType').hasError('required')"> | ||
76 | + {{ 'device-profile.transport-type-required' | translate }} | ||
77 | + </mat-error> | ||
78 | + </mat-form-field> | ||
68 | <tb-device-profile-data | 79 | <tb-device-profile-data |
69 | formControlName="profileData" | 80 | formControlName="profileData" |
70 | required> | 81 | required> |
@@ -27,7 +27,10 @@ import { | @@ -27,7 +27,10 @@ import { | ||
27 | DeviceProfile, | 27 | DeviceProfile, |
28 | DeviceProfileData, | 28 | DeviceProfileData, |
29 | DeviceProfileType, | 29 | DeviceProfileType, |
30 | - deviceProfileTypeTranslationMap | 30 | + deviceProfileTypeTranslationMap, |
31 | + DeviceTransportType, | ||
32 | + deviceTransportTypeTranslationMap, | ||
33 | + createDeviceProfileTransportConfiguration | ||
31 | } from '@shared/models/device.models'; | 34 | } from '@shared/models/device.models'; |
32 | import { EntityType } from '@shared/models/entity-type.models'; | 35 | import { EntityType } from '@shared/models/entity-type.models'; |
33 | import { RuleChainId } from '@shared/models/id/rule-chain-id'; | 36 | import { RuleChainId } from '@shared/models/id/rule-chain-id'; |
@@ -48,6 +51,10 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | @@ -48,6 +51,10 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | ||
48 | 51 | ||
49 | deviceProfileTypeTranslations = deviceProfileTypeTranslationMap; | 52 | deviceProfileTypeTranslations = deviceProfileTypeTranslationMap; |
50 | 53 | ||
54 | + deviceTransportTypes = Object.keys(DeviceTransportType); | ||
55 | + | ||
56 | + deviceTransportTypeTranslations = deviceTransportTypeTranslationMap; | ||
57 | + | ||
51 | constructor(protected store: Store<AppState>, | 58 | constructor(protected store: Store<AppState>, |
52 | protected translate: TranslateService, | 59 | protected translate: TranslateService, |
53 | @Optional() @Inject('entity') protected entityValue: DeviceProfile, | 60 | @Optional() @Inject('entity') protected entityValue: DeviceProfile, |
@@ -68,7 +75,8 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | @@ -68,7 +75,8 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | ||
68 | const form = this.fb.group( | 75 | const form = this.fb.group( |
69 | { | 76 | { |
70 | name: [entity ? entity.name : '', [Validators.required]], | 77 | name: [entity ? entity.name : '', [Validators.required]], |
71 | - type: [entity ? entity.type : '', [Validators.required]], | 78 | + type: [entity ? entity.type : null, [Validators.required]], |
79 | + transportType: [entity ? entity.transportType : null, [Validators.required]], | ||
72 | profileData: [entity && !this.isAdd ? entity.profileData : {}, []], | 80 | profileData: [entity && !this.isAdd ? entity.profileData : {}, []], |
73 | defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], | 81 | defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], |
74 | description: [entity ? entity.description : '', []], | 82 | description: [entity ? entity.description : '', []], |
@@ -77,6 +85,9 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | @@ -77,6 +85,9 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | ||
77 | form.get('type').valueChanges.subscribe(() => { | 85 | form.get('type').valueChanges.subscribe(() => { |
78 | this.deviceProfileTypeChanged(form); | 86 | this.deviceProfileTypeChanged(form); |
79 | }); | 87 | }); |
88 | + form.get('transportType').valueChanges.subscribe(() => { | ||
89 | + this.deviceProfileTransportTypeChanged(form); | ||
90 | + }); | ||
80 | this.checkIsNewDeviceProfile(entity, form); | 91 | this.checkIsNewDeviceProfile(entity, form); |
81 | return form; | 92 | return form; |
82 | } | 93 | } |
@@ -84,6 +95,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | @@ -84,6 +95,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | ||
84 | private checkIsNewDeviceProfile(entity: DeviceProfile, form: FormGroup) { | 95 | private checkIsNewDeviceProfile(entity: DeviceProfile, form: FormGroup) { |
85 | if (entity && !entity.id) { | 96 | if (entity && !entity.id) { |
86 | form.get('type').patchValue(DeviceProfileType.DEFAULT, {emitEvent: true}); | 97 | form.get('type').patchValue(DeviceProfileType.DEFAULT, {emitEvent: true}); |
98 | + form.get('transportType').patchValue(DeviceTransportType.DEFAULT, {emitEvent: true}); | ||
87 | } | 99 | } |
88 | } | 100 | } |
89 | 101 | ||
@@ -92,16 +104,31 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | @@ -92,16 +104,31 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { | ||
92 | let profileData: DeviceProfileData = form.getRawValue().profileData; | 104 | let profileData: DeviceProfileData = form.getRawValue().profileData; |
93 | if (!profileData) { | 105 | if (!profileData) { |
94 | profileData = { | 106 | profileData = { |
95 | - configuration: null | 107 | + configuration: null, |
108 | + transportConfiguration: null | ||
96 | }; | 109 | }; |
97 | } | 110 | } |
98 | profileData.configuration = createDeviceProfileConfiguration(deviceProfileType); | 111 | profileData.configuration = createDeviceProfileConfiguration(deviceProfileType); |
99 | form.patchValue({profileData}); | 112 | form.patchValue({profileData}); |
100 | } | 113 | } |
101 | 114 | ||
115 | + private deviceProfileTransportTypeChanged(form: FormGroup) { | ||
116 | + const deviceTransportType: DeviceTransportType = form.get('transportType').value; | ||
117 | + let profileData: DeviceProfileData = form.getRawValue().profileData; | ||
118 | + if (!profileData) { | ||
119 | + profileData = { | ||
120 | + configuration: null, | ||
121 | + transportConfiguration: null | ||
122 | + }; | ||
123 | + } | ||
124 | + profileData.transportConfiguration = createDeviceProfileTransportConfiguration(deviceTransportType); | ||
125 | + form.patchValue({profileData}); | ||
126 | + } | ||
127 | + | ||
102 | updateForm(entity: DeviceProfile) { | 128 | updateForm(entity: DeviceProfile) { |
103 | this.entityForm.patchValue({name: entity.name}); | 129 | this.entityForm.patchValue({name: entity.name}); |
104 | this.entityForm.patchValue({type: entity.type}); | 130 | this.entityForm.patchValue({type: entity.type}); |
131 | + this.entityForm.patchValue({transportType: entity.transportType}); | ||
105 | this.entityForm.patchValue({profileData: entity.profileData}); | 132 | this.entityForm.patchValue({profileData: entity.profileData}); |
106 | this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}); | 133 | this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}); |
107 | this.entityForm.patchValue({description: entity.description}); | 134 | this.entityForm.patchValue({description: entity.description}); |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2020 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 | +<form [formGroup]="defaultDeviceProfileTransportConfigurationFormGroup" style="padding-bottom: 16px;"> | ||
19 | + <tb-json-object-edit | ||
20 | + [required]="required" | ||
21 | + label="{{ 'device-profile.transport-type-default' | translate }}" | ||
22 | + formControlName="configuration"> | ||
23 | + </tb-json-object-edit> | ||
24 | +</form> |
1 | +/// | ||
2 | +/// Copyright © 2016-2020 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, OnInit } from '@angular/core'; | ||
18 | +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | ||
19 | +import { Store } from '@ngrx/store'; | ||
20 | +import { AppState } from '@app/core/core.state'; | ||
21 | +import { coerceBooleanProperty } from '@angular/cdk/coercion'; | ||
22 | +import { | ||
23 | + DefaultDeviceProfileTransportConfiguration, | ||
24 | + DeviceProfileTransportConfiguration, | ||
25 | + DeviceTransportType | ||
26 | +} from '@shared/models/device.models'; | ||
27 | + | ||
28 | +@Component({ | ||
29 | + selector: 'tb-default-device-profile-transport-configuration', | ||
30 | + templateUrl: './default-device-profile-transport-configuration.component.html', | ||
31 | + styleUrls: [], | ||
32 | + providers: [{ | ||
33 | + provide: NG_VALUE_ACCESSOR, | ||
34 | + useExisting: forwardRef(() => DefaultDeviceProfileTransportConfigurationComponent), | ||
35 | + multi: true | ||
36 | + }] | ||
37 | +}) | ||
38 | +export class DefaultDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit { | ||
39 | + | ||
40 | + defaultDeviceProfileTransportConfigurationFormGroup: FormGroup; | ||
41 | + | ||
42 | + private requiredValue: boolean; | ||
43 | + get required(): boolean { | ||
44 | + return this.requiredValue; | ||
45 | + } | ||
46 | + @Input() | ||
47 | + set required(value: boolean) { | ||
48 | + this.requiredValue = coerceBooleanProperty(value); | ||
49 | + } | ||
50 | + | ||
51 | + @Input() | ||
52 | + disabled: boolean; | ||
53 | + | ||
54 | + private propagateChange = (v: any) => { }; | ||
55 | + | ||
56 | + constructor(private store: Store<AppState>, | ||
57 | + private fb: FormBuilder) { | ||
58 | + } | ||
59 | + | ||
60 | + registerOnChange(fn: any): void { | ||
61 | + this.propagateChange = fn; | ||
62 | + } | ||
63 | + | ||
64 | + registerOnTouched(fn: any): void { | ||
65 | + } | ||
66 | + | ||
67 | + ngOnInit() { | ||
68 | + this.defaultDeviceProfileTransportConfigurationFormGroup = this.fb.group({ | ||
69 | + configuration: [null, Validators.required] | ||
70 | + }); | ||
71 | + this.defaultDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => { | ||
72 | + this.updateModel(); | ||
73 | + }); | ||
74 | + } | ||
75 | + | ||
76 | + setDisabledState(isDisabled: boolean): void { | ||
77 | + this.disabled = isDisabled; | ||
78 | + if (this.disabled) { | ||
79 | + this.defaultDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false}); | ||
80 | + } else { | ||
81 | + this.defaultDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false}); | ||
82 | + } | ||
83 | + } | ||
84 | + | ||
85 | + writeValue(value: DefaultDeviceProfileTransportConfiguration | null): void { | ||
86 | + this.defaultDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false}); | ||
87 | + } | ||
88 | + | ||
89 | + private updateModel() { | ||
90 | + let configuration: DeviceProfileTransportConfiguration = null; | ||
91 | + if (this.defaultDeviceProfileTransportConfigurationFormGroup.valid) { | ||
92 | + configuration = this.defaultDeviceProfileTransportConfigurationFormGroup.getRawValue().configuration; | ||
93 | + configuration.type = DeviceTransportType.DEFAULT; | ||
94 | + } | ||
95 | + this.propagateChange(configuration); | ||
96 | + } | ||
97 | +} |
@@ -20,7 +20,7 @@ import { Store } from '@ngrx/store'; | @@ -20,7 +20,7 @@ import { Store } from '@ngrx/store'; | ||
20 | import { AppState } from '@app/core/core.state'; | 20 | import { AppState } from '@app/core/core.state'; |
21 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; | 21 | import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
22 | import { DeviceProfileConfiguration, DeviceProfileType } from '@shared/models/device.models'; | 22 | import { DeviceProfileConfiguration, DeviceProfileType } from '@shared/models/device.models'; |
23 | -import { deepClone } from '../../../../../core/utils'; | 23 | +import { deepClone } from '@core/utils'; |
24 | 24 | ||
25 | @Component({ | 25 | @Component({ |
26 | selector: 'tb-device-profile-configuration', | 26 | selector: 'tb-device-profile-configuration', |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2020 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 | +<div [formGroup]="deviceProfileTransportConfigurationFormGroup"> | ||
19 | + <div [ngSwitch]="transportType"> | ||
20 | + <ng-template [ngSwitchCase]="deviceTransportType.DEFAULT"> | ||
21 | + <tb-default-device-profile-configuration | ||
22 | + [required]="required" | ||
23 | + formControlName="configuration"> | ||
24 | + </tb-default-device-profile-configuration> | ||
25 | + </ng-template> | ||
26 | + </div> | ||
27 | +</div> |
1 | +/// | ||
2 | +/// Copyright © 2016-2020 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, OnInit } from '@angular/core'; | ||
18 | +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | ||
19 | +import { Store } from '@ngrx/store'; | ||
20 | +import { AppState } from '@app/core/core.state'; | ||
21 | +import { coerceBooleanProperty } from '@angular/cdk/coercion'; | ||
22 | +import { DeviceProfileTransportConfiguration, DeviceTransportType } from '@shared/models/device.models'; | ||
23 | +import { deepClone } from '@core/utils'; | ||
24 | + | ||
25 | +@Component({ | ||
26 | + selector: 'tb-device-profile-transport-configuration', | ||
27 | + templateUrl: './device-profile-transport-configuration.component.html', | ||
28 | + styleUrls: [], | ||
29 | + providers: [{ | ||
30 | + provide: NG_VALUE_ACCESSOR, | ||
31 | + useExisting: forwardRef(() => DeviceProfileTransportConfigurationComponent), | ||
32 | + multi: true | ||
33 | + }] | ||
34 | +}) | ||
35 | +export class DeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit { | ||
36 | + | ||
37 | + deviceTransportType = DeviceTransportType; | ||
38 | + | ||
39 | + deviceProfileTransportConfigurationFormGroup: FormGroup; | ||
40 | + | ||
41 | + private requiredValue: boolean; | ||
42 | + get required(): boolean { | ||
43 | + return this.requiredValue; | ||
44 | + } | ||
45 | + @Input() | ||
46 | + set required(value: boolean) { | ||
47 | + this.requiredValue = coerceBooleanProperty(value); | ||
48 | + } | ||
49 | + | ||
50 | + @Input() | ||
51 | + disabled: boolean; | ||
52 | + | ||
53 | + transportType: DeviceTransportType; | ||
54 | + | ||
55 | + private propagateChange = (v: any) => { }; | ||
56 | + | ||
57 | + constructor(private store: Store<AppState>, | ||
58 | + private fb: FormBuilder) { | ||
59 | + } | ||
60 | + | ||
61 | + registerOnChange(fn: any): void { | ||
62 | + this.propagateChange = fn; | ||
63 | + } | ||
64 | + | ||
65 | + registerOnTouched(fn: any): void { | ||
66 | + } | ||
67 | + | ||
68 | + ngOnInit() { | ||
69 | + this.deviceProfileTransportConfigurationFormGroup = this.fb.group({ | ||
70 | + configuration: [null, Validators.required] | ||
71 | + }); | ||
72 | + this.deviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => { | ||
73 | + this.updateModel(); | ||
74 | + }); | ||
75 | + } | ||
76 | + | ||
77 | + setDisabledState(isDisabled: boolean): void { | ||
78 | + this.disabled = isDisabled; | ||
79 | + if (this.disabled) { | ||
80 | + this.deviceProfileTransportConfigurationFormGroup.disable({emitEvent: false}); | ||
81 | + } else { | ||
82 | + this.deviceProfileTransportConfigurationFormGroup.enable({emitEvent: false}); | ||
83 | + } | ||
84 | + } | ||
85 | + | ||
86 | + writeValue(value: DeviceProfileTransportConfiguration | null): void { | ||
87 | + this.transportType = value?.type; | ||
88 | + const configuration = deepClone(value); | ||
89 | + if (configuration) { | ||
90 | + delete configuration.type; | ||
91 | + } | ||
92 | + this.deviceProfileTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); | ||
93 | + } | ||
94 | + | ||
95 | + private updateModel() { | ||
96 | + let configuration: DeviceProfileTransportConfiguration = null; | ||
97 | + if (this.deviceProfileTransportConfigurationFormGroup.valid) { | ||
98 | + configuration = this.deviceProfileTransportConfigurationFormGroup.getRawValue().configuration; | ||
99 | + configuration.type = this.transportType; | ||
100 | + } | ||
101 | + this.propagateChange(configuration); | ||
102 | + } | ||
103 | +} |
@@ -27,7 +27,11 @@ import { DatePipe } from '@angular/common'; | @@ -27,7 +27,11 @@ import { DatePipe } from '@angular/common'; | ||
27 | import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; | 27 | import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; |
28 | import { EntityAction } from '@home/models/entity/entity-component.models'; | 28 | import { EntityAction } from '@home/models/entity/entity-component.models'; |
29 | import { DialogService } from '@core/services/dialog.service'; | 29 | import { DialogService } from '@core/services/dialog.service'; |
30 | -import { DeviceProfile, deviceProfileTypeTranslationMap } from '@shared/models/device.models'; | 30 | +import { |
31 | + DeviceProfile, | ||
32 | + deviceProfileTypeTranslationMap, | ||
33 | + deviceTransportTypeTranslationMap | ||
34 | +} from '@shared/models/device.models'; | ||
31 | import { DeviceProfileService } from '@core/http/device-profile.service'; | 35 | import { DeviceProfileService } from '@core/http/device-profile.service'; |
32 | import { DeviceProfileComponent } from '../../components/profile/device-profile.component'; | 36 | import { DeviceProfileComponent } from '../../components/profile/device-profile.component'; |
33 | import { DeviceProfileTabsComponent } from './device-profile-tabs.component'; | 37 | import { DeviceProfileTabsComponent } from './device-profile-tabs.component'; |
@@ -56,7 +60,10 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon | @@ -56,7 +60,10 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon | ||
56 | new EntityTableColumn<DeviceProfile>('type', 'device-profile.type', '20%', (deviceProfile) => { | 60 | new EntityTableColumn<DeviceProfile>('type', 'device-profile.type', '20%', (deviceProfile) => { |
57 | return this.translate.instant(deviceProfileTypeTranslationMap.get(deviceProfile.type)); | 61 | return this.translate.instant(deviceProfileTypeTranslationMap.get(deviceProfile.type)); |
58 | }), | 62 | }), |
59 | - new EntityTableColumn<DeviceProfile>('description', 'device-profile.description', '60%'), | 63 | + new EntityTableColumn<DeviceProfile>('transportType', 'device-profile.transport-type', '20%', (deviceProfile) => { |
64 | + return this.translate.instant(deviceTransportTypeTranslationMap.get(deviceProfile.transportType)); | ||
65 | + }), | ||
66 | + new EntityTableColumn<DeviceProfile>('description', 'device-profile.description', '40%'), | ||
60 | new EntityTableColumn<DeviceProfile>('isDefault', 'device-profile.default', '60px', | 67 | new EntityTableColumn<DeviceProfile>('isDefault', 'device-profile.default', '60px', |
61 | entity => { | 68 | entity => { |
62 | return checkBoxCell(entity.default); | 69 | return checkBoxCell(entity.default); |
@@ -28,12 +28,26 @@ export enum DeviceProfileType { | @@ -28,12 +28,26 @@ export enum DeviceProfileType { | ||
28 | DEFAULT = 'DEFAULT' | 28 | DEFAULT = 'DEFAULT' |
29 | } | 29 | } |
30 | 30 | ||
31 | +export enum DeviceTransportType { | ||
32 | + DEFAULT = 'DEFAULT', | ||
33 | + MQTT = 'MQTT', | ||
34 | + LWM2M = 'LWM2M' | ||
35 | +} | ||
36 | + | ||
31 | export const deviceProfileTypeTranslationMap = new Map<DeviceProfileType, string>( | 37 | export const deviceProfileTypeTranslationMap = new Map<DeviceProfileType, string>( |
32 | [ | 38 | [ |
33 | [DeviceProfileType.DEFAULT, 'device-profile.type-default'] | 39 | [DeviceProfileType.DEFAULT, 'device-profile.type-default'] |
34 | ] | 40 | ] |
35 | ); | 41 | ); |
36 | 42 | ||
43 | +export const deviceTransportTypeTranslationMap = new Map<DeviceTransportType, string>( | ||
44 | + [ | ||
45 | + [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default'], | ||
46 | + [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt'], | ||
47 | + [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m'] | ||
48 | + ] | ||
49 | +); | ||
50 | + | ||
37 | export interface DefaultDeviceProfileConfiguration { | 51 | export interface DefaultDeviceProfileConfiguration { |
38 | [key: string]: any; | 52 | [key: string]: any; |
39 | } | 53 | } |
@@ -44,6 +58,26 @@ export interface DeviceProfileConfiguration extends DeviceProfileConfigurations | @@ -44,6 +58,26 @@ export interface DeviceProfileConfiguration extends DeviceProfileConfigurations | ||
44 | type: DeviceProfileType; | 58 | type: DeviceProfileType; |
45 | } | 59 | } |
46 | 60 | ||
61 | +export interface DefaultDeviceProfileTransportConfiguration { | ||
62 | + [key: string]: any; | ||
63 | +} | ||
64 | + | ||
65 | +export interface MqttDeviceProfileTransportConfiguration { | ||
66 | + [key: string]: any; | ||
67 | +} | ||
68 | + | ||
69 | +export interface Lwm2mDeviceProfileTransportConfiguration { | ||
70 | + [key: string]: any; | ||
71 | +} | ||
72 | + | ||
73 | +export type DeviceProfileTransportConfigurations = DefaultDeviceProfileTransportConfiguration & | ||
74 | + MqttDeviceProfileTransportConfiguration & | ||
75 | + Lwm2mDeviceProfileTransportConfiguration; | ||
76 | + | ||
77 | +export interface DeviceProfileTransportConfiguration extends DeviceProfileTransportConfigurations { | ||
78 | + type: DeviceTransportType; | ||
79 | +} | ||
80 | + | ||
47 | export function createDeviceProfileConfiguration(type: DeviceProfileType): DeviceProfileConfiguration { | 81 | export function createDeviceProfileConfiguration(type: DeviceProfileType): DeviceProfileConfiguration { |
48 | let configuration: DeviceProfileConfiguration = null; | 82 | let configuration: DeviceProfileConfiguration = null; |
49 | if (type) { | 83 | if (type) { |
@@ -57,8 +91,30 @@ export function createDeviceProfileConfiguration(type: DeviceProfileType): Devic | @@ -57,8 +91,30 @@ export function createDeviceProfileConfiguration(type: DeviceProfileType): Devic | ||
57 | return configuration; | 91 | return configuration; |
58 | } | 92 | } |
59 | 93 | ||
94 | +export function createDeviceProfileTransportConfiguration(type: DeviceTransportType): DeviceProfileTransportConfiguration { | ||
95 | + let transportConfiguration: DeviceProfileTransportConfiguration = null; | ||
96 | + if (type) { | ||
97 | + switch (type) { | ||
98 | + case DeviceTransportType.DEFAULT: | ||
99 | + const defaultTransportConfiguration: DefaultDeviceProfileTransportConfiguration = {}; | ||
100 | + transportConfiguration = {...defaultTransportConfiguration, type: DeviceTransportType.DEFAULT}; | ||
101 | + break; | ||
102 | + case DeviceTransportType.MQTT: | ||
103 | + const mqttTransportConfiguration: MqttDeviceProfileTransportConfiguration = {}; | ||
104 | + transportConfiguration = {...mqttTransportConfiguration, type: DeviceTransportType.MQTT}; | ||
105 | + break; | ||
106 | + case DeviceTransportType.LWM2M: | ||
107 | + const lwm2mTransportConfiguration: Lwm2mDeviceProfileTransportConfiguration = {}; | ||
108 | + transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M}; | ||
109 | + break; | ||
110 | + } | ||
111 | + } | ||
112 | + return transportConfiguration; | ||
113 | +} | ||
114 | + | ||
60 | export interface DeviceProfileData { | 115 | export interface DeviceProfileData { |
61 | configuration: DeviceProfileConfiguration; | 116 | configuration: DeviceProfileConfiguration; |
117 | + transportConfiguration: DeviceProfileTransportConfiguration; | ||
62 | } | 118 | } |
63 | 119 | ||
64 | export interface DeviceProfile extends BaseData<DeviceProfileId> { | 120 | export interface DeviceProfile extends BaseData<DeviceProfileId> { |
@@ -67,29 +123,49 @@ export interface DeviceProfile extends BaseData<DeviceProfileId> { | @@ -67,29 +123,49 @@ export interface DeviceProfile extends BaseData<DeviceProfileId> { | ||
67 | description?: string; | 123 | description?: string; |
68 | default: boolean; | 124 | default: boolean; |
69 | type: DeviceProfileType; | 125 | type: DeviceProfileType; |
126 | + transportType: DeviceTransportType; | ||
70 | defaultRuleChainId?: RuleChainId; | 127 | defaultRuleChainId?: RuleChainId; |
71 | profileData: DeviceProfileData; | 128 | profileData: DeviceProfileData; |
72 | } | 129 | } |
73 | 130 | ||
74 | export interface DeviceProfileInfo extends EntityInfoData { | 131 | export interface DeviceProfileInfo extends EntityInfoData { |
75 | type: DeviceProfileType; | 132 | type: DeviceProfileType; |
133 | + transportType: DeviceTransportType; | ||
76 | } | 134 | } |
77 | 135 | ||
78 | export interface DefaultDeviceConfiguration { | 136 | export interface DefaultDeviceConfiguration { |
79 | [key: string]: any; | 137 | [key: string]: any; |
80 | } | 138 | } |
81 | -export interface Lwm2mDeviceConfiguration { | ||
82 | - [key: string]: any; | ||
83 | -} | ||
84 | 139 | ||
85 | -export type DeviceConfigurations = DefaultDeviceConfiguration & Lwm2mDeviceConfiguration; | 140 | +export type DeviceConfigurations = DefaultDeviceConfiguration; |
86 | 141 | ||
87 | export interface DeviceConfiguration extends DeviceConfigurations { | 142 | export interface DeviceConfiguration extends DeviceConfigurations { |
88 | type: DeviceProfileType; | 143 | type: DeviceProfileType; |
89 | } | 144 | } |
90 | 145 | ||
146 | +export interface DefaultDeviceTransportConfiguration { | ||
147 | + [key: string]: any; | ||
148 | +} | ||
149 | + | ||
150 | +export interface MqttDeviceTransportConfiguration { | ||
151 | + [key: string]: any; | ||
152 | +} | ||
153 | + | ||
154 | +export interface Lwm2mDeviceTransportConfiguration { | ||
155 | + [key: string]: any; | ||
156 | +} | ||
157 | + | ||
158 | +export type DeviceTransportConfigurations = DefaultDeviceTransportConfiguration & | ||
159 | + MqttDeviceTransportConfiguration & | ||
160 | + Lwm2mDeviceTransportConfiguration; | ||
161 | + | ||
162 | +export interface DeviceTransportConfiguration extends DeviceTransportConfigurations { | ||
163 | + type: DeviceTransportType; | ||
164 | +} | ||
165 | + | ||
91 | export interface DeviceData { | 166 | export interface DeviceData { |
92 | configuration: DeviceConfiguration; | 167 | configuration: DeviceConfiguration; |
168 | + transportConfiguration: DeviceTransportConfiguration; | ||
93 | } | 169 | } |
94 | 170 | ||
95 | export interface Device extends BaseData<DeviceId> { | 171 | export interface Device extends BaseData<DeviceId> { |
@@ -770,6 +770,11 @@ | @@ -770,6 +770,11 @@ | ||
770 | "type": "Profile type", | 770 | "type": "Profile type", |
771 | "type-required": "Profile type is required.", | 771 | "type-required": "Profile type is required.", |
772 | "type-default": "Default", | 772 | "type-default": "Default", |
773 | + "transport-type": "Transport type", | ||
774 | + "transport-type-required": "Transport type is required.", | ||
775 | + "transport-type-default": "Default", | ||
776 | + "transport-type-mqtt": "MQTT", | ||
777 | + "transport-type-lwm2m": "LWM2M", | ||
773 | "description": "Description", | 778 | "description": "Description", |
774 | "default": "Default", | 779 | "default": "Default", |
775 | "profile-configuration": "Profile configuration", | 780 | "profile-configuration": "Profile configuration", |