mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-01-03 02:55:29 +08:00
### What problem does this PR solve? Feat: Adjust the style of the canvas node #10703 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -1,13 +1,22 @@
|
||||
import { BulkOperateBar } from '@/components/bulk-operate-bar';
|
||||
import { CardContainer } from '@/components/card-container';
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import Spotlight from '@/components/spotlight';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { SearchInput } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
||||
import { useListMcpServer } from '@/hooks/use-mcp-request';
|
||||
import { pick } from 'lodash';
|
||||
import { Plus, SquareArrowOutDownLeft } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import {
|
||||
Download,
|
||||
LayoutList,
|
||||
ListChecks,
|
||||
Plus,
|
||||
Trash2,
|
||||
Upload,
|
||||
} from 'lucide-react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ProfileSettingWrapperCard } from '../components';
|
||||
import { EditMcpDialog } from './edit-mcp-dialog';
|
||||
@ -22,11 +31,19 @@ export default function McpServer() {
|
||||
useListMcpServer();
|
||||
const { editVisible, showEditModal, hideEditModal, handleOk, id, loading } =
|
||||
useEditMcp();
|
||||
const { list, selectedList, handleSelectChange } = useBulkOperateMCP();
|
||||
const {
|
||||
selectedList,
|
||||
handleSelectChange,
|
||||
handleDelete,
|
||||
handleExportMcp,
|
||||
handleSelectAll,
|
||||
} = useBulkOperateMCP(data.mcp_servers);
|
||||
const { t } = useTranslation();
|
||||
const { importVisible, showImportModal, hideImportModal, onImportOk } =
|
||||
useImportMcp();
|
||||
|
||||
const [isSelectionMode, setSelectionMode] = useState(false);
|
||||
|
||||
const handlePageChange = useCallback(
|
||||
(page: number, pageSize?: number) => {
|
||||
setPagination({ page, pageSize });
|
||||
@ -34,6 +51,10 @@ export default function McpServer() {
|
||||
[setPagination],
|
||||
);
|
||||
|
||||
const switchSelectionMode = useCallback(() => {
|
||||
setSelectionMode((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ProfileSettingWrapperCard
|
||||
header={
|
||||
@ -51,23 +72,51 @@ export default function McpServer() {
|
||||
value={searchString}
|
||||
onChange={handleInputChange}
|
||||
></SearchInput>
|
||||
<Button onClick={showEditModal('')}>
|
||||
<Plus /> {t('mcp.addMCP')}
|
||||
<Button variant={'secondary'} onClick={switchSelectionMode}>
|
||||
{isSelectionMode ? (
|
||||
<ListChecks className="size-3.5" />
|
||||
) : (
|
||||
<LayoutList className="size-3.5" />
|
||||
)}
|
||||
{t(`mcp.${isSelectionMode ? 'exitBulkManage' : 'bulkManage'}`)}
|
||||
</Button>
|
||||
<Button variant={'secondary'} onClick={showImportModal}>
|
||||
<SquareArrowOutDownLeft /> {t('mcp.import')}
|
||||
<Button variant={'secondary'} onClick={showEditModal('')}>
|
||||
<Plus className="size-3.5" /> {t('mcp.addMCP')}
|
||||
</Button>
|
||||
<Button onClick={showImportModal}>
|
||||
<Download className="size-3.5" />
|
||||
{t('mcp.import')}
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{selectedList.length > 0 && (
|
||||
<BulkOperateBar
|
||||
list={list}
|
||||
count={selectedList.length}
|
||||
className="mb-2.5"
|
||||
></BulkOperateBar>
|
||||
{isSelectionMode && (
|
||||
<section className="pb-5 flex items-center">
|
||||
<Checkbox id="all" onCheckedChange={handleSelectAll} />
|
||||
<Label
|
||||
className="pl-2 text-text-primary cursor-pointer"
|
||||
htmlFor="all"
|
||||
>
|
||||
{t('common.selectAll')}
|
||||
</Label>
|
||||
<span className="text-text-secondary pr-10 pl-5">
|
||||
{t('mcp.selected')} {selectedList.length}
|
||||
</span>
|
||||
<div className="flex gap-10 items-center">
|
||||
<Button variant={'secondary'} onClick={handleExportMcp}>
|
||||
<Upload className="size-3.5"></Upload>
|
||||
{t('mcp.export')}
|
||||
</Button>
|
||||
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||
<Button variant={'danger'}>
|
||||
<Trash2 className="size-3.5 cursor-pointer" />
|
||||
{t('common.delete')}
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
<CardContainer>
|
||||
{data.mcp_servers.map((item) => (
|
||||
@ -77,6 +126,7 @@ export default function McpServer() {
|
||||
selectedList={selectedList}
|
||||
handleSelectChange={handleSelectChange}
|
||||
showEditModal={showEditModal}
|
||||
isSelectionMode={isSelectionMode}
|
||||
></McpCard>
|
||||
))}
|
||||
</CardContainer>
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { MoreButton } from '@/components/more-button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { IMcpServer } from '@/interfaces/database/mcp';
|
||||
@ -6,12 +5,13 @@ import { formatDate } from '@/utils/date';
|
||||
import { isPlainObject } from 'lodash';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { McpDropdown } from './mcp-dropdown';
|
||||
import { McpOperation } from './mcp-operation';
|
||||
import { UseBulkOperateMCPReturnType } from './use-bulk-operate-mcp';
|
||||
import { UseEditMcpReturnType } from './use-edit-mcp';
|
||||
|
||||
export type DatasetCardProps = {
|
||||
data: IMcpServer;
|
||||
isSelectionMode: boolean;
|
||||
} & Pick<UseBulkOperateMCPReturnType, 'handleSelectChange' | 'selectedList'> &
|
||||
Pick<UseEditMcpReturnType, 'showEditModal'>;
|
||||
|
||||
@ -20,6 +20,7 @@ export function McpCard({
|
||||
selectedList,
|
||||
handleSelectChange,
|
||||
showEditModal,
|
||||
isSelectionMode,
|
||||
}: DatasetCardProps) {
|
||||
const { t } = useTranslation();
|
||||
const toolLength = useMemo(() => {
|
||||
@ -34,6 +35,7 @@ export function McpCard({
|
||||
handleSelectChange(data.id, checked);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card key={data.id}>
|
||||
<CardContent className="p-2.5 pt-2 group">
|
||||
@ -42,16 +44,20 @@ export function McpCard({
|
||||
{data.name}
|
||||
</h3>
|
||||
<div className="space-x-4">
|
||||
<McpDropdown mcpId={data.id} showEditModal={showEditModal}>
|
||||
<MoreButton></MoreButton>
|
||||
</McpDropdown>
|
||||
<Checkbox
|
||||
checked={selectedList.includes(data.id)}
|
||||
onCheckedChange={onCheckedChange}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
{isSelectionMode ? (
|
||||
<Checkbox
|
||||
checked={selectedList.includes(data.id)}
|
||||
onCheckedChange={onCheckedChange}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<McpOperation
|
||||
mcpId={data.id}
|
||||
showEditModal={showEditModal}
|
||||
></McpOperation>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
<div className="flex justify-between items-end text-xs text-text-secondary">
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { useDeleteMcpServer } from '@/hooks/use-mcp-request';
|
||||
import { PenLine, Trash2, Upload } from 'lucide-react';
|
||||
import { MouseEventHandler, PropsWithChildren, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { UseEditMcpReturnType } from './use-edit-mcp';
|
||||
import { useExportMcp } from './use-export-mcp';
|
||||
|
||||
export function McpDropdown({
|
||||
children,
|
||||
mcpId,
|
||||
showEditModal,
|
||||
}: PropsWithChildren & { mcpId: string } & Pick<
|
||||
UseEditMcpReturnType,
|
||||
'showEditModal'
|
||||
>) {
|
||||
const { t } = useTranslation();
|
||||
const { deleteMcpServer } = useDeleteMcpServer();
|
||||
const { handleExportMcpJson } = useExportMcp();
|
||||
|
||||
const handleDelete: MouseEventHandler<HTMLDivElement> = useCallback(() => {
|
||||
deleteMcpServer([mcpId]);
|
||||
}, [deleteMcpServer, mcpId]);
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem onClick={showEditModal(mcpId)}>
|
||||
{t('common.edit')} <PenLine />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={handleExportMcpJson([mcpId])}>
|
||||
{t('mcp.export')} <Upload />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||
<DropdownMenuItem
|
||||
className="text-state-error"
|
||||
onSelect={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{t('common.delete')} <Trash2 />
|
||||
</DropdownMenuItem>
|
||||
</ConfirmDeleteDialog>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
43
web/src/pages/profile-setting/mcp/mcp-operation.tsx
Normal file
43
web/src/pages/profile-setting/mcp/mcp-operation.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import { RAGFlowTooltip } from '@/components/ui/tooltip';
|
||||
import { useDeleteMcpServer } from '@/hooks/use-mcp-request';
|
||||
import { PenLine, Trash2, Upload } from 'lucide-react';
|
||||
import { MouseEventHandler, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { UseEditMcpReturnType } from './use-edit-mcp';
|
||||
import { useExportMcp } from './use-export-mcp';
|
||||
|
||||
export function McpOperation({
|
||||
mcpId,
|
||||
showEditModal,
|
||||
}: { mcpId: string } & Pick<UseEditMcpReturnType, 'showEditModal'>) {
|
||||
const { t } = useTranslation();
|
||||
const { deleteMcpServer } = useDeleteMcpServer();
|
||||
const { handleExportMcpJson } = useExportMcp();
|
||||
|
||||
const handleDelete: MouseEventHandler<HTMLDivElement> = useCallback(() => {
|
||||
deleteMcpServer([mcpId]);
|
||||
}, [deleteMcpServer, mcpId]);
|
||||
|
||||
return (
|
||||
<div className="hidden gap-3 group-hover:flex text-text-secondary">
|
||||
<RAGFlowTooltip tooltip={t('mcp.export')}>
|
||||
<Upload
|
||||
className="size-3 cursor-pointer"
|
||||
onClick={handleExportMcpJson([mcpId])}
|
||||
/>
|
||||
</RAGFlowTooltip>
|
||||
<RAGFlowTooltip tooltip={t('common.edit')}>
|
||||
<PenLine
|
||||
className="size-3 cursor-pointer"
|
||||
onClick={showEditModal(mcpId)}
|
||||
/>
|
||||
</RAGFlowTooltip>
|
||||
<RAGFlowTooltip tooltip={t('common.delete')}>
|
||||
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||
<Trash2 className="size-3 cursor-pointer" />
|
||||
</ConfirmDeleteDialog>
|
||||
</RAGFlowTooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,10 +1,11 @@
|
||||
import { useDeleteMcpServer } from '@/hooks/use-mcp-request';
|
||||
import { IMcpServer } from '@/interfaces/database/mcp';
|
||||
import { Trash2, Upload } from 'lucide-react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useExportMcp } from './use-export-mcp';
|
||||
|
||||
export function useBulkOperateMCP() {
|
||||
export function useBulkOperateMCP(mcpList: IMcpServer[]) {
|
||||
const { t } = useTranslation();
|
||||
const [selectedList, setSelectedList] = useState<Array<string>>([]);
|
||||
const { deleteMcpServer } = useDeleteMcpServer();
|
||||
@ -20,6 +21,13 @@ export function useBulkOperateMCP() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleSelectAll = useCallback(
|
||||
(checked: boolean) => {
|
||||
setSelectedList(() => (checked ? mcpList.map((item) => item.id) : []));
|
||||
},
|
||||
[mcpList],
|
||||
);
|
||||
|
||||
const list = [
|
||||
{
|
||||
id: 'export',
|
||||
@ -35,7 +43,14 @@ export function useBulkOperateMCP() {
|
||||
},
|
||||
];
|
||||
|
||||
return { list, selectedList, handleSelectChange };
|
||||
return {
|
||||
list,
|
||||
selectedList,
|
||||
handleSelectChange,
|
||||
handleDelete,
|
||||
handleExportMcp: handleExportMcpJson(selectedList),
|
||||
handleSelectAll,
|
||||
};
|
||||
}
|
||||
|
||||
export type UseBulkOperateMCPReturnType = ReturnType<typeof useBulkOperateMCP>;
|
||||
|
||||
Reference in New Issue
Block a user