6653 serverless functions store and use environment variables in serverless function scripts (#7390)
 
This commit is contained in:
@ -1,9 +1,8 @@
|
||||
import { ServerlessFunctionFormValues } from '@/settings/serverless-functions/hooks/useServerlessFunctionUpdateFormState';
|
||||
import { SettingsServerlessFunctionHotkeyScope } from '@/settings/serverless-functions/types/SettingsServerlessFunctionHotKeyScope';
|
||||
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import { CodeEditor } from '@/ui/input/code-editor/components/CodeEditor';
|
||||
import { CodeEditor, File } from '@/ui/input/code-editor/components/CodeEditor';
|
||||
import { CoreEditorHeader } from '@/ui/input/code-editor/components/CodeEditorHeader';
|
||||
import { Section } from '@/ui/layout/section/components/Section';
|
||||
import { TabList } from '@/ui/layout/tab/components/TabList';
|
||||
@ -13,13 +12,16 @@ import { useNavigate } from 'react-router-dom';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { H2Title, IconGitCommit, IconPlayerPlay, IconRestore } from 'twenty-ui';
|
||||
import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount';
|
||||
import { SETTINGS_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/settings/serverless-functions/constants/SettingsServerlessFunctionTabListComponentId';
|
||||
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
const StyledTabList = styled(TabList)`
|
||||
border-bottom: none;
|
||||
`;
|
||||
|
||||
export const SettingsServerlessFunctionCodeEditorTab = ({
|
||||
formValues,
|
||||
files,
|
||||
handleExecute,
|
||||
handlePublish,
|
||||
handleReset,
|
||||
@ -28,15 +30,19 @@ export const SettingsServerlessFunctionCodeEditorTab = ({
|
||||
onChange,
|
||||
setIsCodeValid,
|
||||
}: {
|
||||
formValues: ServerlessFunctionFormValues;
|
||||
files: File[];
|
||||
handleExecute: () => void;
|
||||
handlePublish: () => void;
|
||||
handleReset: () => void;
|
||||
resetDisabled: boolean;
|
||||
publishDisabled: boolean;
|
||||
onChange: (key: string) => (value: string) => void;
|
||||
onChange: (filePath: string, value: string) => void;
|
||||
setIsCodeValid: (isCodeValid: boolean) => void;
|
||||
}) => {
|
||||
const { activeTabIdState } = useTabList(
|
||||
SETTINGS_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID,
|
||||
);
|
||||
const activeTabId = useRecoilValue(activeTabIdState);
|
||||
const TestButton = (
|
||||
<Button
|
||||
title="Test"
|
||||
@ -68,21 +74,15 @@ export const SettingsServerlessFunctionCodeEditorTab = ({
|
||||
/>
|
||||
);
|
||||
|
||||
const TAB_LIST_COMPONENT_ID = 'serverless-function-editor';
|
||||
|
||||
const HeaderTabList = (
|
||||
<StyledTabList
|
||||
tabListId={TAB_LIST_COMPONENT_ID}
|
||||
tabs={[{ id: 'index.ts', title: 'index.ts' }]}
|
||||
tabListId={SETTINGS_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID}
|
||||
tabs={files.map((file) => {
|
||||
return { id: file.path, title: file.path.split('/').at(-1) || '' };
|
||||
})}
|
||||
/>
|
||||
);
|
||||
|
||||
const Header = (
|
||||
<CoreEditorHeader
|
||||
leftNodes={[HeaderTabList]}
|
||||
rightNodes={[ResetButton, PublishButton, TestButton]}
|
||||
/>
|
||||
);
|
||||
const navigate = useNavigate();
|
||||
useHotkeyScopeOnMount(
|
||||
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionEditorTab,
|
||||
@ -95,18 +95,25 @@ export const SettingsServerlessFunctionCodeEditorTab = ({
|
||||
},
|
||||
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionEditorTab,
|
||||
);
|
||||
|
||||
return (
|
||||
<Section>
|
||||
<H2Title
|
||||
title="Code your function"
|
||||
description="Write your function (in typescript) below"
|
||||
/>
|
||||
<CodeEditor
|
||||
value={formValues.code}
|
||||
onChange={onChange('code')}
|
||||
setIsCodeValid={setIsCodeValid}
|
||||
header={Header}
|
||||
<CoreEditorHeader
|
||||
leftNodes={[HeaderTabList]}
|
||||
rightNodes={[ResetButton, PublishButton, TestButton]}
|
||||
/>
|
||||
{activeTabId && (
|
||||
<CodeEditor
|
||||
files={files}
|
||||
currentFilePath={activeTabId}
|
||||
onChange={(newCodeValue) => onChange(activeTabId, newCodeValue)}
|
||||
setIsCodeValid={setIsCodeValid}
|
||||
/>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
@ -44,28 +44,6 @@ export const SettingsServerlessFunctionTestTab = ({
|
||||
settingsServerlessFunctionOutput.error ||
|
||||
'';
|
||||
|
||||
const InputHeader = (
|
||||
<CoreEditorHeader
|
||||
title={'Input'}
|
||||
rightNodes={[
|
||||
<Button
|
||||
title="Run Function"
|
||||
variant="primary"
|
||||
accent="blue"
|
||||
size="small"
|
||||
Icon={IconPlayerPlay}
|
||||
onClick={handleExecute}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const OutputHeader = (
|
||||
<CoreEditorHeader
|
||||
leftNodes={[<SettingsServerlessFunctionsOutputMetadataInfo />]}
|
||||
rightNodes={[<LightCopyIconButton copyText={result} />]}
|
||||
/>
|
||||
);
|
||||
const navigate = useNavigate();
|
||||
useHotkeyScopeOnMount(
|
||||
SettingsServerlessFunctionHotkeyScope.ServerlessFunctionTestTab,
|
||||
@ -86,20 +64,52 @@ export const SettingsServerlessFunctionTestTab = ({
|
||||
description='Insert a JSON input, then press "Run" to test your function.'
|
||||
/>
|
||||
<StyledInputsContainer>
|
||||
<CodeEditor
|
||||
value={settingsServerlessFunctionInput}
|
||||
height={200}
|
||||
onChange={setSettingsServerlessFunctionInput}
|
||||
language={'json'}
|
||||
header={InputHeader}
|
||||
/>
|
||||
<CodeEditor
|
||||
value={result}
|
||||
height={settingsServerlessFunctionCodeEditorOutputParams.height}
|
||||
language={settingsServerlessFunctionCodeEditorOutputParams.language}
|
||||
options={{ readOnly: true, domReadOnly: true }}
|
||||
header={OutputHeader}
|
||||
/>
|
||||
<div>
|
||||
<CoreEditorHeader
|
||||
title={'Input'}
|
||||
rightNodes={[
|
||||
<Button
|
||||
title="Run Function"
|
||||
variant="primary"
|
||||
accent="blue"
|
||||
size="small"
|
||||
Icon={IconPlayerPlay}
|
||||
onClick={handleExecute}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
<CodeEditor
|
||||
files={[
|
||||
{
|
||||
content: settingsServerlessFunctionInput,
|
||||
language: 'json',
|
||||
path: 'input.json',
|
||||
},
|
||||
]}
|
||||
currentFilePath={'input.json'}
|
||||
height={200}
|
||||
onChange={setSettingsServerlessFunctionInput}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<CoreEditorHeader
|
||||
leftNodes={[<SettingsServerlessFunctionsOutputMetadataInfo />]}
|
||||
rightNodes={[<LightCopyIconButton copyText={result} />]}
|
||||
/>
|
||||
<CodeEditor
|
||||
files={[
|
||||
{
|
||||
content: result,
|
||||
language:
|
||||
settingsServerlessFunctionCodeEditorOutputParams.language,
|
||||
path: 'result.any',
|
||||
},
|
||||
]}
|
||||
currentFilePath={'result.any'}
|
||||
height={settingsServerlessFunctionCodeEditorOutputParams.height}
|
||||
options={{ readOnly: true, domReadOnly: true }}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputsContainer>
|
||||
</Section>
|
||||
);
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
export const SETTINGS_SERVERLESS_FUNCTION_TAB_LIST_COMPONENT_ID =
|
||||
'settings-serverless-function-editor-tab-list';
|
||||
@ -5,7 +5,6 @@ export const SERVERLESS_FUNCTION_FRAGMENT = gql`
|
||||
id
|
||||
name
|
||||
description
|
||||
sourceCodeHash
|
||||
runtime
|
||||
syncStatus
|
||||
latestVersion
|
||||
|
||||
@ -9,7 +9,7 @@ export type ServerlessFunctionNewFormValues = {
|
||||
};
|
||||
|
||||
export type ServerlessFunctionFormValues = ServerlessFunctionNewFormValues & {
|
||||
code: string;
|
||||
code: { [filePath: string]: string } | undefined;
|
||||
};
|
||||
|
||||
type SetServerlessFunctionFormValues = Dispatch<
|
||||
@ -26,7 +26,7 @@ export const useServerlessFunctionUpdateFormState = (
|
||||
const [formValues, setFormValues] = useState<ServerlessFunctionFormValues>({
|
||||
name: '',
|
||||
description: '',
|
||||
code: '',
|
||||
code: undefined,
|
||||
});
|
||||
|
||||
const { serverlessFunction } =
|
||||
@ -37,7 +37,7 @@ export const useServerlessFunctionUpdateFormState = (
|
||||
version: 'draft',
|
||||
onCompleted: (data: FindOneServerlessFunctionSourceCodeQuery) => {
|
||||
const newState = {
|
||||
code: data?.getServerlessFunctionSourceCode || '',
|
||||
code: data?.getServerlessFunctionSourceCode || undefined,
|
||||
name: serverlessFunction?.name || '',
|
||||
description: serverlessFunction?.description || '',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user