+1
-1
@@ -1,6 +1,6 @@
|
||||
import { AGENT_FRAGMENT } from '@/ai/graphql/fragments/agentFragment';
|
||||
import { OBJECT_METADATA_FRAGMENT } from '@/object-metadata/graphql/fragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const APPLICATION_FRAGMENT = gql`
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export const INDEX_FILE_NAME = 'index.ts';
|
||||
@@ -1 +0,0 @@
|
||||
export const SOURCE_FOLDER_NAME = 'src';
|
||||
-1
@@ -8,7 +8,6 @@ export const LOGIC_FUNCTION_FRAGMENT = gql`
|
||||
runtime
|
||||
timeoutSeconds
|
||||
sourceHandlerPath
|
||||
builtHandlerPath
|
||||
handlerName
|
||||
toolInputSchema
|
||||
isTool
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const CREATE_ONE_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
mutation CreateOneLogicFunction($input: CreateLogicFunctionFromSourceInput!) {
|
||||
createOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const DELETE_ONE_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPDATE_LOGIC_FUNCTION_SOURCE = gql`
|
||||
mutation UpdateLogicFunctionSource($input: UpdateLogicFunctionSourceInput!) {
|
||||
updateLogicFunctionSource(input: $input)
|
||||
}
|
||||
`;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPDATE_ONE_LOGIC_FUNCTION = gql`
|
||||
mutation UpdateOneLogicFunction($input: UpdateLogicFunctionFromSourceInput!) {
|
||||
updateOneLogicFunction(input: $input)
|
||||
}
|
||||
`;
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const FIND_MANY_LOGIC_FUNCTIONS = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
query GetManyLogicFunctions {
|
||||
query FindManyLogicFunctions {
|
||||
findManyLogicFunctions {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const FIND_ONE_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
query GetOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
query FindOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
findOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
+19
-4
@@ -1,21 +1,36 @@
|
||||
import { useLogicFunctionUpdateFormState } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { useLogicFunctionUpdateFormState } from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
jest.mock('@/settings/logic-functions/hooks/useGetOneLogicFunction', () => ({
|
||||
jest.mock('@/logic-functions/hooks/useGetOneLogicFunction', () => ({
|
||||
useGetOneLogicFunction: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@/logic-functions/hooks/useGetLogicFunctionSourceCode', () => ({
|
||||
useGetLogicFunctionSourceCode: jest.fn(),
|
||||
}));
|
||||
|
||||
const mockCode = 'export const main = async (): Promise<void> => { return; }';
|
||||
|
||||
describe('useLogicFunctionUpdateFormState', () => {
|
||||
test('should return a form', () => {
|
||||
const logicFunctionId = 'logicFunctionId';
|
||||
const useGetOneLogicFunctionMock = jest.requireMock(
|
||||
'@/settings/logic-functions/hooks/useGetOneLogicFunction',
|
||||
'@/logic-functions/hooks/useGetOneLogicFunction',
|
||||
);
|
||||
const useGetLogicFunctionSourceCodeMock = jest.requireMock(
|
||||
'@/logic-functions/hooks/useGetLogicFunctionSourceCode',
|
||||
);
|
||||
useGetOneLogicFunctionMock.useGetOneLogicFunction.mockReturnValue({
|
||||
logicFunction: { name: 'name' },
|
||||
loading: false,
|
||||
});
|
||||
useGetLogicFunctionSourceCodeMock.useGetLogicFunctionSourceCode.mockReturnValue(
|
||||
{
|
||||
code: mockCode,
|
||||
loading: false,
|
||||
},
|
||||
);
|
||||
const { result } = renderHook(
|
||||
() => useLogicFunctionUpdateFormState({ logicFunctionId }),
|
||||
{
|
||||
@@ -28,7 +43,7 @@ describe('useLogicFunctionUpdateFormState', () => {
|
||||
expect(formValues).toEqual({
|
||||
name: '',
|
||||
description: '',
|
||||
code: { src: { 'index.ts': '' } },
|
||||
code: mockCode,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,4 @@
|
||||
import { EXECUTE_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/mutations/executeOneLogicFunction';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { logicFunctionTestDataFamilyState } from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { useState } from 'react';
|
||||
@@ -11,7 +10,6 @@ import { sleep } from '~/utils/sleep';
|
||||
type ExecuteOneLogicFunctionInput = {
|
||||
id: string;
|
||||
payload: object;
|
||||
forceRebuild?: boolean;
|
||||
};
|
||||
|
||||
type ExecuteOneLogicFunctionResult = {
|
||||
@@ -34,21 +32,16 @@ export const useExecuteLogicFunction = ({
|
||||
callback?: (result: object) => void;
|
||||
}) => {
|
||||
const [isExecuting, setIsExecuting] = useState(false);
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const [executeOneLogicFunctionMutation] = useMutation<
|
||||
{ executeOneLogicFunction: ExecuteOneLogicFunctionResult },
|
||||
{ input: ExecuteOneLogicFunctionInput }
|
||||
>(EXECUTE_ONE_LOGIC_FUNCTION, {
|
||||
client: apolloMetadataClient,
|
||||
});
|
||||
>(EXECUTE_ONE_LOGIC_FUNCTION);
|
||||
|
||||
const [logicFunctionTestData, setLogicFunctionTestData] = useRecoilState(
|
||||
logicFunctionTestDataFamilyState(logicFunctionId),
|
||||
);
|
||||
|
||||
const executeLogicFunction = async ({
|
||||
forceRebuild = false,
|
||||
}: { forceRebuild?: boolean } = {}) => {
|
||||
const executeLogicFunction = async () => {
|
||||
try {
|
||||
setIsExecuting(true);
|
||||
await sleep(200); // Delay artificially to avoid flashing the UI
|
||||
@@ -57,7 +50,6 @@ export const useExecuteLogicFunction = ({
|
||||
input: {
|
||||
id: logicFunctionId,
|
||||
payload: logicFunctionTestData.input,
|
||||
forceRebuild,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
+1
-4
@@ -1,6 +1,5 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { FIND_MANY_AVAILABLE_PACKAGES } from '@/settings/logic-functions/graphql/queries/findManyAvailablePackages';
|
||||
import { FIND_MANY_AVAILABLE_PACKAGES } from '@/logic-functions/graphql/queries/findManyAvailablePackages';
|
||||
import {
|
||||
type FindManyAvailablePackagesQuery,
|
||||
type FindManyAvailablePackagesQueryVariables,
|
||||
@@ -8,12 +7,10 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useGetAvailablePackages = (input: LogicFunctionIdInput) => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const { data } = useQuery<
|
||||
FindManyAvailablePackagesQuery,
|
||||
FindManyAvailablePackagesQueryVariables
|
||||
>(FIND_MANY_AVAILABLE_PACKAGES, {
|
||||
client: apolloMetadataClient ?? undefined,
|
||||
variables: {
|
||||
input,
|
||||
},
|
||||
+2
-12
@@ -1,7 +1,5 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { GET_LOGIC_FUNCTION_SOURCE_CODE } from '@/logic-functions/graphql/queries/getLogicFunctionSourceCode';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
import {
|
||||
type GetLogicFunctionSourceCodeQuery,
|
||||
type GetLogicFunctionSourceCodeQueryVariables,
|
||||
@@ -11,24 +9,16 @@ export const useGetLogicFunctionSourceCode = ({
|
||||
logicFunctionId,
|
||||
}: {
|
||||
logicFunctionId: string;
|
||||
}): { code: Sources | null; loading: boolean } => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
}) => {
|
||||
const { data, loading } = useQuery<
|
||||
GetLogicFunctionSourceCodeQuery,
|
||||
GetLogicFunctionSourceCodeQueryVariables
|
||||
>(GET_LOGIC_FUNCTION_SOURCE_CODE, {
|
||||
client: apolloMetadataClient ?? undefined,
|
||||
variables: {
|
||||
input: { id: logicFunctionId },
|
||||
},
|
||||
skip: !logicFunctionId,
|
||||
});
|
||||
|
||||
const raw = data?.getLogicFunctionSourceCode;
|
||||
const code =
|
||||
raw != null && typeof raw === 'object' && !Array.isArray(raw)
|
||||
? (raw as Sources)
|
||||
: null;
|
||||
|
||||
return { code, loading };
|
||||
return { code: data?.getLogicFunctionSourceCode, loading };
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { FIND_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/queries/findOneLogicFunction';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import {
|
||||
type FindOneLogicFunctionQuery,
|
||||
type FindOneLogicFunctionQueryVariables,
|
||||
type LogicFunctionIdInput,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useGetOneLogicFunction = ({
|
||||
id,
|
||||
onCompleted,
|
||||
}: LogicFunctionIdInput & {
|
||||
onCompleted?: (data: FindOneLogicFunctionQuery) => void;
|
||||
}) => {
|
||||
const { data, loading } = useQuery<
|
||||
FindOneLogicFunctionQuery,
|
||||
FindOneLogicFunctionQueryVariables
|
||||
>(FIND_ONE_LOGIC_FUNCTION, {
|
||||
variables: {
|
||||
input: { id },
|
||||
},
|
||||
onCompleted,
|
||||
});
|
||||
return {
|
||||
logicFunction: data?.findOneLogicFunction || null,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
+19
-8
@@ -1,11 +1,11 @@
|
||||
import { useGetOneLogicFunction } from '@/settings/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { type Dispatch, type SetStateAction, useState } from 'react';
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
import { useGetOneLogicFunction } from '@/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { type Dispatch, type SetStateAction, useEffect, useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
type GetOneLogicFunctionQuery,
|
||||
type FindOneLogicFunctionQuery,
|
||||
type LogicFunction,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { useGetLogicFunctionSourceCode } from '@/logic-functions/hooks/useGetLogicFunctionSourceCode';
|
||||
|
||||
export type LogicFunctionNewFormValues = {
|
||||
name: string;
|
||||
@@ -13,7 +13,7 @@ export type LogicFunctionNewFormValues = {
|
||||
};
|
||||
|
||||
export type LogicFunctionFormValues = LogicFunctionNewFormValues & {
|
||||
code: Sources;
|
||||
code: string;
|
||||
};
|
||||
|
||||
type SetLogicFunctionFormValues = Dispatch<
|
||||
@@ -33,13 +33,18 @@ export const useLogicFunctionUpdateFormState = ({
|
||||
const [formValues, setFormValues] = useState<LogicFunctionFormValues>({
|
||||
name: '',
|
||||
description: '',
|
||||
code: { src: { 'index.ts': '' } },
|
||||
code: '',
|
||||
});
|
||||
|
||||
const { code: codeFromApi, loading: logicFunctionSourceCodeLoading } =
|
||||
useGetLogicFunctionSourceCode({
|
||||
logicFunctionId,
|
||||
});
|
||||
|
||||
const { logicFunction, loading: logicFunctionLoading } =
|
||||
useGetOneLogicFunction({
|
||||
id: logicFunctionId,
|
||||
onCompleted: (data: GetOneLogicFunctionQuery) => {
|
||||
onCompleted: (data: FindOneLogicFunctionQuery) => {
|
||||
const fn = data?.findOneLogicFunction;
|
||||
|
||||
if (isDefined(fn)) {
|
||||
@@ -52,10 +57,16 @@ export const useLogicFunctionUpdateFormState = ({
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(codeFromApi)) {
|
||||
setFormValues((prev) => ({ ...prev, code: codeFromApi }));
|
||||
}
|
||||
}, [codeFromApi]);
|
||||
|
||||
return {
|
||||
formValues,
|
||||
setFormValues,
|
||||
logicFunction,
|
||||
loading: logicFunctionLoading,
|
||||
loading: logicFunctionLoading || logicFunctionSourceCodeLoading,
|
||||
};
|
||||
};
|
||||
+24
-38
@@ -1,65 +1,55 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { UPDATE_LOGIC_FUNCTION_SOURCE } from '@/logic-functions/graphql/mutations/updateLogicFunctionSource';
|
||||
import { UPDATE_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/mutations/updateOneLogicFunction';
|
||||
import { GET_LOGIC_FUNCTION_SOURCE_CODE } from '@/logic-functions/graphql/queries/getLogicFunctionSourceCode';
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { CREATE_DEFAULT_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/mutations/createDefaultLogicFunction';
|
||||
import { DELETE_ONE_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/mutations/deleteOneLogicFunction';
|
||||
import { FIND_MANY_LOGIC_FUNCTIONS } from '@/settings/logic-functions/graphql/queries/findManyLogicFunctions';
|
||||
import { CREATE_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/mutations/createOneLogicFunction';
|
||||
import { DELETE_ONE_LOGIC_FUNCTION } from '@/logic-functions/graphql/mutations/deleteOneLogicFunction';
|
||||
import { FIND_MANY_LOGIC_FUNCTIONS } from '@/logic-functions/graphql/queries/findManyLogicFunctions';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { ApolloError, useMutation } from '@apollo/client';
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { type Sources, CrudOperationType } from 'twenty-shared/types';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
import {
|
||||
type CreateDefaultLogicFunctionItemMutation,
|
||||
type CreateDefaultLogicFunctionItemMutationVariables,
|
||||
type CreateOneLogicFunctionMutation,
|
||||
type CreateOneLogicFunctionMutationVariables,
|
||||
type DeleteOneLogicFunctionMutation,
|
||||
type DeleteOneLogicFunctionMutationVariables,
|
||||
type UpdateOneLogicFunctionMutation,
|
||||
type UpdateOneLogicFunctionMutationVariables,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
type UpdateLogicFunctionSourceMutationVariables = {
|
||||
input: { id: string; code: Sources };
|
||||
};
|
||||
|
||||
export const usePersistLogicFunction = () => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
|
||||
const [createDefaultLogicFunctionMutation] = useMutation<
|
||||
CreateDefaultLogicFunctionItemMutation,
|
||||
CreateDefaultLogicFunctionItemMutationVariables
|
||||
>(CREATE_DEFAULT_LOGIC_FUNCTION, {
|
||||
client: apolloMetadataClient,
|
||||
});
|
||||
const [createLogicFunctionMutation] = useMutation<
|
||||
CreateOneLogicFunctionMutation,
|
||||
CreateOneLogicFunctionMutationVariables
|
||||
>(CREATE_ONE_LOGIC_FUNCTION);
|
||||
|
||||
const [deleteLogicFunctionMutation] = useMutation<
|
||||
DeleteOneLogicFunctionMutation,
|
||||
DeleteOneLogicFunctionMutationVariables
|
||||
>(DELETE_ONE_LOGIC_FUNCTION, {
|
||||
client: apolloMetadataClient,
|
||||
});
|
||||
>(DELETE_ONE_LOGIC_FUNCTION);
|
||||
|
||||
const [updateLogicFunctionSourceMutation] = useMutation<
|
||||
{ updateLogicFunctionSource: boolean },
|
||||
UpdateLogicFunctionSourceMutationVariables
|
||||
>(UPDATE_LOGIC_FUNCTION_SOURCE, {
|
||||
client: apolloMetadataClient,
|
||||
});
|
||||
UpdateOneLogicFunctionMutation,
|
||||
UpdateOneLogicFunctionMutationVariables
|
||||
>(UPDATE_ONE_LOGIC_FUNCTION);
|
||||
|
||||
const createLogicFunction = useCallback(
|
||||
async (
|
||||
variables: CreateDefaultLogicFunctionItemMutationVariables,
|
||||
variables: CreateOneLogicFunctionMutationVariables,
|
||||
): Promise<
|
||||
MetadataRequestResult<
|
||||
Awaited<ReturnType<typeof createDefaultLogicFunctionMutation>>
|
||||
Awaited<ReturnType<typeof createLogicFunctionMutation>>
|
||||
>
|
||||
> => {
|
||||
try {
|
||||
const result = await createDefaultLogicFunctionMutation({
|
||||
const result = await createLogicFunctionMutation({
|
||||
variables,
|
||||
awaitRefetchQueries: true,
|
||||
refetchQueries: [getOperationName(FIND_MANY_LOGIC_FUNCTIONS) ?? ''],
|
||||
@@ -85,16 +75,12 @@ export const usePersistLogicFunction = () => {
|
||||
};
|
||||
}
|
||||
},
|
||||
[
|
||||
createDefaultLogicFunctionMutation,
|
||||
handleMetadataError,
|
||||
enqueueErrorSnackBar,
|
||||
],
|
||||
[createLogicFunctionMutation, handleMetadataError, enqueueErrorSnackBar],
|
||||
);
|
||||
|
||||
const updateLogicFunctionSource = useCallback(
|
||||
const updateLogicFunction = useCallback(
|
||||
async (
|
||||
variables: UpdateLogicFunctionSourceMutationVariables,
|
||||
variables: UpdateOneLogicFunctionMutationVariables,
|
||||
): Promise<
|
||||
MetadataRequestResult<
|
||||
Awaited<ReturnType<typeof updateLogicFunctionSourceMutation>>
|
||||
@@ -174,7 +160,7 @@ export const usePersistLogicFunction = () => {
|
||||
|
||||
return {
|
||||
createLogicFunction,
|
||||
updateLogicFunctionSource,
|
||||
updateLogicFunction,
|
||||
deleteLogicFunction,
|
||||
};
|
||||
};
|
||||
|
||||
-146
@@ -1,146 +0,0 @@
|
||||
import { computeNewSources } from '@/logic-functions/utils/computeNewSources';
|
||||
|
||||
describe('computeNewSources', () => {
|
||||
it('should compute new code input root 0', () => {
|
||||
const previousCodeInput = {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
};
|
||||
|
||||
const filePath = 'index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
'index.ts': 'export const totoUpdated = () => {}',
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 0 file changed', () => {
|
||||
const previousCodeInput = {
|
||||
'.env': 'ENV=env',
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
};
|
||||
|
||||
const filePath = '.env';
|
||||
|
||||
const value = 'ENV=env\nENV2=env2';
|
||||
|
||||
const expectedResult = {
|
||||
'.env': 'ENV=env\nENV2=env2',
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 0 with multiple files', () => {
|
||||
const previousCodeInput = {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
'.env': 'ENV',
|
||||
};
|
||||
|
||||
const filePath = 'index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
'index.ts': 'export const totoUpdated = () => {}',
|
||||
'.env': 'ENV',
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 1', () => {
|
||||
const previousCodeInput = {
|
||||
src: { 'index.ts': 'export const toto = () => {}' },
|
||||
};
|
||||
|
||||
const filePath = 'src/index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
src: { 'index.ts': 'export const totoUpdated = () => {}' },
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 1 with multiple files', () => {
|
||||
const previousCodeInput = {
|
||||
src: {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
'index2.ts': 'export const toto2 = () => {}',
|
||||
},
|
||||
};
|
||||
|
||||
const filePath = 'src/index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
src: {
|
||||
'index.ts': 'export const totoUpdated = () => {}',
|
||||
'index2.ts': 'export const toto2 = () => {}',
|
||||
},
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input root 1 with added files', () => {
|
||||
const previousCodeInput = {
|
||||
src: {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
},
|
||||
};
|
||||
|
||||
const filePath = 'src/index2.ts';
|
||||
|
||||
const value = 'export const toto2 = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
src: {
|
||||
'index.ts': 'export const toto = () => {}',
|
||||
'index2.ts': 'export const toto2 = () => {}',
|
||||
},
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
|
||||
it('should compute new code input multiple roots', () => {
|
||||
const previousCodeInput = {
|
||||
'.env': 'ENV=env',
|
||||
src: { 'index.ts': 'export const toto = () => {}' },
|
||||
};
|
||||
|
||||
const filePath = 'src/index.ts';
|
||||
|
||||
const value = 'export const totoUpdated = () => {}';
|
||||
|
||||
const expectedResult = {
|
||||
src: { 'index.ts': 'export const totoUpdated = () => {}' },
|
||||
'.env': 'ENV=env',
|
||||
};
|
||||
|
||||
expect(
|
||||
computeNewSources({ previousCode: previousCodeInput, filePath, value }),
|
||||
).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
// IA Generated
|
||||
|
||||
import { flattenSources } from '@/logic-functions/utils/flattenSources';
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
|
||||
describe('flattenSources', () => {
|
||||
it('flattens nested sources with root files', () => {
|
||||
const input: Sources = {
|
||||
'.env': 'KEY=VALUE',
|
||||
src: {
|
||||
'index.ts': 'export const a = 1',
|
||||
lib: {
|
||||
'util.ts': 'export const util = () => {}',
|
||||
},
|
||||
},
|
||||
docs: {
|
||||
'README.md': '# Hello',
|
||||
},
|
||||
};
|
||||
|
||||
const result = flattenSources(input);
|
||||
|
||||
expect(result).toEqual([
|
||||
{ path: '.env', content: 'KEY=VALUE' },
|
||||
{ path: 'docs/README.md', content: '# Hello' },
|
||||
{ path: 'src/index.ts', content: 'export const a = 1' },
|
||||
{ path: 'src/lib/util.ts', content: 'export const util = () => {}' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('handles deep nesting and preserves file contents', () => {
|
||||
const input: Sources = {
|
||||
a: { b: { c: { d: { 'file.ts': 'content' } } } },
|
||||
};
|
||||
|
||||
expect(flattenSources(input)).toEqual([
|
||||
{ path: 'a/b/c/d/file.ts', content: 'content' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('ignores empty folders and non-string leaves', () => {
|
||||
const input: Sources = {
|
||||
empty: {},
|
||||
weird: {
|
||||
oops: 42,
|
||||
} as unknown as Sources,
|
||||
file: 'ok',
|
||||
};
|
||||
|
||||
const res = flattenSources(input);
|
||||
expect(res).toEqual([{ path: 'file', content: 'ok' }]);
|
||||
});
|
||||
|
||||
it('accepts a custom basePath prefix', () => {
|
||||
const input: Sources = { src: { 'index.ts': 'x' } };
|
||||
const res = flattenSources(input, 'pkg');
|
||||
expect(res).toEqual([{ path: 'pkg/src/index.ts', content: 'x' }]);
|
||||
});
|
||||
});
|
||||
@@ -1,48 +0,0 @@
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
|
||||
export const computeNewSources = ({
|
||||
previousCode,
|
||||
filePath,
|
||||
value,
|
||||
}: {
|
||||
previousCode: Sources;
|
||||
filePath: string;
|
||||
value: string;
|
||||
}): Sources => {
|
||||
const result = { ...previousCode };
|
||||
|
||||
const parts = filePath.split('/').filter(Boolean);
|
||||
|
||||
if (parts.length === 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (parts.length === 1) {
|
||||
result[filePath] = value;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const [root, ...rest] = parts;
|
||||
|
||||
const newFilePath = rest.join('/');
|
||||
|
||||
if (
|
||||
typeof result?.[root] === 'string' ||
|
||||
typeof previousCode[root] === 'string'
|
||||
) {
|
||||
throw Error('Cannot compute new code input');
|
||||
}
|
||||
|
||||
return {
|
||||
...previousCode,
|
||||
[root]: {
|
||||
...previousCode[root],
|
||||
...computeNewSources({
|
||||
previousCode: result?.[root] ?? {},
|
||||
filePath: newFilePath,
|
||||
value,
|
||||
}),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
// IA Generated
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
|
||||
type FlatSource = { path: string; content: string };
|
||||
|
||||
export const flattenSources = (
|
||||
sources: Sources,
|
||||
basePath = '',
|
||||
): FlatSource[] => {
|
||||
const out: FlatSource[] = [];
|
||||
|
||||
const join = (a: string, b: string) => (a ? `${a}/${b}` : b);
|
||||
|
||||
const walk = (node: Sources, prefix: string) => {
|
||||
for (const [name, value] of Object.entries(node)) {
|
||||
if (typeof value === 'string') {
|
||||
out.push({ path: join(prefix, name), content: value });
|
||||
} else if (value && typeof value === 'object') {
|
||||
walk(value as Sources, join(prefix, name));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
walk(sources, basePath);
|
||||
|
||||
out.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
||||
return out;
|
||||
};
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { useGetAvailablePackages } from '@/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { type EditorProps, type Monaco } from '@monaco-editor/react';
|
||||
import { type editor } from 'monaco-editor';
|
||||
import { AutoTypings } from 'monaco-editor-auto-typings';
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type LogicFunctionNewFormValues } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { type LogicFunctionNewFormValues } from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
|
||||
import { TextArea } from '@/ui/input/components/TextArea';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
-12
@@ -21,13 +21,11 @@ export const SettingsLogicFunctionCodeEditorTab = ({
|
||||
handleExecute,
|
||||
onChange,
|
||||
isTesting = false,
|
||||
isManaged = false,
|
||||
}: {
|
||||
files: File[];
|
||||
handleExecute: () => void;
|
||||
onChange: (filePath: string, value: string) => void;
|
||||
isTesting?: boolean;
|
||||
isManaged?: boolean;
|
||||
}) => {
|
||||
const activeTabId = useRecoilComponentValue(
|
||||
activeTabIdComponentState,
|
||||
@@ -68,16 +66,6 @@ export const SettingsLogicFunctionCodeEditorTab = ({
|
||||
onChange={(newCodeValue: string) =>
|
||||
onChange(activeTabId, newCodeValue)
|
||||
}
|
||||
options={
|
||||
isManaged
|
||||
? {
|
||||
readOnly: true,
|
||||
readOnlyMessage: {
|
||||
value: t`Managed logic functions are not editable`,
|
||||
},
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Section>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { SettingsLogicFunctionNewForm } from '@/settings/logic-functions/components/SettingsLogicFunctionNewForm';
|
||||
import { SettingsLogicFunctionTabEnvironmentVariablesSection } from '@/settings/logic-functions/components/SettingsLogicFunctionTabEnvironmentVariablesSection';
|
||||
import { type LogicFunctionFormValues } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { type LogicFunctionFormValues } from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
|
||||
export const SettingsLogicFunctionSettingsTab = ({
|
||||
formValues,
|
||||
|
||||
+58
-49
@@ -5,21 +5,24 @@ import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { H2Title } from 'twenty-ui/display';
|
||||
import { H2Title, OverflowingTextWithTooltip } from 'twenty-ui/display';
|
||||
import { Section } from 'twenty-ui/layout';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||
import { Tag } from 'twenty-ui/components';
|
||||
import { type LogicFunction } from '~/generated-metadata/graphql';
|
||||
|
||||
export const StyledRouteTriggerTableRow = styled(TableRow)`
|
||||
grid-template-columns: 1fr 120px 120px;
|
||||
`;
|
||||
|
||||
// TODO: @Charles put back with new sources
|
||||
// const StyledTableCell = styled(TableCell)`
|
||||
// color: ${({ theme }) => theme.font.color.tertiary};
|
||||
// gap: ${({ theme }) => theme.spacing(2)};
|
||||
// min-width: 0;
|
||||
// overflow: hidden;
|
||||
// `;
|
||||
const StyledTableCell = styled(TableCell)`
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const StyledRouteTriggerTableHeaderRow = styled(StyledRouteTriggerTableRow)`
|
||||
margin-bottom: ${({ theme }) => theme.spacing(2)};
|
||||
@@ -36,22 +39,31 @@ const StyledEmptyState = styled.div`
|
||||
`;
|
||||
|
||||
export const SettingsLogicFunctionTriggersTab = ({
|
||||
logicFunction: _logicFunction,
|
||||
logicFunction,
|
||||
}: {
|
||||
logicFunction: LogicFunction;
|
||||
}) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const cronTriggers: [] = [];
|
||||
const cronTrigger = logicFunction.cronTriggerSettings;
|
||||
|
||||
const routeTriggers: [] = [];
|
||||
const routeTrigger = logicFunction.httpRouteTriggerSettings;
|
||||
|
||||
const databaseEvents: [] = [];
|
||||
const databaseEventTriggerSettings =
|
||||
logicFunction.databaseEventTriggerSettings;
|
||||
|
||||
const hasNoTriggers =
|
||||
databaseEvents.length === 0 &&
|
||||
cronTriggers.length === 0 &&
|
||||
routeTriggers.length === 0;
|
||||
let databaseEventTrigger = undefined;
|
||||
|
||||
if (isDefined(databaseEventTriggerSettings)) {
|
||||
const [object, action]: [string, string] =
|
||||
databaseEventTriggerSettings.eventName.split('.');
|
||||
databaseEventTrigger = {
|
||||
object,
|
||||
action,
|
||||
updatedFields: databaseEventTriggerSettings.updatedFields,
|
||||
};
|
||||
}
|
||||
const hasNoTriggers = !cronTrigger && !routeTrigger && !databaseEventTrigger;
|
||||
|
||||
if (hasNoTriggers) {
|
||||
return (
|
||||
@@ -69,37 +81,37 @@ export const SettingsLogicFunctionTriggersTab = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{databaseEvents.length > 0 && (
|
||||
{isDefined(databaseEventTrigger) && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Database event`}
|
||||
description={t`Select the events that should trigger the function`}
|
||||
/>
|
||||
<SettingsDatabaseEventsForm events={databaseEvents} disabled />
|
||||
<SettingsDatabaseEventsForm
|
||||
events={[databaseEventTrigger]}
|
||||
disabled
|
||||
/>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{cronTriggers.length > 0 && (
|
||||
{isDefined(cronTrigger) && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Cron`}
|
||||
description={t`Triggers the function at regular intervals`}
|
||||
/>
|
||||
{cronTriggers.map((cronTrigger, index) => (
|
||||
<FormTextFieldInput
|
||||
key={index}
|
||||
label={t`Expression`}
|
||||
placeholder="0 */1 * * *"
|
||||
hint={t`Format: [Minute] [Hour] [Day of Month] [Month] [Day of Week]`}
|
||||
onChange={() => {}}
|
||||
readonly
|
||||
defaultValue={cronTrigger}
|
||||
/>
|
||||
))}
|
||||
<FormTextFieldInput
|
||||
label={t`Expression`}
|
||||
placeholder="0 */1 * * *"
|
||||
hint={t`Format: [Minute] [Hour] [Day of Month] [Month] [Day of Week]`}
|
||||
onChange={() => {}}
|
||||
readonly
|
||||
defaultValue={cronTrigger.pattern}
|
||||
/>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{routeTriggers.length > 0 && (
|
||||
{isDefined(routeTrigger) && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Http`}
|
||||
@@ -111,24 +123,21 @@ export const SettingsLogicFunctionTriggersTab = ({
|
||||
<TableHeader>{t`Method`}</TableHeader>
|
||||
<TableHeader>{t`Auth Required`}</TableHeader>
|
||||
</StyledRouteTriggerTableHeaderRow>
|
||||
{routeTriggers.map((_, _index) => (
|
||||
<></>
|
||||
// <StyledRouteTriggerTableRow key={index}>
|
||||
// <StyledTableCell>
|
||||
// <OverflowingTextWithTooltip
|
||||
// text={`${REACT_APP_SERVER_BASE_URL}/s${routeTrigger.path}`}
|
||||
// />
|
||||
// </StyledTableCell>
|
||||
// <StyledTableCell>{routeTrigger.httpMethod}</StyledTableCell>
|
||||
// <StyledTableCell>
|
||||
// <Tag
|
||||
// text={routeTrigger.isAuthRequired ? t`True` : t`False`}
|
||||
// color={routeTrigger.isAuthRequired ? 'green' : 'orange'}
|
||||
// weight="medium"
|
||||
// />
|
||||
// </StyledTableCell>
|
||||
// </StyledRouteTriggerTableRow>
|
||||
))}
|
||||
<StyledRouteTriggerTableRow>
|
||||
<StyledTableCell>
|
||||
<OverflowingTextWithTooltip
|
||||
text={`${REACT_APP_SERVER_BASE_URL}/s${routeTrigger.path}`}
|
||||
/>
|
||||
</StyledTableCell>
|
||||
<StyledTableCell>{routeTrigger.httpMethod}</StyledTableCell>
|
||||
<StyledTableCell>
|
||||
<Tag
|
||||
text={routeTrigger.isAuthRequired ? t`True` : t`False`}
|
||||
color={routeTrigger.isAuthRequired ? 'green' : 'orange'}
|
||||
weight="medium"
|
||||
/>
|
||||
</StyledTableCell>
|
||||
</StyledRouteTriggerTableRow>
|
||||
</Table>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const CREATE_DEFAULT_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
mutation CreateDefaultLogicFunctionItem(
|
||||
$input: CreateDefaultLogicFunctionInput!
|
||||
) {
|
||||
createDefaultLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { FIND_ONE_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/queries/findOneLogicFunction';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import {
|
||||
type GetOneLogicFunctionQuery,
|
||||
type GetOneLogicFunctionQueryVariables,
|
||||
type LogicFunctionIdInput,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useGetOneLogicFunction = ({
|
||||
id,
|
||||
onCompleted,
|
||||
}: LogicFunctionIdInput & {
|
||||
onCompleted?: (data: GetOneLogicFunctionQuery) => void;
|
||||
}) => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const { data, loading } = useQuery<
|
||||
GetOneLogicFunctionQuery,
|
||||
GetOneLogicFunctionQueryVariables
|
||||
>(FIND_ONE_LOGIC_FUNCTION, {
|
||||
client: apolloMetadataClient ?? undefined,
|
||||
variables: {
|
||||
input: { id },
|
||||
},
|
||||
onCompleted,
|
||||
});
|
||||
return {
|
||||
logicFunction: data?.findOneLogicFunction || null,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { createState } from 'twenty-ui/utilities';
|
||||
import { type GetManyLogicFunctionsQuery } from '~/generated-metadata/graphql';
|
||||
import { type FindManyLogicFunctionsQuery } from '~/generated-metadata/graphql';
|
||||
|
||||
export type LogicFunction =
|
||||
GetManyLogicFunctionsQuery['findManyLogicFunctions'][number];
|
||||
FindManyLogicFunctionsQuery['findManyLogicFunctions'][number];
|
||||
|
||||
export const logicFunctionsState = createState<LogicFunction[]>({
|
||||
key: 'logicFunctionsState',
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
useFindAllCoreViewsQuery,
|
||||
useFindAllRecordPageLayoutsQuery,
|
||||
useGetCurrentUserQuery,
|
||||
useGetManyLogicFunctionsQuery,
|
||||
useFindManyLogicFunctionsQuery,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { dynamicActivate } from '~/utils/i18n/dynamicActivate';
|
||||
@@ -131,7 +131,7 @@ export const MetadataProviderEffect = () => {
|
||||
},
|
||||
);
|
||||
|
||||
const { data: logicFunctionsData } = useGetManyLogicFunctionsQuery({
|
||||
const { data: logicFunctionsData } = useFindManyLogicFunctionsQuery({
|
||||
skip: !isLoggedIn,
|
||||
});
|
||||
|
||||
|
||||
+16
-38
@@ -1,6 +1,8 @@
|
||||
import { useGetLogicFunctionSourceCode } from '@/logic-functions/hooks/useGetLogicFunctionSourceCode';
|
||||
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { type LogicFunctionFormValues } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { useGetAvailablePackages } from '@/logic-functions/hooks/useGetAvailablePackages';
|
||||
import {
|
||||
type LogicFunctionFormValues,
|
||||
useLogicFunctionUpdateFormState,
|
||||
} from '@/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';
|
||||
@@ -11,7 +13,6 @@ import { setNestedValue } from '@/workflow/workflow-steps/workflow-actions/code-
|
||||
|
||||
import { CmdEnterActionButton } from '@/action-menu/components/CmdEnterActionButton';
|
||||
import { LogicFunctionExecutionResult } from '@/logic-functions/components/LogicFunctionExecutionResult';
|
||||
import { INDEX_FILE_NAME } from '@/logic-functions/constants/IndexFileName';
|
||||
import { getFunctionInputFromSourceCode } from '@/logic-functions/utils/getFunctionInputFromSourceCode';
|
||||
import { mergeDefaultFunctionInputAndFunctionInput } from '@/logic-functions/utils/mergeDefaultFunctionInputAndFunctionInput';
|
||||
import { InputLabel } from '@/ui/input/components/InputLabel';
|
||||
@@ -35,10 +36,8 @@ import { WorkflowVariablePicker } from '@/workflow/workflow-variables/components
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
import { SOURCE_FOLDER_NAME } from '@/logic-functions/constants/SourceFolderName';
|
||||
import { useExecuteLogicFunction } from '@/logic-functions/hooks/useExecuteLogicFunction';
|
||||
import { usePersistLogicFunction } from '@/logic-functions/hooks/usePersistLogicFunction';
|
||||
import { computeNewSources } from '@/logic-functions/utils/computeNewSources';
|
||||
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';
|
||||
@@ -104,7 +103,7 @@ export const WorkflowEditActionCode = ({
|
||||
activeTabIdComponentState,
|
||||
WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID,
|
||||
);
|
||||
const { updateLogicFunctionSource } = usePersistLogicFunction();
|
||||
const { updateLogicFunction } = usePersistLogicFunction();
|
||||
const { getUpdatableWorkflowVersion } =
|
||||
useGetUpdatableWorkflowVersionOrThrow();
|
||||
|
||||
@@ -126,21 +125,8 @@ export const WorkflowEditActionCode = ({
|
||||
action.settings.input.logicFunctionInput,
|
||||
);
|
||||
|
||||
const { code: codeFromApi, loading } = useGetLogicFunctionSourceCode({
|
||||
logicFunctionId,
|
||||
});
|
||||
|
||||
const [formValues, setFormValues] = useState<LogicFunctionFormValues>({
|
||||
name: '',
|
||||
description: '',
|
||||
code: { src: { 'index.ts': '' } },
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(codeFromApi)) {
|
||||
setFormValues((prev) => ({ ...prev, code: codeFromApi }));
|
||||
}
|
||||
}, [codeFromApi]);
|
||||
const { formValues, setFormValues, loading } =
|
||||
useLogicFunctionUpdateFormState({ logicFunctionId });
|
||||
|
||||
const updateOutputSchemaFromTestResult = async (testResult: object) => {
|
||||
if (actionOptions.readonly === true) {
|
||||
@@ -159,10 +145,12 @@ export const WorkflowEditActionCode = ({
|
||||
});
|
||||
|
||||
const handleSave = useDebouncedCallback(async () => {
|
||||
await updateLogicFunctionSource({
|
||||
await updateLogicFunction({
|
||||
input: {
|
||||
id: logicFunctionId,
|
||||
code: formValues.code,
|
||||
update: {
|
||||
sourceHandlerCode: formValues.code,
|
||||
},
|
||||
},
|
||||
});
|
||||
}, 500);
|
||||
@@ -174,11 +162,7 @@ export const WorkflowEditActionCode = ({
|
||||
setFormValues((prevState: LogicFunctionFormValues) => {
|
||||
return {
|
||||
...prevState,
|
||||
code: computeNewSources({
|
||||
previousCode: prevState['code'],
|
||||
filePath: `${SOURCE_FOLDER_NAME}/${INDEX_FILE_NAME}`,
|
||||
value: newCode,
|
||||
}),
|
||||
code: newCode,
|
||||
};
|
||||
});
|
||||
await handleSave();
|
||||
@@ -273,7 +257,7 @@ export const WorkflowEditActionCode = ({
|
||||
}
|
||||
|
||||
if (!isExecuting) {
|
||||
await executeLogicFunction({ forceRebuild: true });
|
||||
await executeLogicFunction();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -387,12 +371,6 @@ export const WorkflowEditActionCode = ({
|
||||
setIsFullScreen(false);
|
||||
};
|
||||
|
||||
const indexFileContent =
|
||||
typeof formValues.code?.[SOURCE_FOLDER_NAME] !== 'string' &&
|
||||
typeof formValues.code[SOURCE_FOLDER_NAME][INDEX_FILE_NAME] === 'string'
|
||||
? formValues.code[SOURCE_FOLDER_NAME][INDEX_FILE_NAME]
|
||||
: '';
|
||||
|
||||
const fullScreenOverlay = renderFullScreenModal(
|
||||
<div data-globally-prevent-click-outside="true">
|
||||
<WorkflowEditActionCodeFields
|
||||
@@ -404,7 +382,7 @@ export const WorkflowEditActionCode = ({
|
||||
<StyledFullScreenCodeEditorContainer>
|
||||
<CodeEditor
|
||||
height="100%"
|
||||
value={indexFileContent}
|
||||
value={formValues.code}
|
||||
language="typescript"
|
||||
onChange={handleCodeChange}
|
||||
onMount={handleEditorDidMount}
|
||||
@@ -439,7 +417,7 @@ export const WorkflowEditActionCode = ({
|
||||
readonly={actionOptions.readonly}
|
||||
/>
|
||||
<WorkflowCodeEditor
|
||||
value={indexFileContent}
|
||||
value={formValues.code}
|
||||
onChange={handleCodeChange}
|
||||
onMount={handleEditorDidMount}
|
||||
options={{
|
||||
|
||||
+2
-11
@@ -1,9 +1,7 @@
|
||||
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { useGetAvailablePackages } from '@/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { type WorkflowCodeAction } from '@/workflow/types/Workflow';
|
||||
import { useGetLogicFunctionSourceCode } from '@/logic-functions/hooks/useGetLogicFunctionSourceCode';
|
||||
|
||||
import { INDEX_FILE_NAME } from '@/logic-functions/constants/IndexFileName';
|
||||
import { SOURCE_FOLDER_NAME } from '@/logic-functions/constants/SourceFolderName';
|
||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||
import { WorkflowEditActionCodeFields } from '@/workflow/workflow-steps/workflow-actions/code-action/components/WorkflowEditActionCodeFields';
|
||||
import { getWrongExportedFunctionMarkers } from '@/workflow/workflow-steps/workflow-actions/code-action/utils/getWrongExportedFunctionMarkers';
|
||||
@@ -52,13 +50,6 @@ export const WorkflowReadonlyActionCode = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
const indexFileContent =
|
||||
code != null &&
|
||||
typeof code?.[SOURCE_FOLDER_NAME] !== 'string' &&
|
||||
typeof code[SOURCE_FOLDER_NAME]?.[INDEX_FILE_NAME] === 'string'
|
||||
? code[SOURCE_FOLDER_NAME][INDEX_FILE_NAME]
|
||||
: '';
|
||||
|
||||
return (
|
||||
<>
|
||||
<WorkflowStepBody>
|
||||
@@ -69,7 +60,7 @@ export const WorkflowReadonlyActionCode = ({
|
||||
<StyledCodeEditorContainer>
|
||||
<CodeEditor
|
||||
height={343}
|
||||
value={indexFileContent}
|
||||
value={code ?? undefined}
|
||||
language="typescript"
|
||||
onMount={handleEditorDidMount}
|
||||
setMarkers={getWrongExportedFunctionMarkers}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { getDefaultFunctionInputFromInputSchema } from '@/logic-functions/utils/getDefaultFunctionInputFromInputSchema';
|
||||
import { mergeDefaultFunctionInputAndFunctionInput } from '@/logic-functions/utils/mergeDefaultFunctionInputAndFunctionInput';
|
||||
import { useGetOneLogicFunction } from '@/settings/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { useGetOneLogicFunction } from '@/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { type WorkflowLogicFunctionAction } from '@/workflow/types/Workflow';
|
||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||
import { WorkflowStepFooter } from '@/workflow/workflow-steps/components/WorkflowStepFooter';
|
||||
|
||||
Reference in New Issue
Block a user