37 changed files with 901 additions and 294 deletions
@ -0,0 +1,77 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2024 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]="valueSourceFormGroup" class="tb-value-source tb-form-row no-padding no-border"> |
||||
|
<div class="tb-source-field"> |
||||
|
<mat-form-field class="tb-type-field" appearance="outline" subscriptSizing="dynamic"> |
||||
|
<mat-select formControlName="type"> |
||||
|
<mat-option *ngFor="let type of valueSourceDataKeyTypes" [value]="type"> |
||||
|
{{ valueSourceDataKeyTypeTranslation.get(type) | translate }} |
||||
|
</mat-option> |
||||
|
</mat-select> |
||||
|
</mat-form-field> |
||||
|
<tb-entity-alias-input |
||||
|
class="tb-entity-alias-field" |
||||
|
*ngIf="valueSourceFormGroup.get('type').value === valueSourceDataKeyType.entity" |
||||
|
[aliasController]="aliasController" |
||||
|
required |
||||
|
formControlName="entityAlias"> |
||||
|
</tb-entity-alias-input> |
||||
|
</div> |
||||
|
<div class="tb-key-value-field"> |
||||
|
<mat-form-field *ngIf="valueSourceFormGroup.get('type').value === valueSourceDataKeyType.constant" |
||||
|
appearance="outline" class="tb-constant-field number" subscriptSizing="dynamic" |
||||
|
[class.tb-suffix-absolute]="!valueSourceFormGroup.get('value').value"> |
||||
|
<input required matInput formControlName="value" type="number" placeholder="{{ 'widget-config.set' | translate }}"> |
||||
|
<mat-icon matSuffix |
||||
|
matTooltipPosition="above" |
||||
|
matTooltipClass="tb-error-tooltip" |
||||
|
[matTooltip]="'widgets.value-source.value-required' | translate" |
||||
|
*ngIf="valueSourceFormGroup.get('value').hasError('required') |
||||
|
&& valueSourceFormGroup.get('value').touched" |
||||
|
class="tb-error"> |
||||
|
warning |
||||
|
</mat-icon> |
||||
|
</mat-form-field> |
||||
|
<tb-data-key-input |
||||
|
*ngIf="valueSourceFormGroup.get('type').value === valueSourceDataKeyType.latestKey" |
||||
|
required |
||||
|
requiredText="widgets.value-source.key-required" |
||||
|
[datasourceType]="datasource?.type" |
||||
|
[entityAliasId]="datasource?.entityAliasId" |
||||
|
[deviceId]="datasource?.deviceId" |
||||
|
[aliasController]="aliasController" |
||||
|
[dataKeyType]="datasource?.type === datasourceType.function ? dataKeyType.function : null" |
||||
|
[dataKeyTypes]="[dataKeyType.attribute, dataKeyType.timeseries]" |
||||
|
[callbacks]="dataKeyCallbacks" |
||||
|
[editable]="false" |
||||
|
[formControl]="latestKeyFormControl"> |
||||
|
</tb-data-key-input> |
||||
|
<tb-data-key-input |
||||
|
*ngIf="valueSourceFormGroup.get('type').value === valueSourceDataKeyType.entity" |
||||
|
required |
||||
|
requiredText="widgets.value-source.entity-key-required" |
||||
|
[datasourceType]="datasourceType.entity" |
||||
|
[aliasController]="aliasController" |
||||
|
[entityAlias]="valueSourceFormGroup.get('entityAlias').value" |
||||
|
[dataKeyTypes]="[dataKeyType.attribute, dataKeyType.timeseries]" |
||||
|
[callbacks]="dataKeyCallbacks" |
||||
|
[editable]="false" |
||||
|
[formControl]="entityKeyFormControl"> |
||||
|
</tb-data-key-input> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,40 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2024 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. |
||||
|
*/ |
||||
|
|
||||
|
:host { |
||||
|
.tb-value-source { |
||||
|
display: flex; |
||||
|
gap: 12px; |
||||
|
} |
||||
|
.tb-source-field { |
||||
|
display: flex; |
||||
|
flex: 1; |
||||
|
gap: 12px; |
||||
|
.tb-type-field, .tb-entity-alias-field { |
||||
|
flex: 1; |
||||
|
} |
||||
|
} |
||||
|
.tb-key-value-field, .tb-constant-field { |
||||
|
display: flex; |
||||
|
flex: 1; |
||||
|
} |
||||
|
::ng-deep { |
||||
|
.tb-data-key-input { |
||||
|
flex: 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,191 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2024 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 { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; |
||||
|
import { |
||||
|
ControlValueAccessor, |
||||
|
NG_VALUE_ACCESSOR, |
||||
|
UntypedFormBuilder, |
||||
|
UntypedFormControl, |
||||
|
UntypedFormGroup, |
||||
|
Validators |
||||
|
} from '@angular/forms'; |
||||
|
import { PageComponent } from '@shared/components/page.component'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { IAliasController } from '@core/api/widget-api.models'; |
||||
|
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; |
||||
|
import { DataKey, Datasource, DatasourceType } from '@app/shared/models/widget.models'; |
||||
|
import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models'; |
||||
|
import { |
||||
|
ValueSourceDataKeyType, |
||||
|
ValueSourceDataKeyTypes, |
||||
|
ValueSourceDataKeyTypeTranslation |
||||
|
} from '@shared/models/widget-settings.models'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-value-source-data-key', |
||||
|
templateUrl: './value-source-data-key.component.html', |
||||
|
styleUrls: ['value-source-data-key.component.scss'], |
||||
|
providers: [ |
||||
|
{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => ValueSourceDataKeyComponent), |
||||
|
multi: true |
||||
|
} |
||||
|
] |
||||
|
}) |
||||
|
export class ValueSourceDataKeyComponent extends PageComponent implements OnInit, ControlValueAccessor { |
||||
|
|
||||
|
dataKeyType = DataKeyType; |
||||
|
datasourceType = DatasourceType; |
||||
|
|
||||
|
valueSourceDataKeyType = ValueSourceDataKeyType; |
||||
|
valueSourceDataKeyTypes = ValueSourceDataKeyTypes; |
||||
|
valueSourceDataKeyTypeTranslation = ValueSourceDataKeyTypeTranslation; |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
@Input() |
||||
|
aliasController: IAliasController; |
||||
|
|
||||
|
@Input() |
||||
|
dataKeyCallbacks: DataKeysCallbacks; |
||||
|
|
||||
|
@Input() |
||||
|
datasource: Datasource; |
||||
|
|
||||
|
valueSourceFormGroup: UntypedFormGroup; |
||||
|
|
||||
|
modelValue; |
||||
|
|
||||
|
latestKeyFormControl: UntypedFormControl; |
||||
|
entityKeyFormControl: UntypedFormControl; |
||||
|
|
||||
|
private propagateChange = (_val: any) => {}; |
||||
|
|
||||
|
constructor(protected store: Store<AppState>, |
||||
|
private fb: UntypedFormBuilder, |
||||
|
private cd: ChangeDetectorRef) { |
||||
|
super(store); |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
this.valueSourceFormGroup = this.fb.group({ |
||||
|
type: [ValueSourceDataKeyType.constant, []], |
||||
|
value: [null, [Validators.required]], |
||||
|
entityAlias: [null, [Validators.required]] |
||||
|
}); |
||||
|
this.latestKeyFormControl = this.fb.control(null, [Validators.required]); |
||||
|
this.entityKeyFormControl = this.fb.control(null, [Validators.required]); |
||||
|
this.valueSourceFormGroup.valueChanges.subscribe( |
||||
|
() => this.updateModel() |
||||
|
); |
||||
|
this.latestKeyFormControl.valueChanges.subscribe( |
||||
|
() => this.updateModel() |
||||
|
); |
||||
|
this.entityKeyFormControl.valueChanges.subscribe( |
||||
|
() => this.updateModel() |
||||
|
); |
||||
|
this.valueSourceFormGroup.get('type').valueChanges.subscribe(() => { |
||||
|
this.updateValidators(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
registerOnChange(fn: any): void { |
||||
|
this.propagateChange = fn; |
||||
|
} |
||||
|
|
||||
|
registerOnTouched(fn: any): void { |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (isDisabled) { |
||||
|
this.valueSourceFormGroup.disable({emitEvent: false}); |
||||
|
this.latestKeyFormControl.disable({emitEvent: false}); |
||||
|
this.entityKeyFormControl.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.valueSourceFormGroup.enable({emitEvent: false}); |
||||
|
this.updateValidators(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value): void { |
||||
|
this.modelValue = value; |
||||
|
this.valueSourceFormGroup.patchValue( |
||||
|
{ |
||||
|
type: value.type, |
||||
|
value: value.value, |
||||
|
entityAlias: value.entityAlias |
||||
|
}, {emitEvent: false} |
||||
|
); |
||||
|
if (value.type === ValueSourceDataKeyType.latestKey) { |
||||
|
this.latestKeyFormControl.patchValue({ |
||||
|
type: value.latestKeyType, |
||||
|
name: value.latestKey |
||||
|
}, {emitEvent: false}); |
||||
|
} else if (value.type === ValueSourceDataKeyType.entity) { |
||||
|
this.entityKeyFormControl.patchValue({ |
||||
|
type: value.entityKeyType, |
||||
|
name: value.entityKey |
||||
|
}, {emitEvent: false}); |
||||
|
} |
||||
|
|
||||
|
this.updateValidators(); |
||||
|
this.cd.markForCheck(); |
||||
|
} |
||||
|
|
||||
|
private updateModel() { |
||||
|
const value = this.valueSourceFormGroup.value; |
||||
|
this.modelValue.type = value.type; |
||||
|
this.modelValue.value = value.value; |
||||
|
this.modelValue.entityAlias = value.entityAlias; |
||||
|
|
||||
|
if (value.type === ValueSourceDataKeyType.latestKey) { |
||||
|
const latestKey: DataKey = this.latestKeyFormControl.value; |
||||
|
this.modelValue.latestKey = latestKey?.name; |
||||
|
this.modelValue.latestKeyType = (latestKey?.type as any); |
||||
|
} else if (value.type === ValueSourceDataKeyType.entity) { |
||||
|
const entityKey: DataKey = this.entityKeyFormControl.value; |
||||
|
this.modelValue.entityKey = entityKey?.name; |
||||
|
this.modelValue.entityKeyType = (entityKey?.type as any); |
||||
|
} |
||||
|
this.propagateChange(this.modelValue); |
||||
|
} |
||||
|
|
||||
|
private updateValidators(): void { |
||||
|
const type: ValueSourceDataKeyType = this.valueSourceFormGroup.get('type').value; |
||||
|
if (type === ValueSourceDataKeyType.constant) { |
||||
|
this.valueSourceFormGroup.get('value').enable({emitEvent: false}); |
||||
|
this.valueSourceFormGroup.get('entityAlias').disable({emitEvent: false}); |
||||
|
this.latestKeyFormControl.disable({emitEvent: false}); |
||||
|
this.entityKeyFormControl.disable({emitEvent: false}); |
||||
|
} else if (type === ValueSourceDataKeyType.latestKey) { |
||||
|
this.valueSourceFormGroup.get('value').disable({emitEvent: false}); |
||||
|
this.valueSourceFormGroup.get('entityAlias').disable({emitEvent: false}); |
||||
|
this.latestKeyFormControl.enable({emitEvent: false}); |
||||
|
this.entityKeyFormControl.disable({emitEvent: false}); |
||||
|
} else if (type === ValueSourceDataKeyType.entity) { |
||||
|
this.valueSourceFormGroup.get('value').disable({emitEvent: false}); |
||||
|
this.valueSourceFormGroup.get('entityAlias').enable({emitEvent: false}); |
||||
|
this.latestKeyFormControl.disable({emitEvent: false}); |
||||
|
this.entityKeyFormControl.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue