Browse Source

Merge branch 'develop/3.2' of github.com:thingsboard/thingsboard into develop/3.2

pull/3477/head
Andrii Shvaika 6 years ago
parent
commit
5cad682092
  1. 15
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
  2. 19
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/Lwm2mDeviceTransportConfiguration.java
  3. 19
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/MqttDeviceTransportConfiguration.java
  4. 19
      common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java
  5. 19
      common/data/src/main/java/org/thingsboard/server/common/data/device/profile/MqttDeviceProfileTransportConfiguration.java
  6. 2
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  7. 17
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java
  8. 59
      ui-ngx/src/app/core/http/widget.service.ts
  9. 6
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  10. 1
      ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html
  11. 21
      ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.ts
  12. 4
      ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html
  13. 16
      ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.ts
  14. 12
      ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html
  15. 24
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.html
  16. 96
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.ts
  17. 24
      ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html
  18. 96
      ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts
  19. 1
      ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.html
  20. 20
      ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.ts
  21. 4
      ui-ngx/src/app/modules/home/pages/device/data/device-data.component.html
  22. 15
      ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts
  23. 12
      ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.html
  24. 24
      ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.html
  25. 96
      ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.ts
  26. 24
      ui-ngx/src/app/modules/home/pages/device/data/mqtt-device-transport-configuration.component.html
  27. 96
      ui-ngx/src/app/modules/home/pages/device/data/mqtt-device-transport-configuration.component.ts
  28. 4
      ui-ngx/src/app/modules/home/pages/device/device.component.ts
  29. 4
      ui-ngx/src/app/modules/home/pages/device/device.module.ts
  30. 43
      ui-ngx/src/app/shared/models/device.models.ts

15
application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java

