Browse Source

Merge pull request #8836 from rusikv/feature/test-rulenode-script-function-with-selected-event

Added ability to test/edit rule node script with selected debug event
pull/8946/head
Andrew Shvayka 3 years ago
committed by GitHub
parent
commit
5d98646089
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 50
      ui-ngx/src/app/core/services/script/node-script-test.service.ts
  2. 4
      ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts
  3. 29
      ui-ngx/src/app/modules/home/components/event/event-table-config.ts
  4. 37
      ui-ngx/src/app/modules/home/components/event/event-table.component.ts
  5. 1
      ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts
  6. 33
      ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts
  7. 4
      ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html
  8. 8
      ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts
  9. 9
      ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html
  10. 24
      ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts
  11. 9
      ui-ngx/src/app/shared/models/rule-node.models.ts
  12. 3
      ui-ngx/src/assets/locale/locale.constant-en_US.json

50
ui-ngx/src/app/core/services/script/node-script-test.service.ts

@ -23,8 +23,8 @@ import {
NodeScriptTestDialogComponent,
NodeScriptTestDialogData
} from '@shared/components/dialog/node-script-test-dialog.component';
import { sortObjectKeys } from '@core/utils';
import { ScriptLanguage } from '@shared/models/rule-node.models';
import { DebugRuleNodeEventBody } from '@shared/models/event.models';
@Injectable({
providedIn: 'root'
@ -37,56 +37,52 @@ export class NodeScriptTestService {
testNodeScript(script: string, scriptType: string, functionTitle: string,
functionName: string, argNames: string[], ruleNodeId: string, helpId?: string,
scriptLang?: ScriptLanguage): Observable<string> {
if (ruleNodeId) {
scriptLang?: ScriptLanguage, debugEventBody?: DebugRuleNodeEventBody): Observable<string> {
if (ruleNodeId && !debugEventBody) {
return this.ruleChainService.getLatestRuleNodeDebugInput(ruleNodeId).pipe(
switchMap((debugIn) => {
let msg: any;
let metadata: {[key: string]: string};
let msgType: string;
if (debugIn) {
if (debugIn.data) {
try {
msg = JSON.parse(debugIn.data);
} catch (e) {}
}
if (debugIn.metadata) {
try {
metadata = JSON.parse(debugIn.metadata);
} catch (e) {}
}
msgType = debugIn.msgType;
}
return this.openTestScriptDialog(script, scriptType, functionTitle,
functionName, argNames, msg, metadata, msgType, helpId, scriptLang);
functionName, argNames, debugIn, helpId, scriptLang);
})
);
} else {
return this.openTestScriptDialog(script, scriptType, functionTitle,
functionName, argNames, null, null, null, helpId, scriptLang);
functionName, argNames, debugEventBody, helpId, scriptLang);
}
}
private openTestScriptDialog(script: string, scriptType: string,
functionTitle: string, functionName: string, argNames: string[],
msg?: any, metadata?: {[key: string]: string}, msgType?: string, helpId?: string,
private openTestScriptDialog(script: string, scriptType: string, functionTitle: string, functionName: string,
argNames: string[], eventBody: DebugRuleNodeEventBody, helpId?: string,
scriptLang?: ScriptLanguage): Observable<string> {
let msg: any;
let metadata: {[key: string]: string};
let msgType: string;
if (eventBody && eventBody.data) {
try {
msg = JSON.parse(eventBody.data);
} catch (e) {}
}
if (!msg) {
msg = {
temperature: 22.4,
humidity: 78
};
}
if (eventBody && eventBody.metadata) {
try {
metadata = JSON.parse(eventBody.metadata);
} catch (e) {}
}
if (!metadata) {
metadata = {
deviceName: 'Test Device',
deviceType: 'default',
ts: new Date().getTime() + ''
};
} else {
metadata = sortObjectKeys(metadata);
}
if (!msgType) {
if (eventBody && eventBody.msgType) {
msgType = eventBody.msgType;
} else {
msgType = 'POST_TELEMETRY_REQUEST';
}
return this.dialog.open<NodeScriptTestDialogComponent, NodeScriptTestDialogData, string>(NodeScriptTestDialogComponent,

4
ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts

@ -637,6 +637,10 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
}
}
cellActionDescriptorsUpdated() {
this.cellActionDescriptors = [...this.entitiesTableConfig.cellActionDescriptors];
}
headerCellStyle(column: EntityColumn<BaseData<HasId>>) {
const index = this.entitiesTableConfig.columns.indexOf(column);
let res = this.headerCellStyleCache[index];

29
ui-ngx/src/app/modules/home/components/event/event-table-config.ts

@ -21,7 +21,7 @@ import {
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
import { DebugEventType, Event, EventType, FilterEventBody } from '@shared/models/event.models';
import { DebugEventType, Event, EventBody, EventType, FilterEventBody } from '@shared/models/event.models';
import { TimePageLink } from '@shared/models/page/page-link';
import { TranslateService } from '@ngx-translate/core';
import { DatePipe } from '@angular/common';
@ -41,7 +41,7 @@ import {
} from '@home/components/event/event-content-dialog.component';
import { isEqual, sortObjectKeys } from '@core/utils';
import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
import { ChangeDetectorRef, Injector, StaticProvider, ViewContainerRef } from '@angular/core';
import { ChangeDetectorRef, EventEmitter, Injector, StaticProvider, ViewContainerRef } from '@angular/core';
import { ComponentPortal } from '@angular/cdk/portal';
import {
EVENT_FILTER_PANEL_DATA,
@ -61,6 +61,7 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
set eventType(eventType: EventType | DebugEventType) {
if (this.eventTypeValue !== eventType) {
this.eventTypeValue = eventType;
this.updateCellAction();
this.updateColumns(true);
this.updateFilterColumns();
}
@ -84,7 +85,9 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
private debugEventTypes: Array<DebugEventType> = null,
private overlay: Overlay,
private viewContainerRef: ViewContainerRef,
private cd: ChangeDetectorRef) {
private cd: ChangeDetectorRef,
public testButtonLabel?: string,
private debugEventSelected?: EventEmitter<EventBody>) {
super();
this.loadDataOnInit = false;
this.tableTitle = '';
@ -120,6 +123,7 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
this.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.updateColumns();
this.updateCellAction();
this.updateFilterColumns();
this.headerActionDescriptors.push({
@ -349,6 +353,25 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
}
}
updateCellAction() {
this.cellActionDescriptors = [];
switch (this.eventType) {
case DebugEventType.DEBUG_RULE_NODE:
if (this.testButtonLabel) {
this.cellActionDescriptors.push({
name: this.translate.instant('rulenode.test-with-this-message', {test: this.translate.instant(this.testButtonLabel)}),
icon: 'bug_report',
isEnabled: (entity) => entity.body.type === 'IN',
onAction: ($event, entity) => {
this.debugEventSelected.next(entity.body);
}
});
}
break;
}
this.getTable()?.cellActionDescriptorsUpdated();
}
showContent($event: MouseEvent, content: string, title: string, contentType: ContentType = null, sortKeys = false): void {
if ($event) {
$event.stopPropagation();

37
ui-ngx/src/app/modules/home/components/event/event-table.component.ts

@ -17,10 +17,10 @@
import {
AfterViewInit,
ChangeDetectorRef,
Component,
Component, EventEmitter,
Input,
OnDestroy,
OnInit,
OnInit, Output,
ViewChild,
ViewContainerRef
} from '@angular/core';
@ -32,9 +32,10 @@ import { EntitiesTableComponent } from '@home/components/entity/entities-table.c
import { EventTableConfig } from './event-table-config';
import { EventService } from '@core/http/event.service';
import { DialogService } from '@core/services/dialog.service';
import { DebugEventType, EventType } from '@shared/models/event.models';
import { DebugEventType, EventBody, EventType } from '@shared/models/event.models';
import { Overlay } from '@angular/cdk/overlay';
import { Subscription } from 'rxjs';
import { isNotEmptyStr } from '@core/utils';
@Component({
selector: 'tb-event-table',
@ -59,6 +60,10 @@ export class EventTableComponent implements OnInit, AfterViewInit, OnDestroy {
dirtyValue = false;
entityIdValue: EntityId;
get active(): boolean {
return this.activeValue;
}
@Input()
set active(active: boolean) {
if (this.activeValue !== active) {
@ -83,6 +88,28 @@ export class EventTableComponent implements OnInit, AfterViewInit, OnDestroy {
}
}
private functionTestButtonLabelValue: string;
get functionTestButtonLabel(): string {
return this.functionTestButtonLabelValue;
}
@Input()
set functionTestButtonLabel(value: string) {
if (isNotEmptyStr(value)) {
this.functionTestButtonLabelValue = value;
} else {
this.functionTestButtonLabelValue = '';
}
if (this.eventTableConfig) {
this.eventTableConfig.testButtonLabel = this.functionTestButtonLabel;
this.eventTableConfig.updateCellAction();
}
}
@Output()
debugEventSelected = new EventEmitter<EventBody>();
@ViewChild(EntitiesTableComponent, {static: true}) entitiesTable: EntitiesTableComponent;
eventTableConfig: EventTableConfig;
@ -114,7 +141,9 @@ export class EventTableComponent implements OnInit, AfterViewInit, OnDestroy {
this.debugEventTypes,
this.overlay,
this.viewContainerRef,
this.cd
this.cd,
this.functionTestButtonLabel,
this.debugEventSelected
);
}

1
ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts

@ -80,6 +80,7 @@ export interface IEntitiesTableComponent {
exitFilterMode(): void;
resetSortAndFilter(update?: boolean, preserveTimewindow?: boolean): void;
columnsUpdated(resetData?: boolean): void;
cellActionDescriptorsUpdated(): void;
headerCellStyle(column: EntityColumn<BaseData<HasId>>): any;
clearCellCache(col: number, row: number): void;
cellContent(entity: BaseData<HasId>, column: EntityColumn<BaseData<HasId>>, row: number): any;

33
ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts

@ -18,14 +18,22 @@ import {
AfterViewInit,
Component,
ComponentRef,
EventEmitter,
forwardRef,
Input,
OnDestroy,
OnInit,
Output,
ViewChild,
ViewContainerRef
} from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
UntypedFormBuilder,
UntypedFormGroup,
Validators
} from '@angular/forms';
import {
IRuleNodeConfigurationComponent,
RuleNodeConfiguration,
@ -76,6 +84,12 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
@Input()
ruleChainType: RuleChainType;
@Output()
initRuleNode = new EventEmitter<void>();
@Output()
changeScript = new EventEmitter<void>();
nodeDefinitionValue: RuleNodeDefinition;
@Input()
@ -85,6 +99,7 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
if (this.nodeDefinitionValue) {
this.validateDefinedDirective();
}
setTimeout(() => this.initRuleNode.emit());
}
}
@ -98,8 +113,11 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
changeSubscription: Subscription;
changeScriptSubscription: Subscription;
definedConfigComponent: IRuleNodeConfigurationComponent;
private definedConfigComponentRef: ComponentRef<IRuleNodeConfigurationComponent>;
private definedConfigComponent: IRuleNodeConfigurationComponent;
private configuration: RuleNodeConfiguration;
@ -127,6 +145,14 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
if (this.definedConfigComponentRef) {
this.definedConfigComponentRef.destroy();
}
if (this.changeSubscription) {
this.changeSubscription.unsubscribe();
this.changeSubscription = null;
}
if (this.changeScriptSubscription) {
this.changeScriptSubscription.unsubscribe();
this.changeScriptSubscription = null;
}
}
ngAfterViewInit(): void {
@ -199,6 +225,9 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
this.changeSubscription = this.definedConfigComponent.configurationChanged.subscribe((configuration) => {
this.updateModel(configuration);
});
if (this.definedConfigComponent?.changeScript) {
this.changeScriptSubscription = this.definedConfigComponent.changeScript.subscribe(() => this.changeScript.emit());
}
}
}

4
ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html

@ -50,7 +50,9 @@
[ruleNodeId]="ruleNode.ruleNodeId?.id"
[ruleChainId]="ruleChainId"
[ruleChainType]="ruleChainType"
[nodeDefinition]="ruleNode.component.configurationDescriptor.nodeDefinition">
[nodeDefinition]="ruleNode.component.configurationDescriptor.nodeDefinition"
(initRuleNode)="initRuleNode.emit($event)"
(changeScript)="changeScript.emit($event)">
</tb-rule-node-config>
<div formGroupName="additionalInfo" fxLayout="column" class="description-block">
<mat-form-field class="mat-block">

8
ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -55,6 +55,12 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
@Input()
isAdd = false;
@Output()
initRuleNode = new EventEmitter<void>();
@Output()
changeScript = new EventEmitter<void>();
ruleNodeType = RuleNodeType;
entityType = EntityType;

9
ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html

@ -111,7 +111,9 @@
[ruleChainId]="ruleChain.id?.id"
[ruleChainType]="ruleChainType"
[isEdit]="true"
[isReadOnly]="false">
[isReadOnly]="false"
(initRuleNode)="onRuleNodeInit()"
(changeScript)="switchToFirstTab()">
</tb-rule-node>
</mat-tab>
<mat-tab *ngIf="editingRuleNode.ruleNodeId" label="{{ 'rulenode.events' | translate }}" #eventsTab="matTab">
@ -119,7 +121,10 @@
[defaultEventType]="debugEventTypes.DEBUG_RULE_NODE"
[active]="eventsTab.isActive"
[tenantId]="ruleChain.tenantId.id"
[entityId]="editingRuleNode.ruleNodeId"></tb-event-table>
[entityId]="editingRuleNode.ruleNodeId"
[functionTestButtonLabel]="ruleNodeTestButtonLabel"
(debugEventSelected)="onDebugEventSelected($event)">
</tb-event-table>
</mat-tab>
<mat-tab label="{{ 'rulenode.help' | translate }}">
<div class="tb-rule-node-help">

24
ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts

@ -87,7 +87,7 @@ import { DialogComponent } from '@shared/components/dialog.component';
import { MatMenuTrigger } from '@angular/material/menu';
import { ItemBufferService, RuleNodeConnection } from '@core/services/item-buffer.service';
import { Hotkey } from 'angular2-hotkeys';
import { DebugEventType, EventType } from '@shared/models/event.models';
import { DebugEventType, DebugRuleNodeEventBody, EventType } from '@shared/models/event.models';
import { MatMiniFabButton } from '@angular/material/button';
import { TbPopoverService } from '@shared/components/popover.service';
import { VersionControlComponent } from '@home/components/vc/version-control.component';
@ -153,6 +153,7 @@ export class RuleChainPageComponent extends PageComponent
editingRuleNodeAllowCustomLabels = false;
editingRuleNodeLinkLabels: {[label: string]: LinkLabel};
editingRuleNodeSourceRuleChainId: string;
ruleNodeTestButtonLabel: string;
@ViewChild('tbRuleNode') ruleNodeComponent: RuleNodeDetailsComponent;
@ViewChild('tbRuleNodeLink') ruleNodeLinkComponent: RuleNodeLinkComponent;
@ -1277,6 +1278,27 @@ export class RuleChainPageComponent extends PageComponent
this.editingRuleNodeLink = deepClone(edge);
}
onDebugEventSelected(debugEventBody: DebugRuleNodeEventBody) {
const ruleNodeConfigComponent = this.ruleNodeComponent.ruleNodeConfigComponent;
const ruleNodeConfigDefinedComponent = ruleNodeConfigComponent.definedConfigComponent;
if (ruleNodeConfigComponent.useDefinedDirective() && ruleNodeConfigDefinedComponent.hasScript && ruleNodeConfigDefinedComponent.testScript) {
ruleNodeConfigDefinedComponent.testScript(debugEventBody);
}
}
onRuleNodeInit() {
const ruleNodeConfigDefinedComponent = this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent;
if (this.ruleNodeComponent.ruleNodeConfigComponent.useDefinedDirective() && ruleNodeConfigDefinedComponent.hasScript) {
this.ruleNodeTestButtonLabel = ruleNodeConfigDefinedComponent.testScriptLabel;
} else {
this.ruleNodeTestButtonLabel = '';
}
}
switchToFirstTab() {
this.selectedRuleNodeTabIndex = 0;
}
saveRuleNode() {
this.ruleNodeComponent.validate();
if (this.ruleNodeComponent.ruleNodeFormGroup.valid) {

9
ui-ngx/src/app/shared/models/rule-node.models.ts

@ -26,6 +26,8 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { AbstractControl, UntypedFormGroup } from '@angular/forms';
import { RuleChainType } from '@shared/models/rule-chain.models';
import { DebugRuleNodeEventBody } from '@shared/models/event.models';
import { TranslateService } from '@ngx-translate/core';
export interface RuleNodeConfiguration {
[key: string]: any;
@ -71,10 +73,14 @@ export interface RuleNodeConfigurationDescriptor {
export interface IRuleNodeConfigurationComponent {
ruleNodeId: string;
ruleChainId: string;
hasScript: boolean;
testScriptLabel?: string;
changeScript?: EventEmitter<void>;
ruleChainType: RuleChainType;
configuration: RuleNodeConfiguration;
configurationChanged: Observable<RuleNodeConfiguration>;
validate();
testScript? (debugEventBody?: DebugRuleNodeEventBody);
[key: string]: any;
}
@ -87,6 +93,8 @@ export abstract class RuleNodeConfigurationComponent extends PageComponent imple
ruleChainId: string;
hasScript: boolean = false;
ruleChainType: RuleChainType;
configurationValue: RuleNodeConfiguration;
@ -499,3 +507,4 @@ export function getRuleNodeHelpLink(component: RuleNodeComponentDescriptor): str
}
return 'ruleEngine';
}

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

@ -3467,7 +3467,8 @@
"output": "Output",
"test": "Test",
"help": "Help",
"reset-debug-mode": "Reset debug mode in all nodes"
"reset-debug-mode": "Reset debug mode in all nodes",
"test-with-this-message": "{{test}} with this message"
},
"timezone": {
"timezone": "Timezone",

Loading…
Cancel
Save