22 changed files with 1237 additions and 7 deletions
@ -0,0 +1,67 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
--> |
||||
|
<mat-form-field [formGroup]="selectDeviceProfileFormGroup" class="mat-block"> |
||||
|
<input matInput type="text" placeholder="{{ 'device-profile.device-profile' | translate }}" |
||||
|
#deviceProfileInput |
||||
|
formControlName="deviceProfile" |
||||
|
[required]="required" |
||||
|
(keydown)="deviceProfileEnter($event)" |
||||
|
(keypress)="deviceProfileEnter($event)" |
||||
|
[matAutocomplete]="deviceProfileAutocomplete"> |
||||
|
<button *ngIf="selectDeviceProfileFormGroup.get('deviceProfile').value && !disabled" |
||||
|
type="button" |
||||
|
matSuffix mat-button mat-icon-button aria-label="Clear" |
||||
|
(click)="clear()"> |
||||
|
<mat-icon class="material-icons">close</mat-icon> |
||||
|
</button> |
||||
|
<button *ngIf="selectDeviceProfileFormGroup.get('deviceProfile').value && !disabled" |
||||
|
type="button" |
||||
|
matSuffix mat-button mat-icon-button aria-label="Edit" |
||||
|
matTooltip="{{ 'device-profile.edit' | translate }}" |
||||
|
matTooltipPosition="above" |
||||
|
(click)="editDeviceProfile($event)"> |
||||
|
<mat-icon class="material-icons">edit</mat-icon> |
||||
|
</button> |
||||
|
<mat-autocomplete |
||||
|
class="tb-autocomplete" |
||||
|
#deviceProfileAutocomplete="matAutocomplete" |
||||
|
[displayWith]="displayDeviceProfileFn"> |
||||
|
<mat-option *ngFor="let deviceProfile of filteredDeviceProfiles | async" [value]="deviceProfile"> |
||||
|
<span [innerHTML]="deviceProfile.name | highlight:searchText"></span> |
||||
|
</mat-option> |
||||
|
<mat-option *ngIf="!(filteredDeviceProfiles | async)?.length" [value]="null" class="tb-not-found"> |
||||
|
<div class="tb-not-found-content" (click)="$event.stopPropagation()"> |
||||
|
<div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty"> |
||||
|
<span translate>device-profile.no-device-profiles-found</span> |
||||
|
</div> |
||||
|
<ng-template #searchNotEmpty> |
||||
|
<span> |
||||
|
{{ translate.get('device-profile.no-device-profiles-matching', |
||||
|
{entity: truncate.transform(searchText, true, 6, '...')}) | async }} |
||||
|
</span> |
||||
|
</ng-template> |
||||
|
<span> |
||||
|
<a translate (click)="createDeviceProfile($event, searchText)">device-profile.create-new-device-profile</a> |
||||
|
</span> |
||||
|
</div> |
||||
|
</mat-option> |
||||
|
</mat-autocomplete> |
||||
|
<mat-error *ngIf="selectDeviceProfileFormGroup.get('deviceProfile').hasError('required')"> |
||||
|
{{ 'device-profile.device-profile-required' | translate }} |
||||
|
</mat-error> |
||||
|
</mat-form-field> |
||||
@ -0,0 +1,261 @@ |
|||||
|
///
|
||||
|
/// 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, ElementRef, EventEmitter, forwardRef, Input, OnInit, Output, ViewChild } from '@angular/core'; |
||||
|
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; |
||||
|
import { Observable } from 'rxjs'; |
||||
|
import { PageLink } from '@shared/models/page/page-link'; |
||||
|
import { Direction } from '@shared/models/page/sort-order'; |
||||
|
import { map, mergeMap, startWith, tap } from 'rxjs/operators'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@app/core/core.state'; |
||||
|
import { TranslateService } from '@ngx-translate/core'; |
||||
|
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
||||
|
import { entityIdEquals } from '@shared/models/id/entity-id'; |
||||
|
import { TruncatePipe } from '@shared//pipe/truncate.pipe'; |
||||
|
import { ENTER } from '@angular/cdk/keycodes'; |
||||
|
import { MatDialog } from '@angular/material/dialog'; |
||||
|
import { DeviceProfileId } from '@shared/models/id/device-profile-id'; |
||||
|
import { |
||||
|
createDeviceProfileConfiguration, |
||||
|
createDeviceProfileTransportConfiguration, |
||||
|
DeviceProfile, |
||||
|
DeviceProfileInfo, |
||||
|
DeviceProfileType, |
||||
|
DeviceTransportType |
||||
|
} from '@shared/models/device.models'; |
||||
|
import { DeviceProfileService } from '@core/http/device-profile.service'; |
||||
|
import { DeviceProfileDialogComponent, DeviceProfileDialogData } from './device-profile-dialog.component'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-device-profile-autocomplete', |
||||
|
templateUrl: './device-profile-autocomplete.component.html', |
||||
|
styleUrls: [], |
||||
|
providers: [{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => DeviceProfileAutocompleteComponent), |
||||
|
multi: true |
||||
|
}] |
||||
|
}) |
||||
|
export class DeviceProfileAutocompleteComponent implements ControlValueAccessor, OnInit { |
||||
|
|
||||
|
selectDeviceProfileFormGroup: FormGroup; |
||||
|
|
||||
|
modelValue: DeviceProfileId | null; |
||||
|
|
||||
|
@Input() |
||||
|
selectDefaultProfile = false; |
||||
|
|
||||
|
private requiredValue: boolean; |
||||
|
get required(): boolean { |
||||
|
return this.requiredValue; |
||||
|
} |
||||
|
@Input() |
||||
|
set required(value: boolean) { |
||||
|
this.requiredValue = coerceBooleanProperty(value); |
||||
|
} |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
@Output() |
||||
|
deviceProfileUpdated = new EventEmitter<DeviceProfileId>(); |
||||
|
|
||||
|
@Output() |
||||
|
deviceProfileChanged = new EventEmitter<DeviceProfileInfo>(); |
||||
|
|
||||
|
@ViewChild('deviceProfileInput', {static: true}) deviceProfileInput: ElementRef; |
||||
|
|
||||
|
filteredDeviceProfiles: Observable<Array<DeviceProfileInfo>>; |
||||
|
|
||||
|
searchText = ''; |
||||
|
|
||||
|
private propagateChange = (v: any) => { }; |
||||
|
|
||||
|
constructor(private store: Store<AppState>, |
||||
|
public translate: TranslateService, |
||||
|
public truncate: TruncatePipe, |
||||
|
private deviceProfileService: DeviceProfileService, |
||||
|
private fb: FormBuilder, |
||||
|
private dialog: MatDialog) { |
||||
|
this.selectDeviceProfileFormGroup = this.fb.group({ |
||||
|
deviceProfile: [null] |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
registerOnChange(fn: any): void { |
||||
|
this.propagateChange = fn; |
||||
|
} |
||||
|
|
||||
|
registerOnTouched(fn: any): void { |
||||
|
} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
this.filteredDeviceProfiles = this.selectDeviceProfileFormGroup.get('deviceProfile').valueChanges |
||||
|
.pipe( |
||||
|
tap((value: DeviceProfileInfo | string) => { |
||||
|
let modelValue: DeviceProfileInfo | null; |
||||
|
if (typeof value === 'string' || !value) { |
||||
|
modelValue = null; |
||||
|
} else { |
||||
|
modelValue = value; |
||||
|
} |
||||
|
this.updateView(modelValue); |
||||
|
}), |
||||
|
startWith<string | DeviceProfileInfo>(''), |
||||
|
map(value => value ? (typeof value === 'string' ? value : value.name) : ''), |
||||
|
mergeMap(name => this.fetchDeviceProfiles(name) ) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
selectDefaultDeviceProfileIfNeeded(): void { |
||||
|
if (this.selectDefaultProfile && !this.modelValue) { |
||||
|
this.deviceProfileService.getDefaultDeviceProfileInfo().subscribe( |
||||
|
(profile) => { |
||||
|
if (profile) { |
||||
|
this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(profile, {emitEvent: false}); |
||||
|
this.updateView(profile); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
} |
||||
|
|
||||
|
writeValue(value: DeviceProfileId | null): void { |
||||
|
this.searchText = ''; |
||||
|
if (value != null) { |
||||
|
this.deviceProfileService.getDeviceProfileInfo(value.id).subscribe( |
||||
|
(profile) => { |
||||
|
this.modelValue = new DeviceProfileId(profile.id.id); |
||||
|
this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(profile, {emitEvent: true}); |
||||
|
} |
||||
|
); |
||||
|
} else { |
||||
|
this.modelValue = null; |
||||
|
this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(null, {emitEvent: true}); |
||||
|
this.selectDefaultDeviceProfileIfNeeded(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
updateView(deviceProfile: DeviceProfileInfo | null) { |
||||
|
const idValue = deviceProfile ? new DeviceProfileId(deviceProfile.id.id) : null; |
||||
|
if (!entityIdEquals(this.modelValue, idValue)) { |
||||
|
this.modelValue = idValue; |
||||
|
this.propagateChange(this.modelValue); |
||||
|
this.deviceProfileChanged.emit(deviceProfile); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
displayDeviceProfileFn(profile?: DeviceProfileInfo): string | undefined { |
||||
|
return profile ? profile.name : undefined; |
||||
|
} |
||||
|
|
||||
|
fetchDeviceProfiles(searchText?: string): Observable<Array<DeviceProfileInfo>> { |
||||
|
this.searchText = searchText; |
||||
|
const pageLink = new PageLink(10, 0, searchText, { |
||||
|
property: 'name', |
||||
|
direction: Direction.ASC |
||||
|
}); |
||||
|
return this.deviceProfileService.getDeviceProfileInfos(pageLink, {ignoreLoading: true}).pipe( |
||||
|
map(pageData => { |
||||
|
return pageData.data; |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
clear() { |
||||
|
this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(null, {emitEvent: true}); |
||||
|
setTimeout(() => { |
||||
|
this.deviceProfileInput.nativeElement.blur(); |
||||
|
this.deviceProfileInput.nativeElement.focus(); |
||||
|
}, 0); |
||||
|
} |
||||
|
|
||||
|
textIsNotEmpty(text: string): boolean { |
||||
|
return (text && text.length > 0); |
||||
|
} |
||||
|
|
||||
|
deviceProfileEnter($event: KeyboardEvent) { |
||||
|
if ($event.keyCode === ENTER) { |
||||
|
$event.preventDefault(); |
||||
|
if (!this.modelValue) { |
||||
|
this.createDeviceProfile($event, this.searchText); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
createDeviceProfile($event: Event, profileName: string) { |
||||
|
$event.preventDefault(); |
||||
|
const deviceProfile: DeviceProfile = { |
||||
|
id: null, |
||||
|
name: profileName, |
||||
|
type: DeviceProfileType.DEFAULT, |
||||
|
transportType: DeviceTransportType.DEFAULT, |
||||
|
profileData: { |
||||
|
configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT), |
||||
|
transportConfiguration: createDeviceProfileTransportConfiguration(DeviceTransportType.DEFAULT) |
||||
|
} |
||||
|
}; |
||||
|
this.openDeviceProfileDialog(deviceProfile, true); |
||||
|
} |
||||
|
|
||||
|
editDeviceProfile($event: Event) { |
||||
|
$event.preventDefault(); |
||||
|
this.deviceProfileService.getDeviceProfile(this.modelValue.id).subscribe( |
||||
|
(deviceProfile) => { |
||||
|
this.openDeviceProfileDialog(deviceProfile, false); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
openDeviceProfileDialog(deviceProfile: DeviceProfile, isAdd: boolean) { |
||||
|
this.dialog.open<DeviceProfileDialogComponent, DeviceProfileDialogData, |
||||
|
DeviceProfile>(DeviceProfileDialogComponent, { |
||||
|
disableClose: true, |
||||
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], |
||||
|
data: { |
||||
|
isAdd, |
||||
|
deviceProfile |
||||
|
} |
||||
|
}).afterClosed().subscribe( |
||||
|
(savedDeviceProfile) => { |
||||
|
if (!savedDeviceProfile) { |
||||
|
setTimeout(() => { |
||||
|
this.deviceProfileInput.nativeElement.blur(); |
||||
|
this.deviceProfileInput.nativeElement.focus(); |
||||
|
}, 0); |
||||
|
} else { |
||||
|
this.deviceProfileService.getDeviceProfileInfo(savedDeviceProfile.id.id).subscribe( |
||||
|
(profile) => { |
||||
|
this.modelValue = new DeviceProfileId(profile.id.id); |
||||
|
this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(profile, {emitEvent: true}); |
||||
|
if (isAdd) { |
||||
|
this.propagateChange(this.modelValue); |
||||
|
} else { |
||||
|
this.deviceProfileUpdated.next(savedDeviceProfile.id); |
||||
|
} |
||||
|
this.deviceProfileChanged.emit(profile); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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 (ngSubmit)="save()" style="min-width: 600px;"> |
||||
|
<mat-toolbar color="primary"> |
||||
|
<h2>{{ (isAdd ? 'device-profile.add' : 'device-profile.edit' ) | translate }}</h2> |
||||
|
<span fxFlex></span> |
||||
|
<button mat-icon-button |
||||
|
(click)="cancel()" |
||||
|
type="button"> |
||||
|
<mat-icon class="material-icons">close</mat-icon> |
||||
|
</button> |
||||
|
</mat-toolbar> |
||||
|
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> |
||||
|
</mat-progress-bar> |
||||
|
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div> |
||||
|
<div mat-dialog-content> |
||||
|
<tb-device-profile |
||||
|
#deviceProfileComponent |
||||
|
[standalone]="true" |
||||
|
[entity]="deviceProfile" |
||||
|
[isEdit]="true"> |
||||
|
</tb-device-profile> |
||||
|
</div> |
||||
|
<div mat-dialog-actions fxLayoutAlign="end center"> |
||||
|
<button mat-raised-button color="primary" |
||||
|
type="submit" |
||||
|
[disabled]="(isLoading$ | async) || deviceProfileComponent.entityForm?.invalid || !deviceProfileComponent.entityForm?.dirty"> |
||||
|
{{ (isAdd ? 'action.add' : 'action.save') | translate }} |
||||
|
</button> |
||||
|
<button mat-button color="primary" |
||||
|
type="button" |
||||
|
cdkFocusInitial |
||||
|
[disabled]="(isLoading$ | async)" |
||||
|
(click)="cancel()"> |
||||
|
{{ 'action.cancel' | translate }} |
||||
|
</button> |
||||
|
</div> |
||||
|
</form> |
||||
@ -0,0 +1,101 @@ |
|||||
|
///
|
||||
|
/// 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 { |
||||
|
AfterViewInit, |
||||
|
Component, |
||||
|
ComponentFactoryResolver, |
||||
|
Inject, |
||||
|
Injector, |
||||
|
SkipSelf, |
||||
|
ViewChild |
||||
|
} from '@angular/core'; |
||||
|
import { ErrorStateMatcher } from '@angular/material/core'; |
||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { FormControl, FormGroupDirective, NgForm } from '@angular/forms'; |
||||
|
import { DialogComponent } from '@shared/components/dialog.component'; |
||||
|
import { Router } from '@angular/router'; |
||||
|
import { DeviceProfile } from '@shared/models/device.models'; |
||||
|
import { DeviceProfileComponent } from './device-profile.component'; |
||||
|
import { DeviceProfileService } from '@core/http/device-profile.service'; |
||||
|
|
||||
|
export interface DeviceProfileDialogData { |
||||
|
deviceProfile: DeviceProfile; |
||||
|
isAdd: boolean; |
||||
|
} |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-device-profile-dialog', |
||||
|
templateUrl: './device-profile-dialog.component.html', |
||||
|
providers: [{provide: ErrorStateMatcher, useExisting: DeviceProfileDialogComponent}], |
||||
|
styleUrls: [] |
||||
|
}) |
||||
|
export class DeviceProfileDialogComponent extends |
||||
|
DialogComponent<DeviceProfileDialogComponent, DeviceProfile> implements ErrorStateMatcher, AfterViewInit { |
||||
|
|
||||
|
isAdd: boolean; |
||||
|
deviceProfile: DeviceProfile; |
||||
|
|
||||
|
submitted = false; |
||||
|
|
||||
|
@ViewChild('deviceProfileComponent', {static: true}) deviceProfileComponent: DeviceProfileComponent; |
||||
|
|
||||
|
constructor(protected store: Store<AppState>, |
||||
|
protected router: Router, |
||||
|
@Inject(MAT_DIALOG_DATA) public data: DeviceProfileDialogData, |
||||
|
public dialogRef: MatDialogRef<DeviceProfileDialogComponent, DeviceProfile>, |
||||
|
private componentFactoryResolver: ComponentFactoryResolver, |
||||
|
private injector: Injector, |
||||
|
@SkipSelf() private errorStateMatcher: ErrorStateMatcher, |
||||
|
private deviceProfileService: DeviceProfileService) { |
||||
|
super(store, router, dialogRef); |
||||
|
this.isAdd = this.data.isAdd; |
||||
|
this.deviceProfile = this.data.deviceProfile; |
||||
|
} |
||||
|
|
||||
|
ngAfterViewInit(): void { |
||||
|
if (this.isAdd) { |
||||
|
setTimeout(() => { |
||||
|
this.deviceProfileComponent.entityForm.markAsDirty(); |
||||
|
}, 0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { |
||||
|
const originalErrorState = this.errorStateMatcher.isErrorState(control, form); |
||||
|
const customErrorState = !!(control && control.invalid && this.submitted); |
||||
|
return originalErrorState || customErrorState; |
||||
|
} |
||||
|
|
||||
|
cancel(): void { |
||||
|
this.dialogRef.close(null); |
||||
|
} |
||||
|
|
||||
|
save(): void { |
||||
|
this.submitted = true; |
||||
|
if (this.deviceProfileComponent.entityForm.valid) { |
||||
|
this.deviceProfile = {...this.deviceProfile, ...this.deviceProfileComponent.entityFormValue()}; |
||||
|
this.deviceProfileService.saveDeviceProfile(this.deviceProfile).subscribe( |
||||
|
(deviceProfile) => { |
||||
|
this.dialogRef.close(deviceProfile); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -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]="defaultDeviceConfigurationFormGroup" style="padding-bottom: 16px;"> |
||||
|
<tb-json-object-edit |
||||
|
[required]="required" |
||||
|
label="{{ 'device-profile.type-default' | translate }}" |
||||
|
formControlName="configuration"> |
||||
|
</tb-json-object-edit> |
||||
|
</form> |
||||
@ -0,0 +1,97 @@ |
|||||
|
///
|
||||
|
/// 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 { |
||||
|
DefaultDeviceConfiguration, |
||||
|
DeviceConfiguration, |
||||
|
DeviceProfileType |
||||
|
} from '@shared/models/device.models'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-default-device-configuration', |
||||
|
templateUrl: './default-device-configuration.component.html', |
||||
|
styleUrls: [], |
||||
|
providers: [{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => DefaultDeviceConfigurationComponent), |
||||
|
multi: true |
||||
|
}] |
||||
|
}) |
||||
|
export class DefaultDeviceConfigurationComponent implements ControlValueAccessor, OnInit { |
||||
|
|
||||
|
defaultDeviceConfigurationFormGroup: 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.defaultDeviceConfigurationFormGroup = this.fb.group({ |
||||
|
configuration: [null, Validators.required] |
||||
|
}); |
||||
|
this.defaultDeviceConfigurationFormGroup.valueChanges.subscribe(() => { |
||||
|
this.updateModel(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (this.disabled) { |
||||
|
this.defaultDeviceConfigurationFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.defaultDeviceConfigurationFormGroup.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: DefaultDeviceConfiguration | null): void { |
||||
|
this.defaultDeviceConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false}); |
||||
|
} |
||||
|
|
||||
|
private updateModel() { |
||||
|
let configuration: DeviceConfiguration = null; |
||||
|
if (this.defaultDeviceConfigurationFormGroup.valid) { |
||||
|
configuration = this.defaultDeviceConfigurationFormGroup.getRawValue().configuration; |
||||
|
configuration.type = DeviceProfileType.DEFAULT; |
||||
|
} |
||||
|
this.propagateChange(configuration); |
||||
|
} |
||||
|
} |
||||
@ -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]="defaultDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;"> |
||||
|
<tb-json-object-edit |
||||
|
[required]="required" |
||||
|
label="{{ 'device-profile.transport-type-default' | translate }}" |
||||
|
formControlName="configuration"> |
||||
|
</tb-json-object-edit> |
||||
|
</form> |
||||
@ -0,0 +1,97 @@ |
|||||
|
///
|
||||
|
/// 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 { |
||||
|
DefaultDeviceTransportConfiguration, |
||||
|
DeviceTransportConfiguration, |
||||
|
DeviceTransportType |
||||
|
} from '@shared/models/device.models'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-default-device-transport-configuration', |
||||
|
templateUrl: './default-device-transport-configuration.component.html', |
||||
|
styleUrls: [], |
||||
|
providers: [{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => DefaultDeviceTransportConfigurationComponent), |
||||
|
multi: true |
||||
|
}] |
||||
|
}) |
||||
|
export class DefaultDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit { |
||||
|
|
||||
|
defaultDeviceTransportConfigurationFormGroup: 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.defaultDeviceTransportConfigurationFormGroup = this.fb.group({ |
||||
|
configuration: [null, Validators.required] |
||||
|
}); |
||||
|
this.defaultDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => { |
||||
|
this.updateModel(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (this.disabled) { |
||||
|
this.defaultDeviceTransportConfigurationFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.defaultDeviceTransportConfigurationFormGroup.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: DefaultDeviceTransportConfiguration | null): void { |
||||
|
this.defaultDeviceTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false}); |
||||
|
} |
||||
|
|
||||
|
private updateModel() { |
||||
|
let configuration: DeviceTransportConfiguration = null; |
||||
|
if (this.defaultDeviceTransportConfigurationFormGroup.valid) { |
||||
|
configuration = this.defaultDeviceTransportConfigurationFormGroup.getRawValue().configuration; |
||||
|
configuration.type = DeviceTransportType.DEFAULT; |
||||
|
} |
||||
|
this.propagateChange(configuration); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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]="deviceConfigurationFormGroup"> |
||||
|
<div [ngSwitch]="type"> |
||||
|
<ng-template [ngSwitchCase]="deviceProfileType.DEFAULT"> |
||||
|
<tb-default-device-configuration |
||||
|
[required]="required" |
||||
|
formControlName="configuration"> |
||||
|
</tb-default-device-configuration> |
||||
|
</ng-template> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,103 @@ |
|||||
|
///
|
||||
|
/// 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 { DeviceConfiguration, DeviceProfileType } from '@shared/models/device.models'; |
||||
|
import { deepClone } from '@core/utils'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-device-configuration', |
||||
|
templateUrl: './device-configuration.component.html', |
||||
|
styleUrls: [], |
||||
|
providers: [{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => DeviceConfigurationComponent), |
||||
|
multi: true |
||||
|
}] |
||||
|
}) |
||||
|
export class DeviceConfigurationComponent implements ControlValueAccessor, OnInit { |
||||
|
|
||||
|
deviceProfileType = DeviceProfileType; |
||||
|
|
||||
|
deviceConfigurationFormGroup: FormGroup; |
||||
|
|
||||
|
private requiredValue: boolean; |
||||
|
get required(): boolean { |
||||
|
return this.requiredValue; |
||||
|
} |
||||
|
@Input() |
||||
|
set required(value: boolean) { |
||||
|
this.requiredValue = coerceBooleanProperty(value); |
||||
|
} |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
type: DeviceProfileType; |
||||
|
|
||||
|
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.deviceConfigurationFormGroup = this.fb.group({ |
||||
|
configuration: [null, Validators.required] |
||||
|
}); |
||||
|
this.deviceConfigurationFormGroup.valueChanges.subscribe(() => { |
||||
|
this.updateModel(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (this.disabled) { |
||||
|
this.deviceConfigurationFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.deviceConfigurationFormGroup.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: DeviceConfiguration | null): void { |
||||
|
this.type = value?.type; |
||||
|
const configuration = deepClone(value); |
||||
|
if (configuration) { |
||||
|
delete configuration.type; |
||||
|
} |
||||
|
this.deviceConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); |
||||
|
} |
||||
|
|
||||
|
private updateModel() { |
||||
|
let configuration: DeviceConfiguration = null; |
||||
|
if (this.deviceConfigurationFormGroup.valid) { |
||||
|
configuration = this.deviceConfigurationFormGroup.getRawValue().configuration; |
||||
|
configuration.type = this.type; |
||||
|
} |
||||
|
this.propagateChange(configuration); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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]="deviceDataFormGroup" style="padding-bottom: 16px;"> |
||||
|
<mat-accordion multi="true"> |
||||
|
<mat-expansion-panel [expanded]="true"> |
||||
|
<mat-expansion-panel-header> |
||||
|
<mat-panel-title> |
||||
|
<div translate>device.device-configuration</div> |
||||
|
</mat-panel-title> |
||||
|
</mat-expansion-panel-header> |
||||
|
<tb-device-configuration |
||||
|
formControlName="configuration" |
||||
|
required> |
||||
|
</tb-device-configuration> |
||||
|
</mat-expansion-panel> |
||||
|
<mat-expansion-panel [expanded]="true"> |
||||
|
<mat-expansion-panel-header> |
||||
|
<mat-panel-title> |
||||
|
<div translate>device.transport-configuration</div> |
||||
|
</mat-panel-title> |
||||
|
</mat-expansion-panel-header> |
||||
|
<tb-device-transport-configuration |
||||
|
formControlName="transportConfiguration" |
||||
|
required> |
||||
|
</tb-device-transport-configuration> |
||||
|
</mat-expansion-panel> |
||||
|
</mat-accordion> |
||||
|
</div> |
||||
@ -0,0 +1,94 @@ |
|||||
|
///
|
||||
|
/// 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 { DeviceData } from '@shared/models/device.models'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-device-data', |
||||
|
templateUrl: './device-data.component.html', |
||||
|
styleUrls: [], |
||||
|
providers: [{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => DeviceDataComponent), |
||||
|
multi: true |
||||
|
}] |
||||
|
}) |
||||
|
export class DeviceDataComponent implements ControlValueAccessor, OnInit { |
||||
|
|
||||
|
deviceDataFormGroup: 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.deviceDataFormGroup = this.fb.group({ |
||||
|
configuration: [null, Validators.required], |
||||
|
transportConfiguration: [null, Validators.required] |
||||
|
}); |
||||
|
this.deviceDataFormGroup.valueChanges.subscribe(() => { |
||||
|
this.updateModel(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (this.disabled) { |
||||
|
this.deviceDataFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.deviceDataFormGroup.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: DeviceData | null): void { |
||||
|
this.deviceDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false}); |
||||
|
this.deviceDataFormGroup.patchValue({transportConfiguration: value?.transportConfiguration}, {emitEvent: false}); |
||||
|
} |
||||
|
|
||||
|
private updateModel() { |
||||
|
let deviceData: DeviceData = null; |
||||
|
if (this.deviceDataFormGroup.valid) { |
||||
|
deviceData = this.deviceDataFormGroup.getRawValue(); |
||||
|
} |
||||
|
this.propagateChange(deviceData); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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]="deviceTransportConfigurationFormGroup"> |
||||
|
<div [ngSwitch]="transportType"> |
||||
|
<ng-template [ngSwitchCase]="deviceTransportType.DEFAULT"> |
||||
|
<tb-default-device-transport-configuration |
||||
|
[required]="required" |
||||
|
formControlName="configuration"> |
||||
|
</tb-default-device-transport-configuration> |
||||
|
</ng-template> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,106 @@ |
|||||
|
///
|
||||
|
/// 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 |
||||
|
} from '@shared/models/device.models'; |
||||
|
import { deepClone } from '@core/utils'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-device-transport-configuration', |
||||
|
templateUrl: './device-transport-configuration.component.html', |
||||
|
styleUrls: [], |
||||
|
providers: [{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => DeviceTransportConfigurationComponent), |
||||
|
multi: true |
||||
|
}] |
||||
|
}) |
||||
|
export class DeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit { |
||||
|
|
||||
|
deviceTransportType = DeviceTransportType; |
||||
|
|
||||
|
deviceTransportConfigurationFormGroup: FormGroup; |
||||
|
|
||||
|
private requiredValue: boolean; |
||||
|
get required(): boolean { |
||||
|
return this.requiredValue; |
||||
|
} |
||||
|
@Input() |
||||
|
set required(value: boolean) { |
||||
|
this.requiredValue = coerceBooleanProperty(value); |
||||
|
} |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
transportType: DeviceTransportType; |
||||
|
|
||||
|
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.deviceTransportConfigurationFormGroup = this.fb.group({ |
||||
|
configuration: [null, Validators.required] |
||||
|
}); |
||||
|
this.deviceTransportConfigurationFormGroup.valueChanges.subscribe(() => { |
||||
|
this.updateModel(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (this.disabled) { |
||||
|
this.deviceTransportConfigurationFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.deviceTransportConfigurationFormGroup.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: DeviceTransportConfiguration | null): void { |
||||
|
this.transportType = value?.type; |
||||
|
const configuration = deepClone(value); |
||||
|
if (configuration) { |
||||
|
delete configuration.type; |
||||
|
} |
||||
|
this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); |
||||
|
} |
||||
|
|
||||
|
private updateModel() { |
||||
|
let configuration: DeviceTransportConfiguration = null; |
||||
|
if (this.deviceTransportConfigurationFormGroup.valid) { |
||||
|
configuration = this.deviceTransportConfigurationFormGroup.getRawValue().configuration; |
||||
|
configuration.type = this.transportType; |
||||
|
} |
||||
|
this.propagateChange(configuration); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue