mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Delete or filter conversations #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
14
web/src/hooks/logic-hooks/use-change-search.ts
Normal file
14
web/src/hooks/logic-hooks/use-change-search.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
export const useHandleSearchStrChange = () => {
|
||||||
|
const [searchString, setSearchString] = useState('');
|
||||||
|
const handleInputChange = useCallback(
|
||||||
|
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setSearchString(value);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { handleInputChange, searchString };
|
||||||
|
};
|
||||||
@ -17,6 +17,7 @@ import {
|
|||||||
useGetPaginationWithRouter,
|
useGetPaginationWithRouter,
|
||||||
useHandleSearchChange,
|
useHandleSearchChange,
|
||||||
} from './logic-hooks';
|
} from './logic-hooks';
|
||||||
|
import { useHandleSearchStrChange } from './logic-hooks/use-change-search';
|
||||||
|
|
||||||
export const enum ChatApiAction {
|
export const enum ChatApiAction {
|
||||||
FetchDialogList = 'fetchDialogList',
|
FetchDialogList = 'fetchDialogList',
|
||||||
@ -229,6 +230,9 @@ export const useClickConversationCard = () => {
|
|||||||
export const useFetchConversationList = () => {
|
export const useFetchConversationList = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const { handleClickConversation } = useClickConversationCard();
|
const { handleClickConversation } = useClickConversationCard();
|
||||||
|
|
||||||
|
const { searchString, handleInputChange } = useHandleSearchStrChange();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
isFetching: loading,
|
isFetching: loading,
|
||||||
@ -239,6 +243,11 @@ export const useFetchConversationList = () => {
|
|||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
enabled: !!id,
|
enabled: !!id,
|
||||||
|
select(data) {
|
||||||
|
return searchString
|
||||||
|
? data.filter((x) => x.name.includes(searchString))
|
||||||
|
: data;
|
||||||
|
},
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await chatService.listConversation(
|
const { data } = await chatService.listConversation(
|
||||||
{ params: { dialog_id: id } },
|
{ params: { dialog_id: id } },
|
||||||
@ -255,7 +264,7 @@ export const useFetchConversationList = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return { data, loading, refetch };
|
return { data, loading, refetch, searchString, handleInputChange };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useFetchConversation = () => {
|
export const useFetchConversation = () => {
|
||||||
|
|||||||
@ -75,7 +75,7 @@ export function ChatSettings({ switchSettingVisible }: ChatSettingsProps) {
|
|||||||
</div>
|
</div>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit, onInvalid)}>
|
<form onSubmit={form.handleSubmit(onSubmit, onInvalid)}>
|
||||||
<section className="space-y-6 overflow-auto max-h-[87vh] pr-4">
|
<section className="space-y-6 overflow-auto max-h-[85vh] pr-4">
|
||||||
<ChatBasicSetting></ChatBasicSetting>
|
<ChatBasicSetting></ChatBasicSetting>
|
||||||
<Separator />
|
<Separator />
|
||||||
<ChatPromptEngine></ChatPromptEngine>
|
<ChatPromptEngine></ChatPromptEngine>
|
||||||
|
|||||||
48
web/src/pages/next-chats/chat/conversation-dropdown.tsx
Normal file
48
web/src/pages/next-chats/chat/conversation-dropdown.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
|
import { useRemoveConversation } from '@/hooks/use-chat-request';
|
||||||
|
import { IConversation } from '@/interfaces/database/chat';
|
||||||
|
import { Trash2 } from 'lucide-react';
|
||||||
|
import { MouseEventHandler, PropsWithChildren, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
export function ConversationDropdown({
|
||||||
|
children,
|
||||||
|
conversation,
|
||||||
|
}: PropsWithChildren & {
|
||||||
|
conversation: IConversation;
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { removeConversation } = useRemoveConversation();
|
||||||
|
|
||||||
|
const handleDelete: MouseEventHandler<HTMLDivElement> = useCallback(() => {
|
||||||
|
removeConversation([conversation.id]);
|
||||||
|
}, [conversation.id, removeConversation]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="text-state-error"
|
||||||
|
onSelect={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('common.delete')} <Trash2 />
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</ConfirmDeleteDialog>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -18,13 +18,12 @@ import {
|
|||||||
} from '@/hooks/use-chat-request';
|
} from '@/hooks/use-chat-request';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import { ArrowUpRight, LogOut } from 'lucide-react';
|
import { ArrowUpRight, LogOut, Send } from 'lucide-react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHandleClickConversationCard } from '../hooks/use-click-card';
|
import { useHandleClickConversationCard } from '../hooks/use-click-card';
|
||||||
import { ChatSettings } from './app-settings/chat-settings';
|
import { ChatSettings } from './app-settings/chat-settings';
|
||||||
import { MultipleChatBox } from './chat-box/multiple-chat-box';
|
import { MultipleChatBox } from './chat-box/multiple-chat-box';
|
||||||
import { SingleChatBox } from './chat-box/single-chat-box';
|
import { SingleChatBox } from './chat-box/single-chat-box';
|
||||||
import { LLMSelectForm } from './llm-select-form';
|
|
||||||
import { Sessions } from './sessions';
|
import { Sessions } from './sessions';
|
||||||
import { useAddChatBox } from './use-add-box';
|
import { useAddChatBox } from './use-add-box';
|
||||||
import { useSwitchDebugMode } from './use-switch-debug-mode';
|
import { useSwitchDebugMode } from './use-switch-debug-mode';
|
||||||
@ -88,6 +87,10 @@ export default function Chat() {
|
|||||||
</BreadcrumbItem>
|
</BreadcrumbItem>
|
||||||
</BreadcrumbList>
|
</BreadcrumbList>
|
||||||
</Breadcrumb>
|
</Breadcrumb>
|
||||||
|
<Button>
|
||||||
|
<Send />
|
||||||
|
{t('common.embedIntoSite')}
|
||||||
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div className="flex flex-1 min-h-0">
|
<div className="flex flex-1 min-h-0">
|
||||||
<Sessions
|
<Sessions
|
||||||
@ -103,10 +106,7 @@ export default function Chat() {
|
|||||||
className={cn('p-5', { 'border-b': hasSingleChatBox })}
|
className={cn('p-5', { 'border-b': hasSingleChatBox })}
|
||||||
>
|
>
|
||||||
<CardTitle className="flex justify-between items-center text-base">
|
<CardTitle className="flex justify-between items-center text-base">
|
||||||
<div className="flex gap-3 items-center">
|
<div>{conversation.name}</div>
|
||||||
{conversation.name}
|
|
||||||
<LLMSelectForm></LLMSelectForm>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant={'ghost'}
|
variant={'ghost'}
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
import { LargeModelFormFieldWithoutFilter } from '@/components/large-model-form-field';
|
import { LargeModelFormFieldWithoutFilter } from '@/components/large-model-form-field';
|
||||||
import { LlmSettingSchema } from '@/components/llm-setting-items/next';
|
import { LlmSettingSchema } from '@/components/llm-setting-items/next';
|
||||||
import { Form } from '@/components/ui/form';
|
import { Form } from '@/components/ui/form';
|
||||||
|
import { useFetchDialog } from '@/hooks/use-chat-request';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export function LLMSelectForm() {
|
export function LLMSelectForm() {
|
||||||
const FormSchema = z.object(LlmSettingSchema);
|
const FormSchema = z.object(LlmSettingSchema);
|
||||||
|
const { data } = useFetchDialog();
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof FormSchema>>({
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
resolver: zodResolver(FormSchema),
|
resolver: zodResolver(FormSchema),
|
||||||
@ -15,6 +19,15 @@ export function LLMSelectForm() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// const values = useWatch({ control: form.control, name: ['llm_id'] });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isEmpty(data)) {
|
||||||
|
form.reset({ llm_id: data.llm_id, ...data.llm_setting });
|
||||||
|
}
|
||||||
|
form.reset(data);
|
||||||
|
}, [data, form]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<LargeModelFormFieldWithoutFilter></LargeModelFormFieldWithoutFilter>
|
<LargeModelFormFieldWithoutFilter></LargeModelFormFieldWithoutFilter>
|
||||||
|
|||||||
@ -10,9 +10,10 @@ import {
|
|||||||
} from '@/hooks/use-chat-request';
|
} from '@/hooks/use-chat-request';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { PanelLeftClose, PanelRightClose, Plus } from 'lucide-react';
|
import { PanelLeftClose, PanelRightClose, Plus } from 'lucide-react';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useHandleClickConversationCard } from '../hooks/use-click-card';
|
import { useHandleClickConversationCard } from '../hooks/use-click-card';
|
||||||
import { useSelectDerivedConversationList } from '../hooks/use-select-conversation-list';
|
import { useSelectDerivedConversationList } from '../hooks/use-select-conversation-list';
|
||||||
|
import { ConversationDropdown } from './conversation-dropdown';
|
||||||
|
|
||||||
type SessionProps = Pick<
|
type SessionProps = Pick<
|
||||||
ReturnType<typeof useHandleClickConversationCard>,
|
ReturnType<typeof useHandleClickConversationCard>,
|
||||||
@ -23,11 +24,14 @@ export function Sessions({
|
|||||||
handleConversationCardClick,
|
handleConversationCardClick,
|
||||||
switchSettingVisible,
|
switchSettingVisible,
|
||||||
}: SessionProps) {
|
}: SessionProps) {
|
||||||
const { list: conversationList, addTemporaryConversation } =
|
const {
|
||||||
useSelectDerivedConversationList();
|
list: conversationList,
|
||||||
|
addTemporaryConversation,
|
||||||
|
handleInputChange,
|
||||||
|
searchString,
|
||||||
|
} = useSelectDerivedConversationList();
|
||||||
const { data } = useFetchDialog();
|
const { data } = useFetchDialog();
|
||||||
const { visible, switchVisible } = useSetModalState(true);
|
const { visible, switchVisible } = useSetModalState(true);
|
||||||
const [searchStr, setSearchStr] = useState('');
|
|
||||||
|
|
||||||
const handleCardClick = useCallback(
|
const handleCardClick = useCallback(
|
||||||
(conversationId: string, isNew: boolean) => () => {
|
(conversationId: string, isNew: boolean) => () => {
|
||||||
@ -71,8 +75,8 @@ export function Sessions({
|
|||||||
</div>
|
</div>
|
||||||
<div className="pb-4">
|
<div className="pb-4">
|
||||||
<SearchInput
|
<SearchInput
|
||||||
onChange={(e) => setSearchStr(e.target.value)}
|
onChange={handleInputChange}
|
||||||
value={searchStr}
|
value={searchString}
|
||||||
></SearchInput>
|
></SearchInput>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-4 flex-1 overflow-auto">
|
<div className="space-y-4 flex-1 overflow-auto">
|
||||||
@ -86,7 +90,9 @@ export function Sessions({
|
|||||||
>
|
>
|
||||||
<CardContent className="px-3 py-2 flex justify-between items-center group">
|
<CardContent className="px-3 py-2 flex justify-between items-center group">
|
||||||
{x.name}
|
{x.name}
|
||||||
|
<ConversationDropdown conversation={x}>
|
||||||
<MoreButton></MoreButton>
|
<MoreButton></MoreButton>
|
||||||
|
</ConversationDropdown>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -43,7 +43,12 @@ export const useSelectDerivedConversationList = () => {
|
|||||||
const { t } = useTranslate('chat');
|
const { t } = useTranslate('chat');
|
||||||
|
|
||||||
const [list, setList] = useState<Array<IConversation>>([]);
|
const [list, setList] = useState<Array<IConversation>>([]);
|
||||||
const { data: conversationList, loading } = useFetchConversationList();
|
const {
|
||||||
|
data: conversationList,
|
||||||
|
loading,
|
||||||
|
handleInputChange,
|
||||||
|
searchString,
|
||||||
|
} = useFetchConversationList();
|
||||||
const { id: dialogId } = useParams();
|
const { id: dialogId } = useParams();
|
||||||
const { setNewConversationRouteParams } = useSetNewConversationRouteParams();
|
const { setNewConversationRouteParams } = useSetNewConversationRouteParams();
|
||||||
const prologue = useFindPrologueFromDialogList();
|
const prologue = useFindPrologueFromDialogList();
|
||||||
@ -81,5 +86,11 @@ export const useSelectDerivedConversationList = () => {
|
|||||||
setList([...conversationList]);
|
setList([...conversationList]);
|
||||||
}, [conversationList]);
|
}, [conversationList]);
|
||||||
|
|
||||||
return { list, addTemporaryConversation, loading };
|
return {
|
||||||
|
list,
|
||||||
|
addTemporaryConversation,
|
||||||
|
loading,
|
||||||
|
handleInputChange,
|
||||||
|
searchString,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user