@ -237,21 +237,6 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
} }
@Test
public void testSaveSameDeviceWithDifferentDeviceProfileId() throws Exception {
Device device = new Device();
device.setName("My device");
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2");
DeviceProfile savedDeviceProfile2 = doPost("/api/deviceProfile", deviceProfile2, DeviceProfile.class);
savedDevice.setDeviceProfileId(savedDeviceProfile2.getId());
doPost("/api/device/", savedDevice).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Changing device profile is prohibited")));
}
@Test @Test
public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception { public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception {
loginSysAdmin(); loginSysAdmin();

19
common/data/src/main/java/org/thingsboard/server/common/data/device/data/Lwm2mDeviceTransportConfiguration.java

@ -15,13 +15,32 @@
*/ */
package org.thingsboard.server.common.data.device.data; package org.thingsboard.server.common.data.device.data;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import java.util.HashMap;
import java.util.Map;
@Data @Data
public class Lwm2mDeviceTransportConfiguration implements DeviceTransportConfiguration { public class Lwm2mDeviceTransportConfiguration implements DeviceTransportConfiguration {
@JsonIgnore
private Map<String, Object> properties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> properties() {
return this.properties;
}
@JsonAnySetter
public void put(String name, Object value) {
this.properties.put(name, value);
}
@Override @Override
public DeviceTransportType getType() { public DeviceTransportType getType() {
return DeviceTransportType.LWM2M; return DeviceTransportType.LWM2M;

19
common/data/src/main/java/org/thingsboard/server/common/data/device/data/MqttDeviceTransportConfiguration.java

@ -15,12 +15,31 @@
*/ */
package org.thingsboard.server.common.data.device.data; package org.thingsboard.server.common.data.device.data;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import java.util.HashMap;
import java.util.Map;
@Data @Data
public class MqttDeviceTransportConfiguration implements DeviceTransportConfiguration { public class MqttDeviceTransportConfiguration implements DeviceTransportConfiguration {
@JsonIgnore
private Map<String, Object> properties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> properties() {
return this.properties;
}
@JsonAnySetter
public void put(String name, Object value) {
this.properties.put(name, value);
}
@Override @Override
public DeviceTransportType getType() { public DeviceTransportType getType() {
return DeviceTransportType.MQTT; return DeviceTransportType.MQTT;

19
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/Lwm2mDeviceProfileTransportConfiguration.java

@ -15,13 +15,32 @@
*/ */
package org.thingsboard.server.common.data.device.profile; package org.thingsboard.server.common.data.device.profile;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import java.util.HashMap;
import java.util.Map;
@Data @Data
public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { public class Lwm2mDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration {
@JsonIgnore
private Map<String, Object> properties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> properties() {
return this.properties;
}
@JsonAnySetter
public void put(String name, Object value) {
this.properties.put(name, value);
}
@Override @Override
public DeviceTransportType getType() { public DeviceTransportType getType() {
return DeviceTransportType.LWM2M; return DeviceTransportType.LWM2M;

19
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/MqttDeviceProfileTransportConfiguration.java

@ -15,12 +15,31 @@
*/ */
package org.thingsboard.server.common.data.device.profile; package org.thingsboard.server.common.data.device.profile;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import java.util.HashMap;
import java.util.Map;
@Data @Data
public class MqttDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { public class MqttDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration {
@JsonIgnore
private Map<String, Object> properties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> properties() {
return this.properties;
}
@JsonAnySetter
public void put(String name, Object value) {
this.properties.put(name, value);
}
@Override @Override
public DeviceTransportType getType() { public DeviceTransportType getType() {
return DeviceTransportType.MQTT; return DeviceTransportType.MQTT;

2
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -436,8 +436,6 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
Device old = deviceDao.findById(device.getTenantId(), device.getId().getId()); Device old = deviceDao.findById(device.getTenantId(), device.getId().getId());
if (old == null) { if (old == null) {
throw new DataValidationException("Can't update non existing device!"); throw new DataValidationException("Can't update non existing device!");
} else if (!old.getDeviceProfileId().equals(device.getDeviceProfileId())) {
throw new DataValidationException("Changing device profile is prohibited!");
} }
} }

17
dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java

@ -128,23 +128,6 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
} }
} }
@Test(expected = DataValidationException.class)
public void testSaveSameDeviceWithDifferentDeviceProfileId() {
Device device = new Device();
device.setName("My device");
device.setType("default");
device.setTenantId(tenantId);
device = deviceService.saveDevice(device);
DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId,"Device Profile 2");
DeviceProfile savedDeviceProfile2 = deviceProfileService.saveDeviceProfile(deviceProfile2);
device.setDeviceProfileId(savedDeviceProfile2.getId());
try {
deviceService.saveDevice(device);
} finally {
deviceService.deleteDevice(tenantId, device.getId());
}
}
@Test(expected = DataValidationException.class) @Test(expected = DataValidationException.class)
public void testAssignDeviceToCustomerFromDifferentTenant() { public void testAssignDeviceToCustomerFromDifferentTenant() {
Device device = new Device(); Device device = new Device();

59
ui-ngx/src/app/core/http/widget.service.ts

@ -43,6 +43,8 @@ export class WidgetService {
private systemWidgetsBundles: Array<WidgetsBundle>; private systemWidgetsBundles: Array<WidgetsBundle>;
private tenantWidgetsBundles: Array<WidgetsBundle>; private tenantWidgetsBundles: Array<WidgetsBundle>;
private loadWidgetsBundleCacheSubject: ReplaySubject<any>;
constructor( constructor(
private http: HttpClient, private http: HttpClient,
private utils: UtilsService, private utils: UtilsService,
@ -238,34 +240,36 @@ export class WidgetService {
private loadWidgetsBundleCache(config?: RequestConfig): Observable<any> { private loadWidgetsBundleCache(config?: RequestConfig): Observable<any> {
if (!this.allWidgetsBundles) { if (!this.allWidgetsBundles) {
const loadWidgetsBundleCacheSubject = new ReplaySubject(); if (!this.loadWidgetsBundleCacheSubject) {
this.http.get<Array<WidgetsBundle>>('/api/widgetsBundles', this.loadWidgetsBundleCacheSubject = new ReplaySubject();
defaultHttpOptionsFromConfig(config)).subscribe( this.http.get<Array<WidgetsBundle>>('/api/widgetsBundles',
(allWidgetsBundles) => { defaultHttpOptionsFromConfig(config)).subscribe(
this.allWidgetsBundles = allWidgetsBundles; (allWidgetsBundles) => {
this.systemWidgetsBundles = new Array<WidgetsBundle>(); this.allWidgetsBundles = allWidgetsBundles;
this.tenantWidgetsBundles = new Array<WidgetsBundle>(); this.systemWidgetsBundles = new Array<WidgetsBundle>();
this.allWidgetsBundles = this.allWidgetsBundles.sort((wb1, wb2) => { this.tenantWidgetsBundles = new Array<WidgetsBundle>();
let res = wb1.title.localeCompare(wb2.title); this.allWidgetsBundles = this.allWidgetsBundles.sort((wb1, wb2) => {
if (res === 0) { let res = wb1.title.localeCompare(wb2.title);
res = wb2.createdTime - wb1.createdTime; if (res === 0) {
} res = wb2.createdTime - wb1.createdTime;
return res; }
}); return res;
this.allWidgetsBundles.forEach((widgetsBundle) => { });
if (widgetsBundle.tenantId.id === NULL_UUID) { this.allWidgetsBundles.forEach((widgetsBundle) => {
this.systemWidgetsBundles.push(widgetsBundle); if (widgetsBundle.tenantId.id === NULL_UUID) {
} else { this.systemWidgetsBundles.push(widgetsBundle);
this.tenantWidgetsBundles.push(widgetsBundle); } else {
} this.tenantWidgetsBundles.push(widgetsBundle);
}
});
this.loadWidgetsBundleCacheSubject.next();
this.loadWidgetsBundleCacheSubject.complete();
},
() => {
this.loadWidgetsBundleCacheSubject.error(null);
}); });
loadWidgetsBundleCacheSubject.next(); }
loadWidgetsBundleCacheSubject.complete(); return this.loadWidgetsBundleCacheSubject.asObservable();
},
() => {
loadWidgetsBundleCacheSubject.error(null);
});
return loadWidgetsBundleCacheSubject.asObservable();
} else { } else {
return of(null); return of(null);
} }
@ -275,6 +279,7 @@ export class WidgetService {
this.allWidgetsBundles = undefined; this.allWidgetsBundles = undefined;
this.systemWidgetsBundles = undefined; this.systemWidgetsBundles = undefined;
this.tenantWidgetsBundles = undefined; this.tenantWidgetsBundles = undefined;
this.loadWidgetsBundleCacheSubject = undefined;
} }
} }

6
ui-ngx/src/app/modules/home/components/home-components.module.ts

@ -96,6 +96,8 @@ import { DefaultDeviceProfileTransportConfigurationComponent } from './profile/d
import { DeviceProfileTransportConfigurationComponent } from './profile/device/device-profile-transport-configuration.component'; import { DeviceProfileTransportConfigurationComponent } from './profile/device/device-profile-transport-configuration.component';
import { DeviceProfileDialogComponent } from './profile/device-profile-dialog.component'; import { DeviceProfileDialogComponent } from './profile/device-profile-dialog.component';
import { DeviceProfileAutocompleteComponent } from './profile/device-profile-autocomplete.component'; import { DeviceProfileAutocompleteComponent } from './profile/device-profile-autocomplete.component';
import { MqttDeviceProfileTransportConfigurationComponent } from './profile/device/mqtt-device-profile-transport-configuration.component';
import { Lwm2mDeviceProfileTransportConfigurationComponent } from './profile/device/lwm2m-device-profile-transport-configuration.component';
@NgModule({ @NgModule({
declarations: declarations:
@ -171,6 +173,8 @@ import { DeviceProfileAutocompleteComponent } from './profile/device-profile-aut
DefaultDeviceProfileConfigurationComponent, DefaultDeviceProfileConfigurationComponent,
DeviceProfileConfigurationComponent, DeviceProfileConfigurationComponent,
DefaultDeviceProfileTransportConfigurationComponent, DefaultDeviceProfileTransportConfigurationComponent,
MqttDeviceProfileTransportConfigurationComponent,
Lwm2mDeviceProfileTransportConfigurationComponent,
DeviceProfileTransportConfigurationComponent, DeviceProfileTransportConfigurationComponent,
DeviceProfileDataComponent, DeviceProfileDataComponent,
DeviceProfileComponent, DeviceProfileComponent,
@ -239,6 +243,8 @@ import { DeviceProfileAutocompleteComponent } from './profile/device-profile-aut
DefaultDeviceProfileConfigurationComponent, DefaultDeviceProfileConfigurationComponent,
DeviceProfileConfigurationComponent, DeviceProfileConfigurationComponent,
DefaultDeviceProfileTransportConfigurationComponent, DefaultDeviceProfileTransportConfigurationComponent,
MqttDeviceProfileTransportConfigurationComponent,
Lwm2mDeviceProfileTransportConfigurationComponent,
DeviceProfileTransportConfigurationComponent, DeviceProfileTransportConfigurationComponent,
DeviceProfileDataComponent, DeviceProfileDataComponent,
DeviceProfileComponent, DeviceProfileComponent,

1
ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html

@ -19,6 +19,7 @@
<input matInput type="text" placeholder="{{ 'device-profile.device-profile' | translate }}" <input matInput type="text" placeholder="{{ 'device-profile.device-profile' | translate }}"
#deviceProfileInput #deviceProfileInput
formControlName="deviceProfile" formControlName="deviceProfile"
(focusin)="onFocus()"
[required]="required" [required]="required"
(keydown)="deviceProfileEnter($event)" (keydown)="deviceProfileEnter($event)"
(keypress)="deviceProfileEnter($event)" (keypress)="deviceProfileEnter($event)"

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

@ -19,7 +19,7 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { PageLink } from '@shared/models/page/page-link'; import { PageLink } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order'; import { Direction } from '@shared/models/page/sort-order';
import { map, mergeMap, startWith, tap } from 'rxjs/operators'; import { map, mergeMap, share, startWith, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state'; import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -83,6 +83,8 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
searchText = ''; searchText = '';
private dirty = false;
private propagateChange = (v: any) => { }; private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
@ -115,9 +117,9 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
} }
this.updateView(modelValue); this.updateView(modelValue);
}), }),
startWith<string | DeviceProfileInfo>(''),
map(value => value ? (typeof value === 'string' ? value : value.name) : ''), map(value => value ? (typeof value === 'string' ? value : value.name) : ''),
mergeMap(name => this.fetchDeviceProfiles(name) ) mergeMap(name => this.fetchDeviceProfiles(name) ),
share()
); );
} }
@ -144,14 +146,23 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
this.deviceProfileService.getDeviceProfileInfo(value.id).subscribe( this.deviceProfileService.getDeviceProfileInfo(value.id).subscribe(
(profile) => { (profile) => {
this.modelValue = new DeviceProfileId(profile.id.id); this.modelValue = new DeviceProfileId(profile.id.id);
this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(profile, {emitEvent: true}); this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(profile, {emitEvent: false});
this.deviceProfileChanged.emit(profile);
} }
); );
} else { } else {
this.modelValue = null; this.modelValue = null;
this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(null, {emitEvent: true}); this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(null, {emitEvent: false});
this.selectDefaultDeviceProfileIfNeeded(); this.selectDefaultDeviceProfileIfNeeded();
} }
this.dirty = true;
}
onFocus() {
if (this.dirty) {
this.selectDeviceProfileFormGroup.get('deviceProfile').updateValueAndValidity({onlySelf: true, emitEvent: true});
this.dirty = false;
}
} }
updateView(deviceProfile: DeviceProfileInfo | null) { updateView(deviceProfile: DeviceProfileInfo | null) {

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

@ -17,7 +17,7 @@
--> -->
<div [formGroup]="deviceProfileDataFormGroup" style="padding-bottom: 16px;"> <div [formGroup]="deviceProfileDataFormGroup" style="padding-bottom: 16px;">
<mat-accordion multi="true"> <mat-accordion multi="true">
<mat-expansion-panel [expanded]="true"> <mat-expansion-panel *ngIf="displayProfileConfiguration" [expanded]="true">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<div translate>device-profile.profile-configuration</div> <div translate>device-profile.profile-configuration</div>
@ -28,7 +28,7 @@
required> required>
</tb-device-profile-configuration> </tb-device-profile-configuration>
</mat-expansion-panel> </mat-expansion-panel>
<mat-expansion-panel [expanded]="true"> <mat-expansion-panel *ngIf="displayTransportConfiguration" [expanded]="true">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<div translate>device-profile.transport-configuration</div> <div translate>device-profile.transport-configuration</div>

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

@ -19,7 +19,12 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state'; import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { DeviceProfileData } from '@shared/models/device.models'; import {
DeviceProfileData,
DeviceProfileType,
deviceProfileTypeConfigurationInfoMap,
DeviceTransportType, deviceTransportTypeConfigurationInfoMap
} from '@shared/models/device.models';
@Component({ @Component({
selector: 'tb-device-profile-data', selector: 'tb-device-profile-data',
@ -47,6 +52,9 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit
@Input() @Input()
disabled: boolean; disabled: boolean;
displayProfileConfiguration: boolean;
displayTransportConfiguration: boolean;
private propagateChange = (v: any) => { }; private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
@ -80,6 +88,12 @@ export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit
} }
writeValue(value: DeviceProfileData | null): void { writeValue(value: DeviceProfileData | null): void {
const deviceProfileType = value?.configuration?.type;
this.displayProfileConfiguration = deviceProfileType &&
deviceProfileTypeConfigurationInfoMap.get(deviceProfileType).hasProfileConfiguration;
const deviceTransportType = value?.transportConfiguration?.type;
this.displayTransportConfiguration = deviceTransportType &&
deviceTransportTypeConfigurationInfoMap.get(deviceTransportType).hasProfileConfiguration;
this.deviceProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false}); this.deviceProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false});
this.deviceProfileDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false}); this.deviceProfileDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false});
} }

12
ui-ngx/src/app/modules/home/components/profile/device/device-profile-transport-configuration.component.html

@ -23,5 +23,17 @@
formControlName="configuration"> formControlName="configuration">
</tb-default-device-profile-transport-configuration> </tb-default-device-profile-transport-configuration>
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="deviceTransportType.MQTT">
<tb-mqtt-device-profile-transport-configuration
[required]="required"
formControlName="configuration">
</tb-mqtt-device-profile-transport-configuration>
</ng-template>
<ng-template [ngSwitchCase]="deviceTransportType.LWM2M">
<tb-lwm2m-device-profile-transport-configuration
[required]="required"
formControlName="configuration">
</tb-lwm2m-device-profile-transport-configuration>
</ng-template>
</div> </div>
</div> </div>

24
ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.html

@ -0,0 +1,24 @@
<!--
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.
-->
<form [formGroup]="lwm2mDeviceProfileTransportConfigurationFormGroup" style="padding-bottom: 16px;">
<tb-json-object-edit
[required]="required"
label="{{ 'device-profile.transport-type-lwm2m' | translate }}"
formControlName="configuration">
</tb-json-object-edit>
</form>

96
ui-ngx/src/app/modules/home/components/profile/device/lwm2m-device-profile-transport-configuration.component.ts

@ -0,0 +1,96 @@
///
/// 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, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
DeviceProfileTransportConfiguration,
DeviceTransportType, Lwm2mDeviceProfileTransportConfiguration
} from '@shared/models/device.models';
@Component({
selector: 'tb-lwm2m-device-profile-transport-configuration',
templateUrl: './lwm2m-device-profile-transport-configuration.component.html',
styleUrls: [],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mDeviceProfileTransportConfigurationComponent),
multi: true
}]
})
export class Lwm2mDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
lwm2mDeviceProfileTransportConfigurationFormGroup: FormGroup;
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 store: Store<AppState>,
private fb: FormBuilder) {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
ngOnInit() {
this.lwm2mDeviceProfileTransportConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
});
this.lwm2mDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.lwm2mDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false});
} else {
this.lwm2mDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false});
}
}
writeValue(value: Lwm2mDeviceProfileTransportConfiguration | null): void {
this.lwm2mDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
}
private updateModel() {
let configuration: DeviceProfileTransportConfiguration = null;
if (this.lwm2mDeviceProfileTransportConfigurationFormGroup.valid) {
configuration = this.lwm2mDeviceProfileTransportConfigurationFormGroup.getRawValue().configuration;
configuration.type = DeviceTransportType.LWM2M;
}
this.propagateChange(configuration);
}
}

