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