feat(ai): add mcp integration (#13004)
This commit is contained in:
@ -8,10 +8,12 @@ import { Button } from 'twenty-ui/input';
|
||||
import {
|
||||
IconArrowUpRight,
|
||||
IconBolt,
|
||||
IconCopy,
|
||||
IconPlus,
|
||||
Status,
|
||||
} from 'twenty-ui/display';
|
||||
import { Pill } from 'twenty-ui/components';
|
||||
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
|
||||
|
||||
interface SettingsIntegrationComponentProps {
|
||||
integration: SettingsIntegration;
|
||||
@ -64,6 +66,7 @@ const StyledLogo = styled.img`
|
||||
export const SettingsIntegrationComponent = ({
|
||||
integration,
|
||||
}: SettingsIntegrationComponentProps) => {
|
||||
const { copyToClipboard } = useCopyToClipboard();
|
||||
return (
|
||||
<StyledContainer
|
||||
to={integration.type === 'Active' ? integration.link : undefined}
|
||||
@ -100,6 +103,17 @@ export const SettingsIntegrationComponent = ({
|
||||
title="Use"
|
||||
size="small"
|
||||
/>
|
||||
) : integration.type === 'Copy' ? (
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (isDefined(integration.content)) {
|
||||
copyToClipboard(integration.content);
|
||||
}
|
||||
}}
|
||||
Icon={IconCopy}
|
||||
title={integration.linkText}
|
||||
size="small"
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
to={integration.link}
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
import { SettingsIntegrationCategory } from '@/settings/integrations/types/SettingsIntegrationCategory';
|
||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||
|
||||
export const SETTINGS_INTEGRATION_AI_CATEGORY: SettingsIntegrationCategory = {
|
||||
key: 'ai',
|
||||
title: 'With AI',
|
||||
hyperlink: null,
|
||||
integrations: [
|
||||
{
|
||||
from: {
|
||||
key: 'mcp',
|
||||
image: '/images/integrations/mcp.svg',
|
||||
},
|
||||
to: null,
|
||||
type: 'Copy',
|
||||
content: JSON.stringify(
|
||||
{
|
||||
mcpServers: {
|
||||
twenty: {
|
||||
type: 'remote',
|
||||
url: `${REACT_APP_SERVER_BASE_URL}/mcp`,
|
||||
headers: {
|
||||
Authorization: 'Bearer [API_KEY]',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
text: 'Connect MCP Client',
|
||||
link: '#',
|
||||
linkText: 'Copy',
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -1,21 +0,0 @@
|
||||
import { SettingsIntegrationCategory } from '@/settings/integrations/types/SettingsIntegrationCategory';
|
||||
|
||||
export const SETTINGS_INTEGRATION_WINDMILL_CATEGORY: SettingsIntegrationCategory =
|
||||
{
|
||||
key: 'windmill',
|
||||
title: 'With Windmill',
|
||||
hyperlink: null,
|
||||
integrations: [
|
||||
{
|
||||
from: {
|
||||
key: 'windmill',
|
||||
image: '/images/integrations/windmill-logo.png',
|
||||
},
|
||||
to: null,
|
||||
type: 'Goto',
|
||||
text: 'Create a workflow with Windmill',
|
||||
link: 'https://www.windmill.dev',
|
||||
linkText: 'Go to Windmill',
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
import { MOCK_REMOTE_DATABASES } from '@/settings/integrations/constants/MockRemoteDatabases';
|
||||
import { SETTINGS_INTEGRATION_AI_CATEGORY } from '@/settings/integrations/constants/SettingsIntegrationMcp';
|
||||
import { SETTINGS_INTEGRATION_REQUEST_CATEGORY } from '@/settings/integrations/constants/SettingsIntegrationRequest';
|
||||
import { SETTINGS_INTEGRATION_WINDMILL_CATEGORY } from '@/settings/integrations/constants/SettingsIntegrationWindmill';
|
||||
import { SETTINGS_INTEGRATION_ZAPIER_CATEGORY } from '@/settings/integrations/constants/SettingsIntegrationZapier';
|
||||
import { SettingsIntegrationCategory } from '@/settings/integrations/types/SettingsIntegrationCategory';
|
||||
import { getSettingsIntegrationAll } from '@/settings/integrations/utils/getSettingsIntegrationAll';
|
||||
@ -30,6 +30,10 @@ export const useSettingsIntegrationCategories =
|
||||
({ name }) => name === 'stripe',
|
||||
)?.isActive;
|
||||
|
||||
const isAiIntegrationEnabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_AI_ENABLED,
|
||||
);
|
||||
|
||||
const allIntegrations = getSettingsIntegrationAll({
|
||||
isAirtableIntegrationEnabled,
|
||||
isAirtableIntegrationActive,
|
||||
@ -42,7 +46,7 @@ export const useSettingsIntegrationCategories =
|
||||
return [
|
||||
...(allIntegrations.integrations.length > 0 ? [allIntegrations] : []),
|
||||
SETTINGS_INTEGRATION_ZAPIER_CATEGORY,
|
||||
SETTINGS_INTEGRATION_WINDMILL_CATEGORY,
|
||||
...(isAiIntegrationEnabled ? [SETTINGS_INTEGRATION_AI_CATEGORY] : []),
|
||||
SETTINGS_INTEGRATION_REQUEST_CATEGORY,
|
||||
];
|
||||
};
|
||||
|
||||
@ -3,13 +3,15 @@ export type SettingsIntegrationType =
|
||||
| 'Add'
|
||||
| 'Goto'
|
||||
| 'Soon'
|
||||
| 'Use';
|
||||
| 'Use'
|
||||
| 'Copy';
|
||||
|
||||
export type SettingsIntegration = {
|
||||
from: { key: string; image: string };
|
||||
to?: { key: string; image: string } | null;
|
||||
type: SettingsIntegrationType;
|
||||
linkText?: string;
|
||||
content?: string;
|
||||
link: string;
|
||||
text: string;
|
||||
};
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import { useFindOneAgentQuery } from '~/generated-metadata/graphql';
|
||||
import { UPDATE_ONE_AGENT } from '../graphql/mutations/updateOneAgent';
|
||||
import {
|
||||
useFindOneAgentQuery,
|
||||
useUpdateOneAgentMutation,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
type AgentFormValues = {
|
||||
name: string;
|
||||
@ -39,9 +40,9 @@ export const useAgentUpdateFormState = ({
|
||||
},
|
||||
});
|
||||
|
||||
const [updateAgent] = useMutation(UPDATE_ONE_AGENT);
|
||||
const [updateAgent] = useUpdateOneAgentMutation();
|
||||
|
||||
const updateAgentMutation = async (updates: Partial<AgentFormValues>) => {
|
||||
const updateAgentMutation = async (updates: AgentFormValues) => {
|
||||
if (!agentId) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user