24
ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html

@ -0,0 +1,24 @@
<!--
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.
-->
<form [formGroup]="mqttDeviceProfileTransportConfigurationFormGroup" style="padding-bottom: 16px;">
<tb-json-object-edit
[required]="required"
label="{{ 'device-profile.transport-type-mqtt' | translate }}"
formControlName="configuration">
</tb-json-object-edit>
</form>

96
ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts

@ -0,0 +1,96 @@
///
/// 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, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
DeviceProfileTransportConfiguration,
DeviceTransportType, MqttDeviceProfileTransportConfiguration
} from '@shared/models/device.models';
@Component({
selector: 'tb-mqtt-device-profile-transport-configuration',
templateUrl: './mqtt-device-profile-transport-configuration.component.html',
styleUrls: [],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MqttDeviceProfileTransportConfigurationComponent),
multi: true
}]
})
export class MqttDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
mqttDeviceProfileTransportConfigurationFormGroup: FormGroup;
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 store: Store<AppState>,
private fb: FormBuilder) {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
ngOnInit() {
this.mqttDeviceProfileTransportConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
});
this.mqttDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.mqttDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false});
} else {
this.mqttDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false});
}
}
writeValue(value: MqttDeviceProfileTransportConfiguration | null): void {
this.mqttDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
}
private updateModel() {
let configuration: DeviceProfileTransportConfiguration = null;
if (this.mqttDeviceProfileTransportConfigurationFormGroup.valid) {
configuration = this.mqttDeviceProfileTransportConfigurationFormGroup.getRawValue().configuration;
configuration.type = DeviceTransportType.MQTT;
}
this.propagateChange(configuration);
}
}

