mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Adjust the style of the mcp dialog #10703 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -51,8 +51,8 @@ export function Collapse({
|
|||||||
onOpenChange={handleOpenChange}
|
onOpenChange={handleOpenChange}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<CollapsibleTrigger className="w-full">
|
<CollapsibleTrigger className={'w-full'}>
|
||||||
<section className="flex justify-between items-center pb-2">
|
<section className="flex justify-between items-center">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<IconFontFill
|
<IconFontFill
|
||||||
name={`more`}
|
name={`more`}
|
||||||
@ -60,12 +60,18 @@ export function Collapse({
|
|||||||
'rotate-90': !currentOpen,
|
'rotate-90': !currentOpen,
|
||||||
})}
|
})}
|
||||||
></IconFontFill>
|
></IconFontFill>
|
||||||
{title}
|
<div
|
||||||
|
className={cn('text-text-secondary', {
|
||||||
|
'text-text-primary': open,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>{rightContent}</div>
|
<div>{rightContent}</div>
|
||||||
</section>
|
</section>
|
||||||
</CollapsibleTrigger>
|
</CollapsibleTrigger>
|
||||||
<CollapsibleContent>{children}</CollapsibleContent>
|
<CollapsibleContent className="pt-2">{children}</CollapsibleContent>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,13 +56,13 @@ export function ConfirmDeleteDialog({
|
|||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel onClick={onCancel}>
|
<AlertDialogCancel onClick={onCancel}>
|
||||||
{t('common.cancel')}
|
{t('common.no')}
|
||||||
</AlertDialogCancel>
|
</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
className="bg-state-error text-text-primary"
|
className="bg-state-error text-text-primary"
|
||||||
onClick={onOk}
|
onClick={onOk}
|
||||||
>
|
>
|
||||||
{t('common.ok')}
|
{t('common.yes')}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
|
|||||||
@ -73,7 +73,7 @@ const DialogFooter = ({
|
|||||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-4',
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import * as React from 'react';
|
|||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
const labelVariants = cva(
|
const labelVariants = cva(
|
||||||
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-text-secondary',
|
||||||
);
|
);
|
||||||
|
|
||||||
const Label = React.forwardRef<
|
const Label = React.forwardRef<
|
||||||
|
|||||||
@ -94,9 +94,9 @@ export const useShowDeleteConfirm = () => {
|
|||||||
title: title ?? t('common.deleteModalTitle'),
|
title: title ?? t('common.deleteModalTitle'),
|
||||||
icon: <ExclamationCircleFilled />,
|
icon: <ExclamationCircleFilled />,
|
||||||
content,
|
content,
|
||||||
okText: t('common.ok'),
|
okText: t('common.yes'),
|
||||||
okType: 'danger',
|
okType: 'danger',
|
||||||
cancelText: t('common.cancel'),
|
cancelText: t('common.no'),
|
||||||
async onOk() {
|
async onOk() {
|
||||||
try {
|
try {
|
||||||
const ret = await onOk?.();
|
const ret = await onOk?.();
|
||||||
|
|||||||
@ -6,8 +6,9 @@ export default {
|
|||||||
selectAll: 'Select All',
|
selectAll: 'Select All',
|
||||||
delete: 'Delete',
|
delete: 'Delete',
|
||||||
deleteModalTitle: 'Are you sure to delete this item?',
|
deleteModalTitle: 'Are you sure to delete this item?',
|
||||||
ok: 'Yes',
|
ok: 'Ok',
|
||||||
cancel: 'No',
|
cancel: 'Cancel',
|
||||||
|
yes: 'Yes',
|
||||||
no: 'No',
|
no: 'No',
|
||||||
total: 'Total',
|
total: 'Total',
|
||||||
rename: 'Rename',
|
rename: 'Rename',
|
||||||
@ -1744,6 +1745,7 @@ Important structured information may include: names, dates, locations, events, k
|
|||||||
toolsAvailable: 'tools available',
|
toolsAvailable: 'tools available',
|
||||||
mcpServers: 'MCP Servers',
|
mcpServers: 'MCP Servers',
|
||||||
customizeTheListOfMcpServers: 'Customize the list of MCP servers',
|
customizeTheListOfMcpServers: 'Customize the list of MCP servers',
|
||||||
|
cachedTools: 'cached tools',
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
searchApps: 'Search Apps',
|
searchApps: 'Search Apps',
|
||||||
|
|||||||
@ -6,8 +6,10 @@ export default {
|
|||||||
selectAll: '全选',
|
selectAll: '全选',
|
||||||
delete: '删除',
|
delete: '删除',
|
||||||
deleteModalTitle: '确定删除吗?',
|
deleteModalTitle: '确定删除吗?',
|
||||||
ok: '是',
|
ok: '确认',
|
||||||
cancel: '否',
|
cancel: '取消',
|
||||||
|
yes: '是',
|
||||||
|
no: '否',
|
||||||
total: '总共',
|
total: '总共',
|
||||||
rename: '重命名',
|
rename: '重命名',
|
||||||
name: '名称',
|
name: '名称',
|
||||||
@ -1631,6 +1633,7 @@ Tokenizer 会根据所选方式将内容存储为对应的数据结构。`,
|
|||||||
toolsAvailable: '可用的工具',
|
toolsAvailable: '可用的工具',
|
||||||
mcpServers: 'MCP 服务器',
|
mcpServers: 'MCP 服务器',
|
||||||
customizeTheListOfMcpServers: '自定义 MCP 服务器列表',
|
customizeTheListOfMcpServers: '自定义 MCP 服务器列表',
|
||||||
|
cachedTools: '缓存工具',
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
searchApps: '搜索',
|
searchApps: '搜索',
|
||||||
|
|||||||
@ -124,8 +124,8 @@ export const ParsingStatusCell = ({ record }: IProps) => {
|
|||||||
onConfirm={handleOperationIconClick(true)}
|
onConfirm={handleOperationIconClick(true)}
|
||||||
onCancel={handleOperationIconClick(false)}
|
onCancel={handleOperationIconClick(false)}
|
||||||
disabled={record.chunk_num === 0}
|
disabled={record.chunk_num === 0}
|
||||||
okText={t('common.ok')}
|
okText={t('common.yes')}
|
||||||
cancelText={t('common.cancel')}
|
cancelText={t('common.no')}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={classNames(styles.operationIcon)}
|
className={classNames(styles.operationIcon)}
|
||||||
|
|||||||
@ -1,5 +1,24 @@
|
|||||||
|
import { Card, CardContent, CardHeader } from '@/components/ui/card';
|
||||||
import { PropsWithChildren } from 'react';
|
import { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
export function Title({ children }: PropsWithChildren) {
|
export function Title({ children }: PropsWithChildren) {
|
||||||
return <span className="font-bold text-xl">{children}</span>;
|
return <span className="font-bold text-xl">{children}</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProfileSettingWrapperCardProps = {
|
||||||
|
header: React.ReactNode;
|
||||||
|
} & PropsWithChildren;
|
||||||
|
|
||||||
|
export function ProfileSettingWrapperCard({
|
||||||
|
header,
|
||||||
|
children,
|
||||||
|
}: ProfileSettingWrapperCardProps) {
|
||||||
|
return (
|
||||||
|
<Card className="w-full mb-5 border-border-button bg-transparent">
|
||||||
|
<CardHeader className="border-b border-border-button p-5">
|
||||||
|
{header}
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="p-5">{children}</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { Collapse } from '@/components/collapse';
|
import { Collapse } from '@/components/collapse';
|
||||||
import { Button, ButtonLoading } from '@/components/ui/button';
|
import { Button, ButtonLoading } from '@/components/ui/button';
|
||||||
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
|
DialogClose,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
@ -121,36 +123,44 @@ export function EditMcpDialog({
|
|||||||
form={form}
|
form={form}
|
||||||
setFieldChanged={setFieldChanged}
|
setFieldChanged={setFieldChanged}
|
||||||
></EditMcpForm>
|
></EditMcpForm>
|
||||||
<Collapse
|
<Card>
|
||||||
title={
|
<CardContent className="p-3">
|
||||||
<div>
|
<Collapse
|
||||||
{nextTools?.length || 0} {t('mcp.toolsAvailable')}
|
title={
|
||||||
</div>
|
<div>
|
||||||
}
|
{nextTools?.length || 0} {t('mcp.toolsAvailable')}
|
||||||
open={collapseOpen}
|
</div>
|
||||||
onOpenChange={setCollapseOpen}
|
}
|
||||||
rightContent={
|
open={collapseOpen}
|
||||||
<Button
|
onOpenChange={setCollapseOpen}
|
||||||
variant={'ghost'}
|
rightContent={
|
||||||
form={FormId}
|
<Button
|
||||||
type="submit"
|
variant={'transparent'}
|
||||||
onClick={handleTest}
|
form={FormId}
|
||||||
|
type="submit"
|
||||||
|
onClick={handleTest}
|
||||||
|
className="border-none p-0 hover:bg-transparent"
|
||||||
|
>
|
||||||
|
<RefreshCw
|
||||||
|
className={cn('text-text-secondary', {
|
||||||
|
'animate-spin': testLoading,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<RefreshCw
|
<div className="overflow-auto max-h-80 divide-y bg-bg-card rounded-md px-2.5">
|
||||||
className={cn('text-accent-primary', {
|
{nextTools?.map((x) => (
|
||||||
'animate-spin': testLoading,
|
<McpToolCard key={x.name} data={x}></McpToolCard>
|
||||||
})}
|
))}
|
||||||
/>
|
</div>
|
||||||
</Button>
|
</Collapse>
|
||||||
}
|
</CardContent>
|
||||||
>
|
</Card>
|
||||||
<div className="space-y-2.5 overflow-auto max-h-80">
|
|
||||||
{nextTools?.map((x) => (
|
|
||||||
<McpToolCard key={x.name} data={x}></McpToolCard>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</Collapse>
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button variant="outline">{t('common.cancel')}</Button>
|
||||||
|
</DialogClose>
|
||||||
<ButtonLoading
|
<ButtonLoading
|
||||||
type="submit"
|
type="submit"
|
||||||
form={FormId}
|
form={FormId}
|
||||||
|
|||||||
@ -89,7 +89,7 @@ export function EditMcpForm({
|
|||||||
name="name"
|
name="name"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('common.name')}</FormLabel>
|
<FormLabel required>{t('common.name')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder={t('common.mcp.namePlaceholder')}
|
placeholder={t('common.mcp.namePlaceholder')}
|
||||||
@ -106,7 +106,7 @@ export function EditMcpForm({
|
|||||||
name="url"
|
name="url"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('mcp.url')}</FormLabel>
|
<FormLabel required>{t('mcp.url')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
placeholder={t('common.mcp.urlPlaceholder')}
|
placeholder={t('common.mcp.urlPlaceholder')}
|
||||||
@ -127,7 +127,7 @@ export function EditMcpForm({
|
|||||||
name="server_type"
|
name="server_type"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>{t('mcp.serverType')}</FormLabel>
|
<FormLabel required>{t('mcp.serverType')}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<RAGFlowSelect
|
<RAGFlowSelect
|
||||||
{...field}
|
{...field}
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
import { BulkOperateBar } from '@/components/bulk-operate-bar';
|
import { BulkOperateBar } from '@/components/bulk-operate-bar';
|
||||||
import { CardContainer } from '@/components/card-container';
|
import { CardContainer } from '@/components/card-container';
|
||||||
|
import Spotlight from '@/components/spotlight';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { SearchInput } from '@/components/ui/input';
|
import { SearchInput } from '@/components/ui/input';
|
||||||
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
||||||
import { useListMcpServer } from '@/hooks/use-mcp-request';
|
import { useListMcpServer } from '@/hooks/use-mcp-request';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import { Import, Plus } from 'lucide-react';
|
import { Plus, SquareArrowOutDownLeft } from 'lucide-react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ProfileSettingWrapperCard } from '../components';
|
||||||
import { EditMcpDialog } from './edit-mcp-dialog';
|
import { EditMcpDialog } from './edit-mcp-dialog';
|
||||||
import { ImportMcpDialog } from './import-mcp-dialog';
|
import { ImportMcpDialog } from './import-mcp-dialog';
|
||||||
import { McpCard } from './mcp-card';
|
import { McpCard } from './mcp-card';
|
||||||
@ -33,27 +35,33 @@ export default function McpServer() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="p-4 w-full">
|
<ProfileSettingWrapperCard
|
||||||
<div className="text-text-primary text-2xl">{t('mcp.mcpServers')}</div>
|
header={
|
||||||
<section className="flex items-center justify-between pb-5">
|
<>
|
||||||
<div className="text-text-secondary">
|
<div className="text-text-primary text-2xl font-semibold">
|
||||||
{t('mcp.customizeTheListOfMcpServers')}
|
{t('mcp.mcpServers')}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-5">
|
<section className="flex items-center justify-between">
|
||||||
<SearchInput
|
<div className="text-text-secondary">
|
||||||
className="w-40"
|
{t('mcp.customizeTheListOfMcpServers')}
|
||||||
value={searchString}
|
</div>
|
||||||
onChange={handleInputChange}
|
<div className="flex gap-5">
|
||||||
></SearchInput>
|
<SearchInput
|
||||||
<Button variant={'secondary'} onClick={showImportModal}>
|
className="w-40"
|
||||||
<Import /> {t('mcp.import')}
|
value={searchString}
|
||||||
</Button>
|
onChange={handleInputChange}
|
||||||
<Button onClick={showEditModal('')}>
|
></SearchInput>
|
||||||
<Plus /> {t('mcp.addMCP')}
|
<Button onClick={showEditModal('')}>
|
||||||
</Button>
|
<Plus /> {t('mcp.addMCP')}
|
||||||
</div>
|
</Button>
|
||||||
</section>
|
<Button variant={'secondary'} onClick={showImportModal}>
|
||||||
|
<SquareArrowOutDownLeft /> {t('mcp.import')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
{selectedList.length > 0 && (
|
{selectedList.length > 0 && (
|
||||||
<BulkOperateBar
|
<BulkOperateBar
|
||||||
list={list}
|
list={list}
|
||||||
@ -93,6 +101,7 @@ export default function McpServer() {
|
|||||||
onOk={onImportOk}
|
onOk={onImportOk}
|
||||||
></ImportMcpDialog>
|
></ImportMcpDialog>
|
||||||
)}
|
)}
|
||||||
</section>
|
<Spotlight className="z-0" opcity={0.7} coverage={70} />
|
||||||
|
</ProfileSettingWrapperCard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { IMcpServer } from '@/interfaces/database/mcp';
|
|||||||
import { formatDate } from '@/utils/date';
|
import { formatDate } from '@/utils/date';
|
||||||
import { isPlainObject } from 'lodash';
|
import { isPlainObject } from 'lodash';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { McpDropdown } from './mcp-dropdown';
|
import { McpDropdown } from './mcp-dropdown';
|
||||||
import { UseBulkOperateMCPReturnType } from './use-bulk-operate-mcp';
|
import { UseBulkOperateMCPReturnType } from './use-bulk-operate-mcp';
|
||||||
import { UseEditMcpReturnType } from './use-edit-mcp';
|
import { UseEditMcpReturnType } from './use-edit-mcp';
|
||||||
@ -20,6 +21,7 @@ export function McpCard({
|
|||||||
handleSelectChange,
|
handleSelectChange,
|
||||||
showEditModal,
|
showEditModal,
|
||||||
}: DatasetCardProps) {
|
}: DatasetCardProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
const toolLength = useMemo(() => {
|
const toolLength = useMemo(() => {
|
||||||
const tools = data.variables?.tools;
|
const tools = data.variables?.tools;
|
||||||
if (isPlainObject(tools)) {
|
if (isPlainObject(tools)) {
|
||||||
@ -36,7 +38,9 @@ export function McpCard({
|
|||||||
<Card key={data.id}>
|
<Card key={data.id}>
|
||||||
<CardContent className="p-2.5 pt-2 group">
|
<CardContent className="p-2.5 pt-2 group">
|
||||||
<section className="flex justify-between pb-2">
|
<section className="flex justify-between pb-2">
|
||||||
<h3 className="text-lg font-semibold truncate flex-1">{data.name}</h3>
|
<h3 className="text-base font-normal truncate flex-1 text-text-primary">
|
||||||
|
{data.name}
|
||||||
|
</h3>
|
||||||
<div className="space-x-4">
|
<div className="space-x-4">
|
||||||
<McpDropdown mcpId={data.id} showEditModal={showEditModal}>
|
<McpDropdown mcpId={data.id} showEditModal={showEditModal}>
|
||||||
<MoreButton></MoreButton>
|
<MoreButton></MoreButton>
|
||||||
@ -50,14 +54,12 @@ export function McpCard({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<div className="flex justify-between items-end">
|
<div className="flex justify-between items-end text-xs text-text-secondary">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="text-base font-semibold mb-3 line-clamp-1 text-text-secondary">
|
<div className="line-clamp-1 pb-1">
|
||||||
{toolLength} cached tools
|
{toolLength} {t('mcp.cachedTools')}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-text-secondary">
|
<p>{formatDate(data.update_date)}</p>
|
||||||
{formatDate(data.update_date)}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { Card, CardContent } from '@/components/ui/card';
|
|
||||||
import { IMCPTool } from '@/interfaces/database/mcp';
|
import { IMCPTool } from '@/interfaces/database/mcp';
|
||||||
|
|
||||||
export type McpToolCardProps = {
|
export type McpToolCardProps = {
|
||||||
@ -7,13 +6,11 @@ export type McpToolCardProps = {
|
|||||||
|
|
||||||
export function McpToolCard({ data }: McpToolCardProps) {
|
export function McpToolCard({ data }: McpToolCardProps) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<section className="group py-2.5">
|
||||||
<CardContent className="p-2.5 pt-2 group">
|
<h3 className="text-sm font-semibold line-clamp-1 pb-2">{data.name}</h3>
|
||||||
<h3 className="text-sm font-semibold line-clamp-1 pb-2">{data.name}</h3>
|
<div className="text-xs font-normal text-text-secondary">
|
||||||
<div className="text-xs font-normal mb-3 text-text-secondary">
|
{data.description}
|
||||||
{data.description}
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user