Rename serverlessFunction to logicFunction (#17494)

## Summary

Rename "Serverless Function" to "Logic Function" across the codebase for
clearer naming.

### Environment Variable Changes

| Old | New |
|-----|-----|
| `SERVERLESS_TYPE` | `LOGIC_FUNCTION_TYPE` |
| `SERVERLESS_LAMBDA_REGION` | `LOGIC_FUNCTION_LAMBDA_REGION` |
| `SERVERLESS_LAMBDA_ROLE` | `LOGIC_FUNCTION_LAMBDA_ROLE` |
| `SERVERLESS_LAMBDA_SUBHOSTING_URL` |
`LOGIC_FUNCTION_LAMBDA_SUBHOSTING_URL` |
| `SERVERLESS_LAMBDA_ACCESS_KEY_ID` |
`LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID` |
| `SERVERLESS_LAMBDA_SECRET_ACCESS_KEY` |
`LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY` |

### Breaking Changes

- Environment variables must be updated in production deployments
- Database migration renames `serverlessFunction` → `logicFunction`
tables
This commit is contained in:
Charles Bochet
2026-01-28 01:42:19 +01:00
committed by GitHub
parent 59d123d2b1
commit da6f1bbef3
351 changed files with 5054 additions and 5139 deletions
@@ -5,7 +5,7 @@ import {
} from '@/workflow/types/Workflow';
import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow';
import { WorkflowEditActionAiAgent } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent';
import { WorkflowActionServerlessFunction } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowActionServerlessFunction';
import { WorkflowActionLogicFunction } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowActionLogicFunction';
import { WorkflowEditActionCreateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord';
import { WorkflowEditActionDeleteRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionDeleteRecord';
import { WorkflowEditActionEmpty } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmpty';
@@ -106,7 +106,7 @@ export const WorkflowRunStepNodeDetail = ({
switch (stepDefinition.definition.type) {
case 'CODE': {
return (
<WorkflowActionServerlessFunction
<WorkflowActionLogicFunction
key={stepId}
action={stepDefinition.definition}
actionOptions={{
@@ -4,7 +4,7 @@ import {
} from '@/workflow/types/Workflow';
import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow';
import { WorkflowEditActionAiAgent } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/components/WorkflowEditActionAiAgent';
import { WorkflowActionServerlessFunction } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowActionServerlessFunction';
import { WorkflowActionLogicFunction } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowActionLogicFunction';
import { WorkflowEditActionCreateRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionCreateRecord';
import { WorkflowEditActionDeleteRecord } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionDeleteRecord';
import { WorkflowEditActionEmpty } from '@/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionEmpty';
@@ -108,7 +108,7 @@ export const WorkflowStepDetail = ({
switch (stepDefinition.definition.type) {
case 'CODE': {
return (
<WorkflowActionServerlessFunction
<WorkflowActionLogicFunction
key={stepId}
action={stepDefinition.definition}
actionOptions={props}
@@ -41,9 +41,9 @@ describe('useUpdateStep', () => {
type: 'CODE' as const,
settings: {
input: {
serverlessFunctionId: 'id',
serverlessFunctionVersion: '1',
serverlessFunctionInput: {},
logicFunctionId: 'id',
logicFunctionVersion: '1',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -28,9 +28,9 @@ describe('getIsDescendantOfIterator', () => {
nextStepIds: ['iterator1'],
settings: {
input: {
serverlessFunctionId: 'func2',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'func2',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -48,9 +48,9 @@ describe('getIsDescendantOfIterator', () => {
nextStepIds: [],
settings: {
input: {
serverlessFunctionId: 'func3',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'func3',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -89,9 +89,9 @@ describe('getIsDescendantOfIterator', () => {
nextStepIds: [],
settings: {
input: {
serverlessFunctionId: 'func4',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'func4',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -27,9 +27,9 @@ describe('getStepInfoHistoryItem', () => {
nextStepIds: [],
settings: {
input: {
serverlessFunctionId: 'func',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'func',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -12,9 +12,9 @@ describe('getWorkflowPreviousSteps', () => {
nextStepIds: ['step2', 'step3'],
settings: {
input: {
serverlessFunctionId: 'func1',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'func1',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -31,9 +31,9 @@ describe('getWorkflowPreviousSteps', () => {
nextStepIds: ['step4'],
settings: {
input: {
serverlessFunctionId: 'func2',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'func2',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -50,9 +50,9 @@ describe('getWorkflowPreviousSteps', () => {
nextStepIds: ['step4'],
settings: {
input: {
serverlessFunctionId: 'func3',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'func3',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -69,9 +69,9 @@ describe('getWorkflowPreviousSteps', () => {
nextStepIds: [],
settings: {
input: {
serverlessFunctionId: 'func4',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'func4',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -17,9 +17,9 @@ const mockFlow = {
valid: true,
settings: {
input: {
serverlessFunctionId: '',
serverlessFunctionInput: {},
serverlessFunctionVersion: '',
logicFunctionId: '',
logicFunctionInput: {},
logicFunctionVersion: '',
},
outputSchema: {},
errorHandlingOptions: {
@@ -36,9 +36,9 @@ const mockFlow = {
valid: true,
settings: {
input: {
serverlessFunctionId: '',
serverlessFunctionInput: {},
serverlessFunctionVersion: '',
logicFunctionId: '',
logicFunctionInput: {},
logicFunctionVersion: '',
},
outputSchema: {},
errorHandlingOptions: {
@@ -139,9 +139,9 @@ describe('getWorkflowRunStepContext', () => {
valid: true,
settings: {
input: {
serverlessFunctionId: '',
serverlessFunctionInput: {},
serverlessFunctionVersion: '',
logicFunctionId: '',
logicFunctionInput: {},
logicFunctionVersion: '',
},
outputSchema: {},
errorHandlingOptions: {
@@ -176,9 +176,9 @@ describe('getWorkflowRunStepContext', () => {
valid: true,
settings: {
input: {
serverlessFunctionId: '',
serverlessFunctionInput: {},
serverlessFunctionVersion: '',
logicFunctionId: '',
logicFunctionInput: {},
logicFunctionVersion: '',
},
outputSchema: {},
errorHandlingOptions: {
@@ -21,18 +21,17 @@ describe('getWorkflowRunStepExecutionStatus', () => {
steps: [
{
id: stepId,
name: 'Code - Serverless Function',
name: 'Code - Logic Function',
type: 'CODE',
valid: false,
settings: {
input: {
serverlessFunctionId:
'5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c',
serverlessFunctionInput: {
logicFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c',
logicFunctionInput: {
a: null,
b: null,
},
serverlessFunctionVersion: 'draft',
logicFunctionVersion: 'draft',
},
outputSchema: {
link: {
@@ -87,18 +86,17 @@ describe('getWorkflowRunStepExecutionStatus', () => {
steps: [
{
id: stepId,
name: 'Code - Serverless Function',
name: 'Code - Logic Function',
type: 'CODE',
valid: false,
settings: {
input: {
serverlessFunctionId:
'5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c',
serverlessFunctionInput: {
logicFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c',
logicFunctionInput: {
a: null,
b: null,
},
serverlessFunctionVersion: 'draft',
logicFunctionVersion: 'draft',
},
outputSchema: {
link: {
@@ -154,18 +152,17 @@ describe('getWorkflowRunStepExecutionStatus', () => {
steps: [
{
id: stepId,
name: 'Code - Serverless Function',
name: 'Code - Logic Function',
type: 'CODE',
valid: false,
settings: {
input: {
serverlessFunctionId:
'5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c',
serverlessFunctionInput: {
logicFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c',
logicFunctionInput: {
a: null,
b: null,
},
serverlessFunctionVersion: 'draft',
logicFunctionVersion: 'draft',
},
outputSchema: {
link: {
@@ -188,18 +185,17 @@ describe('getWorkflowRunStepExecutionStatus', () => {
},
{
id: secondStepId,
name: 'Code - Serverless Function',
name: 'Code - Logic Function',
type: 'CODE',
valid: false,
settings: {
input: {
serverlessFunctionId:
'5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c',
serverlessFunctionInput: {
logicFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c',
logicFunctionInput: {
a: null,
b: null,
},
serverlessFunctionVersion: 'draft',
logicFunctionVersion: 'draft',
},
outputSchema: {
link: {
@@ -5,16 +5,16 @@ describe('getWorkflowVariablesUsedInStep', () => {
it('returns the variables used in a one-level object', () => {
const step: WorkflowStep = {
id: '42e8b60e-dd44-417a-875f-823d63f16819',
name: 'Code - Serverless Function',
name: 'Code - Logic Function',
type: 'CODE',
valid: false,
settings: {
input: {
serverlessFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2d',
serverlessFunctionInput: {
logicFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2d',
logicFunctionInput: {
a: '{{5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c.a.b.c.d}}',
},
serverlessFunctionVersion: 'draft',
logicFunctionVersion: 'draft',
},
outputSchema: {},
errorHandlingOptions: {
@@ -97,16 +97,16 @@ Set {
it('returns all the variables used in a single field', () => {
const step: WorkflowStep = {
id: '42e8b60e-dd44-417a-875f-823d63f16819',
name: 'Code - Serverless Function',
name: 'Code - Logic Function',
type: 'CODE',
valid: false,
settings: {
input: {
serverlessFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2d',
serverlessFunctionInput: {
logicFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2d',
logicFunctionInput: {
a: '{{5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c.a}} {{5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c.b}} {{5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c.c}} {{5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c.d}}',
},
serverlessFunctionVersion: 'draft',
logicFunctionVersion: 'draft',
},
outputSchema: {},
errorHandlingOptions: {
@@ -137,16 +137,16 @@ Set {
it('returns the variables used many times only once', () => {
const step: WorkflowStep = {
id: '42e8b60e-dd44-417a-875f-823d63f16819',
name: 'Code - Serverless Function',
name: 'Code - Logic Function',
type: 'CODE',
valid: false,
settings: {
input: {
serverlessFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2d',
serverlessFunctionInput: {
logicFunctionId: '5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2d',
logicFunctionInput: {
a: '{{5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c.a}} {{5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c.a}} {{5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c.a}} {{5f7b9b44-bb07-41ba-aef8-ec0eaa5eea2c.a}}',
},
serverlessFunctionVersion: 'draft',
logicFunctionVersion: 'draft',
},
outputSchema: {},
errorHandlingOptions: {
@@ -2,7 +2,7 @@ import { type WorkflowCodeAction } from '@/workflow/types/Workflow';
import { lazy, Suspense } from 'react';
import { RightDrawerSkeletonLoader } from '~/loading/components/RightDrawerSkeletonLoader';
type WorkflowActionServerlessFunctionProps = {
type WorkflowActionLogicFunctionProps = {
action: WorkflowCodeAction;
actionOptions:
| {
@@ -14,32 +14,32 @@ type WorkflowActionServerlessFunctionProps = {
};
};
const WorkflowEditActionServerlessFunction = lazy(() =>
const WorkflowEditActionLogicFunction = lazy(() =>
import(
'@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction'
'@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionLogicFunction'
).then((module) => ({
default: module.WorkflowEditActionServerlessFunction,
default: module.WorkflowEditActionLogicFunction,
})),
);
const WorkflowReadonlyActionServerlessFunction = lazy(() =>
const WorkflowReadonlyActionLogicFunction = lazy(() =>
import(
'@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowReadonlyActionServerlessFunction'
'@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowReadonlyActionLogicFunction'
).then((module) => ({
default: module.WorkflowReadonlyActionServerlessFunction,
default: module.WorkflowReadonlyActionLogicFunction,
})),
);
export const WorkflowActionServerlessFunction = ({
export const WorkflowActionLogicFunction = ({
action,
actionOptions,
}: WorkflowActionServerlessFunctionProps) => {
}: WorkflowActionLogicFunctionProps) => {
return (
<Suspense fallback={<RightDrawerSkeletonLoader />}>
{actionOptions.readonly ? (
<WorkflowReadonlyActionServerlessFunction action={action} />
<WorkflowReadonlyActionLogicFunction action={action} />
) : (
<WorkflowEditActionServerlessFunction
<WorkflowEditActionLogicFunction
action={action}
actionOptions={actionOptions}
/>
@@ -1,5 +1,8 @@
import { useGetAvailablePackages } from '@/settings/serverless-functions/hooks/useGetAvailablePackages';
import { useServerlessFunctionUpdateFormState } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
import {
type LogicFunctionFormValues,
useLogicFunctionUpdateFormState,
} from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
import { useFullScreenModal } from '@/ui/layout/fullscreen/hooks/useFullScreenModal';
import { type BreadcrumbProps } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
@@ -9,11 +12,11 @@ import { type WorkflowCodeAction } from '@/workflow/types/Workflow';
import { setNestedValue } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/setNestedValue';
import { CmdEnterActionButton } from '@/action-menu/components/CmdEnterActionButton';
import { ServerlessFunctionExecutionResult } from '@/serverless-functions/components/ServerlessFunctionExecutionResult';
import { INDEX_FILE_NAME } from '@/serverless-functions/constants/IndexFileName';
import { useTestServerlessFunction } from '@/serverless-functions/hooks/useTestServerlessFunction';
import { getFunctionInputFromSourceCode } from '@/serverless-functions/utils/getFunctionInputFromSourceCode';
import { mergeDefaultFunctionInputAndFunctionInput } from '@/serverless-functions/utils/mergeDefaultFunctionInputAndFunctionInput';
import { LogicFunctionExecutionResult } from '@/logic-functions/components/LogicFunctionExecutionResult';
import { INDEX_FILE_NAME } from '@/logic-functions/constants/IndexFileName';
import { useTestLogicFunction } from '@/logic-functions/hooks/useTestLogicFunction';
import { getFunctionInputFromSourceCode } from '@/logic-functions/utils/getFunctionInputFromSourceCode';
import { mergeDefaultFunctionInputAndFunctionInput } from '@/logic-functions/utils/mergeDefaultFunctionInputAndFunctionInput';
import { InputLabel } from '@/ui/input/components/InputLabel';
import { TextArea } from '@/ui/input/components/TextArea';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
@@ -22,19 +25,22 @@ import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotke
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { WorkflowEditActionServerlessFunctionFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunctionFields';
import { WorkflowServerlessFunctionCodeEditor } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowServerlessFunctionCodeEditor';
import { WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowServerlessFunctionTabListComponentId';
import { serverlessFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/serverlessFunctionTestDataFamilyState';
import { WorkflowServerlessFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowServerlessFunctionTabId';
import { WorkflowEditActionLogicFunctionFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionLogicFunctionFields';
import { WorkflowLogicFunctionCodeEditor } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowLogicFunctionCodeEditor';
import { WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowLogicFunctionTabListComponentId';
import {
type LogicFunctionTestData,
logicFunctionTestDataFamilyState,
} from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState';
import { WorkflowLogicFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowLogicFunctionTabId';
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers';
import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components/WorkflowVariablePicker';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { SOURCE_FOLDER_NAME } from '@/serverless-functions/constants/SourceFolderName';
import { computeNewSources } from '@/serverless-functions/utils/computeNewSources';
import { usePersistServerlessFunction } from '@/settings/serverless-functions/hooks/usePersistServerlessFunction';
import { SOURCE_FOLDER_NAME } from '@/logic-functions/constants/SourceFolderName';
import { computeNewSources } from '@/logic-functions/utils/computeNewSources';
import { usePersistLogicFunction } from '@/settings/logic-functions/hooks/usePersistLogicFunction';
import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter';
import { CODE_ACTION } from '@/workflow/workflow-steps/workflow-actions/constants/actions/CodeAction';
import { type Monaco } from '@monaco-editor/react';
@@ -71,7 +77,7 @@ const StyledFullScreenCodeEditorContainer = styled.div`
min-height: 0;
`;
type WorkflowEditActionServerlessFunctionProps = {
type WorkflowEditActionLogicFunctionProps = {
action: WorkflowCodeAction;
actionOptions:
| {
@@ -83,24 +89,24 @@ type WorkflowEditActionServerlessFunctionProps = {
};
};
type ServerlessFunctionInputFormData = {
[field: string]: string | ServerlessFunctionInputFormData;
type LogicFunctionInputFormData = {
[field: string]: string | LogicFunctionInputFormData;
};
export const WorkflowEditActionServerlessFunction = ({
export const WorkflowEditActionLogicFunction = ({
action,
actionOptions,
}: WorkflowEditActionServerlessFunctionProps) => {
}: WorkflowEditActionLogicFunctionProps) => {
const { t } = useLingui();
const [isFullScreen, setIsFullScreen] = useState(false);
const isMobile = useIsMobile();
const serverlessFunctionId = action.settings.input.serverlessFunctionId;
const fullScreenFocusId = `code-editor-fullscreen-${serverlessFunctionId}`;
const logicFunctionId = action.settings.input.logicFunctionId;
const fullScreenFocusId = `code-editor-fullscreen-${logicFunctionId}`;
const activeTabId = useRecoilComponentValue(
activeTabIdComponentState,
WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID,
WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID,
);
const { updateServerlessFunction } = usePersistServerlessFunction();
const { updateLogicFunction } = usePersistLogicFunction();
const { getUpdatableWorkflowVersion } =
useGetUpdatableWorkflowVersionOrThrow();
@@ -109,21 +115,23 @@ export const WorkflowEditActionServerlessFunction = ({
);
const workflow = useWorkflowWithCurrentVersion(workflowVisualizerWorkflowId);
const { availablePackages } = useGetAvailablePackages({
id: serverlessFunctionId,
id: logicFunctionId,
});
const [serverlessFunctionTestData, setServerlessFunctionTestData] =
useRecoilState(serverlessFunctionTestDataFamilyState(serverlessFunctionId));
const [logicFunctionTestData, setLogicFunctionTestData] =
useRecoilState<LogicFunctionTestData>(
logicFunctionTestDataFamilyState(logicFunctionId),
);
const [functionInput, setFunctionInput] =
useState<ServerlessFunctionInputFormData>(
action.settings.input.serverlessFunctionInput,
useState<LogicFunctionInputFormData>(
action.settings.input.logicFunctionInput,
);
const { formValues, setFormValues, loading } =
useServerlessFunctionUpdateFormState({
serverlessFunctionId,
serverlessFunctionVersion: 'draft',
useLogicFunctionUpdateFormState({
logicFunctionId,
logicFunctionVersion: 'draft',
});
const updateOutputSchemaFromTestResult = async (testResult: object) => {
@@ -137,15 +145,15 @@ export const WorkflowEditActionServerlessFunction = ({
});
};
const { testServerlessFunction, isTesting } = useTestServerlessFunction({
serverlessFunctionId,
const { testLogicFunction, isTesting } = useTestLogicFunction({
logicFunctionId,
callback: updateOutputSchemaFromTestResult,
});
const handleSave = useDebouncedCallback(async () => {
await updateServerlessFunction({
await updateLogicFunction({
input: {
id: serverlessFunctionId,
id: logicFunctionId,
update: {
name: formValues.name,
description: formValues.description,
@@ -159,7 +167,7 @@ export const WorkflowEditActionServerlessFunction = ({
if (actionOptions.readonly === true) {
return;
}
setFormValues((prevState) => {
setFormValues((prevState: LogicFunctionFormValues) => {
return {
...prevState,
code: computeNewSources({
@@ -186,15 +194,15 @@ export const WorkflowEditActionServerlessFunction = ({
const newFunctionInput = await getFunctionInputFromSourceCode(sourceCode);
const newMergedInput = mergeDefaultFunctionInputAndFunctionInput({
newInput: newFunctionInput,
oldInput: action.settings.input.serverlessFunctionInput,
oldInput: action.settings.input.logicFunctionInput,
});
const newMergedTestInput = mergeDefaultFunctionInputAndFunctionInput({
newInput: newFunctionInput,
oldInput: serverlessFunctionTestData.input,
oldInput: logicFunctionTestData.input,
});
setFunctionInput(newMergedInput);
setServerlessFunctionTestData((prev) => ({
setLogicFunctionTestData((prev) => ({
...prev,
input: newMergedTestInput,
}));
@@ -214,7 +222,7 @@ export const WorkflowEditActionServerlessFunction = ({
},
input: {
...action.settings.input,
serverlessFunctionInput: newMergedInput,
logicFunctionInput: newMergedInput,
},
},
});
@@ -233,7 +241,7 @@ export const WorkflowEditActionServerlessFunction = ({
...action.settings,
input: {
...action.settings.input,
serverlessFunctionInput: updatedFunctionInput,
logicFunctionInput: updatedFunctionInput,
},
},
});
@@ -245,11 +253,11 @@ export const WorkflowEditActionServerlessFunction = ({
}
const updatedTestFunctionInput = setNestedValue(
serverlessFunctionTestData.input,
logicFunctionTestData.input,
path,
value,
);
setServerlessFunctionTestData((prev) => ({
setLogicFunctionTestData((prev) => ({
...prev,
input: updatedTestFunctionInput,
}));
@@ -261,7 +269,7 @@ export const WorkflowEditActionServerlessFunction = ({
}
if (!isTesting) {
await testServerlessFunction();
await testLogicFunction();
}
};
@@ -302,19 +310,19 @@ export const WorkflowEditActionServerlessFunction = ({
const tabs = [
{
id: WorkflowServerlessFunctionTabId.CODE,
id: WorkflowLogicFunctionTabId.CODE,
title: t`Code`,
Icon: IconCode,
},
{
id: WorkflowServerlessFunctionTabId.TEST,
id: WorkflowLogicFunctionTabId.TEST,
title: t`Test`,
Icon: IconPlayerPlay,
},
];
useEffect(() => {
setFunctionInput(action.settings.input.serverlessFunctionInput);
setFunctionInput(action.settings.input.logicFunctionInput);
}, [action]);
useHotkeysOnFocusedElement({
@@ -328,7 +336,7 @@ export const WorkflowEditActionServerlessFunction = ({
dependencies: [isFullScreen],
});
const testLogsTextAreaId = `${serverlessFunctionId}-test-logs`;
const testLogsTextAreaId = `${logicFunctionId}-test-logs`;
const breadcrumbLinks: BreadcrumbProps['links'] = [
{
@@ -358,7 +366,7 @@ export const WorkflowEditActionServerlessFunction = ({
handleExitFullScreen();
}
},
listenerId: `full-screen-overlay-${serverlessFunctionId}`,
listenerId: `full-screen-overlay-${logicFunctionId}`,
enabled: isFullScreen,
});
@@ -383,7 +391,7 @@ export const WorkflowEditActionServerlessFunction = ({
const fullScreenOverlay = renderFullScreenModal(
<div data-globally-prevent-click-outside="true">
<WorkflowEditActionServerlessFunctionFields
<WorkflowEditActionLogicFunctionFields
functionInput={functionInput}
VariablePicker={WorkflowVariablePicker}
onInputChange={handleInputChange}
@@ -415,20 +423,18 @@ export const WorkflowEditActionServerlessFunction = ({
<StyledTabList
tabs={tabs}
behaveAsLinks={false}
componentInstanceId={
WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID
}
componentInstanceId={WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID}
/>
<WorkflowStepBody>
{activeTabId === WorkflowServerlessFunctionTabId.CODE && (
{activeTabId === WorkflowLogicFunctionTabId.CODE && (
<>
<WorkflowEditActionServerlessFunctionFields
<WorkflowEditActionLogicFunctionFields
functionInput={functionInput}
VariablePicker={WorkflowVariablePicker}
onInputChange={handleInputChange}
readonly={actionOptions.readonly}
/>
<WorkflowServerlessFunctionCodeEditor
<WorkflowLogicFunctionCodeEditor
value={indexFileContent}
onChange={handleCodeChange}
onMount={handleEditorDidMount}
@@ -444,28 +450,26 @@ export const WorkflowEditActionServerlessFunction = ({
/>
</>
)}
{activeTabId === WorkflowServerlessFunctionTabId.TEST && (
{activeTabId === WorkflowLogicFunctionTabId.TEST && (
<>
<WorkflowEditActionServerlessFunctionFields
functionInput={serverlessFunctionTestData.input}
<WorkflowEditActionLogicFunctionFields
functionInput={logicFunctionTestData.input}
onInputChange={handleTestInputChange}
readonly={actionOptions.readonly}
/>
<StyledCodeEditorContainer>
<InputLabel>{t`Result`}</InputLabel>
<ServerlessFunctionExecutionResult
serverlessFunctionTestData={serverlessFunctionTestData}
<LogicFunctionExecutionResult
logicFunctionTestData={logicFunctionTestData}
isTesting={isTesting}
/>
</StyledCodeEditorContainer>
{serverlessFunctionTestData.output.logs.length > 0 && (
{logicFunctionTestData.output.logs.length > 0 && (
<StyledCodeEditorContainer>
<InputLabel>{t`Logs`}</InputLabel>
<TextArea
textAreaId={testLogsTextAreaId}
value={
isTesting ? '' : serverlessFunctionTestData.output.logs
}
value={isTesting ? '' : logicFunctionTestData.output.logs}
maxRows={20}
disabled
/>
@@ -478,7 +482,7 @@ export const WorkflowEditActionServerlessFunction = ({
<WorkflowStepFooter
stepId={action.id}
additionalActions={
activeTabId === WorkflowServerlessFunctionTabId.TEST
activeTabId === WorkflowLogicFunctionTabId.TEST
? [
<CmdEnterActionButton
title={t`Test`}
@@ -18,7 +18,7 @@ const StyledContainer = styled.div`
}
`;
type WorkflowEditActionServerlessFunctionFieldsProps = {
type WorkflowEditActionLogicFunctionFieldsProps = {
functionInput: FunctionInput;
path?: string[];
readonly?: boolean;
@@ -26,13 +26,13 @@ type WorkflowEditActionServerlessFunctionFieldsProps = {
VariablePicker?: VariablePickerComponent;
};
export const WorkflowEditActionServerlessFunctionFields = ({
export const WorkflowEditActionLogicFunctionFields = ({
functionInput,
path = [],
readonly,
onInputChange,
VariablePicker,
}: WorkflowEditActionServerlessFunctionFieldsProps) => {
}: WorkflowEditActionLogicFunctionFieldsProps) => {
return (
<StyledContainer>
{Object.entries(functionInput).map(([inputKey, inputValue]) => {
@@ -44,7 +44,7 @@ export const WorkflowEditActionServerlessFunctionFields = ({
<div key={pathKey}>
<InputLabel>{inputKey}</InputLabel>
<FormNestedFieldInputContainer>
<WorkflowEditActionServerlessFunctionFields
<WorkflowEditActionLogicFunctionFields
functionInput={inputValue}
path={currentPath}
readonly={readonly}
@@ -24,7 +24,7 @@ const StyledFullScreenButtonContainer = styled.div`
z-index: 1;
`;
type WorkflowServerlessFunctionCodeEditorProps = {
type WorkflowLogicFunctionCodeEditorProps = {
value?: string;
onChange: (value: string) => void;
onMount: (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => void;
@@ -34,7 +34,7 @@ type WorkflowServerlessFunctionCodeEditorProps = {
onEnterFullScreen?: () => void;
};
export const WorkflowServerlessFunctionCodeEditor = ({
export const WorkflowLogicFunctionCodeEditor = ({
value,
onChange,
onMount,
@@ -42,7 +42,7 @@ export const WorkflowServerlessFunctionCodeEditor = ({
readonly = false,
fullScreenMode = false,
onEnterFullScreen,
}: WorkflowServerlessFunctionCodeEditorProps) => {
}: WorkflowLogicFunctionCodeEditorProps) => {
const { t } = useLingui();
return (
@@ -1,41 +1,40 @@
import { useGetAvailablePackages } from '@/settings/serverless-functions/hooks/useGetAvailablePackages';
import { useServerlessFunctionUpdateFormState } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
import { useLogicFunctionUpdateFormState } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
import { type WorkflowCodeAction } from '@/workflow/types/Workflow';
import { INDEX_FILE_NAME } from '@/serverless-functions/constants/IndexFileName';
import { INDEX_FILE_NAME } from '@/logic-functions/constants/IndexFileName';
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
import { WorkflowEditActionServerlessFunctionFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunctionFields';
import { WorkflowEditActionLogicFunctionFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionLogicFunctionFields';
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers';
import styled from '@emotion/styled';
import { type Monaco } from '@monaco-editor/react';
import { type editor } from 'monaco-editor';
import { AutoTypings } from 'monaco-editor-auto-typings';
import { CodeEditor } from 'twenty-ui/input';
import { SOURCE_FOLDER_NAME } from '@/serverless-functions/constants/SourceFolderName';
import { SOURCE_FOLDER_NAME } from '@/logic-functions/constants/SourceFolderName';
const StyledCodeEditorContainer = styled.div`
display: flex;
flex-direction: column;
`;
type WorkflowReadonlyActionServerlessFunctionProps = {
type WorkflowReadonlyActionLogicFunctionProps = {
action: WorkflowCodeAction;
};
export const WorkflowReadonlyActionServerlessFunction = ({
export const WorkflowReadonlyActionLogicFunction = ({
action,
}: WorkflowReadonlyActionServerlessFunctionProps) => {
const serverlessFunctionId = action.settings.input.serverlessFunctionId;
const serverlessFunctionVersion =
action.settings.input.serverlessFunctionVersion;
}: WorkflowReadonlyActionLogicFunctionProps) => {
const logicFunctionId = action.settings.input.logicFunctionId;
const logicFunctionVersion = action.settings.input.logicFunctionVersion;
const { availablePackages } = useGetAvailablePackages({
id: serverlessFunctionId,
id: logicFunctionId,
});
const { formValues, loading } = useServerlessFunctionUpdateFormState({
serverlessFunctionId,
serverlessFunctionVersion,
const { formValues, loading } = useLogicFunctionUpdateFormState({
logicFunctionId,
logicFunctionVersion,
});
const handleEditorDidMount = async (
@@ -64,8 +63,8 @@ export const WorkflowReadonlyActionServerlessFunction = ({
return (
<>
<WorkflowStepBody>
<WorkflowEditActionServerlessFunctionFields
functionInput={action.settings.input.serverlessFunctionInput}
<WorkflowEditActionLogicFunctionFields
functionInput={action.settings.input.logicFunctionInput}
readonly
/>
<StyledCodeEditorContainer>
@@ -1,5 +1,5 @@
import { type WorkflowCodeAction } from '@/workflow/types/Workflow';
import { WorkflowEditActionServerlessFunction } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionServerlessFunction';
import { WorkflowEditActionLogicFunction } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionLogicFunction';
import { type Meta, type StoryObj } from '@storybook/react-vite';
import { graphql, HttpResponse } from 'msw';
import { fn } from 'storybook/test';
@@ -19,9 +19,9 @@ const DEFAULT_ACTION: WorkflowCodeAction = {
valid: false,
settings: {
input: {
serverlessFunctionId: '',
serverlessFunctionVersion: 'draft',
serverlessFunctionInput: {},
logicFunctionId: '',
logicFunctionVersion: 'draft',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -42,9 +42,9 @@ const CONFIGURED_ACTION: WorkflowCodeAction = {
valid: true,
settings: {
input: {
serverlessFunctionId: 'test-function-id',
serverlessFunctionVersion: 'draft',
serverlessFunctionInput: {
logicFunctionId: 'test-function-id',
logicFunctionVersion: 'draft',
logicFunctionInput: {
name: 'John Doe',
email: 'john@example.com',
score: 95,
@@ -75,21 +75,21 @@ const CONFIGURED_ACTION: WorkflowCodeAction = {
},
};
const meta: Meta<typeof WorkflowEditActionServerlessFunction> = {
const meta: Meta<typeof WorkflowEditActionLogicFunction> = {
title: 'Modules/Workflow/Actions/Code/EditAction',
component: WorkflowEditActionServerlessFunction,
component: WorkflowEditActionLogicFunction,
parameters: {
msw: {
handlers: [
...graphqlMocks.handlers,
graphql.query('FindManyServerlessFunctions', () => {
graphql.query('GetManyLogicFunctions', () => {
return HttpResponse.json({
data: {
findManyServerlessFunctions: [
findManyLogicFunctions: [
{
id: 'test-function-id',
name: 'Test Function',
description: 'A test serverless function',
description: 'A test logic function',
runtime: 'nodejs22.x',
createdAt: '2024-01-01T00:00:00.000Z',
updatedAt: '2024-01-01T00:00:00.000Z',
@@ -98,13 +98,13 @@ const meta: Meta<typeof WorkflowEditActionServerlessFunction> = {
},
});
}),
graphql.query('FindOneServerlessFunction', () => {
graphql.query('GetOneLogicFunction', () => {
return HttpResponse.json({
data: {
findOneServerlessFunction: {
findOneLogicFunction: {
id: 'test-function-id',
name: 'Test Function',
description: 'A test serverless function',
description: 'A test logic function',
runtime: 'nodejs22.x',
createdAt: '2024-01-01T00:00:00.000Z',
updatedAt: '2024-01-01T00:00:00.000Z',
@@ -138,7 +138,7 @@ const meta: Meta<typeof WorkflowEditActionServerlessFunction> = {
export default meta;
type Story = StoryObj<typeof WorkflowEditActionServerlessFunction>;
type Story = StoryObj<typeof WorkflowEditActionLogicFunction>;
export const Default: Story = {
args: {
@@ -207,9 +207,9 @@ export const EmptyFunction: Story = {
settings: {
...DEFAULT_ACTION.settings,
input: {
serverlessFunctionId: '',
serverlessFunctionVersion: 'draft',
serverlessFunctionInput: {},
logicFunctionId: '',
logicFunctionVersion: 'draft',
logicFunctionInput: {},
},
},
},
@@ -0,0 +1,2 @@
export const WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID =
'workflow-logic-function-tab-list-component-id';
@@ -1,2 +0,0 @@
export const WORKFLOW_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID =
'workflow-serverless-function-tab-list-component-id';
@@ -1,14 +1,14 @@
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
import { ServerlessFunctionExecutionStatus } from '~/generated-metadata/graphql';
import { LogicFunctionExecutionStatus } from '~/generated-metadata/graphql';
export type ServerlessFunctionTestData = {
export type LogicFunctionTestData = {
input: { [field: string]: any };
shouldInitInput: boolean;
output: {
data?: string;
logs: string;
duration?: number;
status?: ServerlessFunctionExecutionStatus;
status?: LogicFunctionExecutionStatus;
error?: string;
};
language: 'plaintext' | 'json';
@@ -18,14 +18,14 @@ export type ServerlessFunctionTestData = {
export const DEFAULT_OUTPUT_VALUE = {
data: 'Enter an input above then press "Test"',
logs: '',
status: ServerlessFunctionExecutionStatus.IDLE,
status: LogicFunctionExecutionStatus.IDLE,
};
export const serverlessFunctionTestDataFamilyState = createFamilyState<
ServerlessFunctionTestData,
export const logicFunctionTestDataFamilyState = createFamilyState<
LogicFunctionTestData,
string
>({
key: 'serverlessFunctionTestDataFamilyState',
key: 'logicFunctionTestDataFamilyState',
defaultValue: {
language: 'plaintext',
height: 64,
@@ -0,0 +1,6 @@
export type WorkflowLogicFunctionTabIdType = 'code' | 'test';
export enum WorkflowLogicFunctionTabId {
CODE = 'code',
TEST = 'test',
}
@@ -1,6 +0,0 @@
export type WorkflowServerlessFunctionTabIdType = 'code' | 'test';
export enum WorkflowServerlessFunctionTabId {
CODE = 'code',
TEST = 'test',
}
@@ -5,7 +5,7 @@ export const CODE_ACTION: {
type: Extract<WorkflowActionType, 'CODE'>;
icon: string;
} = {
defaultLabel: 'Code - Serverless Function',
defaultLabel: 'Code - Logic Function',
type: 'CODE',
icon: 'IconCode',
};