1
ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.html

@ -19,6 +19,7 @@
<input matInput type="text" placeholder="{{ 'tenant-profile.tenant-profile' | translate }}" <input matInput type="text" placeholder="{{ 'tenant-profile.tenant-profile' | translate }}"
#tenantProfileInput #tenantProfileInput
formControlName="tenantProfile" formControlName="tenantProfile"
(focusin)="onFocus()"
[required]="required" [required]="required"
(keydown)="tenantProfileEnter($event)" (keydown)="tenantProfileEnter($event)"
(keypress)="tenantProfileEnter($event)" (keypress)="tenantProfileEnter($event)"

20
ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.ts

@ -19,7 +19,7 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { PageLink } from '@shared/models/page/page-link'; import { PageLink } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order'; import { Direction } from '@shared/models/page/sort-order';
import { map, mergeMap, startWith, tap } from 'rxjs/operators'; import { map, mergeMap, share, startWith, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state'; import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
@ -74,6 +74,8 @@ export class TenantProfileAutocompleteComponent implements ControlValueAccessor,
searchText = ''; searchText = '';
private dirty = false;
private propagateChange = (v: any) => { }; private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
@ -106,9 +108,9 @@ export class TenantProfileAutocompleteComponent implements ControlValueAccessor,
} }
this.updateView(modelValue); this.updateView(modelValue);
}), }),
startWith<string | EntityInfoData>(''),
map(value => value ? (typeof value === 'string' ? value : value.name) : ''), map(value => value ? (typeof value === 'string' ? value : value.name) : ''),
mergeMap(name => this.fetchTenantProfiles(name) ) mergeMap(name => this.fetchTenantProfiles(name) ),
share()
); );
} }
@ -136,14 +138,22 @@ export class TenantProfileAutocompleteComponent implements ControlValueAccessor,
this.tenantProfileService.getTenantProfileInfo(value.id).subscribe( this.tenantProfileService.getTenantProfileInfo(value.id).subscribe(
(profile) => { (profile) => {
this.modelValue = new TenantProfileId(profile.id.id); this.modelValue = new TenantProfileId(profile.id.id);
this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(profile, {emitEvent: true}); this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(profile, {emitEvent: false});
} }
); );
} else { } else {
this.modelValue = null; this.modelValue = null;
this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(null, {emitEvent: true}); this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(null, {emitEvent: false});
this.selectDefaultTenantProfileIfNeeded(); this.selectDefaultTenantProfileIfNeeded();
} }
this.dirty = true;
}
onFocus() {
if (this.dirty) {
this.selectTenantProfileFormGroup.get('tenantProfile').updateValueAndValidity({onlySelf: true, emitEvent: true});
this.dirty = false;
}
} }
updateView(value: TenantProfileId | null) { updateView(value: TenantProfileId | null) {

4
ui-ngx/src/app/modules/home/pages/device/data/device-data.component.html

@ -17,7 +17,7 @@
--> -->
<div [formGroup]="deviceDataFormGroup" style="padding-bottom: 16px;"> <div [formGroup]="deviceDataFormGroup" style="padding-bottom: 16px;">
<mat-accordion multi="true"> <mat-accordion multi="true">
<mat-expansion-panel [expanded]="true"> <mat-expansion-panel *ngIf="displayDeviceConfiguration" [expanded]="true">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<div translate>device.device-configuration</div> <div translate>device.device-configuration</div>
@ -28,7 +28,7 @@
required> required>
</tb-device-configuration> </tb-device-configuration>
</mat-expansion-panel> </mat-expansion-panel>
<mat-expansion-panel [expanded]="true"> <mat-expansion-panel *ngIf="displayTransportConfiguration" [expanded]="true">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<div translate>device.transport-configuration</div> <div translate>device.transport-configuration</div>

15
ui-ngx/src/app/modules/home/pages/device/data/device-data.component.ts

@ -19,7 +19,11 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state'; import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { DeviceData } from '@shared/models/device.models'; import {
DeviceData,
deviceProfileTypeConfigurationInfoMap,
deviceTransportTypeConfigurationInfoMap
} from '@shared/models/device.models';
@Component({ @Component({
selector: 'tb-device-data', selector: 'tb-device-data',
@ -47,6 +51,9 @@ export class DeviceDataComponent implements ControlValueAccessor, OnInit {
@Input() @Input()
disabled: boolean; disabled: boolean;
displayDeviceConfiguration: boolean;
displayTransportConfiguration: boolean;
private propagateChange = (v: any) => { }; private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
@ -80,6 +87,12 @@ export class DeviceDataComponent implements ControlValueAccessor, OnInit {
} }
writeValue(value: DeviceData | null): void { writeValue(value: DeviceData | null): void {
const deviceProfileType = value?.configuration?.type;
this.displayDeviceConfiguration = deviceProfileType &&
deviceProfileTypeConfigurationInfoMap.get(deviceProfileType).hasDeviceConfiguration;
const deviceTransportType = value?.transportConfiguration?.type;
this.displayTransportConfiguration = deviceTransportType &&
deviceTransportTypeConfigurationInfoMap.get(deviceTransportType).hasDeviceConfiguration;
this.deviceDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false}); this.deviceDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false});
this.deviceDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false}); this.deviceDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false});
} }

