diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/__tests__/useServerlessFunctionUpdateFormState.test.ts b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/__tests__/useServerlessFunctionUpdateFormState.test.ts index b8e6bd3b1dd8..e0799f13ac2e 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/__tests__/useServerlessFunctionUpdateFormState.test.ts +++ b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/__tests__/useServerlessFunctionUpdateFormState.test.ts @@ -42,7 +42,7 @@ describe('useServerlessFunctionUpdateFormState', () => { }, ); - const [formValues] = result.current; + const { formValues } = result.current; expect(formValues).toEqual({ name: '', description: '', code: '' }); }); diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts index aa336b977162..97780d3fca65 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts +++ b/packages/twenty-front/src/modules/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState.ts @@ -18,7 +18,11 @@ type SetServerlessFunctionFormValues = Dispatch< export const useServerlessFunctionUpdateFormState = ( serverlessFunctionId: string, -): [ServerlessFunctionFormValues, SetServerlessFunctionFormValues] => { +): { + formValues: ServerlessFunctionFormValues; + setFormValues: SetServerlessFunctionFormValues; + loading: boolean; +} => { const [formValues, setFormValues] = useState({ name: '', description: '', @@ -28,7 +32,7 @@ export const useServerlessFunctionUpdateFormState = ( const { serverlessFunction } = useGetOneServerlessFunction(serverlessFunctionId); - useGetOneServerlessFunctionSourceCode({ + const { loading } = useGetOneServerlessFunctionSourceCode({ id: serverlessFunctionId, version: 'draft', onCompleted: (data: FindOneServerlessFunctionSourceCodeQuery) => { @@ -44,5 +48,5 @@ export const useServerlessFunctionUpdateFormState = ( }, }); - return [formValues, setFormValues]; + return { formValues, setFormValues, loading }; }; diff --git a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionDetail.tsx b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionDetail.tsx index 057c8f3ceaa3..fa3d01bbd8a6 100644 --- a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionDetail.tsx +++ b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionDetail.tsx @@ -23,6 +23,7 @@ import { isDefined } from '~/utils/isDefined'; import { useDebouncedCallback } from 'use-debounce'; import { useGetOneServerlessFunctionSourceCode } from '@/settings/serverless-functions/hooks/useGetOneServerlessFunctionSourceCode'; import { useState } from 'react'; +import isEmpty from 'lodash.isempty'; const TAB_LIST_COMPONENT_ID = 'serverless-function-detail'; @@ -37,7 +38,7 @@ export const SettingsServerlessFunctionDetail = () => { const { executeOneServerlessFunction } = useExecuteOneServerlessFunction(); const { updateOneServerlessFunction } = useUpdateOneServerlessFunction(); const { publishOneServerlessFunction } = usePublishOneServerlessFunction(); - const [formValues, setFormValues] = + const { formValues, setFormValues, loading } = useServerlessFunctionUpdateFormState(serverlessFunctionId); const { code: latestVersionCode } = useGetOneServerlessFunctionSourceCode({ id: serverlessFunctionId, @@ -52,6 +53,9 @@ export const SettingsServerlessFunctionDetail = () => { const save = async () => { try { + if (isEmpty(formValues.name)) { + return; + } await updateOneServerlessFunction({ id: serverlessFunctionId, name: formValues.name, @@ -201,7 +205,7 @@ export const SettingsServerlessFunctionDetail = () => { }; return ( - formValues.name && ( + !loading && ( { + await queryRunner.query( + `ALTER TABLE "metadata"."serverlessFunction" DROP CONSTRAINT "IndexOnNameAndWorkspaceIdUnique"`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "metadata"."serverlessFunction" ADD CONSTRAINT "IndexOnNameAndWorkspaceIdUnique" UNIQUE ("name", "workspaceId")`, + ); + } +} diff --git a/packages/twenty-server/src/engine/integrations/serverless/drivers/local.driver.ts b/packages/twenty-server/src/engine/integrations/serverless/drivers/local.driver.ts index 60933461b100..512cd1f82fda 100644 --- a/packages/twenty-server/src/engine/integrations/serverless/drivers/local.driver.ts +++ b/packages/twenty-server/src/engine/integrations/serverless/drivers/local.driver.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import { join } from 'path'; import { tmpdir } from 'os'; import { promises as fs } from 'fs'; @@ -137,7 +138,7 @@ export class LocalDriver }); } child.kill(); - fs.unlink(tmpFilePath); + fs.unlink(tmpFilePath).catch(console.error); }); child.stderr?.on('data', (data) => { @@ -169,19 +170,19 @@ export class LocalDriver }, }); child.kill(); - fs.unlink(tmpFilePath); + fs.unlink(tmpFilePath).catch(console.error); }); child.on('error', (error) => { reject(error); child.kill(); - fs.unlink(tmpFilePath); + fs.unlink(tmpFilePath).catch(console.error); }); child.on('exit', (code) => { if (code && code !== 0) { reject(new Error(`Child process exited with code ${code}`)); - fs.unlink(tmpFilePath); + fs.unlink(tmpFilePath).catch(console.error); } }); diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/dtos/update-serverless-function.input.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/dtos/update-serverless-function.input.ts index 2955137196ee..a757784e04ed 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/dtos/update-serverless-function.input.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/dtos/update-serverless-function.input.ts @@ -23,7 +23,6 @@ export class UpdateServerlessFunctionInput { description?: string; @IsString() - @IsNotEmpty() @Field() code: string; } diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.entity.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.entity.ts index 3e985e5bd95f..7844741873f4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.entity.ts @@ -17,7 +17,6 @@ export enum ServerlessFunctionRuntime { } @Entity('serverlessFunction') -@Unique('IndexOnNameAndWorkspaceIdUnique', ['name', 'workspaceId']) export class ServerlessFunctionEntity { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts index 5b6cf8765639..0e297fe462d4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.service.ts @@ -240,18 +240,6 @@ export class ServerlessFunctionService extends TypeOrmQueryService