Merge branch 'feature/mvel-executor' of github.com:thingsboard/thingsboard into feature/mvel-executor

This commit is contained in:
Andrii Shvaika 2022-10-19 17:50:27 +03:00
commit c76e43ac25
10 changed files with 65 additions and 11 deletions

View File

@ -21,6 +21,7 @@ export interface SysParamsState {
allowedDashboardIds: string[];
edgesSupportEnabled: boolean;
hasRepository: boolean;
mvelEnabled: boolean;
}
export interface AuthPayload extends SysParamsState {

View File

@ -24,7 +24,8 @@ const emptyUserAuthState: AuthPayload = {
forceFullscreen: false,
allowedDashboardIds: [],
edgesSupportEnabled: false,
hasRepository: false
hasRepository: false,
mvelEnabled: false
};
export const initialState: AuthState = {

View File

@ -60,6 +60,11 @@ export const selectHasRepository = createSelector(
(state: AuthState) => state.hasRepository
);
export const selectMvelEnabled = createSelector(
selectAuthState,
(state: AuthState) => state.mvelEnabled
);
export function getCurrentAuthState(store: Store<AppState>): AuthState {
let state: AuthState;
store.pipe(select(selectAuth), take(1)).subscribe(

View File

@ -478,11 +478,20 @@ export class AuthService {
}
}
private loadMvelEnabled(authUser: AuthUser): Observable<boolean> {
if (authUser.authority === Authority.TENANT_ADMIN) {
return this.http.get<boolean>('/api/ruleChain/mvelEnabled', defaultHttpOptions());
} else {
return of(false);
}
}
private loadSystemParams(authPayload: AuthPayload): Observable<SysParamsState> {
const sources = [this.loadIsUserTokenAccessEnabled(authPayload.authUser),
this.fetchAllowedDashboardIds(authPayload),
this.loadIsEdgesSupportEnabled(),
this.loadHasRepository(authPayload.authUser),
this.loadMvelEnabled(authPayload.authUser),
this.timeService.loadMaxDatapointsLimit()];
return forkJoin(sources)
.pipe(map((data) => {
@ -490,7 +499,8 @@ export class AuthService {
const allowedDashboardIds: string[] = data[1] as string[];
const edgesSupportEnabled: boolean = data[2] as boolean;
const hasRepository: boolean = data[3] as boolean;
return {userTokenAccessEnabled, allowedDashboardIds, edgesSupportEnabled, hasRepository};
const mvelEnabled: boolean = data[4] as boolean;
return {userTokenAccessEnabled, allowedDashboardIds, edgesSupportEnabled, hasRepository, mvelEnabled};
}, catchError((err) => {
return of({});
})));

View File

@ -0,0 +1,21 @@
///
/// 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.
///
export * from './auth.actions';
export * from './auth.models';
export * from './auth.reducer';
export * from './auth.selectors';
export * from './auth.service';

View File

@ -31,7 +31,7 @@ import { ComponentDescriptorService } from './component-descriptor.service';
import {
IRuleNodeConfigurationComponent,
LinkLabel,
RuleNodeComponentDescriptor, RuleNodeConfiguration,
RuleNodeComponentDescriptor, RuleNodeConfiguration, ScriptLanguage,
TestScriptInputParams,
TestScriptResult
} from '@app/shared/models/rule-node.models';
@ -170,8 +170,12 @@ export class RuleChainService {
return this.http.get<DebugRuleNodeEventBody>(`/api/ruleNode/${ruleNodeId}/debugIn`, defaultHttpOptionsFromConfig(config));
}
public testScript(inputParams: TestScriptInputParams, config?: RequestConfig): Observable<TestScriptResult> {
return this.http.post<TestScriptResult>('/api/ruleChain/testScript', inputParams, defaultHttpOptionsFromConfig(config));
public testScript(inputParams: TestScriptInputParams, scriptLang?: ScriptLanguage, config?: RequestConfig): Observable<TestScriptResult> {
let url = '/api/ruleChain/testScript';
if (scriptLang) {
url += `?scriptLang=${scriptLang}`;
}
return this.http.post<TestScriptResult>(url, inputParams, defaultHttpOptionsFromConfig(config));
}
private loadRuleNodeComponents(ruleChainType: RuleChainType, config?: RequestConfig): Observable<Array<RuleNodeComponentDescriptor>> {

View File

@ -22,3 +22,4 @@ export * from './ws/telemetry-websocket.service';
export * from './core.state';
export * from './core.module';
export * from './utils';
export * from './auth/public-api';

View File

@ -24,6 +24,7 @@ import {
NodeScriptTestDialogData
} from '@shared/components/dialog/node-script-test-dialog.component';
import { sortObjectKeys } from '@core/utils';
import { ScriptLanguage } from '@shared/models/rule-node.models';
@Injectable({
providedIn: 'root'
@ -35,7 +36,8 @@ export class NodeScriptTestService {
}
testNodeScript(script: string, scriptType: string, functionTitle: string,
functionName: string, argNames: string[], ruleNodeId: string, helpId?: string): Observable<string> {
functionName: string, argNames: string[], ruleNodeId: string, helpId?: string,
scriptLang?: ScriptLanguage): Observable<string> {
if (ruleNodeId) {
return this.ruleChainService.getLatestRuleNodeDebugInput(ruleNodeId).pipe(
switchMap((debugIn) => {
@ -57,13 +59,14 @@ export class NodeScriptTestService {
);
} else {
return this.openTestScriptDialog(script, scriptType, functionTitle,
functionName, argNames, null, null, null, helpId);
functionName, argNames, null, null, null, helpId, scriptLang);
}
}
private openTestScriptDialog(script: string, scriptType: string,
functionTitle: string, functionName: string, argNames: string[],
msg?: any, metadata?: {[key: string]: string}, msgType?: string, helpId?: string): Observable<string> {
msg?: any, metadata?: {[key: string]: string}, msgType?: string, helpId?: string,
scriptLang?: ScriptLanguage): Observable<string> {
if (!msg) {
msg = {
temperature: 22.4,
@ -95,7 +98,8 @@ export class NodeScriptTestService {
script,
scriptType,
argNames,
helpId
helpId,
scriptLang
}
}).afterClosed();
}

View File

@ -37,7 +37,7 @@ import { Router } from '@angular/router';
import { DialogComponent } from '@shared/components/dialog.component';
import { ContentType } from '@shared/models/constants';
import { JsonContentComponent } from '@shared/components/json-content.component';
import { TestScriptInputParams } from '@shared/models/rule-node.models';
import { ScriptLanguage, TestScriptInputParams } from '@shared/models/rule-node.models';
import { RuleChainService } from '@core/http/rule-chain.service';
import { mergeMap } from 'rxjs/operators';
import { ActionNotificationShow } from '@core/notification/notification.actions';
@ -49,6 +49,7 @@ export interface NodeScriptTestDialogData {
functionTitle: string;
functionName: string;
argNames: string[];
scriptLang?: ScriptLanguage;
msg?: any;
metadata?: {[key: string]: string};
msgType?: string;
@ -191,7 +192,8 @@ export class NodeScriptTestDialogComponent extends DialogComponent<NodeScriptTes
metadata: this.nodeScriptTestFormGroup.get('metadata').value,
script: this.nodeScriptTestFormGroup.get('script').value
};
return this.ruleChainService.testScript(inputParams).pipe(
const scriptLang = this.data.scriptLang ? this.data.scriptLang : ScriptLanguage.JS;
return this.ruleChainService.testScript(inputParams, scriptLang).pipe(
mergeMap((result) => {
if (result.error) {
this.store.dispatch(new ActionNotificationShow(

View File

@ -328,6 +328,11 @@ export interface FcRuleEdge extends FcEdge {
labels?: string[];
}
export enum ScriptLanguage {
JS = 'JS',
MVEL = 'MVEL'
}
export interface TestScriptInputParams {
script: string;
scriptType: string;