mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
chore(web): new lint setup (#30020)
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
@ -1,18 +1,18 @@
|
||||
'use client'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import {
|
||||
RiAddCircleFill,
|
||||
RiArrowRightUpLine,
|
||||
RiBookOpenLine,
|
||||
} from '@remixicon/react'
|
||||
import MCPModal from './modal'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import I18n from '@/context/i18n'
|
||||
import { getLanguage } from '@/i18n-config/language'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { useCreateMCP } from '@/service/use-tools'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import MCPModal from './modal'
|
||||
|
||||
type Props = {
|
||||
handleCreate: (provider: ToolWithProvider) => void
|
||||
@ -44,20 +44,20 @@ const NewMCPCard = ({ handleCreate }: Props) => {
|
||||
return (
|
||||
<>
|
||||
{isCurrentWorkspaceManager && (
|
||||
<div className='col-span-1 flex min-h-[108px] cursor-pointer flex-col rounded-xl bg-background-default-dimmed transition-all duration-200 ease-in-out'>
|
||||
<div className='group grow rounded-t-xl' onClick={() => setShowModal(true)}>
|
||||
<div className='flex shrink-0 items-center p-4 pb-3'>
|
||||
<div className='flex h-10 w-10 items-center justify-center rounded-lg border border-dashed border-divider-deep group-hover:border-solid group-hover:border-state-accent-hover-alt group-hover:bg-state-accent-hover'>
|
||||
<RiAddCircleFill className='h-4 w-4 text-text-quaternary group-hover:text-text-accent'/>
|
||||
<div className="col-span-1 flex min-h-[108px] cursor-pointer flex-col rounded-xl bg-background-default-dimmed transition-all duration-200 ease-in-out">
|
||||
<div className="group grow rounded-t-xl" onClick={() => setShowModal(true)}>
|
||||
<div className="flex shrink-0 items-center p-4 pb-3">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-lg border border-dashed border-divider-deep group-hover:border-solid group-hover:border-state-accent-hover-alt group-hover:bg-state-accent-hover">
|
||||
<RiAddCircleFill className="h-4 w-4 text-text-quaternary group-hover:text-text-accent" />
|
||||
</div>
|
||||
<div className='system-md-semibold ml-3 text-text-secondary group-hover:text-text-accent'>{t('tools.mcp.create.cardTitle')}</div>
|
||||
<div className="system-md-semibold ml-3 text-text-secondary group-hover:text-text-accent">{t('tools.mcp.create.cardTitle')}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='rounded-b-xl border-t-[0.5px] border-divider-subtle px-4 py-3 text-text-tertiary hover:text-text-accent'>
|
||||
<a href={linkUrl} target='_blank' rel='noopener noreferrer' className='flex items-center space-x-1'>
|
||||
<RiBookOpenLine className='h-3 w-3 shrink-0' />
|
||||
<div className='system-xs-regular grow truncate' title={t('tools.mcp.create.cardLink') || ''}>{t('tools.mcp.create.cardLink')}</div>
|
||||
<RiArrowRightUpLine className='h-3 w-3 shrink-0' />
|
||||
<div className="rounded-b-xl border-t-[0.5px] border-divider-subtle px-4 py-3 text-text-tertiary hover:text-text-accent">
|
||||
<a href={linkUrl} target="_blank" rel="noopener noreferrer" className="flex items-center space-x-1">
|
||||
<RiBookOpenLine className="h-3 w-3 shrink-0" />
|
||||
<div className="system-xs-regular grow truncate" title={t('tools.mcp.create.cardLink') || ''}>{t('tools.mcp.create.cardLink')}</div>
|
||||
<RiArrowRightUpLine className="h-3 w-3 shrink-0" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,26 +1,23 @@
|
||||
'use client'
|
||||
import React, { useCallback, useEffect } from 'react'
|
||||
import type { FC } from 'react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import type { ToolWithProvider } from '../../../workflow/types'
|
||||
import {
|
||||
RiCloseLine,
|
||||
RiLoader2Line,
|
||||
RiLoopLeftLine,
|
||||
} from '@remixicon/react'
|
||||
import type { ToolWithProvider } from '../../../workflow/types'
|
||||
import Icon from '@/app/components/plugins/card/base/card-icon'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import React, { useCallback, useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import MCPModal from '../modal'
|
||||
import OperationDropdown from './operation-dropdown'
|
||||
import ListLoading from './list-loading'
|
||||
import ToolItem from './tool-item'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import Icon from '@/app/components/plugins/card/base/card-icon'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { openOAuthPopup } from '@/hooks/use-oauth'
|
||||
import {
|
||||
useAuthorizeMCP,
|
||||
useDeleteMCP,
|
||||
@ -29,8 +26,11 @@ import {
|
||||
useUpdateMCP,
|
||||
useUpdateMCPTools,
|
||||
} from '@/service/use-tools'
|
||||
import { openOAuthPopup } from '@/hooks/use-oauth'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import MCPModal from '../modal'
|
||||
import ListLoading from './list-loading'
|
||||
import OperationDropdown from './operation-dropdown'
|
||||
import ToolItem from './tool-item'
|
||||
|
||||
type Props = {
|
||||
detail: ToolWithProvider
|
||||
@ -149,50 +149,50 @@ const MCPDetailContent: FC<Props> = ({
|
||||
return (
|
||||
<>
|
||||
<div className={cn('shrink-0 border-b border-divider-subtle bg-components-panel-bg p-4 pb-3')}>
|
||||
<div className='flex'>
|
||||
<div className='shrink-0 overflow-hidden rounded-xl border border-components-panel-border-subtle'>
|
||||
<div className="flex">
|
||||
<div className="shrink-0 overflow-hidden rounded-xl border border-components-panel-border-subtle">
|
||||
<Icon src={detail.icon} />
|
||||
</div>
|
||||
<div className='ml-3 w-0 grow'>
|
||||
<div className='flex h-5 items-center'>
|
||||
<div className='system-md-semibold truncate text-text-primary' title={detail.name}>{detail.name}</div>
|
||||
<div className="ml-3 w-0 grow">
|
||||
<div className="flex h-5 items-center">
|
||||
<div className="system-md-semibold truncate text-text-primary" title={detail.name}>{detail.name}</div>
|
||||
</div>
|
||||
<div className='mt-0.5 flex items-center gap-1'>
|
||||
<div className="mt-0.5 flex items-center gap-1">
|
||||
<Tooltip popupContent={t('tools.mcp.identifier')}>
|
||||
<div className='system-xs-regular shrink-0 cursor-pointer text-text-secondary' onClick={() => copy(detail.server_identifier || '')}>{detail.server_identifier}</div>
|
||||
<div className="system-xs-regular shrink-0 cursor-pointer text-text-secondary" onClick={() => copy(detail.server_identifier || '')}>{detail.server_identifier}</div>
|
||||
</Tooltip>
|
||||
<div className='system-xs-regular shrink-0 text-text-quaternary'>·</div>
|
||||
<div className="system-xs-regular shrink-0 text-text-quaternary">·</div>
|
||||
<Tooltip popupContent={t('tools.mcp.modal.serverUrl')}>
|
||||
<div className='system-xs-regular truncate text-text-secondary'>{detail.server_url}</div>
|
||||
<div className="system-xs-regular truncate text-text-secondary">{detail.server_url}</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex gap-1'>
|
||||
<div className="flex gap-1">
|
||||
<OperationDropdown
|
||||
onEdit={showUpdateModal}
|
||||
onRemove={showDeleteConfirm}
|
||||
/>
|
||||
<ActionButton onClick={onHide}>
|
||||
<RiCloseLine className='h-4 w-4' />
|
||||
<RiCloseLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-5'>
|
||||
<div className="mt-5">
|
||||
{!isAuthorizing && detail.is_team_authorization && (
|
||||
<Button
|
||||
variant='secondary'
|
||||
className='w-full'
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
onClick={handleAuthorize}
|
||||
disabled={!isCurrentWorkspaceManager}
|
||||
>
|
||||
<Indicator className='mr-2' color={'green'} />
|
||||
<Indicator className="mr-2" color="green" />
|
||||
{t('tools.auth.authorized')}
|
||||
</Button>
|
||||
)}
|
||||
{!detail.is_team_authorization && !isAuthorizing && (
|
||||
<Button
|
||||
variant='primary'
|
||||
className='w-full'
|
||||
variant="primary"
|
||||
className="w-full"
|
||||
onClick={handleAuthorize}
|
||||
disabled={!isCurrentWorkspaceManager}
|
||||
>
|
||||
@ -201,8 +201,8 @@ const MCPDetailContent: FC<Props> = ({
|
||||
)}
|
||||
{isAuthorizing && (
|
||||
<Button
|
||||
variant='primary'
|
||||
className='w-full'
|
||||
variant="primary"
|
||||
className="w-full"
|
||||
disabled
|
||||
>
|
||||
<RiLoader2Line className={cn('mr-1 h-4 w-4 animate-spin')} />
|
||||
@ -211,45 +211,47 @@ const MCPDetailContent: FC<Props> = ({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex grow flex-col'>
|
||||
<div className="flex grow flex-col">
|
||||
{((detail.is_team_authorization && isGettingTools) || isUpdating) && (
|
||||
<>
|
||||
<div className='flex shrink-0 justify-between gap-2 px-4 pb-1 pt-2'>
|
||||
<div className='flex h-6 items-center'>
|
||||
{!isUpdating && <div className='system-sm-semibold-uppercase text-text-secondary'>{t('tools.mcp.gettingTools')}</div>}
|
||||
{isUpdating && <div className='system-sm-semibold-uppercase text-text-secondary'>{t('tools.mcp.updateTools')}</div>}
|
||||
<div className="flex shrink-0 justify-between gap-2 px-4 pb-1 pt-2">
|
||||
<div className="flex h-6 items-center">
|
||||
{!isUpdating && <div className="system-sm-semibold-uppercase text-text-secondary">{t('tools.mcp.gettingTools')}</div>}
|
||||
{isUpdating && <div className="system-sm-semibold-uppercase text-text-secondary">{t('tools.mcp.updateTools')}</div>}
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div className='flex h-full w-full grow flex-col overflow-hidden px-4 pb-4'>
|
||||
<div className="flex h-full w-full grow flex-col overflow-hidden px-4 pb-4">
|
||||
<ListLoading />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{!isUpdating && detail.is_team_authorization && !isGettingTools && !toolList.length && (
|
||||
<div className='flex h-full w-full flex-col items-center justify-center'>
|
||||
<div className='system-sm-regular mb-3 text-text-tertiary'>{t('tools.mcp.toolsEmpty')}</div>
|
||||
<div className="flex h-full w-full flex-col items-center justify-center">
|
||||
<div className="system-sm-regular mb-3 text-text-tertiary">{t('tools.mcp.toolsEmpty')}</div>
|
||||
<Button
|
||||
variant='primary'
|
||||
variant="primary"
|
||||
onClick={handleUpdateTools}
|
||||
>{t('tools.mcp.getTools')}</Button>
|
||||
>
|
||||
{t('tools.mcp.getTools')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{!isUpdating && !isGettingTools && toolList.length > 0 && (
|
||||
<>
|
||||
<div className='flex shrink-0 justify-between gap-2 px-4 pb-1 pt-2'>
|
||||
<div className='flex h-6 items-center'>
|
||||
{toolList.length > 1 && <div className='system-sm-semibold-uppercase text-text-secondary'>{t('tools.mcp.toolsNum', { count: toolList.length })}</div>}
|
||||
{toolList.length === 1 && <div className='system-sm-semibold-uppercase text-text-secondary'>{t('tools.mcp.onlyTool')}</div>}
|
||||
<div className="flex shrink-0 justify-between gap-2 px-4 pb-1 pt-2">
|
||||
<div className="flex h-6 items-center">
|
||||
{toolList.length > 1 && <div className="system-sm-semibold-uppercase text-text-secondary">{t('tools.mcp.toolsNum', { count: toolList.length })}</div>}
|
||||
{toolList.length === 1 && <div className="system-sm-semibold-uppercase text-text-secondary">{t('tools.mcp.onlyTool')}</div>}
|
||||
</div>
|
||||
<div>
|
||||
<Button size='small' onClick={showUpdateConfirm}>
|
||||
<RiLoopLeftLine className='mr-1 h-3.5 w-3.5' />
|
||||
<Button size="small" onClick={showUpdateConfirm}>
|
||||
<RiLoopLeftLine className="mr-1 h-3.5 w-3.5" />
|
||||
{t('tools.mcp.update')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex h-0 w-full grow flex-col gap-2 overflow-y-auto px-4 pb-4'>
|
||||
<div className="flex h-0 w-full grow flex-col gap-2 overflow-y-auto px-4 pb-4">
|
||||
{toolList.map(tool => (
|
||||
<ToolItem
|
||||
key={`${detail.id}${tool.name}`}
|
||||
@ -261,10 +263,10 @@ const MCPDetailContent: FC<Props> = ({
|
||||
)}
|
||||
|
||||
{!isUpdating && !detail.is_team_authorization && (
|
||||
<div className='flex h-full w-full flex-col items-center justify-center'>
|
||||
{!isAuthorizing && <div className='system-md-medium mb-1 text-text-secondary'>{t('tools.mcp.authorizingRequired')}</div>}
|
||||
{isAuthorizing && <div className='system-md-medium mb-1 text-text-secondary'>{t('tools.mcp.authorizing')}</div>}
|
||||
<div className='system-sm-regular text-text-tertiary'>{t('tools.mcp.authorizeTip')}</div>
|
||||
<div className="flex h-full w-full flex-col items-center justify-center">
|
||||
{!isAuthorizing && <div className="system-md-medium mb-1 text-text-secondary">{t('tools.mcp.authorizingRequired')}</div>}
|
||||
{isAuthorizing && <div className="system-md-medium mb-1 text-text-secondary">{t('tools.mcp.authorizing')}</div>}
|
||||
<div className="system-sm-regular text-text-tertiary">{t('tools.mcp.authorizeTip')}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -280,11 +282,11 @@ const MCPDetailContent: FC<Props> = ({
|
||||
<Confirm
|
||||
isShow
|
||||
title={t('tools.mcp.delete')}
|
||||
content={
|
||||
content={(
|
||||
<div>
|
||||
{t('tools.mcp.deleteConfirmTitle', { mcp: detail.name })}
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
onCancel={hideDeleteConfirm}
|
||||
onConfirm={handleDelete}
|
||||
isLoading={deleting}
|
||||
|
||||
@ -5,30 +5,30 @@ import { cn } from '@/utils/classnames'
|
||||
const ListLoading = () => {
|
||||
return (
|
||||
<div className={cn('space-y-2')}>
|
||||
<div className='space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4'>
|
||||
<div className='h-2 w-[180px] rounded-sm bg-text-quaternary opacity-20'></div>
|
||||
<div className='h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className='mr-10 h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className="space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4">
|
||||
<div className="h-2 w-[180px] rounded-sm bg-text-quaternary opacity-20"></div>
|
||||
<div className="h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
<div className="mr-10 h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
</div>
|
||||
<div className='space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4'>
|
||||
<div className='h-2 w-[148px] rounded-sm bg-text-quaternary opacity-20'></div>
|
||||
<div className='h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className='mr-10 h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className="space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4">
|
||||
<div className="h-2 w-[148px] rounded-sm bg-text-quaternary opacity-20"></div>
|
||||
<div className="h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
<div className="mr-10 h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
</div>
|
||||
<div className='space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4'>
|
||||
<div className='h-2 w-[196px] rounded-sm bg-text-quaternary opacity-20'></div>
|
||||
<div className='h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className='mr-10 h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className="space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4">
|
||||
<div className="h-2 w-[196px] rounded-sm bg-text-quaternary opacity-20"></div>
|
||||
<div className="h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
<div className="mr-10 h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
</div>
|
||||
<div className='space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4'>
|
||||
<div className='h-2 w-[148px] rounded-sm bg-text-quaternary opacity-20'></div>
|
||||
<div className='h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className='mr-10 h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className="space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4">
|
||||
<div className="h-2 w-[148px] rounded-sm bg-text-quaternary opacity-20"></div>
|
||||
<div className="h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
<div className="mr-10 h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
</div>
|
||||
<div className='space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4'>
|
||||
<div className='h-2 w-[180px] rounded-sm bg-text-quaternary opacity-20'></div>
|
||||
<div className='h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className='mr-10 h-2 rounded-sm bg-text-quaternary opacity-10'></div>
|
||||
<div className="space-y-3 rounded-xl bg-components-panel-on-panel-item-bg-hover p-4">
|
||||
<div className="h-2 w-[180px] rounded-sm bg-text-quaternary opacity-20"></div>
|
||||
<div className="h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
<div className="mr-10 h-2 rounded-sm bg-text-quaternary opacity-10"></div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useCallback, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
RiEditLine,
|
||||
RiMoreFill,
|
||||
} from '@remixicon/react'
|
||||
import React, { useCallback, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
@ -45,7 +45,7 @@ const OperationDropdown: FC<Props> = ({
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-end'
|
||||
placement="bottom-end"
|
||||
offset={{
|
||||
mainAxis: !inCard ? -12 : 0,
|
||||
crossAxis: !inCard ? 36 : 0,
|
||||
@ -58,27 +58,27 @@ const OperationDropdown: FC<Props> = ({
|
||||
</ActionButton>
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-50'>
|
||||
<div className='w-[160px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-sm'>
|
||||
<PortalToFollowElemContent className="z-50">
|
||||
<div className="w-[160px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-sm">
|
||||
<div
|
||||
className='flex cursor-pointer items-center rounded-lg px-3 py-1.5 hover:bg-state-base-hover'
|
||||
className="flex cursor-pointer items-center rounded-lg px-3 py-1.5 hover:bg-state-base-hover"
|
||||
onClick={() => {
|
||||
onEdit()
|
||||
handleTrigger()
|
||||
}}
|
||||
>
|
||||
<RiEditLine className='h-4 w-4 text-text-tertiary' />
|
||||
<div className='system-md-regular ml-2 text-text-secondary'>{t('tools.mcp.operation.edit')}</div>
|
||||
<RiEditLine className="h-4 w-4 text-text-tertiary" />
|
||||
<div className="system-md-regular ml-2 text-text-secondary">{t('tools.mcp.operation.edit')}</div>
|
||||
</div>
|
||||
<div
|
||||
className='group flex cursor-pointer items-center rounded-lg px-3 py-1.5 hover:bg-state-destructive-hover'
|
||||
className="group flex cursor-pointer items-center rounded-lg px-3 py-1.5 hover:bg-state-destructive-hover"
|
||||
onClick={() => {
|
||||
onRemove()
|
||||
handleTrigger()
|
||||
}}
|
||||
>
|
||||
<RiDeleteBinLine className='h-4 w-4 text-text-tertiary group-hover:text-text-destructive-secondary' />
|
||||
<div className='system-md-regular ml-2 text-text-secondary group-hover:text-text-destructive'>{t('tools.mcp.operation.remove')}</div>
|
||||
<RiDeleteBinLine className="h-4 w-4 text-text-tertiary group-hover:text-text-destructive-secondary" />
|
||||
<div className="system-md-regular ml-2 text-text-secondary group-hover:text-text-destructive">{t('tools.mcp.operation.remove')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import type { FC } from 'react'
|
||||
import Drawer from '@/app/components/base/drawer'
|
||||
import MCPDetailContent from './content'
|
||||
import type { ToolWithProvider } from '../../../workflow/types'
|
||||
import React from 'react'
|
||||
import Drawer from '@/app/components/base/drawer'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import MCPDetailContent from './content'
|
||||
|
||||
type Props = {
|
||||
detail?: ToolWithProvider
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import type { Tool } from '@/app/components/tools/types'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import I18n from '@/context/i18n'
|
||||
import { getLanguage } from '@/i18n-config/language'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type Props = {
|
||||
tool: Tool
|
||||
@ -26,16 +26,23 @@ const MCPToolItem = ({
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className='mt-2'>
|
||||
<div className='title-xs-semi-bold mb-1 text-text-primary'>{t('tools.mcp.toolItem.parameters')}:</div>
|
||||
<ul className='space-y-1'>
|
||||
<div className="mt-2">
|
||||
<div className="title-xs-semi-bold mb-1 text-text-primary">
|
||||
{t('tools.mcp.toolItem.parameters')}
|
||||
:
|
||||
</div>
|
||||
<ul className="space-y-1">
|
||||
{parameters.map((parameter) => {
|
||||
const descriptionContent = parameter.human_description[language] || t('tools.mcp.toolItem.noDescription')
|
||||
return (
|
||||
<li key={parameter.name} className='pl-2'>
|
||||
<span className='system-xs-regular font-bold text-text-secondary'>{parameter.name}</span>
|
||||
<span className='system-xs-regular mr-1 text-text-tertiary'>({parameter.type}):</span>
|
||||
<span className='system-xs-regular text-text-tertiary'>{descriptionContent}</span>
|
||||
<li key={parameter.name} className="pl-2">
|
||||
<span className="system-xs-regular font-bold text-text-secondary">{parameter.name}</span>
|
||||
<span className="system-xs-regular mr-1 text-text-tertiary">
|
||||
(
|
||||
{parameter.type}
|
||||
):
|
||||
</span>
|
||||
<span className="system-xs-regular text-text-tertiary">{descriptionContent}</span>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
@ -47,12 +54,12 @@ const MCPToolItem = ({
|
||||
return (
|
||||
<Tooltip
|
||||
key={tool.name}
|
||||
position='left'
|
||||
popupClassName='!p-0 !px-4 !py-3.5 !w-[360px] !border-[0.5px] !border-components-panel-border !rounded-xl !shadow-lg'
|
||||
position="left"
|
||||
popupClassName="!p-0 !px-4 !py-3.5 !w-[360px] !border-[0.5px] !border-components-panel-border !rounded-xl !shadow-lg"
|
||||
popupContent={(
|
||||
<div>
|
||||
<div className='title-xs-semi-bold mb-1 text-text-primary'>{tool.label[language]}</div>
|
||||
<div className='body-xs-regular text-text-secondary'>{tool.description[language]}</div>
|
||||
<div className="title-xs-semi-bold mb-1 text-text-primary">{tool.label[language]}</div>
|
||||
<div className="body-xs-regular text-text-secondary">{tool.description[language]}</div>
|
||||
{renderParameters()}
|
||||
</div>
|
||||
)}
|
||||
@ -60,8 +67,8 @@ const MCPToolItem = ({
|
||||
<div
|
||||
className={cn('bg-components-panel-item-bg cursor-pointer rounded-xl border-[0.5px] border-components-panel-border-subtle px-4 py-3 shadow-xs hover:bg-components-panel-on-panel-item-bg-hover')}
|
||||
>
|
||||
<div className='system-md-semibold pb-0.5 text-text-secondary'>{tool.label[language]}</div>
|
||||
<div className='system-xs-regular line-clamp-2 text-text-tertiary' title={tool.description[language]}>{tool.description[language]}</div>
|
||||
<div className="system-md-semibold pb-0.5 text-text-secondary">{tool.label[language]}</div>
|
||||
<div className="system-xs-regular line-clamp-2 text-text-tertiary" title={tool.description[language]}>{tool.description[language]}</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
'use client'
|
||||
import { RiAddLine, RiDeleteBinLine } from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { RiAddLine, RiDeleteBinLine } from '@remixicon/react'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Button from '@/app/components/base/button'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
export type HeaderItem = {
|
||||
@ -50,18 +50,18 @@ const HeadersInput = ({
|
||||
|
||||
if (headersItems.length === 0) {
|
||||
return (
|
||||
<div className='space-y-2'>
|
||||
<div className='body-xs-regular text-text-tertiary'>
|
||||
<div className="space-y-2">
|
||||
<div className="body-xs-regular text-text-tertiary">
|
||||
{t('tools.mcp.modal.noHeaders')}
|
||||
</div>
|
||||
{!readonly && (
|
||||
<Button
|
||||
variant='secondary'
|
||||
size='small'
|
||||
variant="secondary"
|
||||
size="small"
|
||||
onClick={handleAddItem}
|
||||
className='w-full'
|
||||
className="w-full"
|
||||
>
|
||||
<RiAddLine className='mr-1 h-4 w-4' />
|
||||
<RiAddLine className="mr-1 h-4 w-4" />
|
||||
{t('tools.mcp.modal.addHeader')}
|
||||
</Button>
|
||||
)}
|
||||
@ -70,45 +70,48 @@ const HeadersInput = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='space-y-2'>
|
||||
<div className="space-y-2">
|
||||
{isMasked && (
|
||||
<div className='body-xs-regular text-text-tertiary'>
|
||||
<div className="body-xs-regular text-text-tertiary">
|
||||
{t('tools.mcp.modal.maskedHeadersTip')}
|
||||
</div>
|
||||
)}
|
||||
<div className='overflow-hidden rounded-lg border border-divider-regular'>
|
||||
<div className='system-xs-medium-uppercase bg-background-secondary flex h-7 items-center leading-7 text-text-tertiary'>
|
||||
<div className='h-full w-1/2 border-r border-divider-regular pl-3'>{t('tools.mcp.modal.headerKey')}</div>
|
||||
<div className='h-full w-1/2 pl-3 pr-1'>{t('tools.mcp.modal.headerValue')}</div>
|
||||
<div className="overflow-hidden rounded-lg border border-divider-regular">
|
||||
<div className="system-xs-medium-uppercase bg-background-secondary flex h-7 items-center leading-7 text-text-tertiary">
|
||||
<div className="h-full w-1/2 border-r border-divider-regular pl-3">{t('tools.mcp.modal.headerKey')}</div>
|
||||
<div className="h-full w-1/2 pl-3 pr-1">{t('tools.mcp.modal.headerValue')}</div>
|
||||
</div>
|
||||
{headersItems.map((item, index) => (
|
||||
<div key={item.id} className={cn(
|
||||
'flex items-center border-divider-regular',
|
||||
index < headersItems.length - 1 && 'border-b',
|
||||
)}>
|
||||
<div className='w-1/2 border-r border-divider-regular'>
|
||||
<div
|
||||
key={item.id}
|
||||
className={cn(
|
||||
'flex items-center border-divider-regular',
|
||||
index < headersItems.length - 1 && 'border-b',
|
||||
)}
|
||||
>
|
||||
<div className="w-1/2 border-r border-divider-regular">
|
||||
<Input
|
||||
value={item.key}
|
||||
onChange={e => handleItemChange(index, 'key', e.target.value)}
|
||||
placeholder={t('tools.mcp.modal.headerKeyPlaceholder')}
|
||||
className='rounded-none border-0'
|
||||
className="rounded-none border-0"
|
||||
readOnly={readonly}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex w-1/2 items-center'>
|
||||
<div className="flex w-1/2 items-center">
|
||||
<Input
|
||||
value={item.value}
|
||||
onChange={e => handleItemChange(index, 'value', e.target.value)}
|
||||
placeholder={t('tools.mcp.modal.headerValuePlaceholder')}
|
||||
className='flex-1 rounded-none border-0'
|
||||
className="flex-1 rounded-none border-0"
|
||||
readOnly={readonly}
|
||||
/>
|
||||
{!readonly && !!headersItems.length && (
|
||||
<ActionButton
|
||||
onClick={() => handleRemoveItem(index)}
|
||||
className='mr-2'
|
||||
className="mr-2"
|
||||
>
|
||||
<RiDeleteBinLine className='h-4 w-4 text-text-destructive' />
|
||||
<RiDeleteBinLine className="h-4 w-4 text-text-destructive" />
|
||||
</ActionButton>
|
||||
)}
|
||||
</div>
|
||||
@ -117,12 +120,12 @@ const HeadersInput = ({
|
||||
</div>
|
||||
{!readonly && (
|
||||
<Button
|
||||
variant='secondary'
|
||||
size='small'
|
||||
variant="secondary"
|
||||
size="small"
|
||||
onClick={handleAddItem}
|
||||
className='w-full'
|
||||
className="w-full"
|
||||
>
|
||||
<RiAddLine className='mr-1 h-4 w-4' />
|
||||
<RiAddLine className="mr-1 h-4 w-4" />
|
||||
{t('tools.mcp.modal.addHeader')}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
'use client'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import { useMemo, useState } from 'react'
|
||||
import NewMCPCard from './create-card'
|
||||
import MCPCard from './provider-card'
|
||||
import MCPDetailPanel from './detail/provider-detail'
|
||||
import {
|
||||
useAllToolProviders,
|
||||
} from '@/service/use-tools'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import NewMCPCard from './create-card'
|
||||
import MCPDetailPanel from './detail/provider-detail'
|
||||
import MCPCard from './provider-card'
|
||||
|
||||
type Props = {
|
||||
searchText: string
|
||||
@ -26,7 +26,8 @@ function renderDefaultCard() {
|
||||
index >= 16 && index < 20 && 'opacity-25',
|
||||
index >= 20 && index < 24 && 'opacity-20',
|
||||
)}
|
||||
></div>
|
||||
>
|
||||
</div>
|
||||
))
|
||||
return defaultCards
|
||||
}
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
'use client'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import MCPServerParamItem from '@/app/components/tools/mcp/mcp-server-param-item'
|
||||
import type {
|
||||
MCPServerDetail,
|
||||
} from '@/app/components/tools/types'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import MCPServerParamItem from '@/app/components/tools/mcp/mcp-server-param-item'
|
||||
import {
|
||||
useCreateMCPServer,
|
||||
useInvalidateMCPServerDetail,
|
||||
@ -93,33 +93,34 @@ const MCPServerModal = ({
|
||||
onClose={onHide}
|
||||
className={cn('relative !max-w-[520px] !p-0')}
|
||||
>
|
||||
<div className='absolute right-5 top-5 z-10 cursor-pointer p-1.5' onClick={onHide}>
|
||||
<RiCloseLine className='h-5 w-5 text-text-tertiary' />
|
||||
<div className="absolute right-5 top-5 z-10 cursor-pointer p-1.5" onClick={onHide}>
|
||||
<RiCloseLine className="h-5 w-5 text-text-tertiary" />
|
||||
</div>
|
||||
<div className='title-2xl-semi-bold relative p-6 pb-3 text-xl text-text-primary'>
|
||||
<div className="title-2xl-semi-bold relative p-6 pb-3 text-xl text-text-primary">
|
||||
{!data ? t('tools.mcp.server.modal.addTitle') : t('tools.mcp.server.modal.editTitle')}
|
||||
</div>
|
||||
<div className='space-y-5 px-6 py-3'>
|
||||
<div className='space-y-0.5'>
|
||||
<div className='flex h-6 items-center gap-1'>
|
||||
<div className='system-sm-medium text-text-secondary'>{t('tools.mcp.server.modal.description')}</div>
|
||||
<div className='system-xs-regular text-text-destructive-secondary'>*</div>
|
||||
<div className="space-y-5 px-6 py-3">
|
||||
<div className="space-y-0.5">
|
||||
<div className="flex h-6 items-center gap-1">
|
||||
<div className="system-sm-medium text-text-secondary">{t('tools.mcp.server.modal.description')}</div>
|
||||
<div className="system-xs-regular text-text-destructive-secondary">*</div>
|
||||
</div>
|
||||
<Textarea
|
||||
className='h-[96px] resize-none'
|
||||
className="h-[96px] resize-none"
|
||||
value={description}
|
||||
placeholder={t('tools.mcp.server.modal.descriptionPlaceholder')}
|
||||
onChange={e => setDescription(e.target.value)}
|
||||
></Textarea>
|
||||
>
|
||||
</Textarea>
|
||||
</div>
|
||||
{latestParams.length > 0 && (
|
||||
<div>
|
||||
<div className='mb-1 flex items-center gap-2'>
|
||||
<div className='system-xs-medium-uppercase shrink-0 text-text-primary'>{t('tools.mcp.server.modal.parameters')}</div>
|
||||
<Divider type='horizontal' className='!m-0 !h-px grow bg-divider-subtle' />
|
||||
<div className="mb-1 flex items-center gap-2">
|
||||
<div className="system-xs-medium-uppercase shrink-0 text-text-primary">{t('tools.mcp.server.modal.parameters')}</div>
|
||||
<Divider type="horizontal" className="!m-0 !h-px grow bg-divider-subtle" />
|
||||
</div>
|
||||
<div className='body-xs-regular mb-2 text-text-tertiary'>{t('tools.mcp.server.modal.parametersTip')}</div>
|
||||
<div className='space-y-3'>
|
||||
<div className="body-xs-regular mb-2 text-text-tertiary">{t('tools.mcp.server.modal.parametersTip')}</div>
|
||||
<div className="space-y-3">
|
||||
{latestParams.map(paramItem => (
|
||||
<MCPServerParamItem
|
||||
key={paramItem.variable}
|
||||
@ -132,8 +133,8 @@ const MCPServerModal = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className='flex flex-row-reverse p-6 pt-5'>
|
||||
<Button disabled={!description || creating || updating} className='ml-2' variant='primary' onClick={submit}>{data ? t('tools.mcp.modal.save') : t('tools.mcp.server.modal.confirm')}</Button>
|
||||
<div className="flex flex-row-reverse p-6 pt-5">
|
||||
<Button disabled={!description || creating || updating} className="ml-2" variant="primary" onClick={submit}>{data ? t('tools.mcp.modal.save') : t('tools.mcp.server.modal.confirm')}</Button>
|
||||
<Button onClick={onHide}>{t('tools.mcp.modal.cancel')}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@ -17,19 +17,20 @@ const MCPServerParamItem = ({
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className='space-y-0.5'>
|
||||
<div className='flex h-6 items-center gap-2'>
|
||||
<div className='system-xs-medium text-text-secondary'>{data.label}</div>
|
||||
<div className='system-xs-medium text-text-quaternary'>·</div>
|
||||
<div className='system-xs-medium text-text-secondary'>{data.variable}</div>
|
||||
<div className='system-xs-medium text-text-tertiary'>{data.type}</div>
|
||||
<div className="space-y-0.5">
|
||||
<div className="flex h-6 items-center gap-2">
|
||||
<div className="system-xs-medium text-text-secondary">{data.label}</div>
|
||||
<div className="system-xs-medium text-text-quaternary">·</div>
|
||||
<div className="system-xs-medium text-text-secondary">{data.variable}</div>
|
||||
<div className="system-xs-medium text-text-tertiary">{data.type}</div>
|
||||
</div>
|
||||
<Textarea
|
||||
className='h-8 resize-none'
|
||||
className="h-8 resize-none"
|
||||
value={value}
|
||||
placeholder={t('tools.mcp.server.modal.parametersPlaceholder')}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
></Textarea>
|
||||
>
|
||||
</Textarea>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,32 +1,33 @@
|
||||
'use client'
|
||||
import type { AppDetailResponse } from '@/models/app'
|
||||
import type { AppSSO } from '@/types/app'
|
||||
import { RiEditLine, RiLoopLeftLine } from '@remixicon/react'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiEditLine, RiLoopLeftLine } from '@remixicon/react'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import CopyFeedback from '@/app/components/base/copy-feedback'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import {
|
||||
Mcp,
|
||||
} from '@/app/components/base/icons/src/vender/other'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import CopyFeedback from '@/app/components/base/copy-feedback'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import type { AppDetailResponse } from '@/models/app'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { AppModeEnum, type AppSSO } from '@/types/app'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import MCPServerModal from '@/app/components/tools/mcp/mcp-server-modal'
|
||||
import { useAppWorkflow } from '@/service/use-workflow'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
import { fetchAppDetail } from '@/service/apps'
|
||||
import {
|
||||
useInvalidateMCPServerDetail,
|
||||
useMCPServerDetail,
|
||||
useRefreshMCPServerCode,
|
||||
useUpdateMCPServer,
|
||||
} from '@/service/use-tools'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { useAppWorkflow } from '@/service/use-workflow'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { fetchAppDetail } from '@/service/apps'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
|
||||
export type IAppCardProps = {
|
||||
appInfo: AppDetailResponse & Partial<AppSSO>
|
||||
@ -54,7 +55,7 @@ function MCPServiceCard({
|
||||
const { data: currentWorkflow } = useAppWorkflow(isAdvancedApp ? appId : '')
|
||||
const [basicAppConfig, setBasicAppConfig] = useState<any>({})
|
||||
const basicAppInputForm = useMemo(() => {
|
||||
if(!isBasicApp || !basicAppConfig?.user_input_form)
|
||||
if (!isBasicApp || !basicAppConfig?.user_input_form)
|
||||
return []
|
||||
return basicAppConfig.user_input_form.map((item: any) => {
|
||||
const type = Object.keys(item)[0]
|
||||
@ -65,7 +66,7 @@ function MCPServiceCard({
|
||||
})
|
||||
}, [basicAppConfig.user_input_form, isBasicApp])
|
||||
useEffect(() => {
|
||||
if(isBasicApp && appId) {
|
||||
if (isBasicApp && appId) {
|
||||
(async () => {
|
||||
const res = await fetchAppDetail({ url: '/apps', id: appId })
|
||||
setBasicAppConfig(res?.model_config || {})
|
||||
@ -89,7 +90,7 @@ function MCPServiceCard({
|
||||
const [activated, setActivated] = useState(serverActivated)
|
||||
|
||||
const latestParams = useMemo(() => {
|
||||
if(isAdvancedApp) {
|
||||
if (isAdvancedApp) {
|
||||
if (!currentWorkflow?.graph)
|
||||
return []
|
||||
const startNode = currentWorkflow?.graph.nodes.find(node => node.data.type === BlockEnum.Start) as any
|
||||
@ -150,21 +151,23 @@ function MCPServiceCard({
|
||||
<div className={cn('w-full max-w-full rounded-xl border-l-[0.5px] border-t border-effects-highlight', isMinimalState && 'h-12')}>
|
||||
<div className={cn('relative rounded-xl bg-background-default', triggerModeDisabled && 'opacity-60')}>
|
||||
{triggerModeDisabled && (
|
||||
triggerModeMessage ? (
|
||||
<Tooltip
|
||||
popupContent={triggerModeMessage}
|
||||
popupClassName="max-w-64 rounded-xl bg-components-panel-bg px-3 py-2 text-xs text-text-secondary shadow-lg"
|
||||
position="right"
|
||||
>
|
||||
<div className='absolute inset-0 z-10 cursor-not-allowed rounded-xl' aria-hidden="true"></div>
|
||||
</Tooltip>
|
||||
) : <div className='absolute inset-0 z-10 cursor-not-allowed rounded-xl' aria-hidden="true"></div>
|
||||
triggerModeMessage
|
||||
? (
|
||||
<Tooltip
|
||||
popupContent={triggerModeMessage}
|
||||
popupClassName="max-w-64 rounded-xl bg-components-panel-bg px-3 py-2 text-xs text-text-secondary shadow-lg"
|
||||
position="right"
|
||||
>
|
||||
<div className="absolute inset-0 z-10 cursor-not-allowed rounded-xl" aria-hidden="true"></div>
|
||||
</Tooltip>
|
||||
)
|
||||
: <div className="absolute inset-0 z-10 cursor-not-allowed rounded-xl" aria-hidden="true"></div>
|
||||
)}
|
||||
<div className={cn('flex w-full flex-col items-start justify-center gap-3 self-stretch p-3', isMinimalState ? 'border-0' : 'border-b-[0.5px] border-divider-subtle')}>
|
||||
<div className='flex w-full items-center gap-3 self-stretch'>
|
||||
<div className='flex grow items-center'>
|
||||
<div className='mr-2 shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-brand-blue-brand-500 p-1 shadow-md'>
|
||||
<Mcp className='h-4 w-4 text-text-primary-on-surface' />
|
||||
<div className="flex w-full items-center gap-3 self-stretch">
|
||||
<div className="flex grow items-center">
|
||||
<div className="mr-2 shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-brand-blue-brand-500 p-1 shadow-md">
|
||||
<Mcp className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
<div className="group w-full">
|
||||
<div className="system-md-semibold min-w-0 overflow-hidden text-ellipsis break-normal text-text-secondary group-hover:text-text-primary">
|
||||
@ -172,7 +175,7 @@ function MCPServiceCard({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center gap-1'>
|
||||
<div className="flex items-center gap-1">
|
||||
<Indicator color={serverActivated ? 'green' : 'yellow'} />
|
||||
<div className={`${serverActivated ? 'text-text-success' : 'text-text-warning'} system-xs-semibold-uppercase`}>
|
||||
{serverActivated
|
||||
@ -182,23 +185,29 @@ function MCPServiceCard({
|
||||
</div>
|
||||
<Tooltip
|
||||
popupContent={
|
||||
toggleDisabled ? (
|
||||
appUnpublished ? (
|
||||
t('tools.mcp.server.publishTip')
|
||||
) : missingStartNode ? (
|
||||
<>
|
||||
<div className="mb-1 text-xs font-normal text-text-secondary">
|
||||
{t('appOverview.overview.appInfo.enableTooltip.description')}
|
||||
</div>
|
||||
<div
|
||||
className="cursor-pointer text-xs font-normal text-text-accent hover:underline"
|
||||
onClick={() => window.open(docLink('/guides/workflow/node/user-input'), '_blank')}
|
||||
>
|
||||
{t('appOverview.overview.appInfo.enableTooltip.learnMore')}
|
||||
</div>
|
||||
</>
|
||||
) : triggerModeMessage || ''
|
||||
) : ''
|
||||
toggleDisabled
|
||||
? (
|
||||
appUnpublished
|
||||
? (
|
||||
t('tools.mcp.server.publishTip')
|
||||
)
|
||||
: missingStartNode
|
||||
? (
|
||||
<>
|
||||
<div className="mb-1 text-xs font-normal text-text-secondary">
|
||||
{t('appOverview.overview.appInfo.enableTooltip.description')}
|
||||
</div>
|
||||
<div
|
||||
className="cursor-pointer text-xs font-normal text-text-accent hover:underline"
|
||||
onClick={() => window.open(docLink('/guides/workflow/node/user-input'), '_blank')}
|
||||
>
|
||||
{t('appOverview.overview.appInfo.enableTooltip.learnMore')}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
: triggerModeMessage || ''
|
||||
)
|
||||
: ''
|
||||
}
|
||||
position="right"
|
||||
popupClassName="w-58 max-w-60 rounded-xl bg-components-panel-bg px-3.5 py-3 shadow-lg"
|
||||
@ -210,7 +219,7 @@ function MCPServiceCard({
|
||||
</Tooltip>
|
||||
</div>
|
||||
{!isMinimalState && (
|
||||
<div className='flex flex-col items-start justify-center self-stretch'>
|
||||
<div className="flex flex-col items-start justify-center self-stretch">
|
||||
<div className="system-xs-medium pb-1 text-text-tertiary">
|
||||
{t('tools.mcp.server.url')}
|
||||
</div>
|
||||
@ -224,7 +233,7 @@ function MCPServiceCard({
|
||||
<>
|
||||
<CopyFeedback
|
||||
content={serverURL}
|
||||
className={'!size-6'}
|
||||
className="!size-6"
|
||||
/>
|
||||
<Divider type="vertical" className="!mx-0.5 !h-3.5 shrink-0" />
|
||||
{isCurrentWorkspaceManager && (
|
||||
@ -235,7 +244,7 @@ function MCPServiceCard({
|
||||
className="cursor-pointer rounded-md p-1 hover:bg-state-base-hover"
|
||||
onClick={() => setShowConfirmDelete(true)}
|
||||
>
|
||||
<RiLoopLeftLine className={cn('h-4 w-4 text-text-tertiary hover:text-text-secondary', genLoading && 'animate-spin')}/>
|
||||
<RiLoopLeftLine className={cn('h-4 w-4 text-text-tertiary hover:text-text-secondary', genLoading && 'animate-spin')} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -246,11 +255,11 @@ function MCPServiceCard({
|
||||
)}
|
||||
</div>
|
||||
{!isMinimalState && (
|
||||
<div className='flex items-center gap-1 self-stretch p-3'>
|
||||
<div className="flex items-center gap-1 self-stretch p-3">
|
||||
<Button
|
||||
disabled={toggleDisabled}
|
||||
size='small'
|
||||
variant='ghost'
|
||||
size="small"
|
||||
variant="ghost"
|
||||
onClick={() => setShowMCPServerModal(true)}
|
||||
>
|
||||
|
||||
@ -276,7 +285,7 @@ function MCPServiceCard({
|
||||
{/* button copy link/ button regenerate */}
|
||||
{showConfirmDelete && (
|
||||
<Confirm
|
||||
type='warning'
|
||||
type="warning"
|
||||
title={t('appOverview.overview.appInfo.regenerate')}
|
||||
content={t('tools.mcp.server.reGen')}
|
||||
isShow={showConfirmDelete}
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
'use client'
|
||||
import type { HeaderItem } from './headers-input'
|
||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import type { AppIconType } from '@/types/app'
|
||||
import { RiCloseLine, RiEditLine } from '@remixicon/react'
|
||||
import { useHover } from 'ahooks'
|
||||
import { noop } from 'lodash-es'
|
||||
import React, { useCallback, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { getDomain } from 'tldts'
|
||||
import { RiCloseLine, RiEditLine } from '@remixicon/react'
|
||||
import { Mcp } from '@/app/components/base/icons/src/vender/other'
|
||||
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { Mcp } from '@/app/components/base/icons/src/vender/other'
|
||||
import AlertTriangle from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle'
|
||||
import Input from '@/app/components/base/input'
|
||||
import HeadersInput from './headers-input'
|
||||
import type { HeaderItem } from './headers-input'
|
||||
import type { AppIconType } from '@/types/app'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import { noop } from 'lodash-es'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import TabSlider from '@/app/components/base/tab-slider'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { MCPAuthMethod } from '@/app/components/tools/types'
|
||||
import { API_PREFIX } from '@/config'
|
||||
import { uploadRemoteFileInfo } from '@/service/common'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useHover } from 'ahooks'
|
||||
import { shouldUseMcpIconForAppIcon } from '@/utils/mcp'
|
||||
import TabSlider from '@/app/components/base/tab-slider'
|
||||
import { MCPAuthMethod } from '@/app/components/tools/types'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import AlertTriangle from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle'
|
||||
import { API_PREFIX } from '@/config'
|
||||
import HeadersInput from './headers-input'
|
||||
|
||||
export type DuplicateAppModalProps = {
|
||||
data?: ToolWithProvider
|
||||
@ -212,7 +212,7 @@ const MCPModal = ({
|
||||
sse_read_timeout: sseReadTimeout || 300,
|
||||
},
|
||||
})
|
||||
if(isCreate)
|
||||
if (isCreate)
|
||||
onHide()
|
||||
}
|
||||
|
||||
@ -227,14 +227,14 @@ const MCPModal = ({
|
||||
onClose={noop}
|
||||
className={cn('relative !max-w-[520px]', 'p-6')}
|
||||
>
|
||||
<div className='absolute right-5 top-5 z-10 cursor-pointer p-1.5' onClick={onHide}>
|
||||
<RiCloseLine className='h-5 w-5 text-text-tertiary' />
|
||||
<div className="absolute right-5 top-5 z-10 cursor-pointer p-1.5" onClick={onHide}>
|
||||
<RiCloseLine className="h-5 w-5 text-text-tertiary" />
|
||||
</div>
|
||||
<div className='title-2xl-semi-bold relative pb-3 text-xl text-text-primary'>{!isCreate ? t('tools.mcp.modal.editTitle') : t('tools.mcp.modal.title')}</div>
|
||||
<div className='space-y-5 py-3'>
|
||||
<div className="title-2xl-semi-bold relative pb-3 text-xl text-text-primary">{!isCreate ? t('tools.mcp.modal.editTitle') : t('tools.mcp.modal.title')}</div>
|
||||
<div className="space-y-5 py-3">
|
||||
<div>
|
||||
<div className='mb-1 flex h-6 items-center'>
|
||||
<span className='system-sm-medium text-text-secondary'>{t('tools.mcp.modal.serverUrl')}</span>
|
||||
<div className="mb-1 flex h-6 items-center">
|
||||
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.serverUrl')}</span>
|
||||
</div>
|
||||
<Input
|
||||
value={url}
|
||||
@ -243,15 +243,15 @@ const MCPModal = ({
|
||||
placeholder={t('tools.mcp.modal.serverUrlPlaceholder')}
|
||||
/>
|
||||
{originalServerUrl && originalServerUrl !== url && (
|
||||
<div className='mt-1 flex h-5 items-center'>
|
||||
<span className='body-xs-regular text-text-warning'>{t('tools.mcp.modal.serverUrlWarning')}</span>
|
||||
<div className="mt-1 flex h-5 items-center">
|
||||
<span className="body-xs-regular text-text-warning">{t('tools.mcp.modal.serverUrlWarning')}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className='flex space-x-3'>
|
||||
<div className='grow pb-1'>
|
||||
<div className='mb-1 flex h-6 items-center'>
|
||||
<span className='system-sm-medium text-text-secondary'>{t('tools.mcp.modal.name')}</span>
|
||||
<div className="flex space-x-3">
|
||||
<div className="grow pb-1">
|
||||
<div className="mb-1 flex h-6 items-center">
|
||||
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.name')}</span>
|
||||
</div>
|
||||
<Input
|
||||
value={name}
|
||||
@ -259,43 +259,46 @@ const MCPModal = ({
|
||||
placeholder={t('tools.mcp.modal.namePlaceholder')}
|
||||
/>
|
||||
</div>
|
||||
<div className='pt-2' ref={appIconRef}>
|
||||
<div className="pt-2" ref={appIconRef}>
|
||||
<AppIcon
|
||||
iconType={appIcon.type}
|
||||
icon={appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId}
|
||||
background={appIcon.type === 'emoji' ? appIcon.background : undefined}
|
||||
imageUrl={appIcon.type === 'image' ? appIcon.url : undefined}
|
||||
innerIcon={shouldUseMcpIconForAppIcon(appIcon.type, appIcon.type === 'emoji' ? appIcon.icon : '') ? <Mcp className='h-8 w-8 text-text-primary-on-surface' /> : undefined}
|
||||
size='xxl'
|
||||
className='relative cursor-pointer rounded-2xl'
|
||||
innerIcon={shouldUseMcpIconForAppIcon(appIcon.type, appIcon.type === 'emoji' ? appIcon.icon : '') ? <Mcp className="h-8 w-8 text-text-primary-on-surface" /> : undefined}
|
||||
size="xxl"
|
||||
className="relative cursor-pointer rounded-2xl"
|
||||
coverElement={
|
||||
isHovering
|
||||
? (<div className='absolute inset-0 flex items-center justify-center overflow-hidden rounded-2xl bg-background-overlay-alt'>
|
||||
<RiEditLine className='size-6 text-text-primary-on-surface' />
|
||||
</div>) : null
|
||||
? (
|
||||
<div className="absolute inset-0 flex items-center justify-center overflow-hidden rounded-2xl bg-background-overlay-alt">
|
||||
<RiEditLine className="size-6 text-text-primary-on-surface" />
|
||||
</div>
|
||||
)
|
||||
: null
|
||||
}
|
||||
onClick={() => { setShowAppIconPicker(true) }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className='flex h-6 items-center'>
|
||||
<span className='system-sm-medium text-text-secondary'>{t('tools.mcp.modal.serverIdentifier')}</span>
|
||||
<div className="flex h-6 items-center">
|
||||
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.serverIdentifier')}</span>
|
||||
</div>
|
||||
<div className='body-xs-regular mb-1 text-text-tertiary'>{t('tools.mcp.modal.serverIdentifierTip')}</div>
|
||||
<div className="body-xs-regular mb-1 text-text-tertiary">{t('tools.mcp.modal.serverIdentifierTip')}</div>
|
||||
<Input
|
||||
value={serverIdentifier}
|
||||
onChange={e => setServerIdentifier(e.target.value)}
|
||||
placeholder={t('tools.mcp.modal.serverIdentifierPlaceholder')}
|
||||
/>
|
||||
{originalServerID && originalServerID !== serverIdentifier && (
|
||||
<div className='mt-1 flex h-5 items-center'>
|
||||
<span className='body-xs-regular text-text-warning'>{t('tools.mcp.modal.serverIdentifierWarning')}</span>
|
||||
<div className="mt-1 flex h-5 items-center">
|
||||
<span className="body-xs-regular text-text-warning">{t('tools.mcp.modal.serverIdentifierWarning')}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<TabSlider
|
||||
className='w-full'
|
||||
className="w-full"
|
||||
itemClassName={(isActive) => {
|
||||
return `flex-1 ${isActive && 'text-text-accent-light-mode-only'}`
|
||||
}}
|
||||
@ -307,20 +310,20 @@ const MCPModal = ({
|
||||
authMethod === MCPAuthMethod.authentication && (
|
||||
<>
|
||||
<div>
|
||||
<div className='mb-1 flex h-6 items-center'>
|
||||
<div className="mb-1 flex h-6 items-center">
|
||||
<Switch
|
||||
className='mr-2'
|
||||
className="mr-2"
|
||||
defaultValue={isDynamicRegistration}
|
||||
onChange={setIsDynamicRegistration}
|
||||
/>
|
||||
<span className='system-sm-medium text-text-secondary'>{t('tools.mcp.modal.useDynamicClientRegistration')}</span>
|
||||
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.useDynamicClientRegistration')}</span>
|
||||
</div>
|
||||
{!isDynamicRegistration && (
|
||||
<div className='mt-2 flex gap-2 rounded-lg bg-state-warning-hover p-3'>
|
||||
<AlertTriangle className='mt-0.5 h-4 w-4 shrink-0 text-text-warning' />
|
||||
<div className='system-xs-regular text-text-secondary'>
|
||||
<div className='mb-1'>{t('tools.mcp.modal.redirectUrlWarning')}</div>
|
||||
<code className='system-xs-medium block break-all rounded bg-state-warning-active px-2 py-1 text-text-secondary'>
|
||||
<div className="mt-2 flex gap-2 rounded-lg bg-state-warning-hover p-3">
|
||||
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0 text-text-warning" />
|
||||
<div className="system-xs-regular text-text-secondary">
|
||||
<div className="mb-1">{t('tools.mcp.modal.redirectUrlWarning')}</div>
|
||||
<code className="system-xs-medium block break-all rounded bg-state-warning-active px-2 py-1 text-text-secondary">
|
||||
{`${API_PREFIX}/mcp/oauth/callback`}
|
||||
</code>
|
||||
</div>
|
||||
@ -329,7 +332,7 @@ const MCPModal = ({
|
||||
</div>
|
||||
<div>
|
||||
<div className={cn('mb-1 flex h-6 items-center', isDynamicRegistration && 'opacity-50')}>
|
||||
<span className='system-sm-medium text-text-secondary'>{t('tools.mcp.modal.clientID')}</span>
|
||||
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.clientID')}</span>
|
||||
</div>
|
||||
<Input
|
||||
value={clientID}
|
||||
@ -341,7 +344,7 @@ const MCPModal = ({
|
||||
</div>
|
||||
<div>
|
||||
<div className={cn('mb-1 flex h-6 items-center', isDynamicRegistration && 'opacity-50')}>
|
||||
<span className='system-sm-medium text-text-secondary'>{t('tools.mcp.modal.clientSecret')}</span>
|
||||
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.clientSecret')}</span>
|
||||
</div>
|
||||
<Input
|
||||
value={credentials}
|
||||
@ -357,10 +360,10 @@ const MCPModal = ({
|
||||
{
|
||||
authMethod === MCPAuthMethod.headers && (
|
||||
<div>
|
||||
<div className='mb-1 flex h-6 items-center'>
|
||||
<span className='system-sm-medium text-text-secondary'>{t('tools.mcp.modal.headers')}</span>
|
||||
<div className="mb-1 flex h-6 items-center">
|
||||
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.headers')}</span>
|
||||
</div>
|
||||
<div className='body-xs-regular mb-2 text-text-tertiary'>{t('tools.mcp.modal.headersTip')}</div>
|
||||
<div className="body-xs-regular mb-2 text-text-tertiary">{t('tools.mcp.modal.headersTip')}</div>
|
||||
<HeadersInput
|
||||
headersItems={headers}
|
||||
onChange={setHeaders}
|
||||
@ -374,11 +377,11 @@ const MCPModal = ({
|
||||
authMethod === MCPAuthMethod.configurations && (
|
||||
<>
|
||||
<div>
|
||||
<div className='mb-1 flex h-6 items-center'>
|
||||
<span className='system-sm-medium text-text-secondary'>{t('tools.mcp.modal.timeout')}</span>
|
||||
<div className="mb-1 flex h-6 items-center">
|
||||
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.timeout')}</span>
|
||||
</div>
|
||||
<Input
|
||||
type='number'
|
||||
type="number"
|
||||
value={timeout}
|
||||
onChange={e => setMcpTimeout(Number(e.target.value))}
|
||||
onBlur={e => handleBlur(e.target.value.trim())}
|
||||
@ -386,11 +389,11 @@ const MCPModal = ({
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className='mb-1 flex h-6 items-center'>
|
||||
<span className='system-sm-medium text-text-secondary'>{t('tools.mcp.modal.sseReadTimeout')}</span>
|
||||
<div className="mb-1 flex h-6 items-center">
|
||||
<span className="system-sm-medium text-text-secondary">{t('tools.mcp.modal.sseReadTimeout')}</span>
|
||||
</div>
|
||||
<Input
|
||||
type='number'
|
||||
type="number"
|
||||
value={sseReadTimeout}
|
||||
onChange={e => setSseReadTimeout(Number(e.target.value))}
|
||||
onBlur={e => handleBlur(e.target.value.trim())}
|
||||
@ -401,21 +404,23 @@ const MCPModal = ({
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div className='flex flex-row-reverse pt-5'>
|
||||
<Button disabled={!name || !url || !serverIdentifier || isFetchingIcon} className='ml-2' variant='primary' onClick={submit}>{data ? t('tools.mcp.modal.save') : t('tools.mcp.modal.confirm')}</Button>
|
||||
<div className="flex flex-row-reverse pt-5">
|
||||
<Button disabled={!name || !url || !serverIdentifier || isFetchingIcon} className="ml-2" variant="primary" onClick={submit}>{data ? t('tools.mcp.modal.save') : t('tools.mcp.modal.confirm')}</Button>
|
||||
<Button onClick={onHide}>{t('tools.mcp.modal.cancel')}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
{showAppIconPicker && <AppIconPicker
|
||||
onSelect={(payload) => {
|
||||
setAppIcon(payload)
|
||||
setShowAppIconPicker(false)
|
||||
}}
|
||||
onClose={() => {
|
||||
setAppIcon(getIcon(data))
|
||||
setShowAppIconPicker(false)
|
||||
}}
|
||||
/>}
|
||||
{showAppIconPicker && (
|
||||
<AppIconPicker
|
||||
onSelect={(payload) => {
|
||||
setAppIcon(payload)
|
||||
setShowAppIconPicker(false)
|
||||
}}
|
||||
onClose={() => {
|
||||
setAppIcon(getIcon(data))
|
||||
setShowAppIconPicker(false)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
)
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
'use client'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import type { ToolWithProvider } from '../../workflow/types'
|
||||
import { RiHammerFill } from '@remixicon/react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import Icon from '@/app/components/plugins/card/base/card-icon'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
|
||||
import type { ToolWithProvider } from '../../workflow/types'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import MCPModal from './modal'
|
||||
import OperationDropdown from './detail/operation-dropdown'
|
||||
import { useDeleteMCP, useUpdateMCP } from '@/service/use-tools'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import OperationDropdown from './detail/operation-dropdown'
|
||||
import MCPModal from './modal'
|
||||
|
||||
type Props = {
|
||||
currentProvider?: ToolWithProvider
|
||||
@ -82,34 +82,34 @@ const MCPCard = ({
|
||||
currentProvider?.id === data.id && 'border-components-option-card-option-selected-border bg-components-card-bg-alt',
|
||||
)}
|
||||
>
|
||||
<div className='flex grow items-center gap-3 rounded-t-xl p-4'>
|
||||
<div className='shrink-0 overflow-hidden rounded-xl border border-components-panel-border-subtle'>
|
||||
<div className="flex grow items-center gap-3 rounded-t-xl p-4">
|
||||
<div className="shrink-0 overflow-hidden rounded-xl border border-components-panel-border-subtle">
|
||||
<Icon src={data.icon} />
|
||||
</div>
|
||||
<div className='grow'>
|
||||
<div className='system-md-semibold mb-1 truncate text-text-secondary' title={data.name}>{data.name}</div>
|
||||
<div className='system-xs-regular text-text-tertiary'>{data.server_identifier}</div>
|
||||
<div className="grow">
|
||||
<div className="system-md-semibold mb-1 truncate text-text-secondary" title={data.name}>{data.name}</div>
|
||||
<div className="system-xs-regular text-text-tertiary">{data.server_identifier}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center gap-1 rounded-b-xl pb-2.5 pl-4 pr-2.5 pt-1.5'>
|
||||
<div className='flex w-0 grow items-center gap-2'>
|
||||
<div className='flex items-center gap-1'>
|
||||
<RiHammerFill className='h-3 w-3 shrink-0 text-text-quaternary' />
|
||||
<div className="flex items-center gap-1 rounded-b-xl pb-2.5 pl-4 pr-2.5 pt-1.5">
|
||||
<div className="flex w-0 grow items-center gap-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<RiHammerFill className="h-3 w-3 shrink-0 text-text-quaternary" />
|
||||
{data.tools.length > 0 && (
|
||||
<div className='system-xs-regular shrink-0 text-text-tertiary'>{t('tools.mcp.toolsCount', { count: data.tools.length })}</div>
|
||||
<div className="system-xs-regular shrink-0 text-text-tertiary">{t('tools.mcp.toolsCount', { count: data.tools.length })}</div>
|
||||
)}
|
||||
{!data.tools.length && (
|
||||
<div className='system-xs-regular shrink-0 text-text-tertiary'>{t('tools.mcp.noTools')}</div>
|
||||
<div className="system-xs-regular shrink-0 text-text-tertiary">{t('tools.mcp.noTools')}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={cn('system-xs-regular text-divider-deep', (!data.is_team_authorization || !data.tools.length) && 'sm:hidden')}>/</div>
|
||||
<div className={cn('system-xs-regular truncate text-text-tertiary', (!data.is_team_authorization || !data.tools.length) && ' sm:hidden')} title={`${t('tools.mcp.updateTime')} ${formatTimeFromNow(data.updated_at! * 1000)}`}>{`${t('tools.mcp.updateTime')} ${formatTimeFromNow(data.updated_at! * 1000)}`}</div>
|
||||
</div>
|
||||
{data.is_team_authorization && data.tools.length > 0 && <Indicator color='green' className='shrink-0' />}
|
||||
{data.is_team_authorization && data.tools.length > 0 && <Indicator color="green" className="shrink-0" />}
|
||||
{(!data.is_team_authorization || !data.tools.length) && (
|
||||
<div className='system-xs-medium flex shrink-0 items-center gap-1 rounded-md border border-util-colors-red-red-500 bg-components-badge-bg-red-soft px-1.5 py-0.5 text-util-colors-red-red-500'>
|
||||
<div className="system-xs-medium flex shrink-0 items-center gap-1 rounded-md border border-util-colors-red-red-500 bg-components-badge-bg-red-soft px-1.5 py-0.5 text-util-colors-red-red-500">
|
||||
{t('tools.mcp.noConfigured')}
|
||||
<Indicator color='red' />
|
||||
<Indicator color="red" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -135,11 +135,11 @@ const MCPCard = ({
|
||||
<Confirm
|
||||
isShow
|
||||
title={t('tools.mcp.delete')}
|
||||
content={
|
||||
content={(
|
||||
<div>
|
||||
{t('tools.mcp.deleteConfirmTitle', { mcp: data.name })}
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
onCancel={hideDeleteConfirm}
|
||||
onConfirm={handleDelete}
|
||||
isLoading={deleting}
|
||||
|
||||
Reference in New Issue
Block a user