Serverless function UI (#6388)

https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=36235-120877

Did not do the file manager part. A Function is defined using one unique
file at the moment

Feature protected by featureFlag `IS_FUNCTION_SETTINGS_ENABLED`

## Demo


https://github.com/user-attachments/assets/0acb8291-47b4-4521-a6fa-a88b9198609b
This commit is contained in:
martmull
2024-07-29 13:03:09 +02:00
committed by GitHub
parent 936279f895
commit 00fea17920
100 changed files with 2283 additions and 121 deletions

View File

@ -0,0 +1,80 @@
import Editor, { Monaco, EditorProps } from '@monaco-editor/react';
import { editor } from 'monaco-editor';
import { codeEditorTheme } from '@/ui/input/code-editor/theme/CodeEditorTheme';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useEffect } from 'react';
export const DEFAULT_CODE = `export const handler = async (
event: object,
context: object
): Promise<object> => {
// Your code here
return {};
}
`;
const StyledEditor = styled(Editor)`
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-top: none;
border-radius: 0 0 ${({ theme }) => theme.border.radius.sm}
${({ theme }) => theme.border.radius.sm};
`;
type CodeEditorProps = Omit<EditorProps, 'onChange'> & {
header: React.ReactNode;
onChange?: (value: string) => void;
};
export const CodeEditor = ({
value = DEFAULT_CODE,
onChange,
language = 'typescript',
height = 500,
options = undefined,
header,
}: CodeEditorProps) => {
const theme = useTheme();
const handleEditorDidMount = (
editor: editor.IStandaloneCodeEditor,
monaco: Monaco,
) => {
monaco.editor.defineTheme('codeEditorTheme', codeEditorTheme(theme));
monaco.editor.setTheme('codeEditorTheme');
};
useEffect(() => {
const style = document.createElement('style');
style.innerHTML = `
.monaco-editor .margin .line-numbers {
font-weight: bold;
}
`;
document.head.appendChild(style);
return () => {
document.head.removeChild(style);
};
}, []);
return (
<div>
{header}
<StyledEditor
height={height}
language={language}
value={value}
onMount={handleEditorDidMount}
onChange={(value?: string) => value && onChange?.(value)}
options={{
...options,
overviewRulerLanes: 0,
scrollbar: {
vertical: 'hidden',
horizontal: 'hidden',
},
minimap: {
enabled: false,
},
}}
/>
</div>
);
};

View File

@ -0,0 +1,51 @@
import styled from '@emotion/styled';
const StyledEditorHeader = styled.div`
align-items: center;
background-color: ${({ theme }) => theme.background.transparent.lighter};
color: ${({ theme }) => theme.font.color.tertiary};
font-weight: ${({ theme }) => theme.font.weight.medium};
display: flex;
height: ${({ theme }) => theme.spacing(10)};
padding: ${({ theme }) => `0 ${theme.spacing(2)}`};
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-top-left-radius: ${({ theme }) => theme.border.radius.sm};
border-top-right-radius: ${({ theme }) => theme.border.radius.sm};
justify-content: space-between;
`;
const StyledElementContainer = styled.div`
align-content: flex-end;
display: flex;
gap: ${({ theme }) => theme.spacing(2)};
`;
export type CoreEditorHeaderProps = {
title?: string;
leftNodes?: React.ReactNode[];
rightNodes?: React.ReactNode[];
};
export const CoreEditorHeader = ({
title,
leftNodes,
rightNodes,
}: CoreEditorHeaderProps) => {
return (
<StyledEditorHeader>
<StyledElementContainer>
{leftNodes &&
leftNodes.map((leftButton, index) => {
return <div key={`left-${index}`}>{leftButton}</div>;
})}
{title}
</StyledElementContainer>
<StyledElementContainer>
{rightNodes &&
rightNodes.map((rightButton, index) => {
return <div key={`right-${index}`}>{rightButton}</div>;
})}
</StyledElementContainer>
</StyledEditorHeader>
);
};

View File

@ -0,0 +1,33 @@
import { editor } from 'monaco-editor';
import { ThemeType } from 'twenty-ui';
export const codeEditorTheme = (theme: ThemeType) => {
return {
base: 'vs' as editor.BuiltinTheme,
inherit: true,
rules: [
{
token: '',
foreground: theme.code.text.gray,
fontStyle: 'bold',
},
{ token: 'keyword', foreground: theme.code.text.sky },
{
token: 'delimiter',
foreground: theme.code.text.gray,
},
{ token: 'string', foreground: theme.code.text.pink },
{
token: 'comment',
foreground: theme.code.text.orange,
},
],
colors: {
'editor.background': theme.background.secondary,
'editorCursor.foreground': theme.font.color.primary,
'editorLineNumber.foreground': theme.font.color.extraLight,
'editorLineNumber.activeForeground': theme.font.color.light,
'editor.lineHighlightBackground': theme.background.tertiary,
},
};
};

View File

@ -29,7 +29,6 @@ const StyledTextArea = styled(TextareaAutosize)`
line-height: 16px;
overflow: auto;
padding: ${({ theme }) => theme.spacing(2)};
padding-top: ${({ theme }) => theme.spacing(3)};
resize: none;
width: 100%;