8726 workflow add a test button in workflow code step (#9016)

- add test button to workflow code step
- add test tab to workflow code step


https://github.com/user-attachments/assets/e180a827-7321-49a2-8026-88490c557da2



![image](https://github.com/user-attachments/assets/cacbd756-de3f-4141-a84c-8e1853f6556b)

![image](https://github.com/user-attachments/assets/ee170d81-8a22-4178-bd6d-11a0e8c73365)
This commit is contained in:
martmull
2024-12-13 11:16:29 +01:00
committed by GitHub
parent 07aaf0801c
commit b10d831371
95 changed files with 1537 additions and 1611 deletions

View File

@ -1,29 +0,0 @@
import { getDefaultFunctionInputFromInputSchema } from '@/workflow/utils/getDefaultFunctionInputFromInputSchema';
import { InputSchema } from '@/workflow/types/InputSchema';
describe('getDefaultFunctionInputFromInputSchema', () => {
it('should init function input properly', () => {
const inputSchema = {
params: {
type: 'object',
properties: {
a: {
type: 'string',
},
b: {
type: 'number',
},
},
},
} as InputSchema;
const expectedResult = {
params: {
a: null,
b: null,
},
};
expect(getDefaultFunctionInputFromInputSchema(inputSchema)).toEqual(
expectedResult,
);
});
});

View File

@ -1,22 +0,0 @@
import { InputSchema } from '@/workflow/types/InputSchema';
import { FunctionInput } from '@/workflow/types/FunctionInput';
import { isDefined } from '~/utils/isDefined';
export const getDefaultFunctionInputFromInputSchema = (
inputSchema: InputSchema | undefined,
): FunctionInput => {
return isDefined(inputSchema)
? Object.entries(inputSchema).reduce((acc, [key, value]) => {
if (['string', 'number', 'boolean'].includes(value.type)) {
acc[key] = null;
} else if (value.type === 'object') {
acc[key] = isDefined(value.properties)
? getDefaultFunctionInputFromInputSchema(value.properties)
: {};
} else if (value.type === 'array' && isDefined(value.items)) {
acc[key] = [];
}
return acc;
}, {} as FunctionInput)
: {};
};

View File

@ -1,129 +0,0 @@
import {
ArrayTypeNode,
ArrowFunction,
createSourceFile,
FunctionDeclaration,
LiteralTypeNode,
PropertySignature,
ScriptTarget,
StringLiteral,
SyntaxKind,
TypeNode,
UnionTypeNode,
VariableStatement,
} from 'typescript';
import { InputSchema, InputSchemaProperty } from '@/workflow/types/InputSchema';
import { isDefined } from 'twenty-ui';
const getTypeString = (typeNode: TypeNode): InputSchemaProperty => {
switch (typeNode.kind) {
case SyntaxKind.NumberKeyword:
return { type: 'number' };
case SyntaxKind.StringKeyword:
return { type: 'string' };
case SyntaxKind.BooleanKeyword:
return { type: 'boolean' };
case SyntaxKind.ArrayType:
return {
type: 'array',
items: getTypeString((typeNode as ArrayTypeNode).elementType),
};
case SyntaxKind.ObjectKeyword:
return { type: 'object' };
case SyntaxKind.TypeLiteral: {
const properties: InputSchema = {};
(typeNode as any).members.forEach((member: PropertySignature) => {
if (isDefined(member.name) && isDefined(member.type)) {
const memberName = (member.name as any).text;
properties[memberName] = getTypeString(member.type);
}
});
return { type: 'object', properties };
}
case SyntaxKind.UnionType: {
const unionNode = typeNode as UnionTypeNode;
const enumValues: string[] = [];
let isEnum = true;
unionNode.types.forEach((subType) => {
if (subType.kind === SyntaxKind.LiteralType) {
const literal = (subType as LiteralTypeNode).literal;
if (literal.kind === SyntaxKind.StringLiteral) {
enumValues.push((literal as StringLiteral).text);
} else {
isEnum = false;
}
} else {
isEnum = false;
}
});
if (isEnum) {
return { type: 'string', enum: enumValues };
}
return { type: 'unknown' };
}
default:
return { type: 'unknown' };
}
};
export const getFunctionInputSchema = (fileContent: string): InputSchema => {
const sourceFile = createSourceFile(
'temp.ts',
fileContent,
ScriptTarget.ESNext,
true,
);
const schema: InputSchema = {};
sourceFile.forEachChild((node) => {
if (node.kind === SyntaxKind.FunctionDeclaration) {
const funcNode = node as FunctionDeclaration;
const params = funcNode.parameters;
params.forEach((param) => {
const paramName = param.name.getText();
const typeNode = param.type;
if (isDefined(typeNode)) {
schema[paramName] = getTypeString(typeNode);
} else {
schema[paramName] = { type: 'unknown' };
}
});
} else if (node.kind === SyntaxKind.VariableStatement) {
const varStatement = node as VariableStatement;
varStatement.declarationList.declarations.forEach((declaration) => {
if (
isDefined(declaration.initializer) &&
declaration.initializer.kind === SyntaxKind.ArrowFunction
) {
const arrowFunction = declaration.initializer as ArrowFunction;
const params = arrowFunction.parameters;
params.forEach((param: any) => {
const paramName = param.name.text;
const typeNode = param.type;
if (isDefined(typeNode)) {
schema[paramName] = getTypeString(typeNode);
} else {
schema[paramName] = { type: 'unknown' };
}
});
}
});
}
});
return schema;
};