12
ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.html

@ -23,5 +23,17 @@
formControlName="configuration"> formControlName="configuration">
</tb-default-device-transport-configuration> </tb-default-device-transport-configuration>
</ng-template> </ng-template>
<ng-template [ngSwitchCase]="deviceTransportType.MQTT">
<tb-mqtt-device-transport-configuration
[required]="required"
formControlName="configuration">
</tb-mqtt-device-transport-configuration>
</ng-template>
<ng-template [ngSwitchCase]="deviceTransportType.LWM2M">
<tb-lwm2m-device-transport-configuration
[required]="required"
formControlName="configuration">
</tb-lwm2m-device-transport-configuration>
</ng-template>
</div> </div>
</div> </div>

24
ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.html

@ -0,0 +1,24 @@
<!--
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.
-->
<form [formGroup]="lwm2mDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;">
<tb-json-object-edit
[required]="required"
label="{{ 'device-profile.transport-type-lwm2m' | translate }}"
formControlName="configuration">
</tb-json-object-edit>
</form>

96
ui-ngx/src/app/modules/home/pages/device/data/lwm2m-device-transport-configuration.component.ts

@ -0,0 +1,96 @@
///
/// 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, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
DeviceTransportConfiguration,
DeviceTransportType, Lwm2mDeviceTransportConfiguration
} from '@shared/models/device.models';
@Component({
selector: 'tb-lwm2m-device-transport-configuration',
templateUrl: './lwm2m-device-transport-configuration.component.html',
styleUrls: [],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Lwm2mDeviceTransportConfigurationComponent),
multi: true
}]
})
export class Lwm2mDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit {
lwm2mDeviceTransportConfigurationFormGroup: FormGroup;
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 store: Store<AppState>,
private fb: FormBuilder) {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
ngOnInit() {
this.lwm2mDeviceTransportConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
});
this.lwm2mDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.lwm2mDeviceTransportConfigurationFormGroup.disable({emitEvent: false});
} else {
this.lwm2mDeviceTransportConfigurationFormGroup.enable({emitEvent: false});
}
}
writeValue(value: Lwm2mDeviceTransportConfiguration | null): void {
this.lwm2mDeviceTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
}
private updateModel() {
let configuration: DeviceTransportConfiguration = null;
if (this.lwm2mDeviceTransportConfigurationFormGroup.valid) {
configuration = this.lwm2mDeviceTransportConfigurationFormGroup.getRawValue().configuration;
configuration.type = DeviceTransportType.LWM2M;
}
this.propagateChange(configuration);
}
}

