mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 12:32:30 +08:00
Fix: Refactoring and enhancing the functionality of the delete confirmation dialog component #10703 (#11542)
### What problem does this PR solve? Fix: Refactoring and enhancing the functionality of the delete confirmation dialog component - Refactoring and enhancing the functionality of the delete confirmation dialog component - Modifying the style of the user center ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -1,9 +1,13 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { t } from 'i18next';
|
||||
import { BrushCleaning } from 'lucide-react';
|
||||
import { ReactNode, useCallback } from 'react';
|
||||
import { ConfirmDeleteDialog } from './confirm-delete-dialog';
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from './confirm-delete-dialog';
|
||||
import { Separator } from './ui/separator';
|
||||
|
||||
export type BulkOperateItemType = {
|
||||
@ -45,6 +49,15 @@ export function BulkOperateBar({
|
||||
<ConfirmDeleteDialog
|
||||
hidden={!isDeleteItem(x.id)}
|
||||
onOk={x.onClick}
|
||||
title={t('deleteModal.delFiles')}
|
||||
content={{
|
||||
title: t('common.deleteThem'),
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode
|
||||
name={`${t('deleteModal.delFilesContent', { count })}`}
|
||||
></ConfirmDeleteDialogNode>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
|
||||
@ -3,19 +3,30 @@ import {
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from '@/components/ui/alert-dialog';
|
||||
import { AlertDialogOverlay } from '@radix-ui/react-alert-dialog';
|
||||
import { DialogProps } from '@radix-ui/react-dialog';
|
||||
import { X } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RAGFlowAvatar } from './ragflow-avatar';
|
||||
import { Separator } from './ui/separator';
|
||||
|
||||
interface IProps {
|
||||
title?: string;
|
||||
onOk?: (...args: any[]) => any;
|
||||
onCancel?: (...args: any[]) => any;
|
||||
hidden?: boolean;
|
||||
content?: {
|
||||
title?: string;
|
||||
node?: React.ReactNode;
|
||||
};
|
||||
okButtonText?: string;
|
||||
cancelButtonText?: string;
|
||||
}
|
||||
|
||||
export function ConfirmDeleteDialog({
|
||||
@ -27,6 +38,9 @@ export function ConfirmDeleteDialog({
|
||||
onOpenChange,
|
||||
open,
|
||||
defaultOpen,
|
||||
content,
|
||||
okButtonText,
|
||||
cancelButtonText,
|
||||
}: IProps & DialogProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -41,32 +55,78 @@ export function ConfirmDeleteDialog({
|
||||
defaultOpen={defaultOpen}
|
||||
>
|
||||
<AlertDialogTrigger asChild>{children}</AlertDialogTrigger>
|
||||
<AlertDialogContent
|
||||
onSelect={(e) => e.preventDefault()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="bg-bg-base"
|
||||
<AlertDialogOverlay
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
{title ?? t('common.deleteModalTitle')}
|
||||
</AlertDialogTitle>
|
||||
{/* <AlertDialogDescription>
|
||||
This action cannot be undone. This will permanently delete your
|
||||
account and remove your data from our servers.
|
||||
</AlertDialogDescription> */}
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel onClick={onCancel}>
|
||||
{t('common.no')}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className="bg-state-error text-text-primary hover:text-text-primary hover:bg-state-error"
|
||||
onClick={onOk}
|
||||
>
|
||||
{t('common.yes')}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
<AlertDialogContent
|
||||
onSelect={(e) => e.preventDefault()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="bg-bg-base "
|
||||
>
|
||||
<AlertDialogHeader className="space-y-5">
|
||||
<AlertDialogTitle>
|
||||
{title ?? t('common.deleteModalTitle')}
|
||||
<AlertDialogCancel
|
||||
onClick={onCancel}
|
||||
className="border-none bg-transparent hover:border-none hover:bg-transparent absolute right-3 top-3 hover:text-text-primary"
|
||||
>
|
||||
<X size={16} />
|
||||
</AlertDialogCancel>
|
||||
</AlertDialogTitle>
|
||||
{content && (
|
||||
<>
|
||||
<Separator className="w-[calc(100%+48px)] -translate-x-6"></Separator>
|
||||
<AlertDialogDescription className="mt-5">
|
||||
<div className="flex flex-col gap-5 text-base mb-10 px-5">
|
||||
<div className="text-text-primary">
|
||||
{content.title || t('common.deleteModalTitle')}
|
||||
</div>
|
||||
{content.node}
|
||||
</div>
|
||||
</AlertDialogDescription>
|
||||
</>
|
||||
)}
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter className="px-5 flex items-center gap-2">
|
||||
<AlertDialogCancel onClick={onCancel}>
|
||||
{okButtonText || t('common.cancel')}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className="bg-state-error text-text-primary hover:text-text-primary hover:bg-state-error"
|
||||
onClick={onOk}
|
||||
>
|
||||
{cancelButtonText || t('common.delete')}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialogOverlay>
|
||||
</AlertDialog>
|
||||
);
|
||||
}
|
||||
|
||||
export const ConfirmDeleteDialogNode = ({
|
||||
avatar,
|
||||
name,
|
||||
children,
|
||||
}: {
|
||||
avatar?: { avatar?: string; name?: string; isPerson?: boolean };
|
||||
name?: string;
|
||||
children?: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex items-center border-0.5 text-text-secondary border-border-button rounded-lg px-3 py-4">
|
||||
{avatar && (
|
||||
<RAGFlowAvatar
|
||||
className="w-8 h-8"
|
||||
avatar={avatar.avatar}
|
||||
isPerson={avatar.isPerson}
|
||||
name={avatar.name}
|
||||
/>
|
||||
)}
|
||||
{name && <div className="ml-3">{name}</div>}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -274,7 +274,7 @@ export function FileUploader(props: FileUploaderProps) {
|
||||
className={cn(
|
||||
'group relative grid h-72 w-full cursor-pointer place-items-center rounded-lg border border-dashed border-border-default px-5 py-2.5 text-center transition hover:bg-border-button bg-bg-card',
|
||||
'ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
||||
isDragActive && 'border-muted-foreground/50',
|
||||
isDragActive && 'border-border-button',
|
||||
isDisabled && 'pointer-events-none opacity-60',
|
||||
className,
|
||||
)}
|
||||
@ -285,7 +285,7 @@ export function FileUploader(props: FileUploaderProps) {
|
||||
<div className="flex flex-col items-center justify-center gap-4 sm:px-5">
|
||||
<div className="rounded-full border border-dashed p-3">
|
||||
<Upload
|
||||
className="size-7 text-text-secondary"
|
||||
className="size-7 text-text-secondary hover:text-text-primary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
@ -297,7 +297,7 @@ export function FileUploader(props: FileUploaderProps) {
|
||||
<div className="flex flex-col items-center justify-center gap-4 sm:px-5">
|
||||
<div className="rounded-full border border-dashed p-3">
|
||||
<Upload
|
||||
className="size-7 text-text-secondary"
|
||||
className="size-7 text-text-secondary hover:text-text-primary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -186,7 +186,9 @@ export const SelectWithSearch = forwardRef<
|
||||
/>
|
||||
)}
|
||||
<CommandList className="mt-2 outline-none">
|
||||
<CommandEmpty>{emptyData}</CommandEmpty>
|
||||
<CommandEmpty>
|
||||
<div dangerouslySetInnerHTML={{ __html: emptyData }}></div>
|
||||
</CommandEmpty>
|
||||
{options.map((group, idx) => {
|
||||
if (group.options) {
|
||||
return (
|
||||
|
||||
@ -53,6 +53,11 @@ const buttonVariants = cva(
|
||||
bg-text-primary text-bg-base border-b-4 border-b-accent-primary
|
||||
hover:bg-text-primary/90 focus-visible:bg-text-primary/90
|
||||
`,
|
||||
delete: `
|
||||
text-text-secondary
|
||||
hover:bg-state-error-5 hover:text-state-error
|
||||
focus-visible:text-state-error focus-visible:bg-state-error-5
|
||||
`,
|
||||
},
|
||||
size: {
|
||||
default: 'h-8 px-2.5 py-1.5 ',
|
||||
|
||||
@ -76,6 +76,7 @@ export function useDynamicSVGImport(
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
header?: string | ReactNode;
|
||||
title?: string;
|
||||
content?: ReactNode;
|
||||
onOk?: (...args: any[]) => any;
|
||||
@ -85,19 +86,19 @@ interface IProps {
|
||||
export const useShowDeleteConfirm = () => {
|
||||
const { t } = useTranslation();
|
||||
const showDeleteConfirm = useCallback(
|
||||
({ title, content, onOk, onCancel }: IProps): Promise<number> => {
|
||||
({ title, content, onOk, onCancel, header }: IProps): Promise<number> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
Modal.show({
|
||||
// title: title ?? t('common.deleteModalTitle'),
|
||||
closable: false,
|
||||
title: header,
|
||||
closable: !!header,
|
||||
visible: true,
|
||||
onVisibleChange: () => {
|
||||
Modal.hide();
|
||||
Modal.destroy();
|
||||
},
|
||||
footer: null,
|
||||
maskClosable: false,
|
||||
okText: t('common.yes'),
|
||||
cancelText: t('common.no'),
|
||||
okText: t('common.delete'),
|
||||
cancelText: t('common.cancel'),
|
||||
style: {
|
||||
width: '450px',
|
||||
},
|
||||
@ -114,7 +115,7 @@ export const useShowDeleteConfirm = () => {
|
||||
},
|
||||
onCancel: () => {
|
||||
onCancel?.();
|
||||
Modal.hide();
|
||||
Modal.destroy();
|
||||
},
|
||||
children: (
|
||||
<div className="flex flex-col justify-start items-start mt-3">
|
||||
|
||||
@ -7,7 +7,8 @@ export default {
|
||||
selectPlaceholder: 'select value',
|
||||
selectAll: 'Select all',
|
||||
delete: 'Delete',
|
||||
deleteModalTitle: 'Are you sure to delete this item?',
|
||||
deleteModalTitle: 'Are you sure to delete it ?',
|
||||
deleteThem: 'Are you sure to delete them ?',
|
||||
ok: 'Ok',
|
||||
cancel: 'Cancel',
|
||||
yes: 'Yes',
|
||||
@ -59,6 +60,7 @@ export default {
|
||||
urlPlaceholder: 'https://api.example.com/v1/mcp',
|
||||
tokenPlaceholder: 'e.g. eyJhbGciOiJIUzI1Ni...',
|
||||
},
|
||||
selected: 'Selected',
|
||||
},
|
||||
login: {
|
||||
loginTitle: 'Sign in to Your Account',
|
||||
@ -92,7 +94,7 @@ export default {
|
||||
home: 'Home',
|
||||
setting: 'User settings',
|
||||
logout: 'Log out',
|
||||
fileManager: 'File Management',
|
||||
fileManager: 'File',
|
||||
flow: 'Agent',
|
||||
search: 'Search',
|
||||
welcome: 'Welcome to',
|
||||
@ -696,8 +698,9 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
||||
tocEnhanceTip: ` During the parsing of the document, table of contents information was generated (see the 'Enable Table of Contents Extraction' option in the General method). This allows the large model to return table of contents items relevant to the user's query, thereby using these items to retrieve related chunks and apply weighting to these chunks during the sorting process. This approach is derived from mimicking the behavioral logic of how humans search for knowledge in books.`,
|
||||
},
|
||||
setting: {
|
||||
deleteModel: 'Delete model',
|
||||
modelEmptyTip:
|
||||
'No models available. Please add models from the panel on the right.',
|
||||
'No models available. <br>Please add models from the panel on the right.',
|
||||
sourceEmptyTip: 'No data sources added yet. Select one below to connect.',
|
||||
seconds: 'seconds',
|
||||
minutes: 'minutes',
|
||||
@ -1917,6 +1920,7 @@ Important structured information may include: names, dates, locations, events, k
|
||||
editMCP: 'Edit MCP',
|
||||
toolsAvailable: 'tools available',
|
||||
mcpServers: 'MCP servers',
|
||||
mcpServer: 'MCP server',
|
||||
customizeTheListOfMcpServers: 'Customize the list of MCP servers',
|
||||
cachedTools: 'cached tools',
|
||||
bulkManage: 'Bulk manage',
|
||||
@ -2014,6 +2018,18 @@ Important structured information may include: names, dates, locations, events, k
|
||||
processingFailedTip: 'Total failed processes',
|
||||
processing: 'Processing',
|
||||
},
|
||||
|
||||
deleteModal: {
|
||||
delAgent: 'Delete agent',
|
||||
delDataset: 'Delete dataset',
|
||||
delSearch: 'Delete search',
|
||||
delFile: 'Delete file',
|
||||
delFiles: 'Delete files',
|
||||
delFilesContent: 'Selected {{count}} files',
|
||||
delChat: 'Delete chat',
|
||||
delMember: 'Delete member',
|
||||
},
|
||||
|
||||
admin: {
|
||||
loginTitle: 'Admin Console',
|
||||
title: 'RAGFlow',
|
||||
|
||||
@ -8,6 +8,7 @@ export default {
|
||||
selectAll: '全选',
|
||||
delete: '删除',
|
||||
deleteModalTitle: '确定删除吗?',
|
||||
deleteThem: '确定要删除吗?',
|
||||
ok: '确认',
|
||||
cancel: '取消',
|
||||
yes: '是',
|
||||
@ -51,6 +52,7 @@ export default {
|
||||
noDataFound: '没有找到数据。',
|
||||
noData: '暂无数据',
|
||||
promptPlaceholder: '请输入或使用 / 快速插入变量。',
|
||||
selected: '已选择',
|
||||
},
|
||||
login: {
|
||||
loginTitle: '登录账户',
|
||||
@ -685,7 +687,8 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
||||
tocEnhanceTip: `解析文档时生成了目录信息(见General方法的‘启用目录抽取’),让大模型返回和用户问题相关的目录项,从而利用目录项拿到相关chunk,对这些chunk在排序中进行加权。这种方法来源于模仿人类查询书本中知识的行为逻辑`,
|
||||
},
|
||||
setting: {
|
||||
modelEmptyTip: '暂无可用模型,请先在右侧面板添加模型。',
|
||||
deleteModel: '删除模型',
|
||||
modelEmptyTip: '暂无可用模型,<br>请先在右侧面板添加模型。',
|
||||
sourceEmptyTip: '暂未添加任何数据源,请从下方选择一个进行连接。',
|
||||
seconds: '秒',
|
||||
minutes: '分',
|
||||
@ -1770,6 +1773,7 @@ Tokenizer 会根据所选方式将内容存储为对应的数据结构。`,
|
||||
editMCP: '编辑 MCP',
|
||||
toolsAvailable: '可用的工具',
|
||||
mcpServers: 'MCP 服务器',
|
||||
mcpServer: 'MCP 服务器',
|
||||
customizeTheListOfMcpServers: '自定义 MCP 服务器列表',
|
||||
cachedTools: '缓存工具',
|
||||
selected: '已选择',
|
||||
@ -1866,5 +1870,16 @@ Tokenizer 会根据所选方式将内容存储为对应的数据结构。`,
|
||||
processingSuccessTip: '处理成功的文件总数',
|
||||
processingFailedTip: '处理失败的文件总数',
|
||||
},
|
||||
|
||||
deleteModal: {
|
||||
delAgent: '删除智能体',
|
||||
delDataset: '删除知识库',
|
||||
delSearch: '删除搜索',
|
||||
delFile: '删除文件',
|
||||
delFiles: '删除文件',
|
||||
delFilesContent: '已选择 {{count}} 个文件',
|
||||
delChat: '删除聊天',
|
||||
delMember: '删除成员',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@ -45,7 +48,18 @@ export function AgentDropdown({
|
||||
{t('common.rename')} <PenLine />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||
<ConfirmDeleteDialog
|
||||
onOk={handleDelete}
|
||||
title={t('deleteModal.delAgent')}
|
||||
content={{
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode
|
||||
avatar={{ avatar: agent.avatar, name: agent.title }}
|
||||
name={agent.title}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className="text-state-error"
|
||||
onSelect={(e) => {
|
||||
|
||||
@ -3,6 +3,7 @@ import isEmpty from 'lodash/isEmpty';
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { buildNodesAndCombos } from './util';
|
||||
|
||||
import { useIsDarkTheme } from '@/components/theme-provider';
|
||||
import styles from './index.less';
|
||||
|
||||
const TooltipColorMap = {
|
||||
@ -19,7 +20,7 @@ interface IProps {
|
||||
const ForceGraph = ({ data, show }: IProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const graphRef = useRef<Graph | null>(null);
|
||||
|
||||
const isDark = useIsDarkTheme();
|
||||
const nextData = useMemo(() => {
|
||||
if (!isEmpty(data)) {
|
||||
const graphData = data;
|
||||
@ -80,8 +81,13 @@ const ForceGraph = ({ data, show }: IProps) => {
|
||||
},
|
||||
node: {
|
||||
style: {
|
||||
size: 150,
|
||||
size: (d) => {
|
||||
let size = 100 + ((d.rank as number) || 0) * 5;
|
||||
size = size > 300 ? 300 : size;
|
||||
return size;
|
||||
},
|
||||
labelText: (d) => d.id,
|
||||
labelFill: isDark ? 'rgba(255,255,255,1)' : 'rgba(0,0,0,1)',
|
||||
// labelPadding: 30,
|
||||
labelFontSize: 40,
|
||||
// labelOffsetX: 20,
|
||||
@ -101,8 +107,9 @@ const ForceGraph = ({ data, show }: IProps) => {
|
||||
const weight: number = Number(model?.weight) || 2;
|
||||
const lineWeight = weight * 4;
|
||||
return {
|
||||
stroke: '#99ADD1',
|
||||
lineWidth: lineWeight > 10 ? 10 : lineWeight,
|
||||
stroke: isDark ? 'rgba(255,255,255,0.5)' : 'rgba(0,0,0,0.5)',
|
||||
lineDash: [10, 10],
|
||||
lineWidth: lineWeight > 8 ? 8 : lineWeight,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@ -45,7 +48,18 @@ export function DatasetDropdown({
|
||||
{t('common.rename')} <PenLine />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||
<ConfirmDeleteDialog
|
||||
onOk={handleDelete}
|
||||
title={t('deleteModal.delDataset')}
|
||||
content={{
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode
|
||||
avatar={{ avatar: dataset.avatar, name: dataset.name }}
|
||||
name={dataset.name}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className="text-state-error"
|
||||
onSelect={(e) => {
|
||||
|
||||
@ -1,13 +1,19 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import { FileIcon } from '@/components/icon-font';
|
||||
import NewDocumentLink from '@/components/new-document-link';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useDownloadFile } from '@/hooks/file-manager-hooks';
|
||||
import { IFile } from '@/interfaces/database/file-manager';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
getExtension,
|
||||
isSupportedPreviewDocumentType,
|
||||
} from '@/utils/document-util';
|
||||
import { CellContext } from '@tanstack/react-table';
|
||||
import { t } from 'i18next';
|
||||
import {
|
||||
ArrowDownToLine,
|
||||
Eye,
|
||||
@ -38,6 +44,9 @@ export function ActionCell({
|
||||
}: IProps) {
|
||||
const record = row.original;
|
||||
const documentId = record.id;
|
||||
const name: string = row.getValue('name');
|
||||
const type = record.type;
|
||||
|
||||
const { downloadFile } = useDownloadFile();
|
||||
const isFolder = isFolderType(record.type);
|
||||
const extension = getExtension(record.name);
|
||||
@ -151,7 +160,28 @@ export function ActionCell({
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu> */}
|
||||
{isKnowledgeBase || (
|
||||
<ConfirmDeleteDialog onOk={onRemoveFile}>
|
||||
<ConfirmDeleteDialog
|
||||
onOk={onRemoveFile}
|
||||
title={t('deleteModal.delFile')}
|
||||
content={{
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode>
|
||||
<div className="flex items-center gap-2 text-text-secondary">
|
||||
<span className="size-4">
|
||||
<FileIcon name={name} type={type}></FileIcon>
|
||||
</span>
|
||||
<span
|
||||
className={cn('truncate text-xs', {
|
||||
['cursor-pointer']: isFolder,
|
||||
})}
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
</ConfirmDeleteDialogNode>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="transparent"
|
||||
className="border-none hover:bg-bg-card text-text-primary"
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@ -45,7 +48,18 @@ export function ChatDropdown({
|
||||
{t('common.rename')} <PenLine />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||
<ConfirmDeleteDialog
|
||||
onOk={handleDelete}
|
||||
title={t('deleteModal.delChat')}
|
||||
content={{
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode
|
||||
avatar={{ avatar: chat.icon, name: chat.name }}
|
||||
name={chat.name}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className="text-state-error"
|
||||
onSelect={(e) => {
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@ -41,9 +44,20 @@ export function SearchDropdown({
|
||||
{t('common.rename')} <PenLine />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||
<ConfirmDeleteDialog
|
||||
onOk={handleDelete}
|
||||
title={t('deleteModal.delSearch')}
|
||||
content={{
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode
|
||||
avatar={{ avatar: dataset.avatar, name: dataset.name }}
|
||||
name={dataset.name}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className="text-text-delete-red"
|
||||
className="text-state-error"
|
||||
onSelect={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
|
||||
@ -31,7 +31,7 @@ export const AddedSourceCard = (props: IAddedSourceCardProps) => {
|
||||
key={item.id}
|
||||
className="flex flex-row items-center justify-between rounded-md bg-bg-card px-[10px] py-4"
|
||||
>
|
||||
<div className="text-sm text-text-secondary ">{item.name}</div>
|
||||
<div className="text-sm text-text-primary ">{item.name}</div>
|
||||
<div className="text-sm text-text-secondary flex gap-2">
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
|
||||
@ -21,28 +21,33 @@ export const delSourceModal = <T extends IDataSourceBase>(
|
||||
? t('setting.deleteSourceModalTitle')
|
||||
: t('dataflowParser.unlinkSourceModalTitle'),
|
||||
content: (
|
||||
<div className="px-2 py-6">
|
||||
<div className="flex items-center gap-1 p-2 border border-border-button rounded-md mb-3">
|
||||
<div className="w-6 h-6 flex-shrink-0">
|
||||
{data?.source ? DataSourceInfo[data?.source].icon : ''}
|
||||
</div>
|
||||
<div>{data?.name}</div>
|
||||
</div>
|
||||
<div className="px-2 space-y-6 pt-5 pb-3">
|
||||
{type === 'delete' ? (
|
||||
<div
|
||||
className="text-sm text-text-secondary"
|
||||
className="text-base text-text-primary"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: t('setting.deleteSourceModalContent'),
|
||||
}}
|
||||
></div>
|
||||
) : (
|
||||
<div
|
||||
className="text-sm text-text-secondary"
|
||||
className="text-base text-text-primary"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: t('dataflowParser.unlinkSourceModalContent'),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center gap-1 p-2 border border-border-button rounded-md mb-3">
|
||||
<div className="w-6 h-6 flex-shrink-0">
|
||||
{data?.source ? DataSourceInfo[data?.source].icon : ''}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-text-secondary text-xs">
|
||||
{/* <div className="h-6 flex-shrink-0 text-text-primary text-base">
|
||||
{data?.source ? DataSourceInfo[data?.source].name : ''}
|
||||
</div> */}
|
||||
{data?.name}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
confirmText:
|
||||
@ -56,12 +61,13 @@ export const delSourceModal = <T extends IDataSourceBase>(
|
||||
...otherProps,
|
||||
title: config.title,
|
||||
children: config.content,
|
||||
titleClassName: 'border-b border-border-button',
|
||||
onVisibleChange: () => {
|
||||
Modal.hide();
|
||||
Modal.destroy();
|
||||
},
|
||||
footer: (
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant={'outline'} onClick={() => Modal.hide()}>
|
||||
<Button variant={'outline'} onClick={() => Modal.destroy()}>
|
||||
{t('dataflowParser.changeStepModalCancelText')}
|
||||
</Button>
|
||||
<Button
|
||||
@ -69,7 +75,7 @@ export const delSourceModal = <T extends IDataSourceBase>(
|
||||
className="!bg-state-error text-text-base"
|
||||
onClick={() => {
|
||||
onOk?.(data);
|
||||
Modal.hide();
|
||||
Modal.destroy();
|
||||
}}
|
||||
>
|
||||
{config.confirmText}
|
||||
|
||||
@ -84,7 +84,7 @@ const DataSource = () => {
|
||||
>
|
||||
<Spotlight />
|
||||
<div className="relative">
|
||||
<div className=" flex flex-col gap-4 max-h-[calc(100vh-230px)] overflow-y-auto overflow-x-hidden scrollbar-auto">
|
||||
<div className=" flex flex-col gap-4 max-h-[calc(100vh-235px)] overflow-y-auto overflow-x-hidden scrollbar-auto">
|
||||
<div className="flex flex-col gap-3">
|
||||
{categorizedList?.length <= 0 && (
|
||||
<div className="text-text-secondary w-full flex justify-center items-center h-20">
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { CardContainer } from '@/components/card-container';
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import Spotlight from '@/components/spotlight';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
@ -110,7 +113,18 @@ export default function McpServer() {
|
||||
<Upload className="size-3.5"></Upload>
|
||||
{t('mcp.export')}
|
||||
</Button>
|
||||
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||
<ConfirmDeleteDialog
|
||||
onOk={handleDelete}
|
||||
title={t('common.delete') + ' ' + t('mcp.mcpServers')}
|
||||
content={{
|
||||
title: t('common.deleteThem'),
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode
|
||||
name={`${t('mcp.selected')} ${selectedList.length} ${t('mcp.mcpServers')}`}
|
||||
></ConfirmDeleteDialogNode>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Button variant={'danger'}>
|
||||
<Trash2 className="size-3.5 cursor-pointer" />
|
||||
{t('common.delete')}
|
||||
|
||||
@ -54,7 +54,7 @@ export function McpCard({
|
||||
/>
|
||||
) : (
|
||||
<McpOperation
|
||||
mcpId={data.id}
|
||||
mcp={data}
|
||||
showEditModal={showEditModal}
|
||||
></McpOperation>
|
||||
)}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import { useDeleteMcpServer } from '@/hooks/use-mcp-request';
|
||||
import { IMcpServer } from '@/interfaces/database/mcp';
|
||||
import { PenLine, Trash2, Upload } from 'lucide-react';
|
||||
import { MouseEventHandler, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -7,33 +11,41 @@ import { UseEditMcpReturnType } from './use-edit-mcp';
|
||||
import { useExportMcp } from './use-export-mcp';
|
||||
|
||||
export function McpOperation({
|
||||
mcpId,
|
||||
mcp,
|
||||
showEditModal,
|
||||
}: { mcpId: string } & Pick<UseEditMcpReturnType, 'showEditModal'>) {
|
||||
}: { mcp: IMcpServer } & Pick<UseEditMcpReturnType, 'showEditModal'>) {
|
||||
const { t } = useTranslation();
|
||||
const { deleteMcpServer } = useDeleteMcpServer();
|
||||
const { handleExportMcpJson } = useExportMcp();
|
||||
|
||||
const handleDelete: MouseEventHandler<HTMLDivElement> = useCallback(() => {
|
||||
deleteMcpServer([mcpId]);
|
||||
}, [deleteMcpServer, mcpId]);
|
||||
deleteMcpServer([mcp.id]);
|
||||
}, [deleteMcpServer, mcp.id]);
|
||||
|
||||
return (
|
||||
<div className="hidden gap-1 group-hover:flex text-text-secondary">
|
||||
{/* <RAGFlowTooltip tooltip={t('mcp.export')}> */}
|
||||
<Upload
|
||||
className="size-5 cursor-pointer p-1 rounded-sm hover:text-text-primary hover:bg-bg-card"
|
||||
onClick={handleExportMcpJson([mcpId])}
|
||||
onClick={handleExportMcpJson([mcp.id])}
|
||||
/>
|
||||
{/* </RAGFlowTooltip>
|
||||
<RAGFlowTooltip tooltip={t('common.edit')}> */}
|
||||
<PenLine
|
||||
className="size-5 cursor-pointer p-1 rounded-sm hover:text-text-primary hover:bg-bg-card"
|
||||
onClick={showEditModal(mcpId)}
|
||||
onClick={showEditModal(mcp.id)}
|
||||
/>
|
||||
{/* </RAGFlowTooltip>
|
||||
<RAGFlowTooltip tooltip={t('common.delete')}> */}
|
||||
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||
<ConfirmDeleteDialog
|
||||
onOk={handleDelete}
|
||||
title={t('common.delete') + ' ' + t('mcp.mcpServer')}
|
||||
content={{
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode name={mcp.name}></ConfirmDeleteDialogNode>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Trash2 className="size-5 cursor-pointer p-1 rounded-sm hover:text-state-error hover:bg-state-error-5" />
|
||||
</ConfirmDeleteDialog>
|
||||
{/* </RAGFlowTooltip> */}
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
// src/components/ModelProviderCard.tsx
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import { LlmIcon } from '@/components/svg-icon';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
@ -54,7 +58,7 @@ export const ModelProviderCard: FC<IModelCardProps> = ({
|
||||
const { visible, switchVisible } = useSetModalState();
|
||||
const { t } = useTranslate('setting');
|
||||
const { handleEnableLlm } = useHandleEnableLlm(item.name);
|
||||
const { handleDeleteFactory } = useHandleDeleteFactory(item.name);
|
||||
const { deleteFactory } = useHandleDeleteFactory(item.name);
|
||||
|
||||
const handleApiKeyClick = () => {
|
||||
clickApiKey(item.name);
|
||||
@ -102,16 +106,31 @@ export const ModelProviderCard: FC<IModelCardProps> = ({
|
||||
{!visible ? <ChevronsDown /> : <ChevronsUp />}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDeleteFactory();
|
||||
<ConfirmDeleteDialog
|
||||
onOk={() => deleteFactory({ llm_factory: item.name })}
|
||||
title={t('deleteModel')}
|
||||
content={{
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode>
|
||||
<div className="flex items-center gap-2">
|
||||
<LlmIcon name={item.name} />
|
||||
{item.name}
|
||||
</div>
|
||||
</ConfirmDeleteDialogNode>
|
||||
),
|
||||
}}
|
||||
className=" hover:text-state-error hover:bg-state-error-5 transition-colors border border-border-default"
|
||||
>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
// onClick={(e) => {
|
||||
// e.stopPropagation();
|
||||
// handleDeleteFactory(item);
|
||||
// }}
|
||||
className=" hover:text-state-error hover:bg-state-error-5 transition-colors border border-border-default"
|
||||
>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
// src/components/AvailableModels.tsx
|
||||
import { LlmIcon } from '@/components/svg-icon';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { SearchInput } from '@/components/ui/input';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { useSelectLlmList } from '@/hooks/llm-hooks';
|
||||
import { Plus, Search } from 'lucide-react';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { FC, useMemo, useState } from 'react';
|
||||
|
||||
type TagType =
|
||||
@ -77,16 +77,16 @@ export const AvailableModels: FC<{
|
||||
</div>
|
||||
{/* Search Bar */}
|
||||
<div className="mb-6">
|
||||
<div className="relative">
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={t('search')}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="w-full px-4 py-2 pl-10 bg-bg-input border border-border-default rounded-lg focus:outline-none focus:ring-1 focus:ring-border-button transition-colors"
|
||||
/>
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-text-secondary" />
|
||||
</div>
|
||||
{/* <div className="relative"> */}
|
||||
<SearchInput
|
||||
type="text"
|
||||
placeholder={t('search')}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="w-full px-4 py-2 pl-10 bg-bg-input border border-border-default rounded-lg focus:outline-none focus:ring-1 focus:ring-border-button transition-colors"
|
||||
/>
|
||||
{/* <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-text-secondary" /> */}
|
||||
{/* </div> */}
|
||||
</div>
|
||||
|
||||
{/* Tags Filter */}
|
||||
|
||||
@ -457,5 +457,5 @@ export const useHandleDeleteFactory = (llmFactory: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
return { handleDeleteFactory };
|
||||
return { handleDeleteFactory, deleteFactory };
|
||||
};
|
||||
@ -51,7 +51,7 @@ export const useHandleDeleteUser = () => {
|
||||
});
|
||||
};
|
||||
|
||||
return { handleDeleteTenantUser, loading };
|
||||
return { handleDeleteTenantUser, deleteTenantUser, loading };
|
||||
};
|
||||
|
||||
export const useHandleAgreeTenant = () => {
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
import {
|
||||
ConfirmDeleteDialog,
|
||||
ConfirmDeleteDialogNode,
|
||||
} from '@/components/confirm-delete-dialog';
|
||||
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@ -26,7 +30,7 @@ const ColorMap: Record<string, string> = {
|
||||
|
||||
const UserTable = ({ searchUser }: { searchUser: string }) => {
|
||||
const { data, loading } = useListTenantUser();
|
||||
const { handleDeleteTenantUser } = useHandleDeleteUser();
|
||||
const { deleteTenantUser } = useHandleDeleteUser();
|
||||
const [sortOrder, setSortOrder] = useState<'asc' | 'desc' | null>(null);
|
||||
const { t } = useTranslation();
|
||||
const sortedData = useMemo(() => {
|
||||
@ -134,14 +138,35 @@ const UserTable = ({ searchUser }: { searchUser: string }) => {
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="p-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 p-0 hover:bg-state-error-5 hover:text-state-error"
|
||||
onClick={handleDeleteTenantUser(record.user_id)}
|
||||
<ConfirmDeleteDialog
|
||||
title={t('deleteModal.delMember')}
|
||||
onOk={async () => {
|
||||
await deleteTenantUser({
|
||||
userId: record.user_id,
|
||||
});
|
||||
return;
|
||||
}}
|
||||
content={{
|
||||
node: (
|
||||
<ConfirmDeleteDialogNode
|
||||
avatar={{
|
||||
avatar: record.avatar,
|
||||
name: record.nickname,
|
||||
isPerson: true,
|
||||
}}
|
||||
name={record.email}
|
||||
></ConfirmDeleteDialogNode>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 p-0 hover:bg-state-error-5 hover:text-state-error"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user