Rename serverlessFunction to logicFunction (#17494)

## Summary

Rename "Serverless Function" to "Logic Function" across the codebase for
clearer naming.

### Environment Variable Changes

| Old | New |
|-----|-----|
| `SERVERLESS_TYPE` | `LOGIC_FUNCTION_TYPE` |
| `SERVERLESS_LAMBDA_REGION` | `LOGIC_FUNCTION_LAMBDA_REGION` |
| `SERVERLESS_LAMBDA_ROLE` | `LOGIC_FUNCTION_LAMBDA_ROLE` |
| `SERVERLESS_LAMBDA_SUBHOSTING_URL` |
`LOGIC_FUNCTION_LAMBDA_SUBHOSTING_URL` |
| `SERVERLESS_LAMBDA_ACCESS_KEY_ID` |
`LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID` |
| `SERVERLESS_LAMBDA_SECRET_ACCESS_KEY` |
`LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY` |

### Breaking Changes

- Environment variables must be updated in production deployments
- Database migration renames `serverlessFunction` → `logicFunction`
tables
This commit is contained in:
Charles Bochet
2026-01-28 01:42:19 +01:00
committed by GitHub
parent 59d123d2b1
commit da6f1bbef3
351 changed files with 5054 additions and 5139 deletions
@@ -0,0 +1,117 @@
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
import { type EditorProps, type Monaco } from '@monaco-editor/react';
import { type editor } from 'monaco-editor';
import { AutoTypings } from 'monaco-editor-auto-typings';
import { useParams } from 'react-router-dom';
import { isDefined } from 'twenty-shared/utils';
import { CodeEditor } from 'twenty-ui/input';
export type File = {
language: string;
content: string;
path: string;
};
type SettingsLogicFunctionCodeEditorProps = Omit<EditorProps, 'onChange'> & {
currentFilePath: string;
files: File[];
onChange: (value: string) => void;
};
export const SettingsLogicFunctionCodeEditor = ({
currentFilePath,
files,
onChange,
height = 450,
options = undefined,
}: SettingsLogicFunctionCodeEditorProps) => {
const { logicFunctionId = '' } = useParams();
const { availablePackages } = useGetAvailablePackages({
id: logicFunctionId,
});
const currentFile = files.find((file) => file.path === currentFilePath);
const handleEditorDidMount = async (
editor: editor.IStandaloneCodeEditor,
monaco: Monaco,
) => {
if (files.length > 1) {
files.forEach((file) => {
const model = monaco.editor.getModel(monaco.Uri.file(file.path));
if (!isDefined(model)) {
monaco.editor.createModel(
file.content,
file.language,
monaco.Uri.file(file.path),
);
}
});
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
...monaco.languages.typescript.typescriptDefaults.getCompilerOptions(),
moduleResolution:
monaco.languages.typescript.ModuleResolutionKind.NodeJs,
baseUrl: 'file:///src',
paths: {
'src/*': ['file:///src/*'],
},
allowSyntheticDefaultImports: true,
esModuleInterop: true,
noEmit: true,
target: monaco.languages.typescript.ScriptTarget.ESNext,
});
// TODO load that with proper env variables
const environmentVariables = {};
if (isDefined(environmentVariables)) {
const envTypeDefinitions = Object.keys(environmentVariables)
// eslint-disable-next-line lingui/no-unlocalized-strings
.map((key) => `${key}: string;`)
.join('\n');
const environmentDefinition = `
declare namespace NodeJS {
interface ProcessEnv {
${envTypeDefinitions}
}
}
declare const process: {
env: NodeJS.ProcessEnv;
};
`;
monaco.languages.typescript.typescriptDefaults.setExtraLibs([
{
content: environmentDefinition,
filePath: 'ts:process-env.d.ts',
},
]);
}
await AutoTypings.create(editor, {
monaco,
preloadPackages: true,
onlySpecifiedPackages: true,
versions: availablePackages,
debounceDuration: 0,
});
}
};
return (
isDefined(currentFile) &&
isDefined(availablePackages) && (
<CodeEditor
height={height}
value={currentFile.content}
language={currentFile.language}
onMount={handleEditorDidMount}
onChange={onChange}
options={options}
variant="with-header"
/>
)
);
};
@@ -0,0 +1,36 @@
import { TitleInput } from '@/ui/input/components/TitleInput';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
const StyledHeaderTitle = styled.div`
color: ${({ theme }) => theme.font.color.primary};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
font-size: ${({ theme }) => theme.font.size.lg};
width: fit-content;
max-width: 420px;
& > input:disabled {
color: ${({ theme }) => theme.font.color.primary};
}
`;
type SettingsLogicFunctionLabelContainerProps = {
value: string;
onChange: (value: string) => void;
};
export const SettingsLogicFunctionLabelContainer = ({
value,
onChange,
}: SettingsLogicFunctionLabelContainerProps) => {
return (
<StyledHeaderTitle>
<TitleInput
instanceId="logic-function-name-input"
sizeVariant="md"
value={value}
onChange={onChange}
placeholder={t`Function name`}
/>
</StyledHeaderTitle>
);
};
@@ -0,0 +1,54 @@
import { type LogicFunctionNewFormValues } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { TextArea } from '@/ui/input/components/TextArea';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
const StyledInputsContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(4)};
`;
export const SettingsLogicFunctionNewForm = ({
formValues,
onChange,
readonly = false,
}: {
formValues: LogicFunctionNewFormValues;
onChange: (key: string) => (value: string) => void;
readonly?: boolean;
}) => {
const descriptionTextAreaId = `${formValues.name}-description`;
const nameTextInputId = `${formValues.name}-name`;
return (
<Section>
<H2Title
title={t`About`}
description={t`Name and describe your function`}
/>
<StyledInputsContainer>
<SettingsTextInput
instanceId={nameTextInputId}
placeholder={t`Name`}
fullWidth
autoFocusOnMount
value={formValues.name}
onChange={onChange('name')}
readOnly={readonly}
/>
<TextArea
textAreaId={descriptionTextAreaId}
placeholder={t`Description`}
minRows={4}
value={formValues.description}
onChange={onChange('description')}
readOnly={readonly}
/>
</StyledInputsContainer>
</Section>
);
};
@@ -0,0 +1,36 @@
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
import { SettingsPath } from 'twenty-shared/types';
import { LinkChip } from 'twenty-ui/components';
import { getSettingsPath } from 'twenty-shared/utils';
import { useParams } from 'react-router-dom';
import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
export const SettingsLogicFunctionTabEnvironmentVariablesSection = () => {
const { applicationId = '' } = useParams<{ applicationId: string }>();
return (
<Section>
<H2Title
title={t`Environment Variables`}
description={t`Accessible in your function via process.env.KEY`}
/>
<Trans>
Environment variables are defined at application level for all
functions. Please check{' '}
<LinkChip
label={t`application detail page`}
to={getSettingsPath(
SettingsPath.ApplicationDetail,
{
applicationId,
},
undefined,
'settings',
)}
/>
.
</Trans>
</Section>
);
};
@@ -0,0 +1,48 @@
import styled from '@emotion/styled';
import { type LogicFunction } from '~/generated-metadata/graphql';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { useTheme } from '@emotion/react';
import { IconChevronRight } from 'twenty-ui/display';
import { StyledTableRow } from '@/settings/logic-functions/components/SettingsLogicFunctionsTable';
const StyledNameTableCell = styled(TableCell)`
color: ${({ theme }) => theme.font.color.primary};
gap: ${({ theme }) => theme.spacing(2)};
`;
const StyledRuntimeTableCell = styled(TableCell)`
color: ${({ theme }) => theme.font.color.secondary};
gap: ${({ theme }) => theme.spacing(2)};
`;
const StyledIconTableCell = styled(TableCell)`
justify-content: center;
padding-right: ${({ theme }) => theme.spacing(1)};
`;
const StyledIconChevronRight = styled(IconChevronRight)`
color: ${({ theme }) => theme.font.color.tertiary};
`;
export const SettingsLogicFunctionsFieldItemTableRow = ({
logicFunction,
to,
}: {
logicFunction: LogicFunction;
to: string;
}) => {
const theme = useTheme();
return (
<StyledTableRow to={to}>
<StyledNameTableCell>{logicFunction.name}</StyledNameTableCell>
<StyledNameTableCell></StyledNameTableCell>
<StyledRuntimeTableCell>{logicFunction.runtime}</StyledRuntimeTableCell>
<StyledIconTableCell>
<StyledIconChevronRight
size={theme.icon.size.md}
stroke={theme.icon.stroke.sm}
/>
</StyledIconTableCell>
</StyledTableRow>
);
};
@@ -0,0 +1,56 @@
import { SettingsLogicFunctionsFieldItemTableRow } from '@/settings/logic-functions/components/SettingsLogicFunctionsFieldItemTableRow';
import { Table } from '@/ui/layout/table/components/Table';
import { TableBody } from '@/ui/layout/table/components/TableBody';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import { type LogicFunction } from '~/generated-metadata/graphql';
import { useLingui } from '@lingui/react/macro';
import { useParams } from 'react-router-dom';
export const StyledTableRow = styled(TableRow)`
grid-template-columns: 164px 1fr 96px 32px;
`;
const StyledTableBody = styled(TableBody)`
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
`;
export const SettingsLogicFunctionsTable = ({
logicFunctions,
}: {
logicFunctions: LogicFunction[];
}) => {
const { applicationId = '' } = useParams();
const { t } = useLingui();
if (logicFunctions.length === 0) {
return null;
}
return (
<Table>
<StyledTableRow>
<TableHeader>{t`Name`}</TableHeader>
<TableHeader></TableHeader>
<TableHeader>{t`Runtime`}</TableHeader>
<TableHeader></TableHeader>
</StyledTableRow>
<StyledTableBody>
{logicFunctions.map((logicFunction: LogicFunction) => (
<SettingsLogicFunctionsFieldItemTableRow
key={logicFunction.id}
logicFunction={logicFunction}
to={getSettingsPath(SettingsPath.ApplicationLogicFunctionDetail, {
applicationId,
logicFunctionId: logicFunction.id,
})}
/>
))}
</StyledTableBody>
</Table>
);
};
@@ -0,0 +1,85 @@
import {
type File,
SettingsLogicFunctionCodeEditor,
} from '@/settings/logic-functions/components/SettingsLogicFunctionCodeEditor';
import { SETTINGS_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/settings/logic-functions/constants/SettingsLogicFunctionTabListComponentId';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { H2Title, IconPlayerPlay } from 'twenty-ui/display';
import { Button, CoreEditorHeader } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout';
const StyledTabList = styled(TabList)`
border-bottom: none;
`;
export const SettingsLogicFunctionCodeEditorTab = ({
files,
handleExecute,
onChange,
isTesting = false,
isManaged = false,
}: {
files: File[];
handleExecute: () => void;
onChange: (filePath: string, value: string) => void;
isTesting?: boolean;
isManaged?: boolean;
}) => {
const activeTabId = useRecoilComponentValue(
activeTabIdComponentState,
SETTINGS_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID,
);
const TestButton = (
<Button
title={t`Test`}
variant="primary"
accent="blue"
size="small"
Icon={IconPlayerPlay}
disabled={isTesting}
onClick={handleExecute}
/>
);
const HeaderTabList = (
<StyledTabList
tabs={files.map((file) => {
return { id: file.path, title: file.path.split('/').at(-1) || '' };
})}
componentInstanceId={SETTINGS_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID}
/>
);
return (
<Section>
<H2Title
title={t`Code your function`}
description={t`Write your function (in typescript) below`}
/>
<CoreEditorHeader leftNodes={[HeaderTabList]} rightNodes={[TestButton]} />
{activeTabId && (
<SettingsLogicFunctionCodeEditor
files={files}
currentFilePath={activeTabId}
onChange={(newCodeValue: string) =>
onChange(activeTabId, newCodeValue)
}
options={
isManaged
? {
readOnly: true,
readOnlyMessage: {
value: t`Managed logic functions are not editable`,
},
}
: undefined
}
/>
)}
</Section>
);
};
@@ -0,0 +1,21 @@
import { SettingsLogicFunctionNewForm } from '@/settings/logic-functions/components/SettingsLogicFunctionNewForm';
import { SettingsLogicFunctionTabEnvironmentVariablesSection } from '@/settings/logic-functions/components/SettingsLogicFunctionTabEnvironmentVariablesSection';
import { type LogicFunctionFormValues } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
export const SettingsLogicFunctionSettingsTab = ({
formValues,
onChange,
}: {
formValues: LogicFunctionFormValues;
onChange: (key: string) => (value: string) => void;
}) => {
return (
<>
<SettingsLogicFunctionNewForm
formValues={formValues}
onChange={onChange}
/>
<SettingsLogicFunctionTabEnvironmentVariablesSection />
</>
);
};
@@ -0,0 +1,139 @@
import { TextInput } from '@/ui/input/components/TextInput';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useState } from 'react';
import {
IconCheck,
IconDotsVertical,
IconPencil,
IconTrash,
IconX,
OverflowingTextWithTooltip,
} from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
import { MenuItem } from 'twenty-ui/navigation';
import type { ApplicationVariable } from '~/generated/graphql';
const StyledEditModeTableRow = styled(TableRow)`
grid-template-columns: 180px auto 56px;
`;
const StyledTableRow = styled(TableRow)`
grid-template-columns: 180px 300px 32px;
`;
export const SettingsLogicFunctionTabEnvironmentVariableTableRow = ({
envVariable,
onChange,
onDelete,
initialEditMode = false,
}: {
envVariable: ApplicationVariable;
onChange: (newEnvVariable: ApplicationVariable) => void;
onDelete: () => void;
initialEditMode?: boolean;
}) => {
const [editedEnvVariable, setEditedEnvVariable] = useState(envVariable);
const [editMode, setEditMode] = useState(initialEditMode);
const dropDownId = `settings-environment-variable-dropdown-${envVariable.id}`;
const { closeDropdown } = useCloseDropdown();
return editMode ? (
<StyledEditModeTableRow>
<TableCell>
<TextInput
autoFocus
value={editedEnvVariable.key}
onChange={(newKey) =>
setEditedEnvVariable({ ...editedEnvVariable, key: newKey })
}
placeholder={t`Name`}
fullWidth
/>
</TableCell>
<TableCell>
<TextInput
value={editedEnvVariable.value}
onChange={(newValue) =>
setEditedEnvVariable({ ...editedEnvVariable, value: newValue })
}
placeholder={t`Value`}
fullWidth
/>
</TableCell>
<TableCell>
<LightIconButton
accent="tertiary"
Icon={IconX}
onClick={() => {
if (envVariable.key === '' && envVariable.value === '') {
onDelete();
}
setEditedEnvVariable(envVariable);
setEditMode(false);
}}
/>
<LightIconButton
accent="tertiary"
Icon={IconCheck}
disabled={
editedEnvVariable.key === '' || editedEnvVariable.value === ''
}
onClick={() => {
onChange(editedEnvVariable);
setEditMode(false);
}}
/>
</TableCell>
</StyledEditModeTableRow>
) : (
<StyledTableRow onClick={() => setEditMode(true)}>
<TableCell>
<OverflowingTextWithTooltip text={envVariable.key} />
</TableCell>
<TableCell>
<OverflowingTextWithTooltip text={envVariable.value} />
</TableCell>
<TableCell>
<Dropdown
dropdownId={dropDownId}
clickableComponent={
<LightIconButton
aria-label={t`Env Variable Options`}
Icon={IconDotsVertical}
accent="tertiary"
/>
}
dropdownComponents={
<DropdownContent>
<DropdownMenuItemsContainer>
<MenuItem
text={t`Edit`}
LeftIcon={IconPencil}
onClick={() => {
setEditMode(true);
closeDropdown(dropDownId);
}}
/>
<MenuItem
text={t`Delete`}
LeftIcon={IconTrash}
onClick={() => {
onDelete();
closeDropdown(dropDownId);
}}
/>
</DropdownMenuItemsContainer>
</DropdownContent>
}
/>
</TableCell>
</StyledTableRow>
);
};
@@ -0,0 +1,101 @@
import { LogicFunctionExecutionResult } from '@/logic-functions/components/LogicFunctionExecutionResult';
import {
type LogicFunctionTestData,
logicFunctionTestDataFamilyState,
} from '@/workflow/workflow-steps/workflow-actions/code-action/states/logicFunctionTestDataFamilyState';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useRecoilState } from 'recoil';
import { H2Title, IconPlayerPlay } from 'twenty-ui/display';
import { Button, CodeEditor, CoreEditorHeader } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout';
import { InputLabel } from '@/ui/input/components/InputLabel';
import { TextArea } from '@/ui/input/components/TextArea';
const StyledInputsContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(4)};
`;
const StyledCodeEditorContainer = styled.div`
display: flex;
flex-direction: column;
`;
export const SettingsLogicFunctionTestTab = ({
handleExecute,
logicFunctionId,
isTesting = false,
}: {
handleExecute: () => void;
logicFunctionId: string;
isTesting?: boolean;
}) => {
const { t } = useLingui();
const [logicFunctionTestData, setLogicFunctionTestData] =
useRecoilState<LogicFunctionTestData>(
logicFunctionTestDataFamilyState(logicFunctionId),
);
const onChange = (newInput: string) => {
setLogicFunctionTestData((prev) => ({
...prev,
input: JSON.parse(newInput),
}));
};
const testLogsTextAreaId = `${logicFunctionId}-test-logs`;
return (
<Section>
<H2Title
title={t`Test your function`}
description={t`Insert a JSON input, then press "Run" to test your function.`}
/>
<StyledInputsContainer>
<StyledCodeEditorContainer>
<CoreEditorHeader
title={t`Input`}
rightNodes={[
<Button
title={t`Run Function`}
variant="primary"
accent="blue"
size="small"
Icon={IconPlayerPlay}
onClick={handleExecute}
disabled={isTesting}
/>,
]}
/>
<CodeEditor
value={JSON.stringify(logicFunctionTestData.input, null, 4)}
language="json"
height={100}
onChange={onChange}
variant="with-header"
/>
</StyledCodeEditorContainer>
<LogicFunctionExecutionResult
logicFunctionTestData={logicFunctionTestData}
maxHeight={
logicFunctionTestData.output.logs.length > 0 ? 200 : undefined
}
isTesting={isTesting}
/>
{logicFunctionTestData.output.logs.length > 0 && (
<StyledCodeEditorContainer>
<InputLabel>{t`Logs`}</InputLabel>
<TextArea
textAreaId={testLogsTextAreaId}
value={isTesting ? '' : logicFunctionTestData.output.logs}
maxRows={20}
disabled
/>
</StyledCodeEditorContainer>
)}
</StyledInputsContainer>
</Section>
);
};
@@ -0,0 +1,137 @@
import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormTextFieldInput';
import { SettingsDatabaseEventsForm } from '@/settings/components/SettingsDatabaseEventsForm';
import { Table } from '@/ui/layout/table/components/Table';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
import { type LogicFunction } from '~/generated/graphql';
export const StyledRouteTriggerTableRow = styled(TableRow)`
grid-template-columns: 1fr 120px 120px;
`;
// TODO: @Charles put back with new sources
// const StyledTableCell = styled(TableCell)`
// color: ${({ theme }) => theme.font.color.tertiary};
// gap: ${({ theme }) => theme.spacing(2)};
// min-width: 0;
// overflow: hidden;
// `;
const StyledRouteTriggerTableHeaderRow = styled(StyledRouteTriggerTableRow)`
margin-bottom: ${({ theme }) => theme.spacing(2)};
`;
const StyledEmptyState = styled.div`
align-items: center;
color: ${({ theme }) => theme.font.color.tertiary};
display: flex;
font-size: ${({ theme }) => theme.font.size.md};
height: 160px;
justify-content: center;
text-align: center;
`;
export const SettingsLogicFunctionTriggersTab = ({
logicFunction: _logicFunction,
}: {
logicFunction: LogicFunction;
}) => {
const { t } = useLingui();
const cronTriggers: [] = [];
const routeTriggers: [] = [];
const databaseEvents: [] = [];
const hasNoTriggers =
databaseEvents.length === 0 &&
cronTriggers.length === 0 &&
routeTriggers.length === 0;
if (hasNoTriggers) {
return (
<Section>
<H2Title
title={t`Triggers`}
description={t`Configure when this function should be executed`}
/>
<StyledEmptyState>
{t`No triggers configured for this function.`}
</StyledEmptyState>
</Section>
);
}
return (
<>
{databaseEvents.length > 0 && (
<Section>
<H2Title
title={t`Database event`}
description={t`Select the events that should trigger the function`}
/>
<SettingsDatabaseEventsForm events={databaseEvents} disabled />
</Section>
)}
{cronTriggers.length > 0 && (
<Section>
<H2Title
title={t`Cron`}
description={t`Triggers the function at regular intervals`}
/>
{cronTriggers.map((cronTrigger, index) => (
<FormTextFieldInput
key={index}
label={t`Expression`}
placeholder="0 */1 * * *"
hint={t`Format: [Minute] [Hour] [Day of Month] [Month] [Day of Week]`}
onChange={() => {}}
readonly
defaultValue={cronTrigger}
/>
))}
</Section>
)}
{routeTriggers.length > 0 && (
<Section>
<H2Title
title={t`Http`}
description={t`Triggers the function with Http request`}
/>
<Table>
<StyledRouteTriggerTableHeaderRow>
<TableHeader>{t`Path`}</TableHeader>
<TableHeader>{t`Method`}</TableHeader>
<TableHeader>{t`Auth Required`}</TableHeader>
</StyledRouteTriggerTableHeaderRow>
{routeTriggers.map((_, _index) => (
<></>
// <StyledRouteTriggerTableRow key={index}>
// <StyledTableCell>
// <OverflowingTextWithTooltip
// text={`${REACT_APP_SERVER_BASE_URL}/s${routeTrigger.path}`}
// />
// </StyledTableCell>
// <StyledTableCell>{routeTrigger.httpMethod}</StyledTableCell>
// <StyledTableCell>
// <Tag
// text={routeTrigger.isAuthRequired ? t`True` : t`False`}
// color={routeTrigger.isAuthRequired ? 'green' : 'orange'}
// weight="medium"
// />
// </StyledTableCell>
// </StyledRouteTriggerTableRow>
))}
</Table>
</Section>
)}
</>
);
};