mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Render dialog list #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -35,9 +35,12 @@ export const useNavigatePage = () => {
|
|||||||
navigate(Routes.Chats);
|
navigate(Routes.Chats);
|
||||||
}, [navigate]);
|
}, [navigate]);
|
||||||
|
|
||||||
const navigateToChat = useCallback(() => {
|
const navigateToChat = useCallback(
|
||||||
navigate(Routes.Chat);
|
(id: string) => () => {
|
||||||
}, [navigate]);
|
navigate(`${Routes.Chat}/${id}`);
|
||||||
|
},
|
||||||
|
[navigate],
|
||||||
|
);
|
||||||
|
|
||||||
const navigateToAgents = useCallback(() => {
|
const navigateToAgents = useCallback(() => {
|
||||||
navigate(Routes.Agents);
|
navigate(Routes.Agents);
|
||||||
|
|||||||
@ -1,9 +1,22 @@
|
|||||||
|
import message from '@/components/ui/message';
|
||||||
import { ChatSearchParams } from '@/constants/chat';
|
import { ChatSearchParams } from '@/constants/chat';
|
||||||
import { IDialog } from '@/interfaces/database/chat';
|
import { IDialog } from '@/interfaces/database/chat';
|
||||||
import chatService from '@/services/chat-service';
|
import chatService from '@/services/chat-service';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { useDebounce } from 'ahooks';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { history, useSearchParams } from 'umi';
|
import { history, useSearchParams } from 'umi';
|
||||||
|
import {
|
||||||
|
useGetPaginationWithRouter,
|
||||||
|
useHandleSearchChange,
|
||||||
|
} from './logic-hooks';
|
||||||
|
|
||||||
|
export const enum ChatApiAction {
|
||||||
|
FetchDialogList = 'fetchDialogList',
|
||||||
|
RemoveDialog = 'removeDialog',
|
||||||
|
SetDialog = 'setDialog',
|
||||||
|
}
|
||||||
|
|
||||||
export const useGetChatSearchParams = () => {
|
export const useGetChatSearchParams = () => {
|
||||||
const [currentQueryParameters] = useSearchParams();
|
const [currentQueryParameters] = useSearchParams();
|
||||||
@ -42,13 +55,22 @@ export const useClickDialogCard = () => {
|
|||||||
export const useFetchDialogList = (pureFetch = false) => {
|
export const useFetchDialogList = (pureFetch = false) => {
|
||||||
const { handleClickDialog } = useClickDialogCard();
|
const { handleClickDialog } = useClickDialogCard();
|
||||||
const { dialogId } = useGetChatSearchParams();
|
const { dialogId } = useGetChatSearchParams();
|
||||||
|
const { searchString, handleInputChange } = useHandleSearchChange();
|
||||||
|
const { pagination, setPagination } = useGetPaginationWithRouter();
|
||||||
|
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
isFetching: loading,
|
isFetching: loading,
|
||||||
refetch,
|
refetch,
|
||||||
} = useQuery<IDialog[]>({
|
} = useQuery<IDialog[]>({
|
||||||
queryKey: ['fetchDialogList'],
|
queryKey: [
|
||||||
|
ChatApiAction.FetchDialogList,
|
||||||
|
{
|
||||||
|
debouncedSearchString,
|
||||||
|
...pagination,
|
||||||
|
},
|
||||||
|
],
|
||||||
initialData: [],
|
initialData: [],
|
||||||
gcTime: 0,
|
gcTime: 0,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
@ -73,5 +95,76 @@ export const useFetchDialogList = (pureFetch = false) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return { data, loading, refetch };
|
const onInputChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(
|
||||||
|
(e) => {
|
||||||
|
handleInputChange(e);
|
||||||
|
},
|
||||||
|
[handleInputChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
loading,
|
||||||
|
refetch,
|
||||||
|
searchString,
|
||||||
|
handleInputChange: onInputChange,
|
||||||
|
pagination: { ...pagination, total: data?.total },
|
||||||
|
setPagination,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRemoveDialog = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: [ChatApiAction.RemoveDialog],
|
||||||
|
mutationFn: async (dialogIds: string[]) => {
|
||||||
|
const { data } = await chatService.removeDialog({ dialogIds });
|
||||||
|
if (data.code === 0) {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['fetchDialogList'] });
|
||||||
|
|
||||||
|
message.success(t('message.deleted'));
|
||||||
|
}
|
||||||
|
return data.code;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, removeDialog: mutateAsync };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSetDialog = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: [ChatApiAction.SetDialog],
|
||||||
|
mutationFn: async (params: IDialog) => {
|
||||||
|
const { data } = await chatService.setDialog(params);
|
||||||
|
if (data.code === 0) {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
exact: false,
|
||||||
|
queryKey: ['fetchDialogList'],
|
||||||
|
});
|
||||||
|
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ['fetchDialog'],
|
||||||
|
});
|
||||||
|
message.success(
|
||||||
|
t(`message.${params.dialog_id ? 'modified' : 'created'}`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return data?.code;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, setDialog: mutateAsync };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -562,6 +562,7 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
|||||||
tavilyApiKeyHelp: 'How to get it?',
|
tavilyApiKeyHelp: 'How to get it?',
|
||||||
crossLanguage: 'Cross-language search',
|
crossLanguage: 'Cross-language search',
|
||||||
crossLanguageTip: `Select one or more languages for cross‑language search. If no language is selected, the system searches with the original query.`,
|
crossLanguageTip: `Select one or more languages for cross‑language search. If no language is selected, the system searches with the original query.`,
|
||||||
|
createChat: 'Create chat',
|
||||||
},
|
},
|
||||||
setting: {
|
setting: {
|
||||||
profile: 'Profile',
|
profile: 'Profile',
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import Editor, { loader } from '@monaco-editor/react';
|
|||||||
import { INextOperatorForm } from '../../interface';
|
import { INextOperatorForm } from '../../interface';
|
||||||
|
|
||||||
import { FormContainer } from '@/components/form-container';
|
import { FormContainer } from '@/components/form-container';
|
||||||
|
import { useIsDarkTheme } from '@/components/theme-provider';
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
@ -46,6 +47,7 @@ function CodeForm({ node }: INextOperatorForm) {
|
|||||||
const formData = node?.data.form as ICodeForm;
|
const formData = node?.data.form as ICodeForm;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const values = useValues(node);
|
const values = useValues(node);
|
||||||
|
const isDarkTheme = useIsDarkTheme();
|
||||||
|
|
||||||
const form = useForm<FormSchemaType>({
|
const form = useForm<FormSchemaType>({
|
||||||
defaultValues: values,
|
defaultValues: values,
|
||||||
@ -94,7 +96,7 @@ function CodeForm({ node }: INextOperatorForm) {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<Editor
|
<Editor
|
||||||
height={300}
|
height={300}
|
||||||
theme="vs-dark"
|
theme={isDarkTheme ? 'vs-dark' : 'vs'}
|
||||||
language={formData.lang}
|
language={formData.lang}
|
||||||
options={{
|
options={{
|
||||||
minimap: { enabled: false },
|
minimap: { enabled: false },
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { useCallback } from 'react';
|
|||||||
import { AgentCard } from './agent-card';
|
import { AgentCard } from './agent-card';
|
||||||
import { useRenameAgent } from './use-rename-agent';
|
import { useRenameAgent } from './use-rename-agent';
|
||||||
|
|
||||||
export default function Agent() {
|
export default function Agents() {
|
||||||
const { data, pagination, setPagination, searchString, handleInputChange } =
|
const { data, pagination, setPagination, searchString, handleInputChange } =
|
||||||
useFetchAgentListByPage();
|
useFetchAgentListByPage();
|
||||||
const { navigateToAgentTemplates } = useNavigatePage();
|
const { navigateToAgentTemplates } = useNavigatePage();
|
||||||
|
|||||||
@ -53,7 +53,7 @@ export default function Datasets() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="py-4 text-foreground">
|
<section className="py-4 flex-1 flex flex-col">
|
||||||
<ListFilterBar
|
<ListFilterBar
|
||||||
title={t('header.knowledgeBase')}
|
title={t('header.knowledgeBase')}
|
||||||
searchString={searchString}
|
searchString={searchString}
|
||||||
@ -69,16 +69,18 @@ export default function Datasets() {
|
|||||||
{t('knowledgeList.createKnowledgeBase')}
|
{t('knowledgeList.createKnowledgeBase')}
|
||||||
</Button>
|
</Button>
|
||||||
</ListFilterBar>
|
</ListFilterBar>
|
||||||
<div className="flex flex-wrap gap-4 max-h-[78vh] overflow-auto px-8">
|
<div className="flex-1">
|
||||||
{kbs.map((dataset) => {
|
<div className="flex flex-wrap gap-4 max-h-[78vh] overflow-auto px-8">
|
||||||
return (
|
{kbs.map((dataset) => {
|
||||||
<DatasetCard
|
return (
|
||||||
dataset={dataset}
|
<DatasetCard
|
||||||
key={dataset.id}
|
dataset={dataset}
|
||||||
showDatasetRenameModal={showDatasetRenameModal}
|
key={dataset.id}
|
||||||
></DatasetCard>
|
showDatasetRenameModal={showDatasetRenameModal}
|
||||||
);
|
></DatasetCard>
|
||||||
})}
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-8 px-8">
|
<div className="mt-8 px-8">
|
||||||
<RAGFlowPagination
|
<RAGFlowPagination
|
||||||
|
|||||||
@ -1,52 +1,45 @@
|
|||||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
import { MoreButton } from '@/components/more-button';
|
||||||
import { Button } from '@/components/ui/button';
|
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||||
import { Card, CardContent } from '@/components/ui/card';
|
import { Card, CardContent } from '@/components/ui/card';
|
||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import { IDialog } from '@/interfaces/database/chat';
|
import { IDialog } from '@/interfaces/database/chat';
|
||||||
import { formatPureDate } from '@/utils/date';
|
import { formatDate } from '@/utils/date';
|
||||||
import { ChevronRight, Trash2 } from 'lucide-react';
|
import { ChatDropdown } from './chat-dropdown';
|
||||||
|
import { useRenameChat } from './hooks/use-rename-chat';
|
||||||
|
|
||||||
interface IProps {
|
export type IProps = {
|
||||||
data: IDialog;
|
data: IDialog;
|
||||||
}
|
} & Pick<ReturnType<typeof useRenameChat>, 'showChatRenameModal'>;
|
||||||
|
|
||||||
export function ChatCard({ data }: IProps) {
|
export function ChatCard({ data, showChatRenameModal }: IProps) {
|
||||||
const { navigateToChat } = useNavigatePage();
|
const { navigateToChat } = useNavigatePage();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="bg-colors-background-inverse-weak border-colors-outline-neutral-standard">
|
<Card key={data.id} className="w-40" onClick={navigateToChat(data.id)}>
|
||||||
<CardContent className="p-4">
|
<CardContent className="p-2.5 pt-2 group">
|
||||||
<div className="flex justify-between mb-4">
|
<section className="flex justify-between mb-2">
|
||||||
{data.icon ? (
|
<div className="flex gap-2 items-center">
|
||||||
<div
|
<RAGFlowAvatar
|
||||||
className="w-[70px] h-[70px] rounded-xl bg-cover"
|
className="size-6 rounded-lg"
|
||||||
style={{ backgroundImage: `url(${data.icon})` }}
|
avatar={data.icon}
|
||||||
/>
|
name={data.name || 'CN'}
|
||||||
) : (
|
></RAGFlowAvatar>
|
||||||
<Avatar className="w-[70px] h-[70px]">
|
</div>
|
||||||
<AvatarImage src="https://github.com/shadcn.png" />
|
<ChatDropdown chat={data} showChatRenameModal={showChatRenameModal}>
|
||||||
<AvatarFallback>CN</AvatarFallback>
|
<MoreButton></MoreButton>
|
||||||
</Avatar>
|
</ChatDropdown>
|
||||||
)}
|
</section>
|
||||||
</div>
|
<div className="flex justify-between items-end">
|
||||||
<h3 className="text-xl font-bold mb-2">{data.name}</h3>
|
<div className="w-full">
|
||||||
<p>An app that does things An app that does things</p>
|
<h3 className="text-lg font-semibold mb-2 line-clamp-1">
|
||||||
<section className="flex justify-between pt-3">
|
{data.name}
|
||||||
<div>
|
</h3>
|
||||||
Search app
|
<p className="text-xs text-text-sub-title">{data.description}</p>
|
||||||
<p className="text-sm opacity-80">
|
<p className="text-xs text-text-sub-title">
|
||||||
{formatPureDate(data.update_time)}
|
{formatDate(data.update_time)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-x-2">
|
</div>
|
||||||
<Button variant="icon" size="icon" onClick={navigateToChat}>
|
|
||||||
<ChevronRight className="h-6 w-6" />
|
|
||||||
</Button>
|
|
||||||
<Button variant="icon" size="icon">
|
|
||||||
<Trash2 />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
64
web/src/pages/next-chats/chat-dropdown.tsx
Normal file
64
web/src/pages/next-chats/chat-dropdown.tsx
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
|
import { useRemoveDialog } from '@/hooks/use-chat-request';
|
||||||
|
import { IDialog } from '@/interfaces/database/chat';
|
||||||
|
import { PenLine, Trash2 } from 'lucide-react';
|
||||||
|
import { MouseEventHandler, PropsWithChildren, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useRenameChat } from './hooks/use-rename-chat';
|
||||||
|
|
||||||
|
export function ChatDropdown({
|
||||||
|
children,
|
||||||
|
showChatRenameModal,
|
||||||
|
chat,
|
||||||
|
}: PropsWithChildren &
|
||||||
|
Pick<ReturnType<typeof useRenameChat>, 'showChatRenameModal'> & {
|
||||||
|
chat: IDialog;
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { removeDialog } = useRemoveDialog();
|
||||||
|
|
||||||
|
const handleShowChatRenameModal: MouseEventHandler<HTMLDivElement> =
|
||||||
|
useCallback(
|
||||||
|
(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
showChatRenameModal(chat);
|
||||||
|
},
|
||||||
|
[chat, showChatRenameModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDelete: MouseEventHandler<HTMLDivElement> = useCallback(() => {
|
||||||
|
removeDialog([chat.id]);
|
||||||
|
}, [chat.id, removeDialog]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
<DropdownMenuItem onClick={handleShowChatRenameModal}>
|
||||||
|
{t('common.rename')} <PenLine />
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="text-text-delete-red"
|
||||||
|
onSelect={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('common.delete')} <Trash2 />
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</ConfirmDeleteDialog>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
45
web/src/pages/next-chats/hooks/use-rename-chat.ts
Normal file
45
web/src/pages/next-chats/hooks/use-rename-chat.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
|
import { useSetDialog } from '@/hooks/use-chat-request';
|
||||||
|
import { IDialog } from '@/interfaces/database/chat';
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
export const useRenameChat = () => {
|
||||||
|
const [chat, setChat] = useState<IDialog>({} as IDialog);
|
||||||
|
const {
|
||||||
|
visible: chatRenameVisible,
|
||||||
|
hideModal: hideChatRenameModal,
|
||||||
|
showModal: showChatRenameModal,
|
||||||
|
} = useSetModalState();
|
||||||
|
const { setDialog, loading } = useSetDialog();
|
||||||
|
|
||||||
|
const onChatRenameOk = useCallback(
|
||||||
|
async (name: string) => {
|
||||||
|
const ret = await setDialog({
|
||||||
|
...chat,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ret === 0) {
|
||||||
|
hideChatRenameModal();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setDialog, chat, hideChatRenameModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleShowChatRenameModal = useCallback(
|
||||||
|
async (record: IDialog) => {
|
||||||
|
setChat(record);
|
||||||
|
showChatRenameModal();
|
||||||
|
},
|
||||||
|
[showChatRenameModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
chatRenameLoading: loading,
|
||||||
|
initialChatName: chat?.name,
|
||||||
|
onChatRenameOk,
|
||||||
|
chatRenameVisible,
|
||||||
|
hideChatRenameModal,
|
||||||
|
showChatRenameModal: handleShowChatRenameModal,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,25 +1,72 @@
|
|||||||
import ListFilterBar from '@/components/list-filter-bar';
|
import ListFilterBar from '@/components/list-filter-bar';
|
||||||
|
import { RenameDialog } from '@/components/rename-dialog';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useFetchChatAppList } from '@/hooks/chat-hooks';
|
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
||||||
|
import { useFetchDialogList } from '@/hooks/use-chat-request';
|
||||||
|
import { pick } from 'lodash';
|
||||||
import { Plus } from 'lucide-react';
|
import { Plus } from 'lucide-react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ChatCard } from './chat-card';
|
import { ChatCard } from './chat-card';
|
||||||
|
import { useRenameChat } from './hooks/use-rename-chat';
|
||||||
|
|
||||||
export default function ChatList() {
|
export default function ChatList() {
|
||||||
const { data: chatList } = useFetchChatAppList();
|
const { data: chatList, setPagination, pagination } = useFetchDialogList();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const {
|
||||||
|
initialChatName,
|
||||||
|
chatRenameVisible,
|
||||||
|
showChatRenameModal,
|
||||||
|
hideChatRenameModal,
|
||||||
|
onChatRenameOk,
|
||||||
|
chatRenameLoading,
|
||||||
|
} = useRenameChat();
|
||||||
|
|
||||||
|
const handlePageChange = useCallback(
|
||||||
|
(page: number, pageSize?: number) => {
|
||||||
|
setPagination({ page, pageSize });
|
||||||
|
},
|
||||||
|
[setPagination],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="p-8">
|
<section className="flex flex-col w-full flex-1">
|
||||||
<ListFilterBar title="Chat apps">
|
<div className="px-8 pt-8">
|
||||||
<Button variant={'tertiary'} size={'sm'}>
|
<ListFilterBar title="Chat apps">
|
||||||
<Plus className="mr-2 h-4 w-4" />
|
<Button>
|
||||||
Create app
|
<Plus className="size-2.5" />
|
||||||
</Button>
|
{t('chat.createChat')}
|
||||||
</ListFilterBar>
|
</Button>
|
||||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-8">
|
</ListFilterBar>
|
||||||
{chatList.map((x) => {
|
|
||||||
return <ChatCard key={x.id} data={x}></ChatCard>;
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex-1 overflow-auto">
|
||||||
|
<div className="flex flex-wrap gap-4 px-8">
|
||||||
|
{chatList.map((x) => {
|
||||||
|
return (
|
||||||
|
<ChatCard
|
||||||
|
key={x.id}
|
||||||
|
data={x}
|
||||||
|
showChatRenameModal={showChatRenameModal}
|
||||||
|
></ChatCard>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-8 px-8 pb-8">
|
||||||
|
<RAGFlowPagination
|
||||||
|
{...pick(pagination, 'current', 'pageSize')}
|
||||||
|
total={pagination.total}
|
||||||
|
onChange={handlePageChange}
|
||||||
|
></RAGFlowPagination>
|
||||||
|
</div>
|
||||||
|
{chatRenameVisible && (
|
||||||
|
<RenameDialog
|
||||||
|
hideModal={hideChatRenameModal}
|
||||||
|
onOk={onChatRenameOk}
|
||||||
|
initialName={initialChatName}
|
||||||
|
loading={chatRenameLoading}
|
||||||
|
></RenameDialog>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -214,7 +214,7 @@ const routes = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: Routes.Chat,
|
path: Routes.Chat + '/:id',
|
||||||
layout: false,
|
layout: false,
|
||||||
component: `@/pages${Routes.Chats}/chat`,
|
component: `@/pages${Routes.Chats}/chat`,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user