15 changed files with 895 additions and 10 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,31 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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. |
|||
|
|||
--> |
|||
|
|||
<section class="tb-widget-settings" [formGroup]="roundSwitchWidgetSettingsForm" fxLayout="column"> |
|||
<fieldset class="fields-group"> |
|||
<legend class="group-title" translate>widgets.rpc.common-settings</legend> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.switch-title</mat-label> |
|||
<input matInput formControlName="title"> |
|||
</mat-form-field> |
|||
</fieldset> |
|||
<tb-switch-rpc-settings [aliasController]="aliasController" |
|||
[targetDeviceAliasId]="targetDeviceAliasId" |
|||
formControlName="switchRpcSettings"> |
|||
</tb-switch-rpc-settings> |
|||
</section> |
|||
@ -0,0 +1,79 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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 } from '@angular/core'; |
|||
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; |
|||
import { FormBuilder, FormGroup } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { switchRpcDefaultSettings } from '@home/components/widget/lib/settings/control/switch-rpc-settings.component'; |
|||
import { deepClone } from '@core/utils'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-round-switch-widget-settings', |
|||
templateUrl: './round-switch-widget-settings.component.html', |
|||
styleUrls: ['./../widget-settings.scss'] |
|||
}) |
|||
export class RoundSwitchWidgetSettingsComponent extends WidgetSettingsComponent { |
|||
|
|||
roundSwitchWidgetSettingsForm: FormGroup; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
private fb: FormBuilder) { |
|||
super(store); |
|||
} |
|||
|
|||
get targetDeviceAliasId(): string { |
|||
const aliasIds = this.widget.config.targetDeviceAliasIds; |
|||
if (aliasIds && aliasIds.length) { |
|||
return aliasIds[0]; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
protected settingsForm(): FormGroup { |
|||
return this.roundSwitchWidgetSettingsForm; |
|||
} |
|||
|
|||
protected defaultSettings(): WidgetSettings { |
|||
return { |
|||
title: '', |
|||
...switchRpcDefaultSettings() |
|||
}; |
|||
} |
|||
|
|||
protected onSettingsSet(settings: WidgetSettings) { |
|||
this.roundSwitchWidgetSettingsForm = this.fb.group({ |
|||
title: [settings.title, []], |
|||
switchRpcSettings: [settings.switchRpcSettings, []] |
|||
}); |
|||
} |
|||
|
|||
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { |
|||
const switchRpcSettings = deepClone(settings, ['title']); |
|||
return { |
|||
title: settings.title, |
|||
switchRpcSettings |
|||
}; |
|||
} |
|||
|
|||
protected prepareOutputSettings(settings: any): WidgetSettings { |
|||
return { |
|||
title: settings.title, |
|||
...settings.switchRpcSettings |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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. |
|||
|
|||
--> |
|||
|
|||
<section class="tb-widget-settings" [formGroup]="slideToggleWidgetSettingsForm" fxLayout="column"> |
|||
<fieldset class="fields-group"> |
|||
<legend class="group-title" translate>widgets.rpc.common-settings</legend> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.slide-toggle-label</mat-label> |
|||
<input matInput formControlName="title"> |
|||
</mat-form-field> |
|||
<section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="8px"> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.label-position</mat-label> |
|||
<mat-select formControlName="labelPosition"> |
|||
<mat-option [value]="'before'"> |
|||
{{ 'widgets.rpc.label-position-before' | translate }} |
|||
</mat-option> |
|||
<mat-option [value]="'after'"> |
|||
{{ 'widgets.rpc.label-position-after' | translate }} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.slider-color</mat-label> |
|||
<mat-select formControlName="sliderColor"> |
|||
<mat-option [value]="'primary'"> |
|||
{{ 'widgets.rpc.slider-color-primary' | translate }} |
|||
</mat-option> |
|||
<mat-option [value]="'accent'"> |
|||
{{ 'widgets.rpc.slider-color-accent' | translate }} |
|||
</mat-option> |
|||
<mat-option [value]="'warn'"> |
|||
{{ 'widgets.rpc.slider-color-warn' | translate }} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
</section> |
|||
</fieldset> |
|||
<tb-switch-rpc-settings [aliasController]="aliasController" |
|||
[targetDeviceAliasId]="targetDeviceAliasId" |
|||
formControlName="switchRpcSettings"> |
|||
</tb-switch-rpc-settings> |
|||
</section> |
|||
@ -0,0 +1,87 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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 } from '@angular/core'; |
|||
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; |
|||
import { FormBuilder, FormGroup } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { switchRpcDefaultSettings } from '@home/components/widget/lib/settings/control/switch-rpc-settings.component'; |
|||
import { deepClone } from '@core/utils'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-slide-toggle-widget-settings', |
|||
templateUrl: './slide-toggle-widget-settings.component.html', |
|||
styleUrls: ['./../widget-settings.scss'] |
|||
}) |
|||
export class SlideToggleWidgetSettingsComponent extends WidgetSettingsComponent { |
|||
|
|||
slideToggleWidgetSettingsForm: FormGroup; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
private fb: FormBuilder) { |
|||
super(store); |
|||
} |
|||
|
|||
get targetDeviceAliasId(): string { |
|||
const aliasIds = this.widget.config.targetDeviceAliasIds; |
|||
if (aliasIds && aliasIds.length) { |
|||
return aliasIds[0]; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
protected settingsForm(): FormGroup { |
|||
return this.slideToggleWidgetSettingsForm; |
|||
} |
|||
|
|||
protected defaultSettings(): WidgetSettings { |
|||
return { |
|||
title: '', |
|||
labelPosition: 'after', |
|||
sliderColor: 'accent', |
|||
...switchRpcDefaultSettings() |
|||
}; |
|||
} |
|||
|
|||
protected onSettingsSet(settings: WidgetSettings) { |
|||
this.slideToggleWidgetSettingsForm = this.fb.group({ |
|||
title: [settings.title, []], |
|||
labelPosition: [settings.labelPosition, []], |
|||
sliderColor: [settings.sliderColor, []], |
|||
switchRpcSettings: [settings.switchRpcSettings, []] |
|||
}); |
|||
} |
|||
|
|||
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { |
|||
const switchRpcSettings = deepClone(settings, ['title', 'labelPosition', 'sliderColor']); |
|||
return { |
|||
title: settings.title, |
|||
labelPosition: settings.labelPosition, |
|||
sliderColor: settings.sliderColor, |
|||
switchRpcSettings |
|||
}; |
|||
} |
|||
|
|||
protected prepareOutputSettings(settings: any): WidgetSettings { |
|||
return { |
|||
title: settings.title, |
|||
labelPosition: settings.labelPosition, |
|||
sliderColor: settings.sliderColor, |
|||
...settings.switchRpcSettings |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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. |
|||
|
|||
--> |
|||
|
|||
<section class="tb-widget-settings" [formGroup]="switchControlWidgetSettingsForm" fxLayout="column"> |
|||
<fieldset class="fields-group"> |
|||
<legend class="group-title" translate>widgets.rpc.common-settings</legend> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.switch-title</mat-label> |
|||
<input matInput formControlName="title"> |
|||
</mat-form-field> |
|||
<mat-slide-toggle formControlName="showOnOffLabels" class="slide-block"> |
|||
{{ 'widgets.rpc.show-on-off-labels' | translate }} |
|||
</mat-slide-toggle> |
|||
</fieldset> |
|||
<tb-switch-rpc-settings [aliasController]="aliasController" |
|||
[targetDeviceAliasId]="targetDeviceAliasId" |
|||
formControlName="switchRpcSettings"> |
|||
</tb-switch-rpc-settings> |
|||
</section> |
|||
@ -0,0 +1,83 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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 } from '@angular/core'; |
|||
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; |
|||
import { FormBuilder, FormGroup } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { switchRpcDefaultSettings } from '@home/components/widget/lib/settings/control/switch-rpc-settings.component'; |
|||
import { deepClone } from '@core/utils'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-switch-control-widget-settings', |
|||
templateUrl: './switch-control-widget-settings.component.html', |
|||
styleUrls: ['./../widget-settings.scss'] |
|||
}) |
|||
export class SwitchControlWidgetSettingsComponent extends WidgetSettingsComponent { |
|||
|
|||
switchControlWidgetSettingsForm: FormGroup; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
private fb: FormBuilder) { |
|||
super(store); |
|||
} |
|||
|
|||
get targetDeviceAliasId(): string { |
|||
const aliasIds = this.widget.config.targetDeviceAliasIds; |
|||
if (aliasIds && aliasIds.length) { |
|||
return aliasIds[0]; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
protected settingsForm(): FormGroup { |
|||
return this.switchControlWidgetSettingsForm; |
|||
} |
|||
|
|||
protected defaultSettings(): WidgetSettings { |
|||
return { |
|||
title: '', |
|||
showOnOffLabels: true, |
|||
...switchRpcDefaultSettings() |
|||
}; |
|||
} |
|||
|
|||
protected onSettingsSet(settings: WidgetSettings) { |
|||
this.switchControlWidgetSettingsForm = this.fb.group({ |
|||
title: [settings.title, []], |
|||
showOnOffLabels: [settings.showOnOffLabels, []], |
|||
switchRpcSettings: [settings.switchRpcSettings, []] |
|||
}); |
|||
} |
|||
|
|||
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { |
|||
const switchRpcSettings = deepClone(settings, ['title', 'showOnOffLabels']); |
|||
return { |
|||
title: settings.title, |
|||
showOnOffLabels: settings.showOnOffLabels, |
|||
switchRpcSettings |
|||
}; |
|||
} |
|||
|
|||
protected prepareOutputSettings(settings: any): WidgetSettings { |
|||
return { |
|||
title: settings.title, |
|||
showOnOffLabels: settings.showOnOffLabels, |
|||
...settings.switchRpcSettings |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,123 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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. |
|||
|
|||
--> |
|||
<section class="tb-widget-settings" [formGroup]="switchRpcSettingsFormGroup" fxLayout="column"> |
|||
<fieldset class="fields-group"> |
|||
<legend class="group-title" translate>widgets.rpc.value-settings</legend> |
|||
<mat-checkbox formControlName="initialValue" style="margin-bottom: 16px;"> |
|||
{{ 'widgets.rpc.initial-value' | translate }} |
|||
</mat-checkbox> |
|||
<fieldset class="fields-group"> |
|||
<legend class="group-title" translate>widgets.rpc.retrieve-value-settings</legend> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.retrieve-value-method</mat-label> |
|||
<mat-select formControlName="retrieveValueMethod"> |
|||
<mat-option [value]="'none'"> |
|||
{{ 'widgets.rpc.retrieve-value-method-none' | translate }} |
|||
</mat-option> |
|||
<mat-option [value]="'rpc'"> |
|||
{{ 'widgets.rpc.retrieve-value-method-rpc' | translate }} |
|||
</mat-option> |
|||
<mat-option [value]="'attribute'"> |
|||
{{ 'widgets.rpc.retrieve-value-method-attribute' | translate }} |
|||
</mat-option> |
|||
<mat-option [value]="'timeseries'"> |
|||
{{ 'widgets.rpc.retrieve-value-method-timeseries' | translate }} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
<mat-form-field [fxShow]="switchRpcSettingsFormGroup.get('retrieveValueMethod').value === 'attribute' || |
|||
switchRpcSettingsFormGroup.get('retrieveValueMethod').value === 'timeseries'" fxFlex class="mat-block"> |
|||
<mat-label>{{ (switchRpcSettingsFormGroup.get('retrieveValueMethod').value === 'attribute' |
|||
? 'widgets.rpc.attribute-value-key' |
|||
: 'widgets.rpc.timeseries-value-key') | translate }}</mat-label> |
|||
<input required matInput |
|||
type="text" placeholder="{{ 'entity.key-name' | translate }}" |
|||
#keyInput |
|||
formControlName="valueKey" |
|||
[matAutocomplete]="keyAutocomplete"> |
|||
<button *ngIf="switchRpcSettingsFormGroup.get('valueKey').value && !switchRpcSettingsFormGroup.get('valueKey').disabled" |
|||
type="button" |
|||
matSuffix mat-icon-button aria-label="Clear" |
|||
(click)="clearKey()"> |
|||
<mat-icon class="material-icons">close</mat-icon> |
|||
</button> |
|||
<mat-autocomplete |
|||
class="tb-autocomplete" |
|||
#keyAutocomplete="matAutocomplete"> |
|||
<mat-option *ngFor="let key of filteredKeys | async" [value]="key"> |
|||
<span [innerHTML]="key | highlight:keySearchText"></span> |
|||
</mat-option> |
|||
</mat-autocomplete> |
|||
</mat-form-field> |
|||
<mat-form-field [fxShow]="switchRpcSettingsFormGroup.get('retrieveValueMethod').value === 'rpc'" fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.get-value-method</mat-label> |
|||
<input required matInput formControlName="getValueMethod"> |
|||
</mat-form-field> |
|||
<tb-js-func [fxHide]="switchRpcSettingsFormGroup.get('retrieveValueMethod').value === 'none'" |
|||
formControlName="parseValueFunction" |
|||
[globalVariables]="functionScopeVariables" |
|||
[functionArgs]="['data']" |
|||
functionTitle="{{ 'widgets.rpc.parse-value-function' | translate }}" |
|||
helpId="widget/lib/rpc/parse_value_fn"> |
|||
</tb-js-func> |
|||
</fieldset> |
|||
<fieldset class="fields-group"> |
|||
<legend class="group-title" translate>widgets.rpc.update-value-settings</legend> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.set-value-method</mat-label> |
|||
<input required matInput formControlName="setValueMethod"> |
|||
</mat-form-field> |
|||
<tb-js-func |
|||
formControlName="convertValueFunction" |
|||
[globalVariables]="functionScopeVariables" |
|||
[functionArgs]="['value']" |
|||
functionTitle="{{ 'widgets.rpc.convert-value-function' | translate }}" |
|||
helpId="widget/lib/rpc/convert_value_fn"> |
|||
</tb-js-func> |
|||
</fieldset> |
|||
</fieldset> |
|||
<fieldset class="fields-group"> |
|||
<legend class="group-title" translate>widgets.rpc.rpc-settings</legend> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.request-timeout</mat-label> |
|||
<input matInput type="number" min="0" formControlName="requestTimeout"> |
|||
</mat-form-field> |
|||
<fieldset class="fields-group fields-group-slider"> |
|||
<legend class="group-title" translate>widgets.rpc.persistent-rpc-settings</legend> |
|||
<mat-expansion-panel class="tb-settings" [expanded]="switchRpcSettingsFormGroup.get('requestPersistent').value"> |
|||
<mat-expansion-panel-header fxLayout="row wrap"> |
|||
<mat-panel-title> |
|||
<mat-slide-toggle formControlName="requestPersistent" (click)="$event.stopPropagation()" |
|||
fxLayoutAlign="center"> |
|||
{{ 'widgets.rpc.request-persistent' | translate }} |
|||
</mat-slide-toggle> |
|||
</mat-panel-title> |
|||
<mat-panel-description fxLayoutAlign="end center" fxHide.xs translate> |
|||
widget-config.advanced-settings |
|||
</mat-panel-description> |
|||
</mat-expansion-panel-header> |
|||
<ng-template matExpansionPanelContent> |
|||
<mat-form-field fxFlex class="mat-block"> |
|||
<mat-label translate>widgets.rpc.persistent-polling-interval</mat-label> |
|||
<input matInput type="number" min="1000" formControlName="persistentPollingInterval"> |
|||
</mat-form-field> |
|||
</ng-template> |
|||
</mat-expansion-panel> |
|||
</fieldset> |
|||
</fieldset> |
|||
</section> |
|||
@ -0,0 +1,308 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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, forwardRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core'; |
|||
import { |
|||
ControlValueAccessor, |
|||
FormBuilder, |
|||
FormControl, |
|||
FormGroup, |
|||
NG_VALIDATORS, |
|||
NG_VALUE_ACCESSOR, |
|||
Validator, |
|||
Validators |
|||
} from '@angular/forms'; |
|||
import { PageComponent } from '@shared/components/page.component'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; |
|||
import { WidgetService } from '@core/http/widget.service'; |
|||
import { Observable, of } from 'rxjs'; |
|||
import { IAliasController } from '@core/api/widget-api.models'; |
|||
import { catchError, map, mergeMap, publishReplay, refCount, tap } from 'rxjs/operators'; |
|||
import { DataKey } from '@shared/models/widget.models'; |
|||
import { EntityService } from '@core/http/entity.service'; |
|||
|
|||
export declare type RpcRetrieveValueMethod = 'none' | 'rpc' | 'attribute' | 'timeseries'; |
|||
|
|||
export interface SwitchRpcSettings { |
|||
initialValue: boolean; |
|||
retrieveValueMethod: RpcRetrieveValueMethod; |
|||
valueKey: string; |
|||
getValueMethod: string; |
|||
setValueMethod: string; |
|||
parseValueFunction: string; |
|||
convertValueFunction: string; |
|||
requestTimeout: number; |
|||
requestPersistent: boolean; |
|||
persistentPollingInterval: number; |
|||
} |
|||
|
|||
export function switchRpcDefaultSettings(): SwitchRpcSettings { |
|||
return { |
|||
initialValue: false, |
|||
retrieveValueMethod: 'rpc', |
|||
valueKey: 'value', |
|||
getValueMethod: 'getValue', |
|||
parseValueFunction: 'return data ? true : false;', |
|||
setValueMethod: 'setValue', |
|||
convertValueFunction: 'return value;', |
|||
requestTimeout: 500, |
|||
requestPersistent: false, |
|||
persistentPollingInterval: 5000 |
|||
}; |
|||
} |
|||
|
|||
@Component({ |
|||
selector: 'tb-switch-rpc-settings', |
|||
templateUrl: './switch-rpc-settings.component.html', |
|||
styleUrls: ['./../widget-settings.scss'], |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => SwitchRpcSettingsComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => SwitchRpcSettingsComponent), |
|||
multi: true |
|||
} |
|||
] |
|||
}) |
|||
export class SwitchRpcSettingsComponent extends PageComponent implements OnInit, ControlValueAccessor, Validator, OnChanges { |
|||
|
|||
@ViewChild('keyInput') keyInput: ElementRef; |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
@Input() |
|||
aliasController: IAliasController; |
|||
|
|||
@Input() |
|||
targetDeviceAliasId: string; |
|||
|
|||
functionScopeVariables = this.widgetService.getWidgetScopeVariables(); |
|||
|
|||
private modelValue: SwitchRpcSettings; |
|||
|
|||
private propagateChange = null; |
|||
|
|||
public switchRpcSettingsFormGroup: FormGroup; |
|||
|
|||
filteredKeys: Observable<Array<string>>; |
|||
keySearchText = ''; |
|||
|
|||
private latestKeySearchResult: Array<string> = null; |
|||
private keysFetchObservable$: Observable<Array<string>> = null; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
private translate: TranslateService, |
|||
private widgetService: WidgetService, |
|||
private entityService: EntityService, |
|||
private fb: FormBuilder) { |
|||
super(store); |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
this.switchRpcSettingsFormGroup = this.fb.group({ |
|||
|
|||
// Value settings
|
|||
|
|||
initialValue: [false, []], |
|||
|
|||
// --> Retrieve value settings
|
|||
|
|||
retrieveValueMethod: ['rpc', []], |
|||
valueKey: ['value', [Validators.required]], |
|||
getValueMethod: ['getValue', [Validators.required]], |
|||
parseValueFunction: ['return data ? true : false;', []], |
|||
|
|||
// --> Update value settings
|
|||
|
|||
setValueMethod: ['setValue', [Validators.required]], |
|||
convertValueFunction: ['return value;', []], |
|||
|
|||
// RPC settings
|
|||
|
|||
requestTimeout: [500, [Validators.min(0)]], |
|||
|
|||
// Persistent RPC settings
|
|||
|
|||
requestPersistent: [false, []], |
|||
persistentPollingInterval: [5000, [Validators.min(1000)]], |
|||
}); |
|||
this.switchRpcSettingsFormGroup.get('retrieveValueMethod').valueChanges.subscribe(() => { |
|||
this.clearKeysCache(); |
|||
this.updateValidators(true); |
|||
}); |
|||
this.switchRpcSettingsFormGroup.get('requestPersistent').valueChanges.subscribe(() => { |
|||
this.updateValidators(true); |
|||
}); |
|||
this.switchRpcSettingsFormGroup.valueChanges.subscribe(() => { |
|||
this.updateModel(); |
|||
}); |
|||
this.updateValidators(false); |
|||
|
|||
this.filteredKeys = this.switchRpcSettingsFormGroup.get('valueKey').valueChanges |
|||
.pipe( |
|||
map(value => value ? value : ''), |
|||
mergeMap(name => this.fetchKeys(name) ) |
|||
); |
|||
} |
|||
|
|||
ngOnChanges(changes: SimpleChanges): void { |
|||
for (const propName of Object.keys(changes)) { |
|||
const change = changes[propName]; |
|||
if (!change.firstChange && change.currentValue !== change.previousValue) { |
|||
if (propName === 'targetDeviceAliasId') { |
|||
this.clearKeysCache(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (isDisabled) { |
|||
this.switchRpcSettingsFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.switchRpcSettingsFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: SwitchRpcSettings): void { |
|||
this.modelValue = value; |
|||
this.switchRpcSettingsFormGroup.patchValue( |
|||
value, {emitEvent: false} |
|||
); |
|||
this.updateValidators(false); |
|||
} |
|||
|
|||
clearKey() { |
|||
this.switchRpcSettingsFormGroup.get('valueKey').patchValue(null, {emitEvent: true}); |
|||
setTimeout(() => { |
|||
this.keyInput.nativeElement.blur(); |
|||
this.keyInput.nativeElement.focus(); |
|||
}, 0); |
|||
} |
|||
|
|||
public validate(c: FormControl) { |
|||
return this.switchRpcSettingsFormGroup.valid ? null : { |
|||
switchRpcSettings: { |
|||
valid: false, |
|||
}, |
|||
}; |
|||
} |
|||
|
|||
private updateModel() { |
|||
const value: SwitchRpcSettings = this.switchRpcSettingsFormGroup.value; |
|||
this.modelValue = value; |
|||
this.propagateChange(this.modelValue); |
|||
} |
|||
|
|||
private updateValidators(emitEvent?: boolean): void { |
|||
const retrieveValueMethod: RpcRetrieveValueMethod = this.switchRpcSettingsFormGroup.get('retrieveValueMethod').value; |
|||
const requestPersistent: boolean = this.switchRpcSettingsFormGroup.get('requestPersistent').value; |
|||
if (retrieveValueMethod === 'none') { |
|||
this.switchRpcSettingsFormGroup.get('valueKey').disable({emitEvent}); |
|||
this.switchRpcSettingsFormGroup.get('getValueMethod').disable({emitEvent}); |
|||
this.switchRpcSettingsFormGroup.get('parseValueFunction').disable({emitEvent}); |
|||
} else if (retrieveValueMethod === 'rpc') { |
|||
this.switchRpcSettingsFormGroup.get('valueKey').disable({emitEvent}); |
|||
this.switchRpcSettingsFormGroup.get('getValueMethod').enable({emitEvent}); |
|||
this.switchRpcSettingsFormGroup.get('parseValueFunction').enable({emitEvent}); |
|||
} else { |
|||
this.switchRpcSettingsFormGroup.get('valueKey').enable({emitEvent}); |
|||
this.switchRpcSettingsFormGroup.get('getValueMethod').disable({emitEvent}); |
|||
this.switchRpcSettingsFormGroup.get('parseValueFunction').enable({emitEvent}); |
|||
} |
|||
if (requestPersistent) { |
|||
this.switchRpcSettingsFormGroup.get('persistentPollingInterval').enable({emitEvent}); |
|||
} else { |
|||
this.switchRpcSettingsFormGroup.get('persistentPollingInterval').disable({emitEvent}); |
|||
} |
|||
this.switchRpcSettingsFormGroup.get('valueKey').updateValueAndValidity({emitEvent: false}); |
|||
this.switchRpcSettingsFormGroup.get('getValueMethod').updateValueAndValidity({emitEvent: false}); |
|||
this.switchRpcSettingsFormGroup.get('parseValueFunction').updateValueAndValidity({emitEvent: false}); |
|||
this.switchRpcSettingsFormGroup.get('persistentPollingInterval').updateValueAndValidity({emitEvent: false}); |
|||
} |
|||
|
|||
private clearKeysCache(): void { |
|||
this.latestKeySearchResult = null; |
|||
this.keysFetchObservable$ = null; |
|||
} |
|||
|
|||
private fetchKeys(searchText?: string): Observable<Array<string>> { |
|||
if (this.keySearchText !== searchText || this.latestKeySearchResult === null) { |
|||
this.keySearchText = searchText; |
|||
const dataKeyFilter = this.createKeyFilter(this.keySearchText); |
|||
return this.getKeys().pipe( |
|||
map(name => name.filter(dataKeyFilter)), |
|||
tap(res => this.latestKeySearchResult = res) |
|||
); |
|||
} |
|||
return of(this.latestKeySearchResult); |
|||
} |
|||
|
|||
private getKeys() { |
|||
if (this.keysFetchObservable$ === null) { |
|||
let fetchObservable: Observable<Array<DataKey>>; |
|||
if (this.targetDeviceAliasId) { |
|||
const retrieveValueMethod: RpcRetrieveValueMethod = this.switchRpcSettingsFormGroup.get('retrieveValueMethod').value; |
|||
const dataKeyTypes = retrieveValueMethod === 'attribute' ? [DataKeyType.attribute] : [DataKeyType.timeseries]; |
|||
fetchObservable = this.fetchEntityKeys(this.targetDeviceAliasId, dataKeyTypes); |
|||
} else { |
|||
fetchObservable = of([]); |
|||
} |
|||
this.keysFetchObservable$ = fetchObservable.pipe( |
|||
map((dataKeys) => dataKeys.map((dataKey) => dataKey.name)), |
|||
publishReplay(1), |
|||
refCount() |
|||
); |
|||
} |
|||
return this.keysFetchObservable$; |
|||
} |
|||
|
|||
private fetchEntityKeys(entityAliasId: string, dataKeyTypes: Array<DataKeyType>): Observable<Array<DataKey>> { |
|||
return this.aliasController.getAliasInfo(entityAliasId).pipe( |
|||
mergeMap((aliasInfo) => { |
|||
return this.entityService.getEntityKeysByEntityFilter( |
|||
aliasInfo.entityFilter, |
|||
dataKeyTypes, |
|||
{ignoreLoading: true, ignoreErrors: true} |
|||
).pipe( |
|||
catchError(() => of([])) |
|||
); |
|||
}), |
|||
catchError(() => of([] as Array<DataKey>)) |
|||
); |
|||
} |
|||
|
|||
private createKeyFilter(query: string): (key: string) => boolean { |
|||
const lowercaseQuery = query.toLowerCase(); |
|||
return key => key.toLowerCase().startsWith(lowercaseQuery); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue