+1
-1
@@ -1,4 +1,4 @@
|
||||
import { useGetAvailablePackages } from '@/settings/logic-functions/hooks/useGetAvailablePackages';
|
||||
import { useGetAvailablePackages } from '@/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';
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type LogicFunctionNewFormValues } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { type LogicFunctionNewFormValues } from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
|
||||
import { TextArea } from '@/ui/input/components/TextArea';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
-12
@@ -21,13 +21,11 @@ export const SettingsLogicFunctionCodeEditorTab = ({
|
||||
handleExecute,
|
||||
onChange,
|
||||
isTesting = false,
|
||||
isManaged = false,
|
||||
}: {
|
||||
files: File[];
|
||||
handleExecute: () => void;
|
||||
onChange: (filePath: string, value: string) => void;
|
||||
isTesting?: boolean;
|
||||
isManaged?: boolean;
|
||||
}) => {
|
||||
const activeTabId = useRecoilComponentValue(
|
||||
activeTabIdComponentState,
|
||||
@@ -68,16 +66,6 @@ export const SettingsLogicFunctionCodeEditorTab = ({
|
||||
onChange={(newCodeValue: string) =>
|
||||
onChange(activeTabId, newCodeValue)
|
||||
}
|
||||
options={
|
||||
isManaged
|
||||
? {
|
||||
readOnly: true,
|
||||
readOnlyMessage: {
|
||||
value: t`Managed logic functions are not editable`,
|
||||
},
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Section>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
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';
|
||||
import { type LogicFunctionFormValues } from '@/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
|
||||
export const SettingsLogicFunctionSettingsTab = ({
|
||||
formValues,
|
||||
|
||||
+58
-49
@@ -5,21 +5,24 @@ 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 { H2Title, OverflowingTextWithTooltip } from 'twenty-ui/display';
|
||||
import { Section } from 'twenty-ui/layout';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||
import { Tag } from 'twenty-ui/components';
|
||||
import { type LogicFunction } from '~/generated-metadata/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 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)};
|
||||
@@ -36,22 +39,31 @@ const StyledEmptyState = styled.div`
|
||||
`;
|
||||
|
||||
export const SettingsLogicFunctionTriggersTab = ({
|
||||
logicFunction: _logicFunction,
|
||||
logicFunction,
|
||||
}: {
|
||||
logicFunction: LogicFunction;
|
||||
}) => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const cronTriggers: [] = [];
|
||||
const cronTrigger = logicFunction.cronTriggerSettings;
|
||||
|
||||
const routeTriggers: [] = [];
|
||||
const routeTrigger = logicFunction.httpRouteTriggerSettings;
|
||||
|
||||
const databaseEvents: [] = [];
|
||||
const databaseEventTriggerSettings =
|
||||
logicFunction.databaseEventTriggerSettings;
|
||||
|
||||
const hasNoTriggers =
|
||||
databaseEvents.length === 0 &&
|
||||
cronTriggers.length === 0 &&
|
||||
routeTriggers.length === 0;
|
||||
let databaseEventTrigger = undefined;
|
||||
|
||||
if (isDefined(databaseEventTriggerSettings)) {
|
||||
const [object, action]: [string, string] =
|
||||
databaseEventTriggerSettings.eventName.split('.');
|
||||
databaseEventTrigger = {
|
||||
object,
|
||||
action,
|
||||
updatedFields: databaseEventTriggerSettings.updatedFields,
|
||||
};
|
||||
}
|
||||
const hasNoTriggers = !cronTrigger && !routeTrigger && !databaseEventTrigger;
|
||||
|
||||
if (hasNoTriggers) {
|
||||
return (
|
||||
@@ -69,37 +81,37 @@ export const SettingsLogicFunctionTriggersTab = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{databaseEvents.length > 0 && (
|
||||
{isDefined(databaseEventTrigger) && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Database event`}
|
||||
description={t`Select the events that should trigger the function`}
|
||||
/>
|
||||
<SettingsDatabaseEventsForm events={databaseEvents} disabled />
|
||||
<SettingsDatabaseEventsForm
|
||||
events={[databaseEventTrigger]}
|
||||
disabled
|
||||
/>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{cronTriggers.length > 0 && (
|
||||
{isDefined(cronTrigger) && (
|
||||
<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}
|
||||
/>
|
||||
))}
|
||||
<FormTextFieldInput
|
||||
label={t`Expression`}
|
||||
placeholder="0 */1 * * *"
|
||||
hint={t`Format: [Minute] [Hour] [Day of Month] [Month] [Day of Week]`}
|
||||
onChange={() => {}}
|
||||
readonly
|
||||
defaultValue={cronTrigger.pattern}
|
||||
/>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{routeTriggers.length > 0 && (
|
||||
{isDefined(routeTrigger) && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title={t`Http`}
|
||||
@@ -111,24 +123,21 @@ export const SettingsLogicFunctionTriggersTab = ({
|
||||
<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>
|
||||
))}
|
||||
<StyledRouteTriggerTableRow>
|
||||
<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>
|
||||
)}
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const LOGIC_FUNCTION_FRAGMENT = gql`
|
||||
fragment LogicFunctionFields on LogicFunction {
|
||||
id
|
||||
name
|
||||
description
|
||||
runtime
|
||||
timeoutSeconds
|
||||
sourceHandlerPath
|
||||
builtHandlerPath
|
||||
handlerName
|
||||
toolInputSchema
|
||||
isTool
|
||||
applicationId
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
`;
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const CREATE_DEFAULT_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
mutation CreateDefaultLogicFunctionItem(
|
||||
$input: CreateDefaultLogicFunctionInput!
|
||||
) {
|
||||
createDefaultLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const DELETE_ONE_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
mutation DeleteOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
deleteOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const FIND_MANY_AVAILABLE_PACKAGES = gql`
|
||||
query FindManyAvailablePackages($input: LogicFunctionIdInput!) {
|
||||
getAvailablePackages(input: $input)
|
||||
}
|
||||
`;
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const FIND_MANY_LOGIC_FUNCTIONS = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
query GetManyLogicFunctions {
|
||||
findManyLogicFunctions {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment';
|
||||
|
||||
export const FIND_ONE_LOGIC_FUNCTION = gql`
|
||||
${LOGIC_FUNCTION_FRAGMENT}
|
||||
query GetOneLogicFunction($input: LogicFunctionIdInput!) {
|
||||
findOneLogicFunction(input: $input) {
|
||||
...LogicFunctionFields
|
||||
}
|
||||
}
|
||||
`;
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
import { useLogicFunctionUpdateFormState } from '@/settings/logic-functions/hooks/useLogicFunctionUpdateFormState';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
jest.mock('@/settings/logic-functions/hooks/useGetOneLogicFunction', () => ({
|
||||
useGetOneLogicFunction: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('useLogicFunctionUpdateFormState', () => {
|
||||
test('should return a form', () => {
|
||||
const logicFunctionId = 'logicFunctionId';
|
||||
const useGetOneLogicFunctionMock = jest.requireMock(
|
||||
'@/settings/logic-functions/hooks/useGetOneLogicFunction',
|
||||
);
|
||||
useGetOneLogicFunctionMock.useGetOneLogicFunction.mockReturnValue({
|
||||
logicFunction: { name: 'name' },
|
||||
loading: false,
|
||||
});
|
||||
const { result } = renderHook(
|
||||
() => useLogicFunctionUpdateFormState({ logicFunctionId }),
|
||||
{
|
||||
wrapper: RecoilRoot,
|
||||
},
|
||||
);
|
||||
|
||||
const { formValues } = result.current;
|
||||
|
||||
expect(formValues).toEqual({
|
||||
name: '',
|
||||
description: '',
|
||||
code: { src: { 'index.ts': '' } },
|
||||
});
|
||||
});
|
||||
});
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { FIND_MANY_AVAILABLE_PACKAGES } from '@/settings/logic-functions/graphql/queries/findManyAvailablePackages';
|
||||
import {
|
||||
type FindManyAvailablePackagesQuery,
|
||||
type FindManyAvailablePackagesQueryVariables,
|
||||
type LogicFunctionIdInput,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useGetAvailablePackages = (input: LogicFunctionIdInput) => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const { data } = useQuery<
|
||||
FindManyAvailablePackagesQuery,
|
||||
FindManyAvailablePackagesQueryVariables
|
||||
>(FIND_MANY_AVAILABLE_PACKAGES, {
|
||||
client: apolloMetadataClient ?? undefined,
|
||||
variables: {
|
||||
input,
|
||||
},
|
||||
});
|
||||
return {
|
||||
availablePackages: data?.getAvailablePackages || null,
|
||||
};
|
||||
};
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { FIND_ONE_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/queries/findOneLogicFunction';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import {
|
||||
type GetOneLogicFunctionQuery,
|
||||
type GetOneLogicFunctionQueryVariables,
|
||||
type LogicFunctionIdInput,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const useGetOneLogicFunction = ({
|
||||
id,
|
||||
onCompleted,
|
||||
}: LogicFunctionIdInput & {
|
||||
onCompleted?: (data: GetOneLogicFunctionQuery) => void;
|
||||
}) => {
|
||||
const apolloMetadataClient = useApolloCoreClient();
|
||||
const { data, loading } = useQuery<
|
||||
GetOneLogicFunctionQuery,
|
||||
GetOneLogicFunctionQueryVariables
|
||||
>(FIND_ONE_LOGIC_FUNCTION, {
|
||||
client: apolloMetadataClient ?? undefined,
|
||||
variables: {
|
||||
input: { id },
|
||||
},
|
||||
onCompleted,
|
||||
});
|
||||
return {
|
||||
logicFunction: data?.findOneLogicFunction || null,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
import { useGetOneLogicFunction } from '@/settings/logic-functions/hooks/useGetOneLogicFunction';
|
||||
import { type Dispatch, type SetStateAction, useState } from 'react';
|
||||
import { type Sources } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
type GetOneLogicFunctionQuery,
|
||||
type LogicFunction,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export type LogicFunctionNewFormValues = {
|
||||
name: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type LogicFunctionFormValues = LogicFunctionNewFormValues & {
|
||||
code: Sources;
|
||||
};
|
||||
|
||||
type SetLogicFunctionFormValues = Dispatch<
|
||||
SetStateAction<LogicFunctionFormValues>
|
||||
>;
|
||||
|
||||
export const useLogicFunctionUpdateFormState = ({
|
||||
logicFunctionId,
|
||||
}: {
|
||||
logicFunctionId: string;
|
||||
}): {
|
||||
formValues: LogicFunctionFormValues;
|
||||
logicFunction: LogicFunction | null;
|
||||
setFormValues: SetLogicFunctionFormValues;
|
||||
loading: boolean;
|
||||
} => {
|
||||
const [formValues, setFormValues] = useState<LogicFunctionFormValues>({
|
||||
name: '',
|
||||
description: '',
|
||||
code: { src: { 'index.ts': '' } },
|
||||
});
|
||||
|
||||
const { logicFunction, loading: logicFunctionLoading } =
|
||||
useGetOneLogicFunction({
|
||||
id: logicFunctionId,
|
||||
onCompleted: (data: GetOneLogicFunctionQuery) => {
|
||||
const fn = data?.findOneLogicFunction;
|
||||
|
||||
if (isDefined(fn)) {
|
||||
setFormValues((prevState) => ({
|
||||
...prevState,
|
||||
name: fn.name || '',
|
||||
description: fn.description || '',
|
||||
}));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
formValues,
|
||||
setFormValues,
|
||||
logicFunction,
|
||||
loading: logicFunctionLoading,
|
||||
};
|
||||
};
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { createState } from 'twenty-ui/utilities';
|
||||
import { type GetManyLogicFunctionsQuery } from '~/generated-metadata/graphql';
|
||||
import { type FindManyLogicFunctionsQuery } from '~/generated-metadata/graphql';
|
||||
|
||||
export type LogicFunction =
|
||||
GetManyLogicFunctionsQuery['findManyLogicFunctions'][number];
|
||||
FindManyLogicFunctionsQuery['findManyLogicFunctions'][number];
|
||||
|
||||
export const logicFunctionsState = createState<LogicFunction[]>({
|
||||
key: 'logicFunctionsState',
|
||||
|
||||
Reference in New Issue
Block a user