From bc7935d627abcd9ebd2afdb38c44e7b2f019526c Mon Sep 17 00:00:00 2001 From: LGRY <48902505+LGRY@users.noreply.github.com> Date: Tue, 20 Jan 2026 19:13:53 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20add=20batch=20delete=20for=20conversati?= =?UTF-8?q?ons=20in=20chat=EF=BC=88web=EF=BC=89=20(#12584)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #12572 ## What problem does this PR solve? The conversation list in chat sessions previously only supported deleting conversations one by one. This was inefficient when users needed to clean up multiple conversations. This PR adds batch delete functionality to improve user experience. ## Type of change - [x] New Feature (non-breaking change which adds functionality) ## Specific changes - Add selection mode with checkboxes for conversation list - Add batch delete functionality with custom icons - Add internationalization support (en/zh) - Use existing removeConversation API which supports batch deletion ## UI modification status - Default: Show [+] and [batch delete icon] - Selection mode: Show checkboxes, keep [+] and [select all icon] - Items selected: Show [return icon] and [red trash icon]" ### Repair Comparison **1.Before Repair** image **2.After Repair** 新增批量删除效果图 --- Co-authored-by: Gongzi --------- Co-authored-by: Liu An --- web/public/batch_delete2.png | Bin 0 -> 3074 bytes web/public/return2.png | Bin 0 -> 6472 bytes web/src/locales/en.ts | 10 +- web/src/locales/zh.ts | 4 +- web/src/pages/next-chats/chat/sessions.tsx | 171 +++++++++++++++++++-- 5 files changed, 164 insertions(+), 21 deletions(-) create mode 100644 web/public/batch_delete2.png create mode 100644 web/public/return2.png diff --git a/web/public/batch_delete2.png b/web/public/batch_delete2.png new file mode 100644 index 0000000000000000000000000000000000000000..91d5342cb861c91d69f9d0cee65ec0476ea53832 GIT binary patch literal 3074 zcmds3d03L^7AFu~QbJSQ4Ux>osIVND#-!9MW|`UIZn$R(rlwAVq)b+zX=JWhT8=h1 z7jj7v_k9_fY_v>6rA)4&;#Mwc>JU(Oo_n9?{xN^vKfdpK&UfDTob&$9`Mu}R935;G zMu({jL`p~H#?+Wgna8kC{xVjI+2z_Fa&~wEw zv%wJNjIRZTf!`Hl1HjLU0UnzKa&0OD(cp~LfcQ6rH|i7XJ1@2=q#7MR-T&xm;Rl;j z^fmm(;M*nFmvJvgWOb*lDKaOn02T8fV5GHzoHbQLnF=#Dfa#uhL>zu`9~=MALw{Xh zBVAs(FxgjF`0z9@VA1ggY-YHZ)M#$@>Ej|Yt&K1L$SS{HVt}My=&!CTh7wqU zcm7^!4h|uvrE za8;BaVwN9U3fMyXPNgd=3(VL7XX-A{;OjdA4^Q&yvou)uz`$&egG0J46v4($&7UV` zIA5<)Myf|;Ewt>efLGnnXJd5^-W8ZR*M}WOwQnp>8D=xaw6ZaYEmx z)G=lFMF|z#;`+|XByy{o9dRO^jQ9qp8}|iz65HaRCS2>*JMoa{Dm{;5@)TuDmrzN> z&aGYF)3fc1E-b?GjE{v*q!SS4Bx>q@i$p(7Dq-sQs!^pCRe68SqwGtWXA#2B`=9kq zBH2c;+PXU&-pdE*tGH{P0nJ~2(e)c~25mjfJnb)_$o44ux6(5(AhAQ&kC&>d(=7CO)KP)UVA;UX#hL8O%3<45XU)aXrE7HkzQb3* z2|wRSIHRe#4qj2jlO2DX6r8%^mK(lk(HJa|x6`p_Qx=UgWJQ%cqzhKUvwzEZr7GTj9gd6Jjt+K!iYr*# z2SH)*1S_8+u82-F?Ff>+xIN6dCwre{y%r8p`Sek4j|xz1?}4-u&R~IJ(ZdL)SsXtR zCM9;8EDWO%_u9!vYm*pLUs=@iXjDOmqPPMMJj4RYHcsK+)SFRF$@w2mfnqnEYPdL+ zZrG@dB&=XzSbFM5zO9C$o}WfpCFqGs7Cl9ga5TFwKS2aF|hQyVly)d0Ou&B z1^zvgn!}2Gglp!j<@K3baz8=I2HU) zmlkT#zeeqUIBD9CO7JtzTHevw$xbWzO2QyYJ}gH$Oz?~~N%M&{9>Vt%Mu>zAfzr9)Y+AT13&%hkpr1~fK$3v6?{^`c=pP34o}1EVPqdAX6N6@K)`PZOJ%_Co z`Z}kDd$ZzX_}P|J@2zSe2%YG-e;Pr_#=+sVXDDRKev?Sw=jL>5^-xXqg^fOv(%ill zQt~O`Upk6z{5B*!lIP`|md#PO$?zP#Mid5%2tvf}_}n&pIO{d0;<`_~i}JmZ7fFW# lDKZ$T|2ZxH=Qus9iqUi?KLPG~E1c~Cb~X;yjKlb!{{(%VS?B-& literal 0 HcmV?d00001 diff --git a/web/public/return2.png b/web/public/return2.png new file mode 100644 index 0000000000000000000000000000000000000000..4655fb319cb0e33aa48a7be0e28bd2fe7dd11cae GIT binary patch literal 6472 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

*~X>EXB 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 WVIntSWmw!BfbuhSWTl*0@c#gh@fgqm literal 0 HcmV?d00001 diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 89416aea7..04afa82fc 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -427,7 +427,8 @@ Example: A 1 KB message with 1024-dim embedding uses ~9 KB. The 5 MB default lim paddleocrOptions: 'PaddleOCR Options', paddleocrApiUrl: 'PaddleOCR API URL', paddleocrApiUrlTip: 'The API endpoint URL for PaddleOCR service', - paddleocrApiUrlPlaceholder: 'e.g. https://paddleocr-server.com/layout-parsing', + paddleocrApiUrlPlaceholder: + 'e.g. https://paddleocr-server.com/layout-parsing', paddleocrAccessToken: 'AI Studio Access Token', paddleocrAccessTokenTip: 'Access token for PaddleOCR API (optional)', paddleocrAccessTokenPlaceholder: 'Your AI Studio token (optional)', @@ -866,6 +867,8 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s chatSetting: 'Chat setting', tocEnhance: 'TOC enhance', 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.`, + batchDeleteSessions: 'Batch delete', + deleteSelectedConfirm: 'Delete the selected {count} session(s)?', }, setting: { deleteModel: 'Delete model', @@ -1107,14 +1110,15 @@ Example: Virtual Hosted Style`, baseUrlNameMessage: 'Please input your base url!', paddleocr: { apiUrl: 'PaddleOCR API URL', - apiUrlPlaceholder: 'For example: https://paddleocr-server.com/layout-parsing', + apiUrlPlaceholder: + 'For example: https://paddleocr-server.com/layout-parsing', accessToken: 'AI Studio Access Token', accessTokenPlaceholder: 'Your AI Studio token (optional)', algorithm: 'PaddleOCR Algorithm', selectAlgorithm: 'Select Algorithm', modelNamePlaceholder: 'For example: paddleocr-from-env-1', modelNameRequired: 'Model name is required', - apiUrlRequired: 'PaddleOCR API URL is required' + apiUrlRequired: 'PaddleOCR API URL is required', }, vision: 'Does it support Vision?', ollamaLink: 'How to integrate {{name}}', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index a92294361..a4d8e5662 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -826,7 +826,9 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 avatarHidden: '隐藏头像', locale: '地区', tocEnhance: '目录增强', - tocEnhanceTip: `解析文档时生成了目录信息(见General方法的‘启用目录抽取’),让大模型返回和用户问题相关的目录项,从而利用目录项拿到相关chunk,对这些chunk在排序中进行加权。这种方法来源于模仿人类查询书本中知识的行为逻辑`, + tocEnhanceTip: `解析文档时生成了目录信息(见General方法的'启用目录抽取'),让大模型返回和用户问题相关的目录项,从而利用目录项拿到相关chunk,对这些chunk在排序中进行加权。这种方法来源于模仿人类查询书本中知识的行为逻辑`, + batchDeleteSessions: '批量删除', + deleteSelectedConfirm: '删除选中的 {count} 个会话?', }, setting: { deleteModel: '删除模型', diff --git a/web/src/pages/next-chats/chat/sessions.tsx b/web/src/pages/next-chats/chat/sessions.tsx index 15433b38d..34519b32d 100644 --- a/web/src/pages/next-chats/chat/sessions.tsx +++ b/web/src/pages/next-chats/chat/sessions.tsx @@ -1,16 +1,25 @@ +import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; import { MoreButton } from '@/components/more-button'; import { RAGFlowAvatar } from '@/components/ragflow-avatar'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; +import { Checkbox } from '@/components/ui/checkbox'; import { SearchInput } from '@/components/ui/input'; import { useSetModalState } from '@/hooks/common-hooks'; import { useFetchDialog, useGetChatSearchParams, + useRemoveConversation, } from '@/hooks/use-chat-request'; import { cn } from '@/lib/utils'; -import { PanelLeftClose, PanelRightClose, Plus } from 'lucide-react'; -import { useCallback } from 'react'; +import { + Check, + PanelLeftClose, + PanelRightClose, + Plus, + Trash2, +} from 'lucide-react'; +import { useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useHandleClickConversationCard } from '../hooks/use-click-card'; import { useSelectDerivedConversationList } from '../hooks/use-select-conversation-list'; @@ -35,12 +44,71 @@ export function Sessions({ } = useSelectDerivedConversationList(); const { data } = useFetchDialog(); const { visible, switchVisible } = useSetModalState(true); + const { removeConversation } = useRemoveConversation(); + + // Selection mode state + const [selectionMode, setSelectionMode] = useState(false); + const [selectedIds, setSelectedIds] = useState>(new Set()); + + // Toggle selection mode (click batch delete icon) + const toggleSelectionMode = useCallback(() => { + setSelectionMode(true); + setSelectedIds(new Set()); + }, []); + + // Exit selection mode (click return icon) + const exitSelectionMode = useCallback(() => { + setSelectionMode(false); + setSelectedIds(new Set()); + }, []); + + // Toggle single item selection + const toggleSelection = useCallback((id: string) => { + setSelectedIds((prev) => { + const newSet = new Set(prev); + if (newSet.has(id)) { + newSet.delete(id); + } else { + newSet.add(id); + } + return newSet; + }); + }, []); + + // Toggle select all + const toggleSelectAll = useCallback(() => { + setSelectedIds((prev) => { + if (prev.size === conversationList.length) { + return new Set(); + } + return new Set(conversationList.map((x) => x.id)); + }); + }, [conversationList]); + + // Batch delete + const handleBatchDelete = useCallback(async () => { + if (selectedIds.size > 0) { + await removeConversation(Array.from(selectedIds)); + exitSelectionMode(); + } + }, [selectedIds, removeConversation, exitSelectionMode]); + + const selectedCount = useMemo(() => selectedIds.size, [selectedIds]); + const allSelected = useMemo( + () => + selectedCount === conversationList.length && conversationList.length > 0, + [selectedCount, conversationList.length], + ); const handleCardClick = useCallback( (conversationId: string, isNew: boolean) => () => { - handleConversationCardClick(conversationId, isNew); + if (selectionMode) { + toggleSelection(conversationId); + } else { + handleConversationCardClick(conversationId, isNew); + } }, - [handleConversationCardClick], + [handleConversationCardClick, selectionMode, toggleSelection], ); const { conversationId } = useGetChatSearchParams(); @@ -55,7 +123,7 @@ export function Sessions({ } return ( -

+
- + {selectionMode && selectedCount > 0 ? ( + // Selection mode with items selected: show return and delete +
+ + + + +
+ ) : ( + // Default or selection mode without selection: show plus and batch delete +
+ + +
+ )}
-
{x.name}
- - - +
+ {selectionMode && ( + e.stopPropagation()} + onMouseDown={(e) => e.stopPropagation()} + > + toggleSelection(x.id)} + /> + + )} +
{x.name}
+
+ {!selectionMode && ( + + + + )}
))}