mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Fix: Optimize list display and rename functionality #3221 - Updated the homepage search list display style and added rename functionality - Used the RenameDialog component for rename searches - Optimized list height calculation - Updated the style and layout of related pages - fix issue #9779 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -20,6 +20,10 @@ body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vue-office-excel {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Scroll bar stylings */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
|
||||
@ -440,6 +440,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
||||
delete: '删除',
|
||||
},
|
||||
chat: {
|
||||
createChat: '创建聊天',
|
||||
newConversation: '新会话',
|
||||
createAssistant: '新建助理',
|
||||
assistantSetting: '助理设置',
|
||||
@ -1436,7 +1437,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
||||
cancelText: '取消',
|
||||
},
|
||||
search: {
|
||||
createSearch: '新建查询',
|
||||
createSearch: '创建查询',
|
||||
searchGreeting: '今天我能为你做些什么?',
|
||||
profile: '隐藏个人资料',
|
||||
locale: '语言',
|
||||
|
||||
@ -48,7 +48,7 @@ export default function Agents() {
|
||||
</ListFilterBar>
|
||||
</div>
|
||||
<div className="flex-1 overflow-auto">
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[78vh] overflow-auto px-8">
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[calc(100dvh-280px)] overflow-auto px-8">
|
||||
{data.map((x) => {
|
||||
return (
|
||||
<AgentCard
|
||||
|
||||
@ -70,7 +70,7 @@ export default function Datasets() {
|
||||
</Button>
|
||||
</ListFilterBar>
|
||||
<div className="flex-1">
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[78vh] overflow-auto px-8">
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[calc(100dvh-280px)] overflow-auto px-8">
|
||||
{kbs.map((dataset) => {
|
||||
return (
|
||||
<DatasetCard
|
||||
|
||||
@ -7,8 +7,10 @@ const Home = () => {
|
||||
<div className="mx-8">
|
||||
<section>
|
||||
<NextBanner></NextBanner>
|
||||
<Datasets></Datasets>
|
||||
<Applications></Applications>
|
||||
<section className="h-[calc(100dvh-260px)] overflow-auto scrollbar-thin">
|
||||
<Datasets></Datasets>
|
||||
<Applications></Applications>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,20 +1,57 @@
|
||||
import { IconFont } from '@/components/icon-font';
|
||||
import { MoreButton } from '@/components/more-button';
|
||||
import { RenameDialog } from '@/components/rename-dialog';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import { useFetchSearchList } from '../next-searches/hooks';
|
||||
import { useFetchSearchList, useRenameSearch } from '../next-searches/hooks';
|
||||
import { SearchDropdown } from '../next-searches/search-dropdown';
|
||||
import { ApplicationCard } from './application-card';
|
||||
|
||||
export function SearchList() {
|
||||
const { data } = useFetchSearchList();
|
||||
const { data, refetch: refetchList } = useFetchSearchList();
|
||||
const { navigateToSearch } = useNavigatePage();
|
||||
|
||||
return data?.data.search_apps.slice(0, 10).map((x) => (
|
||||
<ApplicationCard
|
||||
key={x.id}
|
||||
app={{
|
||||
avatar: x.avatar,
|
||||
title: x.name,
|
||||
update_time: x.update_time,
|
||||
}}
|
||||
onClick={navigateToSearch(x.id)}
|
||||
></ApplicationCard>
|
||||
));
|
||||
const {
|
||||
openCreateModal,
|
||||
showSearchRenameModal,
|
||||
hideSearchRenameModal,
|
||||
searchRenameLoading,
|
||||
onSearchRenameOk,
|
||||
initialSearchName,
|
||||
} = useRenameSearch();
|
||||
const onSearchRenameConfirm = (name: string) => {
|
||||
onSearchRenameOk(name, () => {
|
||||
refetchList();
|
||||
});
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{data?.data.search_apps.slice(0, 10).map((x) => (
|
||||
<ApplicationCard
|
||||
key={x.id}
|
||||
app={{
|
||||
avatar: x.avatar,
|
||||
title: x.name,
|
||||
update_time: x.update_time,
|
||||
}}
|
||||
onClick={navigateToSearch(x.id)}
|
||||
moreDropdown={
|
||||
<SearchDropdown
|
||||
dataset={x}
|
||||
showSearchRenameModal={showSearchRenameModal}
|
||||
>
|
||||
<MoreButton></MoreButton>
|
||||
</SearchDropdown>
|
||||
}
|
||||
></ApplicationCard>
|
||||
))}
|
||||
{openCreateModal && (
|
||||
<RenameDialog
|
||||
hideModal={hideSearchRenameModal}
|
||||
onOk={onSearchRenameConfirm}
|
||||
initialName={initialSearchName}
|
||||
loading={searchRenameLoading}
|
||||
title={<IconFont name="search" className="size-6"></IconFont>}
|
||||
></RenameDialog>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ export default function ChatList() {
|
||||
</ListFilterBar>
|
||||
</div>
|
||||
<div className="flex-1 overflow-auto">
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[84vh] overflow-auto px-8">
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[calc(100dvh-280px)] overflow-auto px-8">
|
||||
{data.dialogs.map((x) => {
|
||||
return (
|
||||
<ChatCard
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
// src/pages/next-searches/hooks.ts
|
||||
|
||||
import message from '@/components/ui/message';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import searchService from '@/services/search-service';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useCallback, useState } from 'react';
|
||||
@ -296,3 +298,72 @@ export const useUpdateSearch = () => {
|
||||
|
||||
return { data, isError, updateSearch };
|
||||
};
|
||||
|
||||
export const useRenameSearch = () => {
|
||||
const [search, setSearch] = useState<ISearchAppProps>({} as ISearchAppProps);
|
||||
const { navigateToSearch } = useNavigatePage();
|
||||
const {
|
||||
visible: openCreateModal,
|
||||
hideModal: hideChatRenameModal,
|
||||
showModal: showChatRenameModal,
|
||||
} = useSetModalState();
|
||||
const { updateSearch } = useUpdateSearch();
|
||||
const { createSearch } = useCreateSearch();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleShowChatRenameModal = useCallback(
|
||||
(record?: ISearchAppProps) => {
|
||||
if (record) {
|
||||
setSearch(record);
|
||||
}
|
||||
showChatRenameModal();
|
||||
},
|
||||
[showChatRenameModal],
|
||||
);
|
||||
|
||||
const handleHideModal = useCallback(() => {
|
||||
hideChatRenameModal();
|
||||
setSearch({} as ISearchAppProps);
|
||||
}, [hideChatRenameModal]);
|
||||
|
||||
const onSearchRenameOk = useCallback(
|
||||
async (name: string, callBack?: () => void) => {
|
||||
let res;
|
||||
setLoading(true);
|
||||
if (search?.id) {
|
||||
try {
|
||||
const reponse = await searchService.getSearchDetail({
|
||||
search_id: search?.id,
|
||||
});
|
||||
const detail = reponse.data?.data;
|
||||
console.log('detail-->', detail);
|
||||
const { id, created_by, update_time, ...searchDataTemp } = detail;
|
||||
res = await updateSearch({
|
||||
...searchDataTemp,
|
||||
name: name,
|
||||
search_id: search?.id,
|
||||
} as unknown as IUpdateSearchProps);
|
||||
} catch (e) {
|
||||
console.error('error', e);
|
||||
}
|
||||
} else {
|
||||
res = await createSearch({ name: name });
|
||||
}
|
||||
if (res && !search?.id) {
|
||||
navigateToSearch(res?.search_id)();
|
||||
}
|
||||
callBack?.();
|
||||
setLoading(false);
|
||||
handleHideModal();
|
||||
},
|
||||
[search, createSearch, handleHideModal, navigateToSearch, updateSearch],
|
||||
);
|
||||
return {
|
||||
searchRenameLoading: loading,
|
||||
initialSearchName: search?.name,
|
||||
onSearchRenameOk,
|
||||
openCreateModal,
|
||||
hideSearchRenameModal: handleHideModal,
|
||||
showSearchRenameModal: handleShowChatRenameModal,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,114 +1,49 @@
|
||||
import { IconFont } from '@/components/icon-font';
|
||||
import ListFilterBar from '@/components/list-filter-bar';
|
||||
import { Input } from '@/components/originui/input';
|
||||
import { RenameDialog } from '@/components/rename-dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form';
|
||||
import { Modal } from '@/components/ui/modal/modal';
|
||||
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import searchService from '@/services/search-service';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Plus, Search } from 'lucide-react';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import {
|
||||
ISearchAppProps,
|
||||
IUpdateSearchProps,
|
||||
useCreateSearch,
|
||||
useFetchSearchList,
|
||||
useUpdateSearch,
|
||||
} from './hooks';
|
||||
import { useFetchSearchList, useRenameSearch } from './hooks';
|
||||
import { SearchCard } from './search-card';
|
||||
const searchFormSchema = z.object({
|
||||
name: z.string().min(1, {
|
||||
message: 'Name is required',
|
||||
}),
|
||||
});
|
||||
|
||||
type SearchFormValues = z.infer<typeof searchFormSchema> & {
|
||||
search_id?: string;
|
||||
};
|
||||
|
||||
export default function SearchList() {
|
||||
// const { data } = useFetchFlowList();
|
||||
const { t } = useTranslate('search');
|
||||
const { navigateToSearch } = useNavigatePage();
|
||||
const { isLoading, createSearch } = useCreateSearch();
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [searchData, setSearchData] = useState<ISearchAppProps | null>(null);
|
||||
const {
|
||||
data: list,
|
||||
searchParams,
|
||||
setSearchListParams,
|
||||
refetch: refetchList,
|
||||
} = useFetchSearchList();
|
||||
const [openCreateModal, setOpenCreateModal] = useState(false);
|
||||
const form = useForm<SearchFormValues>({
|
||||
resolver: zodResolver(searchFormSchema),
|
||||
defaultValues: {
|
||||
name: '',
|
||||
},
|
||||
});
|
||||
const {
|
||||
openCreateModal,
|
||||
showSearchRenameModal,
|
||||
hideSearchRenameModal,
|
||||
searchRenameLoading,
|
||||
onSearchRenameOk,
|
||||
initialSearchName,
|
||||
} = useRenameSearch();
|
||||
const handleSearchChange = (value: string) => {
|
||||
console.log(value);
|
||||
};
|
||||
const { updateSearch } = useUpdateSearch();
|
||||
const onSubmit = async (values: SearchFormValues) => {
|
||||
let res;
|
||||
if (isEdit) {
|
||||
try {
|
||||
const reponse = await searchService.getSearchDetail({
|
||||
search_id: searchData?.id,
|
||||
});
|
||||
const detail = reponse.data?.data;
|
||||
console.log('detail-->', detail);
|
||||
const { id, created_by, update_time, ...searchDataTemp } = detail;
|
||||
res = await updateSearch({
|
||||
...searchDataTemp,
|
||||
name: values.name,
|
||||
search_id: searchData?.id,
|
||||
} as unknown as IUpdateSearchProps);
|
||||
refetchList();
|
||||
} catch (e) {
|
||||
console.error('error', e);
|
||||
}
|
||||
} else {
|
||||
res = await createSearch({ name: values.name });
|
||||
}
|
||||
if (res && !searchData?.id) {
|
||||
navigateToSearch(res?.search_id)();
|
||||
}
|
||||
if (!isLoading) {
|
||||
setOpenCreateModal(false);
|
||||
}
|
||||
form.reset({ name: '' });
|
||||
const onSearchRenameConfirm = (name: string) => {
|
||||
onSearchRenameOk(name, () => {
|
||||
refetchList();
|
||||
});
|
||||
};
|
||||
const openCreateModalFun = () => {
|
||||
setIsEdit(false);
|
||||
setOpenCreateModal(true);
|
||||
showSearchRenameModal();
|
||||
};
|
||||
const handlePageChange = (page: number, pageSize: number) => {
|
||||
setIsEdit(false);
|
||||
setSearchListParams({ ...searchParams, page, page_size: pageSize });
|
||||
};
|
||||
|
||||
const showSearchRenameModal = (data: ISearchAppProps) => {
|
||||
form.setValue('name', data.name);
|
||||
if (data.id) {
|
||||
setIsEdit(true);
|
||||
}
|
||||
|
||||
setSearchData(data);
|
||||
setOpenCreateModal(true);
|
||||
};
|
||||
return (
|
||||
<section className="w-full h-full flex flex-col">
|
||||
<div className="px-8 pt-8">
|
||||
@ -130,13 +65,15 @@ export default function SearchList() {
|
||||
</ListFilterBar>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[84vh] overflow-auto px-8">
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 max-h-[calc(100dvh-280px)] overflow-auto px-8">
|
||||
{list?.data.search_apps.map((x) => {
|
||||
return (
|
||||
<SearchCard
|
||||
key={x.id}
|
||||
data={x}
|
||||
showSearchRenameModal={showSearchRenameModal}
|
||||
showSearchRenameModal={() => {
|
||||
showSearchRenameModal(x);
|
||||
}}
|
||||
></SearchCard>
|
||||
);
|
||||
})}
|
||||
@ -153,57 +90,15 @@ export default function SearchList() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Modal
|
||||
open={openCreateModal}
|
||||
onOpenChange={(open) => {
|
||||
setOpenCreateModal(open);
|
||||
}}
|
||||
title={
|
||||
<div className="rounded-sm bg-emerald-400 bg-gradient-to-t from-emerald-400 via-emerald-400 to-emerald-200 p-1 size-6 flex justify-center items-center">
|
||||
<Search size={14} className="font-bold m-auto" />
|
||||
</div>
|
||||
}
|
||||
className="!w-[480px] rounded-xl"
|
||||
titleClassName="border-none"
|
||||
footerClassName="border-none"
|
||||
showfooter={false}
|
||||
maskClosable={false}
|
||||
>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="text-base mb-4">{t('createSearch')}</div>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
<span className="text-destructive mr-1"> *</span>Name
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end gap-2 mt-8 mb-6">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => setOpenCreateModal(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" disabled={isLoading}>
|
||||
{isLoading ? 'Confirm...' : 'Confirm'}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</Modal>
|
||||
{openCreateModal && (
|
||||
<RenameDialog
|
||||
hideModal={hideSearchRenameModal}
|
||||
onOk={onSearchRenameConfirm}
|
||||
initialName={initialSearchName}
|
||||
loading={searchRenameLoading}
|
||||
title={<IconFont name="search" className="size-6"></IconFont>}
|
||||
></RenameDialog>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user