Merge pull request #12551 from vvlladd28/feature/get-action-type/dashboard-state-with-params

Add 'Get dashboard state object' action type
This commit is contained in:
Andrew Shvayka 2025-02-11 15:02:37 +02:00 committed by GitHub
commit b29d1722ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 110 additions and 12 deletions

View File

@ -25,6 +25,7 @@ import { WidgetContext } from '@home/models/widget-component.models';
import {
BehaviorSubject,
forkJoin,
merge,
Observable,
Observer,
of,
@ -33,7 +34,7 @@ import {
switchMap,
throwError
} from 'rxjs';
import { catchError, delay, map, share, take } from 'rxjs/operators';
import { catchError, debounceTime, delay, map, share, take } from 'rxjs/operators';
import { AfterViewInit, ChangeDetectorRef, Directive, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';
import {
DataToValueSettings,
@ -53,10 +54,11 @@ import {
import { ValueType } from '@shared/models/constants';
import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models';
import { EntityId } from '@shared/models/id/entity-id';
import { isDefinedAndNotNull } from '@core/utils';
import { deepClone, isDefinedAndNotNull } from '@core/utils';
import { parseError } from '@shared/models/error.models';
import { CompiledTbFunction, compileTbFunction } from '@shared/models/js-function.models';
import { HttpClient } from '@angular/common/http';
import { StateObject } from '@core/api/widget-api.models';
@Directive()
// eslint-disable-next-line @angular-eslint/directive-class-suffix
@ -269,6 +271,8 @@ export abstract class ValueGetter<V> extends ValueAction {
return new AlarmStatusValueGetter<V>(ctx, settings, valueType, valueObserver, simulated);
case GetValueAction.GET_DASHBOARD_STATE:
return new DashboardStateGetter<V>(ctx, settings, valueType, valueObserver, simulated);
case GetValueAction.GET_DASHBOARD_STATE_OBJECT:
return new DashboardStateWithParamsGetter<V>(ctx, settings, valueType, valueObserver, simulated);
}
}
@ -641,6 +645,33 @@ export class DashboardStateGetter<V> extends ValueGetter<V> {
}
}
export class DashboardStateWithParamsGetter<V> extends ValueGetter<V> {
constructor(protected ctx: WidgetContext,
protected settings: GetValueSettings<V>,
protected valueType: ValueType,
protected valueObserver: Partial<Observer<V>>,
protected simulated: boolean) {
super(ctx, settings, valueType, valueObserver, simulated);
}
protected doGetValue(): Observable<StateObject> {
if (this.simulated) {
return of({id: 'default', params: {}});
} else {
return merge(
this.ctx.stateController.dashboardCtrl.dashboardCtx.stateId,
this.ctx.stateController.dashboardCtrl.dashboardCtx.stateChanged
).pipe(
debounceTime(10),
map(() => ({
id: this.ctx.stateController.getStateId(),
params: deepClone(this.ctx.stateController.getStateParams())
}))
);
}
}
}
export class ExecuteRpcValueSetter<V> extends ValueSetter<V> {
private readonly executeRpcSettings: RpcSettings;

View File

@ -131,7 +131,9 @@
class="tb-form-panel stroked" formGroupName="dataToValue">
<div class="tb-form-row no-padding no-border column-xs">
<div class="fixed-title-width" translate>widgets.value-action.action-result-converter</div>
<tb-toggle-select class="flex-1" formControlName="type">
<tb-toggle-select formControlName="type"
class="flex-1"
[class.invisible]="getValueSettingsFormGroup.get('action').value === getValueAction.GET_DASHBOARD_STATE_OBJECT">
<tb-toggle-option [value]="dataToValueType.NONE">{{ 'widgets.value-action.converter-none' | translate }}</tb-toggle-option>
<tb-toggle-option [value]="dataToValueType.FUNCTION">{{ 'widgets.value-action.converter-function' | translate }}</tb-toggle-option>
</tb-toggle-select>
@ -143,7 +145,7 @@
[globalVariables]="functionScopeVariables"
[functionArgs]="['data']"
functionTitle="{{ 'widgets.value-action.parse-value-function' | translate }}"
helpId="widget/lib/rpc/parse_value_fn">
[helpId]="getParseValueFunctionHelpId()">
</tb-js-func>
<div *ngIf="valueType === ValueType.BOOLEAN" class="tb-form-row align-start no-gap column-xs">
<div class="fixed-title-width fixed-title-height">{{ 'widgets.value-action.state-when-result-is' | translate:{state: stateLabel} }}</div>

View File

@ -99,6 +99,8 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen
getValueSettingsFormGroup: UntypedFormGroup;
entityType = EntityType;
alarmSeverities = Object.keys(AlarmSeverity) as AlarmSeverity[];
alarmSeverityTranslationMap = alarmSeverityTranslations;
@ -165,9 +167,17 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen
this.getValueSettingsApplied.emit(getValueSettings);
}
getParseValueFunctionHelpId(): string {
const action: GetValueAction = this.getValueSettingsFormGroup.get('action').value;
if (action === GetValueAction.GET_DASHBOARD_STATE_OBJECT) {
return 'widget/config/parse_value_get_dashboard_state_object_fn';
}
return 'widget/lib/rpc/parse_value_fn';
}
private updateValidators() {
const action: GetValueAction = this.getValueSettingsFormGroup.get('action').value;
const dataToValueType: DataToValueType = this.getValueSettingsFormGroup.get('dataToValue').get('type').value;
let dataToValueType: DataToValueType = this.getValueSettingsFormGroup.get('dataToValue').get('type').value;
this.getValueSettingsFormGroup.get('defaultValue').disable({emitEvent: false});
this.getValueSettingsFormGroup.get('executeRpc').disable({emitEvent: false});
@ -196,6 +206,10 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen
case GetValueAction.GET_ALARM_STATUS:
this.getValueSettingsFormGroup.get('getAlarmStatus').enable({emitEvent: false});
break;
case GetValueAction.GET_DASHBOARD_STATE_OBJECT:
this.getValueSettingsFormGroup.get('dataToValue.type').setValue(DataToValueType.FUNCTION, {emitEvent: false});
dataToValueType = DataToValueType.FUNCTION;
break
}
if (action === GetValueAction.DO_NOTHING || action === GetValueAction.GET_ALARM_STATUS) {
this.getValueSettingsFormGroup.get('dataToValue').disable({emitEvent: false});
@ -208,6 +222,4 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen
}
}
}
protected readonly entityType = EntityType;
}

