6654 serverless functions add a deploy button disable deploy when autosave (#6715)

- improvements on serverless function behavior (autosave performances,
deploy on execution only)
- add versioning to serverless functions
- add a publish endpoint to create a new version of a serverless
function
  - add deploy and reset to lastVersion button in the settings section:
<img width="736" alt="image"
src="https://github.com/user-attachments/assets/2001f8d2-07a4-4f79-84dd-ec74b6f301d3">
This commit is contained in:
martmull
2024-08-23 12:06:03 +02:00
committed by GitHub
parent 7ca091faa5
commit 6f9aa1e870
42 changed files with 850 additions and 269 deletions

View File

@ -9,6 +9,13 @@ jest.mock(
}),
);
jest.mock(
'@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode',
() => ({
useGetOneServerlessFunctionSourceCode: jest.fn(),
}),
);
describe('useServerlessFunctionUpdateFormState', () => {
test('should return a form', () => {
const serverlessFunctionId = 'serverlessFunctionId';
@ -20,6 +27,14 @@ describe('useServerlessFunctionUpdateFormState', () => {
serverlessFunction: { sourceCodeFullPath: undefined },
},
);
const useGetOneServerlessFunctionSourceCodeMock = jest.requireMock(
'@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode',
);
useGetOneServerlessFunctionSourceCodeMock.useGetOneServerlessFunctionSourceCode.mockReturnValue(
{
code: 'export const handler = () => {}',
},
);
const { result } = renderHook(
() => useServerlessFunctionUpdateFormState(serverlessFunctionId),
{

View File

@ -1,13 +1,13 @@
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
import { ApolloClient, useMutation } from '@apollo/client';
import { getOperationName } from '@apollo/client/utilities';
import { FIND_MANY_SERVERLESS_FUNCTIONS } from '@/settings/serverless-functions/graphql/queries/findManyServerlessFunctions';
import { DELETE_ONE_SERVERLESS_FUNCTION } from '@/settings/serverless-functions/graphql/mutations/deleteOneServerlessFunction';
import {
DeleteServerlessFunctionInput,
DeleteOneServerlessFunctionMutation,
DeleteOneServerlessFunctionMutationVariables,
} from '~/generated-metadata/graphql';
import { FIND_ONE_SERVERLESS_FUNCTION_SOURCE_CODE } from '@/settings/serverless-functions/graphql/queries/findOneServerlessFunctionSourceCode';
export const useDeleteOneServerlessFunction = () => {
const apolloMetadataClient = useApolloMetadataClient();
@ -26,7 +26,9 @@ export const useDeleteOneServerlessFunction = () => {
input,
},
awaitRefetchQueries: true,
refetchQueries: [getOperationName(FIND_MANY_SERVERLESS_FUNCTIONS) ?? ''],
refetchQueries: [
getOperationName(FIND_ONE_SERVERLESS_FUNCTION_SOURCE_CODE) ?? '',
],
});
};

View File

@ -2,6 +2,7 @@ import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetada
import { ApolloClient, useMutation } from '@apollo/client';
import { EXECUTE_ONE_SERVERLESS_FUNCTION } from '@/settings/serverless-functions/graphql/mutations/executeOneServerlessFunction';
import {
ExecuteServerlessFunctionInput,
ExecuteOneServerlessFunctionMutation,
ExecuteOneServerlessFunctionMutationVariables,
} from '~/generated-metadata/graphql';
@ -16,13 +17,11 @@ export const useExecuteOneServerlessFunction = () => {
});
const executeOneServerlessFunction = async (
id: string,
payload: object = {},
input: ExecuteServerlessFunctionInput,
) => {
return await mutate({
variables: {
id,
payload,
input,
},
});
};

View File

@ -0,0 +1,30 @@
import { useQuery } from '@apollo/client';
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
import { FIND_ONE_SERVERLESS_FUNCTION_SOURCE_CODE } from '@/settings/serverless-functions/graphql/queries/findOneServerlessFunctionSourceCode';
import {
FindOneServerlessFunctionSourceCodeQuery,
FindOneServerlessFunctionSourceCodeQueryVariables,
} from '~/generated-metadata/graphql';
export const useGetOneServerlessFunctionSourceCode = ({
id,
version,
onCompleted,
}: {
id: string;
version: string;
onCompleted?: (data: FindOneServerlessFunctionSourceCodeQuery) => void;
}) => {
const apolloMetadataClient = useApolloMetadataClient();
const { data, loading } = useQuery<
FindOneServerlessFunctionSourceCodeQuery,
FindOneServerlessFunctionSourceCodeQueryVariables
>(FIND_ONE_SERVERLESS_FUNCTION_SOURCE_CODE, {
client: apolloMetadataClient ?? undefined,
variables: {
input: { id, version },
},
onCompleted,
});
return { code: data?.getServerlessFunctionSourceCode, loading };
};

View File

@ -0,0 +1,36 @@
import { ApolloClient, useMutation } from '@apollo/client';
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
import { PUBLISH_ONE_SERVERLESS_FUNCTION } from '@/settings/serverless-functions/graphql/mutations/publishOneServerlessFunction';
import {
PublishServerlessFunctionInput,
PublishOneServerlessFunctionMutation,
PublishOneServerlessFunctionMutationVariables,
} from '~/generated-metadata/graphql';
import { getOperationName } from '@apollo/client/utilities';
import { FIND_ONE_SERVERLESS_FUNCTION_SOURCE_CODE } from '@/settings/serverless-functions/graphql/queries/findOneServerlessFunctionSourceCode';
export const usePublishOneServerlessFunction = () => {
const apolloMetadataClient = useApolloMetadataClient();
const [mutate] = useMutation<
PublishOneServerlessFunctionMutation,
PublishOneServerlessFunctionMutationVariables
>(PUBLISH_ONE_SERVERLESS_FUNCTION, {
client: apolloMetadataClient ?? ({} as ApolloClient<any>),
});
const publishOneServerlessFunction = async (
input: PublishServerlessFunctionInput,
) => {
return await mutate({
variables: {
input,
},
awaitRefetchQueries: true,
refetchQueries: [
getOperationName(FIND_ONE_SERVERLESS_FUNCTION_SOURCE_CODE) ?? '',
],
});
};
return { publishOneServerlessFunction };
};

View File

@ -1,7 +1,7 @@
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { getFileAbsoluteURI } from '~/utils/file/getFileAbsoluteURI';
import { isDefined } from '~/utils/isDefined';
import { Dispatch, SetStateAction, useState } from 'react';
import { useGetOneServerlessFunction } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunction';
import { useGetOneServerlessFunctionSourceCode } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode';
import { FindOneServerlessFunctionSourceCodeQuery } from '~/generated-metadata/graphql';
export type ServerlessFunctionNewFormValues = {
name: string;
@ -28,30 +28,21 @@ export const useServerlessFunctionUpdateFormState = (
const { serverlessFunction } =
useGetOneServerlessFunction(serverlessFunctionId);
useEffect(() => {
const getFileContent = async () => {
const resp = await fetch(
getFileAbsoluteURI(serverlessFunction?.sourceCodeFullPath),
);
if (resp.status !== 200) {
throw new Error('Network response was not ok');
} else {
const result = await resp.text();
const newState = {
code: result,
name: serverlessFunction?.name || '',
description: serverlessFunction?.description || '',
};
setFormValues((prevState) => ({
...prevState,
...newState,
}));
}
};
if (isDefined(serverlessFunction?.sourceCodeFullPath)) {
getFileContent();
}
}, [serverlessFunction, setFormValues]);
useGetOneServerlessFunctionSourceCode({
id: serverlessFunctionId,
version: 'draft',
onCompleted: (data: FindOneServerlessFunctionSourceCodeQuery) => {
const newState = {
code: data?.getServerlessFunctionSourceCode || '',
name: serverlessFunction?.name || '',
description: serverlessFunction?.description || '',
};
setFormValues((prevState) => ({
...prevState,
...newState,
}));
},
});
return [formValues, setFormValues];
};