Browse Source

UI: Add settings forms for 'Slide toggle'/'Round switch'/'Switch control' control widgets.

pull/6545/head
Igor Kulikov 5 years ago
parent
commit
54d256279a
  1. 9
      application/src/main/data/json/system/widget_bundles/control_widgets.json
  2. 8
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-key-settings.component.ts
  3. 8
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-widget-settings.component.ts
  4. 8
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-key-settings.component.ts
  5. 9
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-widget-settings.component.ts
  6. 31
      ui-ngx/src/app/modules/home/components/widget/lib/settings/control/round-switch-widget-settings.component.html
  7. 79
      ui-ngx/src/app/modules/home/components/widget/lib/settings/control/round-switch-widget-settings.component.ts
  8. 58
      ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.html
  9. 87
      ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.ts
  10. 34
      ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.html
  11. 83
      ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.ts
  12. 123
      ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.html
  13. 308
      ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.ts
  14. 27
      ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
  15. 33
      ui-ngx/src/assets/locale/locale.constant-en_US.json

9
application/src/main/data/json/system/widget_bundles/control_widgets.json

File diff suppressed because one or more lines are too long

8
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-key-settings.component.ts

@ -45,10 +45,16 @@ export class FlotBarKeySettingsComponent extends WidgetSettingsComponent {
protected onSettingsSet(settings: WidgetSettings) { protected onSettingsSet(settings: WidgetSettings) {
this.flotBarKeySettingsForm = this.fb.group({ this.flotBarKeySettingsForm = this.fb.group({
flotKeySettings: [settings, []] flotKeySettings: [settings.flotKeySettings, []]
}); });
} }
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
return {
flotKeySettings: settings
};
}
protected prepareOutputSettings(settings: any): WidgetSettings { protected prepareOutputSettings(settings: any): WidgetSettings {
return settings.flotKeySettings; return settings.flotKeySettings;
} }

8
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-widget-settings.component.ts

@ -45,10 +45,16 @@ export class FlotBarWidgetSettingsComponent extends WidgetSettingsComponent {
protected onSettingsSet(settings: WidgetSettings) { protected onSettingsSet(settings: WidgetSettings) {
this.flotBarWidgetSettingsForm = this.fb.group({ this.flotBarWidgetSettingsForm = this.fb.group({
flotSettings: [settings, []] flotSettings: [settings.flotSettings, []]
}); });
} }
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
return {
flotSettings: settings
};
}
protected prepareOutputSettings(settings: any): WidgetSettings { protected prepareOutputSettings(settings: any): WidgetSettings {
return settings.flotSettings; return settings.flotSettings;
} }

8
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-key-settings.component.ts

@ -45,10 +45,16 @@ export class FlotLineKeySettingsComponent extends WidgetSettingsComponent {
protected onSettingsSet(settings: WidgetSettings) { protected onSettingsSet(settings: WidgetSettings) {
this.flotLineKeySettingsForm = this.fb.group({ this.flotLineKeySettingsForm = this.fb.group({
flotKeySettings: [settings, []] flotKeySettings: [settings.flotKeySettings, []]
}); });
} }
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
return {
flotKeySettings: settings
};
}
protected prepareOutputSettings(settings: any): WidgetSettings { protected prepareOutputSettings(settings: any): WidgetSettings {
return settings.flotKeySettings; return settings.flotKeySettings;
} }

9
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-widget-settings.component.ts

@ -20,6 +20,7 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { flotDefaultSettings } from '@home/components/widget/lib/settings/chart/flot-widget-settings.component'; import { flotDefaultSettings } from '@home/components/widget/lib/settings/chart/flot-widget-settings.component';
import { deepClone } from '@core/utils';
@Component({ @Component({
selector: 'tb-flot-line-widget-settings', selector: 'tb-flot-line-widget-settings',
@ -45,10 +46,16 @@ export class FlotLineWidgetSettingsComponent extends WidgetSettingsComponent {
protected onSettingsSet(settings: WidgetSettings) { protected onSettingsSet(settings: WidgetSettings) {
this.flotLineWidgetSettingsForm = this.fb.group({ this.flotLineWidgetSettingsForm = this.fb.group({
flotSettings: [settings, []] flotSettings: [settings.flotSettings, []]
}); });
} }
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
return {
flotSettings: settings
};
}
protected prepareOutputSettings(settings: any): WidgetSettings { protected prepareOutputSettings(settings: any): WidgetSettings {
return settings.flotSettings; return settings.flotSettings;
} }

31
ui-ngx/src/app/modules/home/components/widget/lib/settings/control/round-switch-widget-settings.component.html

@ -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>

79
ui-ngx/src/app/modules/home/components/widget/lib/settings/control/round-switch-widget-settings.component.ts

@ -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
};
}
}

58
ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.html

@ -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>

87
ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.ts

@ -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
};
}
}

34
ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.html

@ -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>

83
ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.ts

@ -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
};
}
}

123
ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.html

