Переглянути джерело

Feat: Delete or filter conversations #3221 (#9491)

### What problem does this PR solve?

Feat: Delete or filter conversations #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
tags/v0.20.2
balibabu 2 місяці тому
джерело
коміт
30ae78755b
Аккаунт користувача з таким Email не знайдено

+ 14
- 0
web/src/hooks/logic-hooks/use-change-search.ts Переглянути файл

@@ -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 };
};

+ 10
- 1
web/src/hooks/use-chat-request.ts Переглянути файл

@@ -17,6 +17,7 @@ import {
useGetPaginationWithRouter,
useHandleSearchChange,
} from './logic-hooks';
import { useHandleSearchStrChange } from './logic-hooks/use-change-search';

export const enum ChatApiAction {
FetchDialogList = 'fetchDialogList',
@@ -229,6 +230,9 @@ export const useClickConversationCard = () => {
export const useFetchConversationList = () => {
const { id } = useParams();
const { handleClickConversation } = useClickConversationCard();

const { searchString, handleInputChange } = useHandleSearchStrChange();

const {
data,
isFetching: loading,
@@ -239,6 +243,11 @@ export const useFetchConversationList = () => {
gcTime: 0,
refetchOnWindowFocus: false,
enabled: !!id,
select(data) {
return searchString
? data.filter((x) => x.name.includes(searchString))
: data;
},
queryFn: async () => {
const { data } = await chatService.listConversation(
{ params: { dialog_id: id } },
@@ -255,7 +264,7 @@ export const useFetchConversationList = () => {
},
});

return { data, loading, refetch };
return { data, loading, refetch, searchString, handleInputChange };
};

export const useFetchConversation = () => {

+ 1
- 1
web/src/pages/next-chats/chat/app-settings/chat-settings.tsx Переглянути файл

@@ -75,7 +75,7 @@ export function ChatSettings({ switchSettingVisible }: ChatSettingsProps) {
</div>
<Form {...form}>
<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>
<Separator />
<ChatPromptEngine></ChatPromptEngine>

+ 48
- 0
web/src/pages/next-chats/chat/conversation-dropdown.tsx Переглянути файл

@@ -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>
);
}

+ 6
- 6
web/src/pages/next-chats/chat/index.tsx Переглянути файл

@@ -18,13 +18,12 @@ import {
} from '@/hooks/use-chat-request';
import { cn } from '@/lib/utils';
import { isEmpty } from 'lodash';
import { ArrowUpRight, LogOut } from 'lucide-react';
import { ArrowUpRight, LogOut, Send } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { useHandleClickConversationCard } from '../hooks/use-click-card';
import { ChatSettings } from './app-settings/chat-settings';
import { MultipleChatBox } from './chat-box/multiple-chat-box';
import { SingleChatBox } from './chat-box/single-chat-box';
import { LLMSelectForm } from './llm-select-form';
import { Sessions } from './sessions';
import { useAddChatBox } from './use-add-box';
import { useSwitchDebugMode } from './use-switch-debug-mode';
@@ -88,6 +87,10 @@ export default function Chat() {
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
<Button>
<Send />
{t('common.embedIntoSite')}
</Button>
</PageHeader>
<div className="flex flex-1 min-h-0">
<Sessions
@@ -103,10 +106,7 @@ export default function Chat() {
className={cn('p-5', { 'border-b': hasSingleChatBox })}
>
<CardTitle className="flex justify-between items-center text-base">
<div className="flex gap-3 items-center">
{conversation.name}
<LLMSelectForm></LLMSelectForm>
</div>
<div>{conversation.name}</div>

<Button
variant={'ghost'}

+ 13
- 0
web/src/pages/next-chats/chat/llm-select-form.tsx Переглянути файл

@@ -1,12 +1,16 @@
import { LargeModelFormFieldWithoutFilter } from '@/components/large-model-form-field';
import { LlmSettingSchema } from '@/components/llm-setting-items/next';
import { Form } from '@/components/ui/form';
import { useFetchDialog } from '@/hooks/use-chat-request';
import { zodResolver } from '@hookform/resolvers/zod';
import { isEmpty } from 'lodash';
import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';

export function LLMSelectForm() {
const FormSchema = z.object(LlmSettingSchema);
const { data } = useFetchDialog();

const form = useForm<z.infer<typeof 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 (
<Form {...form}>
<LargeModelFormFieldWithoutFilter></LargeModelFormFieldWithoutFilter>

+ 13
- 7
web/src/pages/next-chats/chat/sessions.tsx Переглянути файл

@@ -10,9 +10,10 @@ import {
} from '@/hooks/use-chat-request';
import { cn } from '@/lib/utils';
import { PanelLeftClose, PanelRightClose, Plus } from 'lucide-react';
import { useCallback, useState } from 'react';
import { useCallback } from 'react';
import { useHandleClickConversationCard } from '../hooks/use-click-card';
import { useSelectDerivedConversationList } from '../hooks/use-select-conversation-list';
import { ConversationDropdown } from './conversation-dropdown';

type SessionProps = Pick<
ReturnType<typeof useHandleClickConversationCard>,
@@ -23,11 +24,14 @@ export function Sessions({
handleConversationCardClick,
switchSettingVisible,
}: SessionProps) {
const { list: conversationList, addTemporaryConversation } =
useSelectDerivedConversationList();
const {
list: conversationList,
addTemporaryConversation,
handleInputChange,
searchString,
} = useSelectDerivedConversationList();
const { data } = useFetchDialog();
const { visible, switchVisible } = useSetModalState(true);
const [searchStr, setSearchStr] = useState('');

const handleCardClick = useCallback(
(conversationId: string, isNew: boolean) => () => {
@@ -71,8 +75,8 @@ export function Sessions({
</div>
<div className="pb-4">
<SearchInput
onChange={(e) => setSearchStr(e.target.value)}
value={searchStr}
onChange={handleInputChange}
value={searchString}
></SearchInput>
</div>
<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">
{x.name}
<MoreButton></MoreButton>
<ConversationDropdown conversation={x}>
<MoreButton></MoreButton>
</ConversationDropdown>
</CardContent>
</Card>
))}

+ 13
- 2
web/src/pages/next-chats/hooks/use-select-conversation-list.ts Переглянути файл

@@ -43,7 +43,12 @@ export const useSelectDerivedConversationList = () => {
const { t } = useTranslate('chat');

const [list, setList] = useState<Array<IConversation>>([]);
const { data: conversationList, loading } = useFetchConversationList();
const {
data: conversationList,
loading,
handleInputChange,
searchString,
} = useFetchConversationList();
const { id: dialogId } = useParams();
const { setNewConversationRouteParams } = useSetNewConversationRouteParams();
const prologue = useFindPrologueFromDialogList();
@@ -81,5 +86,11 @@ export const useSelectDerivedConversationList = () => {
setList([...conversationList]);
}, [conversationList]);

return { list, addTemporaryConversation, loading };
return {
list,
addTemporaryConversation,
loading,
handleInputChange,
searchString,
};
};

Завантаження…
Відмінити
Зберегти