View File

@ -191,6 +191,14 @@ export class GetValueActionSettingsComponent implements OnInit, ControlValueAcce
this.displayValue = this.translate.instant('widgets.value-action.get-dashboard-state-text');
}
break;
case GetValueAction.GET_DASHBOARD_STATE_OBJECT:
if (this.valueType === ValueType.BOOLEAN) {
const state = this.modelValue.dataToValue?.compareToValue;
this.displayValue = this.translate.instant('widgets.value-action.when-dashboard-state-object-function-is-text', {state});
} else {
this.displayValue = this.translate.instant('widgets.value-action.get-dashboard-state-object-text');
}
break;
}
this.cd.markForCheck();
}

View File

@ -25,7 +25,8 @@ export enum GetValueAction {
GET_ATTRIBUTE = 'GET_ATTRIBUTE',
GET_TIME_SERIES = 'GET_TIME_SERIES',
GET_ALARM_STATUS = 'GET_ALARM_STATUS',
GET_DASHBOARD_STATE = 'GET_DASHBOARD_STATE'
GET_DASHBOARD_STATE = 'GET_DASHBOARD_STATE',
GET_DASHBOARD_STATE_OBJECT = 'GET_DASHBOARD_STATE_OBJECT',
}
export const getValueActions = Object.keys(GetValueAction) as GetValueAction[];
@ -45,7 +46,8 @@ export const getValueActionTranslations = new Map<GetValueAction, string>(
[GetValueAction.GET_ATTRIBUTE, 'widgets.value-action.get-attribute'],
[GetValueAction.GET_TIME_SERIES, 'widgets.value-action.get-time-series'],
[GetValueAction.GET_ALARM_STATUS, 'widgets.value-action.get-alarm-status'],
[GetValueAction.GET_DASHBOARD_STATE, 'widgets.value-action.get-dashboard-state']
[GetValueAction.GET_DASHBOARD_STATE, 'widgets.value-action.get-dashboard-state'],
[GetValueAction.GET_DASHBOARD_STATE_OBJECT, 'widgets.value-action.get-dashboard-state-object'],
]
);

View File

@ -0,0 +1,40 @@
#### Parse value function
<div class="divider"></div>
<br/>
*function (data): boolean*
A JavaScript function that converts the current dashboard state object into a boolean value.
**Parameters:**
<ul>
<li><b>data:</b> <a href="https://github.com/thingsboard/thingsboard/blob/master/ui-ngx/src/app/core/api/widget-api.models.ts#L150" target="_blank">StateObject</a> - the current dashboard state object.
</li>
</ul>
**Returns:**
`true` if the widget should be in an activated state, `false` otherwise.
<div class="divider"></div>
##### Examples
* Check if the current dashboard state id is "default":
```javascript
return data.id === 'default' ? true : false;
{:copy-code}
```
* Check if the current dashboard state parameters are empty:
```javascript
return Object.keys(data.params).length ? true : false;
{:copy-code}
```
<br>
<br>

View File

@ -8352,15 +8352,18 @@
"set-attribute": "Set attribute",
"get-time-series": "Get time series",
"get-alarm-status": "Get alarm status",
"get-dashboard-state": "Get dashboard state",
"get-dashboard-state": "Get dashboard state id",
"get-dashboard-state-object": "Get dashboard state object",
"add-time-series": "Add time series",
"execute-rpc-text": "Execute RPC method '{{methodName}}'",
"get-time-series-text": "Use time series '{{key}}'",
"get-attribute-text": "Use attribute '{{key}}'",
"get-alarm-status-text": "Use alarm status",
"get-dashboard-state-text": "Use dashboard state",
"when-dashboard-state-is-text": "When dashboard state is '{{state}}'",
"when-dashboard-state-function-is-text": "When f(dashboard state) is '{{state}}'",
"get-dashboard-state-object-text": "Use dashboard state object",
"when-dashboard-state-is-text": "When dashboard state id is '{{state}}'",
"when-dashboard-state-function-is-text": "When f(dashboard state id) is '{{state}}'",
"when-dashboard-state-object-function-is-text": "When f(dashboard state object) is '{{state}}'",
"set-attribute-to-value-text": "Set '{{key}}' attribute to: {{value}}",
"add-time-series-value-text": "Add '{{key}}' time series value: {{value}}",
"set-attribute-text": "Set '{{key}}' attribute",