24
ui-ngx/src/app/modules/home/pages/device/data/mqtt-device-transport-configuration.component.html

@ -0,0 +1,24 @@
<!--
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.
-->
<form [formGroup]="mqttDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;">
<tb-json-object-edit
[required]="required"
label="{{ 'device-profile.transport-type-mqtt' | translate }}"
formControlName="configuration">
</tb-json-object-edit>
</form>

96
ui-ngx/src/app/modules/home/pages/device/data/mqtt-device-transport-configuration.component.ts

@ -0,0 +1,96 @@
///
/// 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, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import {
DeviceTransportConfiguration,
DeviceTransportType, MqttDeviceTransportConfiguration
} from '@shared/models/device.models';
@Component({
selector: 'tb-mqtt-device-transport-configuration',
templateUrl: './mqtt-device-transport-configuration.component.html',
styleUrls: [],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MqttDeviceTransportConfigurationComponent),
multi: true
}]
})
export class MqttDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit {
mqttDeviceTransportConfigurationFormGroup: FormGroup;
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 store: Store<AppState>,
private fb: FormBuilder) {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
ngOnInit() {
this.mqttDeviceTransportConfigurationFormGroup = this.fb.group({
configuration: [null, Validators.required]
});
this.mqttDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.mqttDeviceTransportConfigurationFormGroup.disable({emitEvent: false});
} else {
this.mqttDeviceTransportConfigurationFormGroup.enable({emitEvent: false});
}
}
writeValue(value: MqttDeviceTransportConfiguration | null): void {
this.mqttDeviceTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
}
private updateModel() {
let configuration: DeviceTransportConfiguration = null;
if (this.mqttDeviceTransportConfigurationFormGroup.valid) {
configuration = this.mqttDeviceTransportConfigurationFormGroup.getRawValue().configuration;
configuration.type = DeviceTransportType.MQTT;
}
this.propagateChange(configuration);
}
}

