Fix missing test input values (#18424)

- refactor
- fix issue
This commit is contained in:
martmull
2026-03-05 14:36:36 +01:00
committed by GitHub
parent 1acbf28316
commit 7293d4c1f8
7 changed files with 129 additions and 75 deletions
@@ -0,0 +1,60 @@
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { useSetAtomFamilyState } from '@/ui/utilities/state/jotai/hooks/useSetAtomFamilyState';
import { logicFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState';
import { useEffect } from 'react';
import { type InputJsonSchema } from 'twenty-shared/logic-function';
import { isDefined } from 'twenty-shared/utils';
import { getFunctionInputFromInputSchema } from 'twenty-shared/workflow';
import { useLogicFunctionForm } from '@/logic-functions/hooks/useLogicFunctionForm';
export const LogicFunctionTestInputInitEffect = ({
logicFunctionId,
}: {
logicFunctionId: string;
}) => {
const { logicFunction } = useLogicFunctionForm({ logicFunctionId });
const toolInputSchema = logicFunction?.toolInputSchema;
const logicFunctionTestData = useAtomFamilyStateValue(
logicFunctionTestDataFamilyState,
logicFunctionId,
);
const setLogicFunctionTestData = useSetAtomFamilyState(
logicFunctionTestDataFamilyState,
logicFunctionId,
);
useEffect(() => {
if (!logicFunctionTestData.shouldInitInput) {
return;
}
if (!isDefined(toolInputSchema)) {
return;
}
const schemaArray: InputJsonSchema[] = Array.isArray(toolInputSchema)
? toolInputSchema
: [toolInputSchema];
const defaultInput = getFunctionInputFromInputSchema(schemaArray)[0];
if (!isDefined(defaultInput)) {
return;
}
setLogicFunctionTestData((prev) => ({
...prev,
input: defaultInput as { [field: string]: any },
shouldInitInput: false,
}));
}, [
toolInputSchema,
logicFunctionTestData.shouldInitInput,
setLogicFunctionTestData,
]);
return null;
};
@@ -42,11 +42,19 @@ export const useExecuteLogicFunction = ({
logicFunctionTestDataFamilyState,
logicFunctionId,
);
const setLogicFunctionTestData = useSetAtomFamilyState(
logicFunctionTestDataFamilyState,
logicFunctionId,
);
const updateLogicFunctionInput = (input: object) => {
setLogicFunctionTestData((prev) => ({
...prev,
input,
}));
};
const executeLogicFunction = async () => {
if (isExecuting) {
return;
@@ -94,5 +102,10 @@ export const useExecuteLogicFunction = ({
}
};
return { executeLogicFunction, isExecuting };
return {
executeLogicFunction,
updateLogicFunctionInput,
logicFunctionTestData,
isExecuting,
};
};
@@ -1,4 +1,3 @@
import { useExecuteLogicFunction } from '@/logic-functions/hooks/useExecuteLogicFunction';
import {
type LogicFunctionFormValues,
useLogicFunctionUpdateFormState,
@@ -10,23 +9,16 @@ import {
} from 'twenty-shared/logic-function';
import { useDebouncedCallback } from 'use-debounce';
export const useLogicFunctionEditor = ({
export const useLogicFunctionForm = ({
logicFunctionId,
executeCallback,
}: {
logicFunctionId: string;
executeCallback?: (result: object) => void;
}) => {
const { updateLogicFunction } = usePersistLogicFunction();
const { formValues, setFormValues, logicFunction, loading } =
useLogicFunctionUpdateFormState({ logicFunctionId });
const { executeLogicFunction, isExecuting } = useExecuteLogicFunction({
logicFunctionId,
callback: executeCallback,
});
const handleSave = useDebouncedCallback(async () => {
await updateLogicFunction({
input: {
@@ -74,7 +66,5 @@ export const useLogicFunctionEditor = ({
loading,
handleSave,
onChange,
executeLogicFunction,
isExecuting,
};
};
@@ -33,15 +33,15 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => {
return (
<JotaiProvider store={jotaiStore}>
<RecordTableComponentInstance recordTableId={recordTableId}>
<RecordTableContextProvider
recordTableId={recordTableId}
viewBarId="viewBarId"
objectNameSingular={CoreObjectNameSingular.Person}
onRecordIdentifierClick={() => {}}
>
<RecordComponentInstanceContextsWrapper
componentInstanceId={recordTableId}
<RecordComponentInstanceContextsWrapper
componentInstanceId={recordTableId}
>
<RecordTableComponentInstance recordTableId={recordTableId}>
<RecordTableContextProvider
recordTableId={recordTableId}
viewBarId="viewBarId"
objectNameSingular={CoreObjectNameSingular.Person}
onRecordIdentifierClick={() => {}}
>
<FieldContext.Provider
value={{
@@ -63,9 +63,9 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => {
</RecordTableRowDraggableContextProvider>
</RecordTableRowContextProvider>
</FieldContext.Provider>
</RecordComponentInstanceContextsWrapper>
</RecordTableContextProvider>
</RecordTableComponentInstance>
</RecordTableContextProvider>
</RecordTableComponentInstance>
</RecordComponentInstanceContextsWrapper>
</JotaiProvider>
);
};
@@ -1,14 +1,12 @@
import { LogicFunctionExecutionResult } from '@/logic-functions/components/LogicFunctionExecutionResult';
import { LogicFunctionLogs } from '@/logic-functions/components/LogicFunctionLogs';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { useSetAtomFamilyState } from '@/ui/utilities/state/jotai/hooks/useSetAtomFamilyState';
import { logicFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState';
import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { H2Title, IconPlayerPlay } from 'twenty-ui/display';
import { Button, CodeEditor, CoreEditorHeader } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { useExecuteLogicFunction } from '@/logic-functions/hooks/useExecuteLogicFunction';
const StyledInputsContainer = styled.div`
display: flex;
@@ -31,20 +29,18 @@ export const SettingsLogicFunctionTestTab = ({
isTesting?: boolean;
}) => {
const { t } = useLingui();
const logicFunctionTestData = useAtomFamilyStateValue(
logicFunctionTestDataFamilyState,
logicFunctionId,
);
const setLogicFunctionTestData = useSetAtomFamilyState(
logicFunctionTestDataFamilyState,
logicFunctionId,
);
const onChange = (newInput: string) => {
setLogicFunctionTestData((prev) => ({
...prev,
input: JSON.parse(newInput),
}));
const { updateLogicFunctionInput, logicFunctionTestData } =
useExecuteLogicFunction({
logicFunctionId,
});
const onChange = (value: string) => {
try {
updateLogicFunctionInput(JSON.parse(value));
} catch {
// ignore invalid JSON while user is still typing
}
};
return (
@@ -1,5 +1,5 @@
import { useGetAvailablePackages } from '@/logic-functions/hooks/useGetAvailablePackages';
import { useLogicFunctionEditor } from '@/logic-functions/hooks/useLogicFunctionEditor';
import { useLogicFunctionForm } from '@/logic-functions/hooks/useLogicFunctionForm';
import { useFullScreenModal } from '@/ui/layout/fullscreen/hooks/useFullScreenModal';
import { type BreadcrumbProps } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUpdatableWorkflowVersionOrThrow';
@@ -22,9 +22,6 @@ import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowS
import { WorkflowCodeEditor } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowCodeEditor';
import { WorkflowEditActionCodeFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields';
import { WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowLogicFunctionTabListComponentId';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { useSetAtomFamilyState } from '@/ui/utilities/state/jotai/hooks/useSetAtomFamilyState';
import { 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';
@@ -49,6 +46,8 @@ import { useIsMobile } from 'twenty-ui/utilities';
import { useDebouncedCallback } from 'use-debounce';
import { getFunctionInputFromInputSchema } from 'twenty-shared/workflow';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { LogicFunctionTestInputInitEffect } from '@/logic-functions/components/LogicFunctionTestInputInitEffect';
import { useExecuteLogicFunction } from '@/logic-functions/hooks/useExecuteLogicFunction';
const StyledCodeEditorContainer = styled.div`
display: flex;
@@ -114,25 +113,24 @@ export const WorkflowEditActionCode = ({
});
};
const { formValues, loading, executeLogicFunction, onChange, isExecuting } =
useLogicFunctionEditor({
logicFunctionId,
executeCallback: updateOutputSchemaFromTestResult,
});
const { formValues, loading, onChange } = useLogicFunctionForm({
logicFunctionId,
});
const {
executeLogicFunction,
isExecuting,
logicFunctionTestData,
updateLogicFunctionInput,
} = useExecuteLogicFunction({
logicFunctionId,
callback: updateOutputSchemaFromTestResult,
});
const { availablePackages } = useGetAvailablePackages({
id: logicFunctionId,
});
const logicFunctionTestData = useAtomFamilyStateValue(
logicFunctionTestDataFamilyState,
logicFunctionId,
);
const setLogicFunctionTestData = useSetAtomFamilyState(
logicFunctionTestDataFamilyState,
logicFunctionId,
);
const [functionInput, setFunctionInput] =
useState<LogicFunctionInputFormData>(
action.settings.input.logicFunctionInput,
@@ -158,6 +156,7 @@ export const WorkflowEditActionCode = ({
newInput: newFunctionInput,
oldInput: action.settings.input.logicFunctionInput,
});
const newMergedTestInput = mergeDefaultFunctionInputAndFunctionInput({
newInput: newFunctionInput,
oldInput: logicFunctionTestData.input,
@@ -165,10 +164,7 @@ export const WorkflowEditActionCode = ({
setFunctionInput(newMergedInput);
setLogicFunctionTestData((prev) => ({
...prev,
input: newMergedTestInput,
}));
updateLogicFunctionInput(newMergedTestInput);
updateAction({
...action,
@@ -220,10 +216,8 @@ export const WorkflowEditActionCode = ({
path,
value,
);
setLogicFunctionTestData((prev) => ({
...prev,
input: updatedTestFunctionInput,
}));
updateLogicFunctionInput(updatedTestFunctionInput);
};
const handleTestFunction = async () => {
@@ -375,6 +369,7 @@ export const WorkflowEditActionCode = ({
return (
!loading && (
<>
<LogicFunctionTestInputInitEffect logicFunctionId={logicFunctionId} />
<StyledTabList
tabs={tabs}
behaveAsLinks={false}
@@ -1,6 +1,6 @@
import { useNavigate, useParams } from 'react-router-dom';
import { useLogicFunctionEditor } from '@/logic-functions/hooks/useLogicFunctionEditor';
import { useLogicFunctionForm } from '@/logic-functions/hooks/useLogicFunctionForm';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsLogicFunctionLabelContainer } from '@/settings/logic-functions/components/SettingsLogicFunctionLabelContainer';
import { SettingsLogicFunctionSettingsTab } from '@/settings/logic-functions/components/tabs/SettingsLogicFunctionSettingsTab';
@@ -23,6 +23,7 @@ import { useFindOneApplicationQuery } from '~/generated-metadata/graphql';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { SettingsLogicFunctionCodeEditorTab } from '@/settings/logic-functions/components/tabs/SettingsLogicFunctionCodeEditorTab';
import { useExecuteLogicFunction } from '@/logic-functions/hooks/useExecuteLogicFunction';
const LOGIC_FUNCTION_DETAIL_ID = 'logic-function-detail';
@@ -51,14 +52,13 @@ export const SettingsLogicFunctionDetail = () => {
instanceId,
);
const {
formValues,
logicFunction,
loading,
onChange,
executeLogicFunction,
isExecuting,
} = useLogicFunctionEditor({ logicFunctionId });
const { formValues, logicFunction, loading, onChange } = useLogicFunctionForm(
{ logicFunctionId },
);
const { executeLogicFunction, isExecuting } = useExecuteLogicFunction({
logicFunctionId,
});
const handleTestFunction = async () => {
navigate('#test');