Add support for run time params in action execution (#98)
Adds a third parameter to the Action.run function that can be referenced inside an action config
Usage
`{{ Api1.run(...,...,{key: value}) }}` inside property pane
`{{this.params.key}}` inside action pane
* You can reference data tree properties in the params values:
`{{ Api1.run(..., ..., { key: "Input1.text.toUpperCase()" })`
* Bindings can have both params and data tree values referenced.
* Param values can be javascript functions
`body: {{ this.params.list.map(i => Input1.text + i ) }}`
This commit is contained in:
parent
70c4dd5964
commit
b6c710cfa2
|
|
@ -28,13 +28,14 @@ export type RunActionPayload = {
|
|||
actionId: string;
|
||||
onSuccess: string;
|
||||
onError: string;
|
||||
params: Record<string, any>;
|
||||
};
|
||||
|
||||
export interface DataTreeAction extends Omit<ActionData, "data" | "config"> {
|
||||
data: ActionResponse["body"];
|
||||
actionId: string;
|
||||
config: Partial<ActionConfig>;
|
||||
run: ActionDispatcher<RunActionPayload, [string, string]> | {};
|
||||
run: ActionDispatcher<RunActionPayload, [string, string, string]> | {};
|
||||
dynamicBindingPathList: Property[];
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION;
|
||||
}
|
||||
|
|
@ -103,13 +104,19 @@ export class DataTreeFactory {
|
|||
dynamicBindingPathList,
|
||||
data: a.data ? a.data.body : {},
|
||||
run: withFunctions
|
||||
? function(this: DataTreeAction, onSuccess: string, onError: string) {
|
||||
? function(
|
||||
this: DataTreeAction,
|
||||
onSuccess: string,
|
||||
onError: string,
|
||||
params = "",
|
||||
) {
|
||||
return {
|
||||
type: "RUN_ACTION",
|
||||
payload: {
|
||||
actionId: this.actionId,
|
||||
onSuccess: onSuccess ? `{{${onSuccess.toString()}}}` : "",
|
||||
onError: onError ? `{{${onError.toString()}}}` : "",
|
||||
params,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,20 +143,68 @@ export function* evaluateDynamicBoundValueSaga(path: string): any {
|
|||
return dynamicResult.result;
|
||||
}
|
||||
|
||||
export function* getActionParams(jsonPathKeys: string[] | undefined) {
|
||||
if (_.isNil(jsonPathKeys)) return [];
|
||||
const EXECUTION_PARAM_PATH = "this.params";
|
||||
const getExecutionParamPath = (key: string) => `${EXECUTION_PARAM_PATH}.${key}`;
|
||||
|
||||
export function* getActionParams(
|
||||
bindings: string[] | undefined,
|
||||
executionParams?: Record<string, any>,
|
||||
) {
|
||||
if (_.isNil(bindings)) return [];
|
||||
let dataTreeBindings = bindings;
|
||||
|
||||
if (executionParams && Object.keys(executionParams).length) {
|
||||
// List of params in the path format
|
||||
const executionParamsPathList = Object.keys(executionParams).map(
|
||||
getExecutionParamPath,
|
||||
);
|
||||
const paramSearchRegex = new RegExp(executionParamsPathList.join("|"), "g");
|
||||
// Bindings with references to execution params
|
||||
const executionBindings = bindings.filter(binding =>
|
||||
paramSearchRegex.test(binding),
|
||||
);
|
||||
|
||||
// Replace references with values
|
||||
const replacedBindings = executionBindings.map(binding => {
|
||||
let replaced = binding;
|
||||
const matches = binding.match(paramSearchRegex);
|
||||
if (matches && matches.length) {
|
||||
matches.forEach(match => {
|
||||
// we add one for substring index to account for '.'
|
||||
const paramKey = match.substring(EXECUTION_PARAM_PATH.length + 1);
|
||||
let paramValue = executionParams[paramKey];
|
||||
if (paramValue) {
|
||||
if (typeof paramValue === "object") {
|
||||
paramValue = JSON.stringify(paramValue);
|
||||
}
|
||||
replaced = replaced.replace(match, paramValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
return replaced;
|
||||
});
|
||||
// Replace binding with replaced bindings for evaluation
|
||||
dataTreeBindings = dataTreeBindings.map(key => {
|
||||
if (executionBindings.includes(key)) {
|
||||
return replacedBindings[executionBindings.indexOf(key)];
|
||||
}
|
||||
return key;
|
||||
});
|
||||
}
|
||||
// Evaluate all values
|
||||
const values: any = yield all(
|
||||
jsonPathKeys.map((jsonPath: string) => {
|
||||
return call(evaluateDynamicBoundValueSaga, jsonPath);
|
||||
dataTreeBindings.map((binding: string) => {
|
||||
return call(evaluateDynamicBoundValueSaga, binding);
|
||||
}),
|
||||
);
|
||||
const dynamicBindings: Record<string, string> = {};
|
||||
jsonPathKeys.forEach((key, i) => {
|
||||
// convert to object and transform non string values
|
||||
const actionParams: Record<string, string> = {};
|
||||
bindings.forEach((key, i) => {
|
||||
let value = values[i];
|
||||
if (typeof value === "object") value = JSON.stringify(value);
|
||||
dynamicBindings[key] = value;
|
||||
actionParams[key] = value;
|
||||
});
|
||||
return mapToPropList(dynamicBindings);
|
||||
return mapToPropList(actionParams);
|
||||
}
|
||||
|
||||
export function extractBindingsFromAction(action: Action) {
|
||||
|
|
@ -175,11 +223,15 @@ export function* executeActionSaga(
|
|||
apiAction: RunActionPayload,
|
||||
event: ExecuteActionPayloadEvent,
|
||||
) {
|
||||
const { actionId, onSuccess, onError } = apiAction;
|
||||
const { actionId, onSuccess, onError, params } = apiAction;
|
||||
try {
|
||||
yield put(executeApiActionRequest({ id: apiAction.actionId }));
|
||||
const api: RestAction = yield select(getAction, actionId);
|
||||
const params: Property[] = yield call(getActionParams, api.jsonPathKeys);
|
||||
const actionParams: Property[] = yield call(
|
||||
getActionParams,
|
||||
api.jsonPathKeys,
|
||||
params,
|
||||
);
|
||||
const pagination =
|
||||
event.type === EventType.ON_NEXT_PAGE
|
||||
? "NEXT"
|
||||
|
|
@ -188,7 +240,7 @@ export function* executeActionSaga(
|
|||
: undefined;
|
||||
const executeActionRequest: ExecuteActionRequest = {
|
||||
action: { id: actionId },
|
||||
params,
|
||||
params: actionParams,
|
||||
paginationField: pagination,
|
||||
};
|
||||
const timeout = yield select(getActionTimeout, actionId);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user