4
ui-ngx/src/app/modules/home/pages/device/device.component.ts

@ -141,7 +141,7 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
} }
onDeviceProfileChanged(deviceProfile: DeviceProfileInfo) { onDeviceProfileChanged(deviceProfile: DeviceProfileInfo) {
if (deviceProfile) { if (deviceProfile && this.isEdit) {
const deviceProfileType: DeviceProfileType = deviceProfile.type; const deviceProfileType: DeviceProfileType = deviceProfile.type;
const deviceTransportType: DeviceTransportType = deviceProfile.transportType; const deviceTransportType: DeviceTransportType = deviceProfile.transportType;
let deviceData: DeviceData = this.entityForm.getRawValue().deviceData; let deviceData: DeviceData = this.entityForm.getRawValue().deviceData;
@ -151,6 +151,7 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
transportConfiguration: createDeviceTransportConfiguration(deviceTransportType) transportConfiguration: createDeviceTransportConfiguration(deviceTransportType)
}; };
this.entityForm.patchValue({deviceData}); this.entityForm.patchValue({deviceData});
this.entityForm.markAsDirty();
} else { } else {
let changed = false; let changed = false;
if (deviceData.configuration.type !== deviceProfileType) { if (deviceData.configuration.type !== deviceProfileType) {
@ -163,6 +164,7 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
} }
if (changed) { if (changed) {
this.entityForm.patchValue({deviceData}); this.entityForm.patchValue({deviceData});
this.entityForm.markAsDirty();
} }
} }
} }

