Rule node test script dialog
This commit is contained in:
parent
c6c53fc77c
commit
642c9fabe6
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
const ruleNodeUiforwardHost = 'localhost';
|
||||
const ruleNodeUiforwardPort = 8080;
|
||||
const ruleNodeUiforwardPort = 5000;
|
||||
|
||||
const PROXY_CONFIG = {
|
||||
'/api': {
|
||||
|
||||
@ -38,6 +38,7 @@ import { catchError, map, mergeMap } from 'rxjs/operators';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { EntityType } from '@shared/models/entity-type.models';
|
||||
import { deepClone, snakeCase } from '@core/utils';
|
||||
import { DebugRuleNodeEventBody } from '@app/shared/models/event.models';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -170,6 +171,10 @@ export class RuleChainService {
|
||||
return component.configurationDescriptor.nodeDefinition.customRelations;
|
||||
}
|
||||
|
||||
public getLatestRuleNodeDebugInput(ruleNodeId: string, config?: RequestConfig): Observable<DebugRuleNodeEventBody> {
|
||||
return this.http.get<DebugRuleNodeEventBody>(`/api/ruleNode/${ruleNodeId}/debugIn`, defaultHttpOptionsFromConfig(config));
|
||||
}
|
||||
|
||||
private resolveTargetRuleChains(ruleChainConnections: Array<RuleChainConnectionInfo>): Observable<{[ruleChainId: string]: RuleChain}> {
|
||||
if (ruleChainConnections && ruleChainConnections.length) {
|
||||
const tasks: Observable<RuleChain>[] = [];
|
||||
|
||||
@ -0,0 +1,93 @@
|
||||
<!--
|
||||
|
||||
Copyright © 2016-2019 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.
|
||||
|
||||
-->
|
||||
<form #nodeScriptTestForm="ngForm" [formGroup]="nodeScriptTestFormGroup" (ngSubmit)="save()" style="width: 800px;">
|
||||
<mat-toolbar fxLayout="row" color="primary">
|
||||
<h2>{{ 'rulenode.test-script-function' | translate }}</h2>
|
||||
<span fxFlex></span>
|
||||
<button mat-button mat-icon-button
|
||||
(click)="cancel()"
|
||||
type="button">
|
||||
<mat-icon class="material-icons">close</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
|
||||
</mat-progress-bar>
|
||||
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
|
||||
<div mat-dialog-content fxFlex style="position: relative;">
|
||||
<div class="tb-absolute-fill">
|
||||
<div #topPanel class="tb-split tb-split-vertical">
|
||||
<div #topLeftPanel class="tb-split tb-content">
|
||||
<div class="tb-resize-container">
|
||||
<div class="tb-editor-area-title-panel">
|
||||
<label translate>rulenode.message</label>
|
||||
</div>
|
||||
TODO: payloadForm
|
||||
</div>
|
||||
</div>
|
||||
<div #topRightPanel class="tb-split tb-content">
|
||||
<div tb-toast toastTarget="metadataPanel" class="tb-resize-container">
|
||||
<div class="tb-editor-area-title-panel">
|
||||
<label translate>rulenode.metadata</label>
|
||||
TODO: metadataForm
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div #bottomPanel class="tb-split tb-split-vertical">
|
||||
<div #bottomLeftPanel class="tb-split tb-content">
|
||||
<div class="tb-resize-container">
|
||||
<div class="tb-editor-area-title-panel tb-js-function">
|
||||
<label>{{ functionTitle }}</label>
|
||||
</div>
|
||||
TODO: funcBodyForm
|
||||
</div>
|
||||
</div>
|
||||
<div #bottomRightPanel class="tb-split tb-content">
|
||||
<div class="tb-resize-container">
|
||||
<div class="tb-editor-area-title-panel">
|
||||
<label translate>rulenode.output</label>
|
||||
</div>
|
||||
TODO: output
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div mat-dialog-actions fxLayout="row">
|
||||
<button mat-button mat-raised-button color="primary"
|
||||
type="button"
|
||||
(click)="test()"
|
||||
cdkFocusInitial
|
||||
[disabled]="(isLoading$ | async) || nodeScriptTestFormGroup.invalid">
|
||||
{{ 'rulenode.test' | translate }}
|
||||
</button>
|
||||
<span fxFlex></span>
|
||||
<button mat-button mat-raised-button color="primary"
|
||||
type="submit"
|
||||
[disabled]="(isLoading$ | async) || nodeScriptTestFormGroup.get('funcBody').invalid || !nodeScriptTestFormGroup.get('funcBody').dirty">
|
||||
{{ 'action.save' | translate }}
|
||||
</button>
|
||||
<button mat-button color="primary"
|
||||
style="margin-right: 20px;"
|
||||
type="button"
|
||||
[disabled]="(isLoading$ | async)"
|
||||
(click)="cancel()">
|
||||
{{ 'action.cancel' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -0,0 +1,93 @@
|
||||
:host {
|
||||
.tb-split {
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.tb-content {
|
||||
padding-top: 5px;
|
||||
padding-left: 5px;
|
||||
border: 1px solid #c0c0c0;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
background-color: #eee;
|
||||
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50%;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
background-color: #eee;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50%;
|
||||
}
|
||||
|
||||
.gutter.gutter-horizontal {
|
||||
cursor: col-resize;
|
||||
background-image: url("../../../../assets/split.js/grips/vertical.png");
|
||||
}
|
||||
|
||||
.gutter.gutter-vertical {
|
||||
cursor: row-resize;
|
||||
background-image: url("../../../../assets/split.js/grips/horizontal.png");
|
||||
}
|
||||
|
||||
.tb-split.tb-split-horizontal,
|
||||
.gutter.gutter-horizontal {
|
||||
float: left;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tb-split.tb-split-vertical {
|
||||
display: flex;
|
||||
|
||||
.tb-split.tb-content {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
div.tb-editor-area-title-panel {
|
||||
position: absolute;
|
||||
top: 13px;
|
||||
right: 40px;
|
||||
z-index: 5;
|
||||
font-size: .8rem;
|
||||
font-weight: 500;
|
||||
|
||||
&.tb-js-function {
|
||||
right: 80px;
|
||||
}
|
||||
|
||||
label {
|
||||
padding: 4px;
|
||||
color: #00acc1;
|
||||
text-transform: uppercase;
|
||||
background: rgba(220, 220, 220, .35);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.mat-button {
|
||||
min-width: 32px;
|
||||
min-height: 15px;
|
||||
padding: 4px;
|
||||
margin: 0;
|
||||
font-size: .8rem;
|
||||
line-height: 15px;
|
||||
color: #7b7b7b;
|
||||
background: rgba(220, 220, 220, .35);
|
||||
}
|
||||
}
|
||||
|
||||
.tb-resize-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.ace_editor {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,176 @@
|
||||
///
|
||||
/// Copyright © 2016-2019 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 {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
Inject,
|
||||
OnInit,
|
||||
QueryList,
|
||||
SkipSelf,
|
||||
ViewChild,
|
||||
ViewChildren
|
||||
} from '@angular/core';
|
||||
import { ErrorStateMatcher, MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import {
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
FormGroupDirective,
|
||||
NgForm,
|
||||
ValidatorFn,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
import { DialogComponent } from '@app/shared/components/dialog.component';
|
||||
import {
|
||||
toCustomAction,
|
||||
WidgetActionCallbacks,
|
||||
WidgetActionDescriptorInfo,
|
||||
WidgetActionsData
|
||||
} from '@home/components/widget/action/manage-widget-actions.component.models';
|
||||
import { UtilsService } from '@core/services/utils.service';
|
||||
import { WidgetActionSource, WidgetActionType, widgetActionTypeTranslationMap } from '@shared/models/widget.models';
|
||||
import { map, mergeMap, startWith, tap } from 'rxjs/operators';
|
||||
import { DashboardService } from '@core/http/dashboard.service';
|
||||
import { Dashboard } from '@shared/models/dashboard.models';
|
||||
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
|
||||
|
||||
export interface NodeScriptTestDialogData {
|
||||
script: string;
|
||||
scriptType: string;
|
||||
functionTitle: string;
|
||||
functionName: string;
|
||||
argNames: string[];
|
||||
msg?: any;
|
||||
metadata?: any;
|
||||
msgType?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tb-node-script-test-dialog',
|
||||
templateUrl: './node-script-test-dialog.component.html',
|
||||
providers: [{provide: ErrorStateMatcher, useExisting: NodeScriptTestDialogComponent}],
|
||||
styleUrls: ['./node-script-test-dialog.component.scss']
|
||||
})
|
||||
export class NodeScriptTestDialogComponent extends DialogComponent<NodeScriptTestDialogComponent,
|
||||
string> implements OnInit, AfterViewInit, ErrorStateMatcher {
|
||||
|
||||
@ViewChildren('topPanel')
|
||||
topPanelElmRef: QueryList<ElementRef<HTMLElement>>;
|
||||
|
||||
@ViewChildren('topLeftPanel')
|
||||
topLeftPanelElmRef: QueryList<ElementRef<HTMLElement>>;
|
||||
|
||||
@ViewChildren('topRightPanel')
|
||||
topRightPanelElmRef: QueryList<ElementRef<HTMLElement>>;
|
||||
|
||||
@ViewChildren('bottomPanel')
|
||||
bottomPanelElmRef: QueryList<ElementRef<HTMLElement>>;
|
||||
|
||||
@ViewChildren('bottomLeftPanel')
|
||||
bottomLeftPanelElmRef: QueryList<ElementRef<HTMLElement>>;
|
||||
|
||||
@ViewChildren('bottomLeftPanel')
|
||||
bottomRightPanelElmRef: QueryList<ElementRef<HTMLElement>>;
|
||||
|
||||
nodeScriptTestFormGroup: FormGroup;
|
||||
|
||||
functionTitle: string;
|
||||
|
||||
submitted = false;
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
protected router: Router,
|
||||
@Inject(MAT_DIALOG_DATA) public data: NodeScriptTestDialogData,
|
||||
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
|
||||
public dialogRef: MatDialogRef<NodeScriptTestDialogComponent, string>,
|
||||
public fb: FormBuilder) {
|
||||
super(store, router, dialogRef);
|
||||
this.functionTitle = this.data.functionTitle;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.nodeScriptTestFormGroup = this.fb.group({});
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
combineLatest(this.topPanelElmRef.changes,
|
||||
this.topLeftPanelElmRef.changes,
|
||||
this.topRightPanelElmRef.changes,
|
||||
this.bottomPanelElmRef.changes,
|
||||
this.bottomLeftPanelElmRef.changes,
|
||||
this.bottomRightPanelElmRef.changes).subscribe(() => {
|
||||
if (this.topPanelElmRef.length && this.topLeftPanelElmRef.length &&
|
||||
this.topRightPanelElmRef.length && this.bottomPanelElmRef.length &&
|
||||
this.bottomLeftPanelElmRef.length && this.bottomRightPanelElmRef.length) {
|
||||
this.initSplitLayout(this.topPanelElmRef.first.nativeElement,
|
||||
this.topLeftPanelElmRef.first.nativeElement,
|
||||
this.topRightPanelElmRef.first.nativeElement,
|
||||
this.bottomPanelElmRef.first.nativeElement,
|
||||
this.bottomLeftPanelElmRef.first.nativeElement,
|
||||
this.bottomRightPanelElmRef.first.nativeElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private initSplitLayout(topPanel: any,
|
||||
topLeftPanel: any,
|
||||
topRightPanel: any,
|
||||
bottomPanel: any,
|
||||
bottomLeftPanel: any,
|
||||
bottomRightPanel: any) {
|
||||
|
||||
Split([topPanel, bottomPanel], {
|
||||
sizes: [35, 65],
|
||||
gutterSize: 8,
|
||||
cursor: 'row-resize',
|
||||
direction: 'vertical'
|
||||
});
|
||||
|
||||
Split([topLeftPanel, topRightPanel], {
|
||||
sizes: [50, 50],
|
||||
gutterSize: 8,
|
||||
cursor: 'col-resize'
|
||||
});
|
||||
|
||||
Split([bottomLeftPanel, bottomRightPanel], {
|
||||
sizes: [50, 50],
|
||||
gutterSize: 8,
|
||||
cursor: 'col-resize'
|
||||
});
|
||||
}
|
||||
|
||||
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
|
||||
const customErrorState = !!(control && control.invalid && this.submitted);
|
||||
return originalErrorState || customErrorState;
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
this.dialogRef.close(null);
|
||||
}
|
||||
|
||||
save(): void {
|
||||
this.submitted = true;
|
||||
const script: string = this.nodeScriptTestFormGroup.get('funcBody').value;
|
||||
this.dialogRef.close(script);
|
||||
}
|
||||
}
|
||||
@ -16,14 +16,63 @@
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { RuleChainService } from '@core/http/rule-chain.service';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class NodeScriptTestService {
|
||||
|
||||
testNodeScript(script: string, scriptType: any, functionTitle: string,
|
||||
constructor(private ruleChainService: RuleChainService) {
|
||||
}
|
||||
|
||||
testNodeScript(script: string, scriptType: string, functionTitle: string,
|
||||
functionName: string, argNames: string[], ruleNodeId: string): Observable<string> {
|
||||
if (ruleNodeId) {
|
||||
return this.ruleChainService.getLatestRuleNodeDebugInput(ruleNodeId).pipe(
|
||||
switchMap((debugIn) => {
|
||||
let msg: any;
|
||||
let metadata: any;
|
||||
let msgType: string;
|
||||
if (debugIn) {
|
||||
if (debugIn.data) {
|
||||
msg = JSON.parse(debugIn.data);
|
||||
}
|
||||
if (debugIn.metadata) {
|
||||
metadata = JSON.parse(debugIn.metadata);
|
||||
}
|
||||
msgType = debugIn.msgType;
|
||||
}
|
||||
return this.openTestScriptDialog(script, scriptType, functionTitle,
|
||||
functionName, argNames, msg, metadata, msgType);
|
||||
})
|
||||
);
|
||||
} else {
|
||||
return this.openTestScriptDialog(script, scriptType, functionTitle,
|
||||
functionName, argNames);
|
||||
}
|
||||
}
|
||||
|
||||
private openTestScriptDialog(script: string, scriptType: string,
|
||||
functionTitle: string, functionName: string, argNames: string[],
|
||||
msg?: any, metadata?: any, msgType?: string): Observable<string> {
|
||||
if (!msg) {
|
||||
msg = {
|
||||
temperature: 22.4,
|
||||
humidity: 78
|
||||
};
|
||||
}
|
||||
if (!metadata) {
|
||||
metadata = {
|
||||
deviceType: 'default',
|
||||
deviceName: 'Test Device',
|
||||
ts: new Date().getTime() + ''
|
||||
};
|
||||
}
|
||||
if (!msgType) {
|
||||
msgType = 'POST_TELEMETRY_REQUEST';
|
||||
}
|
||||
console.log(`testNodeScript TODO: ${script}`);
|
||||
return of(script);
|
||||
}
|
||||
|
||||
@ -205,4 +205,10 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
validate() {
|
||||
if (this.useDefinedDirective()) {
|
||||
this.definedConfigComponent.validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
{{ 'rulenode.debug-mode' | translate }}
|
||||
</mat-checkbox>
|
||||
</section>
|
||||
<tb-rule-node-config
|
||||
<tb-rule-node-config #ruleNodeConfigComponent
|
||||
formControlName="configuration"
|
||||
[ruleNodeId]="ruleNode.ruleNodeId?.id"
|
||||
[nodeDefinition]="ruleNode.component.configurationDescriptor.nodeDefinition">
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { PageComponent } from '@shared/components/page.component';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
@ -24,6 +24,8 @@ import { RuleNodeType } from '@shared/models/rule-node.models';
|
||||
import { EntityType } from '@shared/models/entity-type.models';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { RuleChainService } from '@core/http/rule-chain.service';
|
||||
import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component';
|
||||
import { RuleNodeConfigComponent } from './rule-node-config.component';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-rule-node',
|
||||
@ -34,6 +36,8 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
|
||||
|
||||
@ViewChild('ruleNodeForm', {static: true}) ruleNodeForm: NgForm;
|
||||
|
||||
@ViewChild('ruleNodeConfigComponent', {static: false}) ruleNodeConfigComponent: RuleNodeConfigComponent;
|
||||
|
||||
@Input()
|
||||
ruleNode: FcRuleNode;
|
||||
|
||||
@ -127,4 +131,10 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validate() {
|
||||
if (this.ruleNode.component.type !== RuleNodeType.RULE_CHAIN) {
|
||||
this.ruleNodeConfigComponent.validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@ import { DialogComponent } from '@shared/components/dialog.component';
|
||||
import { UtilsService } from '@core/services/utils.service';
|
||||
import { EntityService } from '@core/http/entity.service';
|
||||
import { AddWidgetDialogComponent, AddWidgetDialogData } from '@home/pages/dashboard/add-widget-dialog.component';
|
||||
import { RuleNodeConfigComponent } from '@home/pages/rulechain/rule-node-config.component';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-rulechain-page',
|
||||
@ -585,6 +586,8 @@ export class RuleChainPageComponent extends PageComponent
|
||||
}
|
||||
|
||||
saveRuleNode() {
|
||||
this.ruleNodeComponent.validate();
|
||||
if (this.ruleNodeComponent.ruleNodeFormGroup.valid) {
|
||||
this.ruleNodeComponent.ruleNodeFormGroup.markAsPristine();
|
||||
if (this.editingRuleNode.error) {
|
||||
delete this.editingRuleNode.error;
|
||||
@ -594,6 +597,7 @@ export class RuleChainPageComponent extends PageComponent
|
||||
this.onModelChanged();
|
||||
this.updateRuleNodesHighlight();
|
||||
}
|
||||
}
|
||||
|
||||
saveRuleNodeLink() {
|
||||
this.ruleNodeLinkComponent.ruleNodeLinkFormGroup.markAsPristine();
|
||||
@ -938,6 +942,8 @@ export interface AddRuleNodeDialogData {
|
||||
export class AddRuleNodeDialogComponent extends DialogComponent<AddRuleNodeDialogComponent, FcRuleNode>
|
||||
implements OnInit, ErrorStateMatcher {
|
||||
|
||||
@ViewChild('tbRuleNode', {static: true}) ruleNodeDetailsComponent: RuleNodeDetailsComponent;
|
||||
|
||||
ruleNode: FcRuleNode;
|
||||
ruleChainId: string;
|
||||
|
||||
@ -973,6 +979,9 @@ export class AddRuleNodeDialogComponent extends DialogComponent<AddRuleNodeDialo
|
||||
|
||||
add(): void {
|
||||
this.submitted = true;
|
||||
this.ruleNodeDetailsComponent.validate();
|
||||
if (this.ruleNodeDetailsComponent.ruleNodeFormGroup.valid) {
|
||||
this.dialogRef.close(this.ruleNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,3 +15,4 @@
|
||||
///
|
||||
|
||||
export * from './page.component';
|
||||
export * from './js-func.component';
|
||||
|
||||
@ -78,6 +78,7 @@ export interface IRuleNodeConfigurationComponent {
|
||||
ruleNodeId: string;
|
||||
configuration: RuleNodeConfiguration;
|
||||
configurationChanged: Observable<RuleNodeConfiguration>;
|
||||
validate();
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@ -97,11 +98,17 @@ export abstract class RuleNodeConfigurationComponent extends PageComponent imple
|
||||
this.onConfigurationSet(this.configuration);
|
||||
}
|
||||
|
||||
validate() {
|
||||
this.onValidate();
|
||||
}
|
||||
|
||||
protected abstract onConfigurationSet(configuration: RuleNodeConfiguration);
|
||||
|
||||
protected notifyConfigurationUpdated(configuration: RuleNodeConfiguration) {
|
||||
this.configurationChangedEmiter.emit(configuration);
|
||||
}
|
||||
|
||||
protected onValidate() {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user