@ -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>

308
ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.ts

@ -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);
}
}

27
ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts

@ -106,6 +106,16 @@ import {
import { import {
DoughnutChartWidgetSettingsComponent DoughnutChartWidgetSettingsComponent
} from '@home/components/widget/lib/settings/chart/doughnut-chart-widget-settings.component'; } from '@home/components/widget/lib/settings/chart/doughnut-chart-widget-settings.component';
import { SwitchRpcSettingsComponent } from '@home/components/widget/lib/settings/control/switch-rpc-settings.component';
import {
RoundSwitchWidgetSettingsComponent
} from '@home/components/widget/lib/settings/control/round-switch-widget-settings.component';
import {
SwitchControlWidgetSettingsComponent
} from '@home/components/widget/lib/settings/control/switch-control-widget-settings.component';
import {
SlideToggleWidgetSettingsComponent
} from '@home/components/widget/lib/settings/control/slide-toggle-widget-settings.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -145,7 +155,11 @@ import {
FlotPieWidgetSettingsComponent, FlotPieWidgetSettingsComponent,
FlotPieKeySettingsComponent, FlotPieKeySettingsComponent,
ChartWidgetSettingsComponent, ChartWidgetSettingsComponent,
DoughnutChartWidgetSettingsComponent DoughnutChartWidgetSettingsComponent,
SwitchRpcSettingsComponent,
RoundSwitchWidgetSettingsComponent,
SwitchControlWidgetSettingsComponent,
SlideToggleWidgetSettingsComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -189,7 +203,11 @@ import {
FlotPieWidgetSettingsComponent, FlotPieWidgetSettingsComponent,
FlotPieKeySettingsComponent, FlotPieKeySettingsComponent,
ChartWidgetSettingsComponent, ChartWidgetSettingsComponent,
DoughnutChartWidgetSettingsComponent DoughnutChartWidgetSettingsComponent,
SwitchRpcSettingsComponent,
RoundSwitchWidgetSettingsComponent,
SwitchControlWidgetSettingsComponent,
SlideToggleWidgetSettingsComponent
] ]
}) })
export class WidgetSettingsModule { export class WidgetSettingsModule {
@ -222,5 +240,8 @@ export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsCo
'tb-flot-pie-widget-settings': FlotPieWidgetSettingsComponent, 'tb-flot-pie-widget-settings': FlotPieWidgetSettingsComponent,
'tb-flot-pie-key-settings': FlotPieKeySettingsComponent, 'tb-flot-pie-key-settings': FlotPieKeySettingsComponent,
'tb-chart-widget-settings': ChartWidgetSettingsComponent, 'tb-chart-widget-settings': ChartWidgetSettingsComponent,
'tb-doughnut-chart-widget-settings': DoughnutChartWidgetSettingsComponent 'tb-doughnut-chart-widget-settings': DoughnutChartWidgetSettingsComponent,
'tb-round-switch-widget-settings': RoundSwitchWidgetSettingsComponent,
'tb-switch-control-widget-settings': SwitchControlWidgetSettingsComponent,
'tb-slide-toggle-widget-settings': SlideToggleWidgetSettingsComponent
}; };

33
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -3599,6 +3599,39 @@
"true": "One-way" "true": "One-way"
} }
}, },
"rpc": {
"value-settings": "Value settings",
"initial-value": "Initial value",
"retrieve-value-settings": "Retrieve on/off value settings",
"retrieve-value-method": "Retrieve value using method",
"retrieve-value-method-none": "Don't retrieve",
"retrieve-value-method-rpc": "Call RPC get value method",
"retrieve-value-method-attribute": "Subscribe for attribute",
"retrieve-value-method-timeseries": "Subscribe for timeseries",
"attribute-value-key": "Attribute key",
"timeseries-value-key": "Timeseries key",
"get-value-method": "RPC get value method",
"parse-value-function": "Parse value function",
"update-value-settings": "Update value settings",
"set-value-method": "RPC set value method",
"convert-value-function": "Convert value function",
"rpc-settings": "RPC settings",
"request-timeout": "RPC request timeout",
"persistent-rpc-settings": "Persistent RPC settings",
"request-persistent": "RPC request persistent",
"persistent-polling-interval": "Polling interval (ms) to get persistent RPC command response",
"common-settings": "Common settings",
"switch-title": "Switch title",
"show-on-off-labels": "Show on/off labels",
"slide-toggle-label": "Slide toggle label",
"label-position": "Label position",
"label-position-before": "Before",
"label-position-after": "After",
"slider-color": "Slider color",
"slider-color-primary": "Primary",
"slider-color-accent": "Accent",
"slider-color-warn": "Warn"
},
"maps": { "maps": {
"select-entity": "Select entity", "select-entity": "Select entity",
"select-entity-hint": "Hint: after selection click at the map to set position", "select-entity-hint": "Hint: after selection click at the map to set position",

Loading…
Cancel
Save