4
ui-ngx/src/app/modules/home/pages/device/device.module.ts

@ -29,12 +29,16 @@ import { DeviceConfigurationComponent } from './data/device-configuration.compon
import { DeviceDataComponent } from './data/device-data.component'; import { DeviceDataComponent } from './data/device-data.component';
import { DefaultDeviceTransportConfigurationComponent } from './data/default-device-transport-configuration.component'; import { DefaultDeviceTransportConfigurationComponent } from './data/default-device-transport-configuration.component';
import { DeviceTransportConfigurationComponent } from './data/device-transport-configuration.component'; import { DeviceTransportConfigurationComponent } from './data/device-transport-configuration.component';
import { MqttDeviceTransportConfigurationComponent } from './data/mqtt-device-transport-configuration.component';
import { Lwm2mDeviceTransportConfigurationComponent } from './data/lwm2m-device-transport-configuration.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
DefaultDeviceConfigurationComponent, DefaultDeviceConfigurationComponent,
DeviceConfigurationComponent, DeviceConfigurationComponent,
DefaultDeviceTransportConfigurationComponent, DefaultDeviceTransportConfigurationComponent,
MqttDeviceTransportConfigurationComponent,
Lwm2mDeviceTransportConfigurationComponent,
DeviceTransportConfigurationComponent, DeviceTransportConfigurationComponent,
DeviceDataComponent, DeviceDataComponent,
DeviceComponent, DeviceComponent,

43
ui-ngx/src/app/shared/models/device.models.ts

@ -34,12 +34,29 @@ export enum DeviceTransportType {
LWM2M = 'LWM2M' LWM2M = 'LWM2M'
} }
export interface DeviceConfigurationFormInfo {
hasProfileConfiguration: boolean;
hasDeviceConfiguration: boolean;
}
export const deviceProfileTypeTranslationMap = new Map<DeviceProfileType, string>( export const deviceProfileTypeTranslationMap = new Map<DeviceProfileType, string>(
[ [
[DeviceProfileType.DEFAULT, 'device-profile.type-default'] [DeviceProfileType.DEFAULT, 'device-profile.type-default']
] ]
); );
export const deviceProfileTypeConfigurationInfoMap = new Map<DeviceProfileType, DeviceConfigurationFormInfo>(
[
[
DeviceProfileType.DEFAULT,
{
hasProfileConfiguration: false,
hasDeviceConfiguration: false,
}
]
]
);
export const deviceTransportTypeTranslationMap = new Map<DeviceTransportType, string>( export const deviceTransportTypeTranslationMap = new Map<DeviceTransportType, string>(
[ [
[DeviceTransportType.DEFAULT, 'device-profile.transport-type-default'], [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default'],
@ -48,6 +65,32 @@ export const deviceTransportTypeTranslationMap = new Map<DeviceTransportType, st
] ]
); );
export const deviceTransportTypeConfigurationInfoMap = new Map<DeviceTransportType, DeviceConfigurationFormInfo>(
[
[
DeviceTransportType.DEFAULT,
{
hasProfileConfiguration: false,
hasDeviceConfiguration: false,
}
],
[
DeviceTransportType.MQTT,
{
hasProfileConfiguration: true,
hasDeviceConfiguration: true,
}
],
[
DeviceTransportType.LWM2M,
{
hasProfileConfiguration: true,
hasDeviceConfiguration: true,
}
]
]
);
export interface DefaultDeviceProfileConfiguration { export interface DefaultDeviceProfileConfiguration {
[key: string]: any; [key: string]: any;
} }

Loading…
Cancel
Save