Serverless function follow up (#9924)

- remove asynchronous serverless function build
- build serverless function synchronously instead on activate workflow
or execute
- add a loader on workflow code step test tab test button
- add a new `ServerlessFunctionSyncStatus` `BUILDING`
- add a new route to build a serverless function draft version 
- delay artificially execution to avoid UI flashing



https://github.com/user-attachments/assets/8d958d9a-ef41-4261-999e-6ea374191e33
This commit is contained in:
martmull
2025-01-31 17:12:42 +01:00
committed by GitHub
parent f47c0d45e3
commit ae62789159
28 changed files with 430 additions and 224 deletions

View File

@ -1,15 +1,16 @@
import styled from '@emotion/styled';
import { LightCopyIconButton } from '@/object-record/record-field/components/LightCopyIconButton';
import {
DEFAULT_OUTPUT_VALUE,
ServerlessFunctionTestData,
} from '@/workflow/states/serverlessFunctionTestDataFamilyState';
import { ServerlessFunctionTestData } from '@/workflow/states/serverlessFunctionTestDataFamilyState';
import { useTheme } from '@emotion/react';
import {
CodeEditor,
CoreEditorHeader,
IconSquareRoundedCheck,
IconSquareRoundedX,
IconLoader,
IconSettings,
AnimatedCircleLoading,
} from 'twenty-ui';
import { ServerlessFunctionExecutionStatus } from '~/generated-metadata/graphql';
@ -18,20 +19,33 @@ const StyledContainer = styled.div`
flex-direction: column;
`;
const StyledOutput = styled.div<{ status?: ServerlessFunctionExecutionStatus }>`
type OutputAccent = 'default' | 'success' | 'error';
const StyledInfoContainer = styled.div`
display: flex;
font-size: ${({ theme }) => theme.font.size.md};
`;
const StyledOutput = styled.div<{ accent?: OutputAccent }>`
align-items: center;
gap: ${({ theme }) => theme.spacing(1)};
color: ${({ theme, status }) =>
status === ServerlessFunctionExecutionStatus.SUCCESS
color: ${({ theme, accent }) =>
accent === 'success'
? theme.color.turquoise
: theme.color.red};
: accent === 'error'
? theme.color.red
: theme.font.color.secondary};
display: flex;
`;
export const ServerlessFunctionExecutionResult = ({
serverlessFunctionTestData,
isTesting = false,
isBuilding = false,
}: {
serverlessFunctionTestData: ServerlessFunctionTestData;
isTesting?: boolean;
isBuilding?: boolean;
}) => {
const theme = useTheme();
@ -40,25 +54,60 @@ export const ServerlessFunctionExecutionResult = ({
serverlessFunctionTestData.output.error ||
'';
const leftNode =
serverlessFunctionTestData.output.data === DEFAULT_OUTPUT_VALUE ? (
'Output'
) : (
<StyledOutput status={serverlessFunctionTestData.output.status}>
<IconSquareRoundedCheck size={theme.icon.size.md} />
{serverlessFunctionTestData.output.status ===
ServerlessFunctionExecutionStatus.SUCCESS
? '200 OK'
: '500 Error'}
{' - '}
{serverlessFunctionTestData.output.duration}ms
</StyledOutput>
);
const SuccessLeftNode = (
<StyledOutput accent="success">
<IconSquareRoundedCheck size={theme.icon.size.md} />
200 OK - {serverlessFunctionTestData.output.duration}ms
</StyledOutput>
);
const ErrorLeftNode = (
<StyledOutput accent="error">
<IconSquareRoundedX size={theme.icon.size.md} />
500 Error - {serverlessFunctionTestData.output.duration}ms
</StyledOutput>
);
const IdleLeftNode = 'Output';
const PendingLeftNode = (isTesting || isBuilding) && (
<StyledOutput>
<AnimatedCircleLoading>
{isTesting ? (
<IconLoader size={theme.icon.size.md} />
) : (
<IconSettings size={theme.icon.size.md} />
)}
</AnimatedCircleLoading>
<StyledInfoContainer>
{isTesting ? 'Running function' : 'Building function'}
</StyledInfoContainer>
</StyledOutput>
);
const computeLeftNode = () => {
if (isTesting || isBuilding) {
return PendingLeftNode;
}
if (
serverlessFunctionTestData.output.status ===
ServerlessFunctionExecutionStatus.ERROR
) {
return ErrorLeftNode;
}
if (
serverlessFunctionTestData.output.status ===
ServerlessFunctionExecutionStatus.SUCCESS
) {
return SuccessLeftNode;
}
return IdleLeftNode;
};
return (
<StyledContainer>
<CoreEditorHeader
leftNodes={[leftNode]}
leftNodes={[computeLeftNode()]}
rightNodes={[<LightCopyIconButton copyText={result} />]}
/>
<CodeEditor
@ -66,6 +115,7 @@ export const ServerlessFunctionExecutionResult = ({
language={serverlessFunctionTestData.language}
height={serverlessFunctionTestData.height}
options={{ readOnly: true, domReadOnly: true }}
isLoading={isTesting || isBuilding}
withHeader
/>
</StyledContainer>