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%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vue-office-excel {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
/* Scroll bar stylings */
|
/* Scroll bar stylings */
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 10px;
|
width: 10px;
|
||||||
|
|||||||
@ -440,6 +440,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
|||||||
delete: '删除',
|
delete: '删除',
|
||||||
},
|
},
|
||||||
chat: {
|
chat: {
|
||||||
|
createChat: '创建聊天',
|
||||||
newConversation: '新会话',
|
newConversation: '新会话',
|
||||||
createAssistant: '新建助理',
|
createAssistant: '新建助理',
|
||||||
assistantSetting: '助理设置',
|
assistantSetting: '助理设置',
|
||||||
@ -1436,7 +1437,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
|||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
createSearch: '新建查询',
|
createSearch: '创建查询',
|
||||||
searchGreeting: '今天我能为你做些什么?',
|
searchGreeting: '今天我能为你做些什么?',
|
||||||
profile: '隐藏个人资料',
|
profile: '隐藏个人资料',
|
||||||
locale: '语言',
|
locale: '语言',
|
||||||
|
|||||||
@ -48,7 +48,7 @@ export default function Agents() {
|
|||||||
</ListFilterBar>
|
</ListFilterBar>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-auto">
|
<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) => {
|
{data.map((x) => {
|
||||||
return (
|
return (
|
||||||
<AgentCard
|
<AgentCard
|
||||||
|
|||||||
@ -70,7 +70,7 @@ export default function Datasets() {
|
|||||||
</Button>
|
</Button>
|
||||||
</ListFilterBar>
|
</ListFilterBar>
|
||||||
<div className="flex-1">
|
<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) => {
|
{kbs.map((dataset) => {
|
||||||
return (
|
return (
|
||||||
<DatasetCard
|
<DatasetCard
|
||||||
|
|||||||
@ -7,8 +7,10 @@ const Home = () => {
|
|||||||
<div className="mx-8">
|
<div className="mx-8">
|
||||||
<section>
|
<section>
|
||||||
<NextBanner></NextBanner>
|
<NextBanner></NextBanner>
|
||||||
<Datasets></Datasets>
|
<section className="h-[calc(100dvh-260px)] overflow-auto scrollbar-thin">
|
||||||
<Applications></Applications>
|
<Datasets></Datasets>
|
||||||
|
<Applications></Applications>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</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 { 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';
|
import { ApplicationCard } from './application-card';
|
||||||
|
|
||||||
export function SearchList() {
|
export function SearchList() {
|
||||||
const { data } = useFetchSearchList();
|
const { data, refetch: refetchList } = useFetchSearchList();
|
||||||
const { navigateToSearch } = useNavigatePage();
|
const { navigateToSearch } = useNavigatePage();
|
||||||
|
const {
|
||||||
return data?.data.search_apps.slice(0, 10).map((x) => (
|
openCreateModal,
|
||||||
<ApplicationCard
|
showSearchRenameModal,
|
||||||
key={x.id}
|
hideSearchRenameModal,
|
||||||
app={{
|
searchRenameLoading,
|
||||||
avatar: x.avatar,
|
onSearchRenameOk,
|
||||||
title: x.name,
|
initialSearchName,
|
||||||
update_time: x.update_time,
|
} = useRenameSearch();
|
||||||
}}
|
const onSearchRenameConfirm = (name: string) => {
|
||||||
onClick={navigateToSearch(x.id)}
|
onSearchRenameOk(name, () => {
|
||||||
></ApplicationCard>
|
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>
|
</ListFilterBar>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-auto">
|
<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) => {
|
{data.dialogs.map((x) => {
|
||||||
return (
|
return (
|
||||||
<ChatCard
|
<ChatCard
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
// src/pages/next-searches/hooks.ts
|
// src/pages/next-searches/hooks.ts
|
||||||
|
|
||||||
import message from '@/components/ui/message';
|
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 searchService from '@/services/search-service';
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
@ -296,3 +298,72 @@ export const useUpdateSearch = () => {
|
|||||||
|
|
||||||
return { data, isError, updateSearch };
|
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 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 { 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 { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
import { Plus } from 'lucide-react';
|
||||||
import searchService from '@/services/search-service';
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
|
||||||
import { Plus, Search } from 'lucide-react';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useFetchSearchList, useRenameSearch } from './hooks';
|
||||||
import { z } from 'zod';
|
|
||||||
import {
|
|
||||||
ISearchAppProps,
|
|
||||||
IUpdateSearchProps,
|
|
||||||
useCreateSearch,
|
|
||||||
useFetchSearchList,
|
|
||||||
useUpdateSearch,
|
|
||||||
} from './hooks';
|
|
||||||
import { SearchCard } from './search-card';
|
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() {
|
export default function SearchList() {
|
||||||
// const { data } = useFetchFlowList();
|
// const { data } = useFetchFlowList();
|
||||||
const { t } = useTranslate('search');
|
const { t } = useTranslate('search');
|
||||||
const { navigateToSearch } = useNavigatePage();
|
|
||||||
const { isLoading, createSearch } = useCreateSearch();
|
|
||||||
const [isEdit, setIsEdit] = useState(false);
|
const [isEdit, setIsEdit] = useState(false);
|
||||||
const [searchData, setSearchData] = useState<ISearchAppProps | null>(null);
|
|
||||||
const {
|
const {
|
||||||
data: list,
|
data: list,
|
||||||
searchParams,
|
searchParams,
|
||||||
setSearchListParams,
|
setSearchListParams,
|
||||||
refetch: refetchList,
|
refetch: refetchList,
|
||||||
} = useFetchSearchList();
|
} = useFetchSearchList();
|
||||||
const [openCreateModal, setOpenCreateModal] = useState(false);
|
const {
|
||||||
const form = useForm<SearchFormValues>({
|
openCreateModal,
|
||||||
resolver: zodResolver(searchFormSchema),
|
showSearchRenameModal,
|
||||||
defaultValues: {
|
hideSearchRenameModal,
|
||||||
name: '',
|
searchRenameLoading,
|
||||||
},
|
onSearchRenameOk,
|
||||||
});
|
initialSearchName,
|
||||||
|
} = useRenameSearch();
|
||||||
const handleSearchChange = (value: string) => {
|
const handleSearchChange = (value: string) => {
|
||||||
console.log(value);
|
console.log(value);
|
||||||
};
|
};
|
||||||
const { updateSearch } = useUpdateSearch();
|
const onSearchRenameConfirm = (name: string) => {
|
||||||
const onSubmit = async (values: SearchFormValues) => {
|
onSearchRenameOk(name, () => {
|
||||||
let res;
|
refetchList();
|
||||||
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 openCreateModalFun = () => {
|
const openCreateModalFun = () => {
|
||||||
setIsEdit(false);
|
setIsEdit(false);
|
||||||
setOpenCreateModal(true);
|
showSearchRenameModal();
|
||||||
};
|
};
|
||||||
const handlePageChange = (page: number, pageSize: number) => {
|
const handlePageChange = (page: number, pageSize: number) => {
|
||||||
setIsEdit(false);
|
setIsEdit(false);
|
||||||
setSearchListParams({ ...searchParams, page, page_size: pageSize });
|
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 (
|
return (
|
||||||
<section className="w-full h-full flex flex-col">
|
<section className="w-full h-full flex flex-col">
|
||||||
<div className="px-8 pt-8">
|
<div className="px-8 pt-8">
|
||||||
@ -130,13 +65,15 @@ export default function SearchList() {
|
|||||||
</ListFilterBar>
|
</ListFilterBar>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<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) => {
|
{list?.data.search_apps.map((x) => {
|
||||||
return (
|
return (
|
||||||
<SearchCard
|
<SearchCard
|
||||||
key={x.id}
|
key={x.id}
|
||||||
data={x}
|
data={x}
|
||||||
showSearchRenameModal={showSearchRenameModal}
|
showSearchRenameModal={() => {
|
||||||
|
showSearchRenameModal(x);
|
||||||
|
}}
|
||||||
></SearchCard>
|
></SearchCard>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@ -153,57 +90,15 @@ export default function SearchList() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Modal
|
{openCreateModal && (
|
||||||
open={openCreateModal}
|
<RenameDialog
|
||||||
onOpenChange={(open) => {
|
hideModal={hideSearchRenameModal}
|
||||||
setOpenCreateModal(open);
|
onOk={onSearchRenameConfirm}
|
||||||
}}
|
initialName={initialSearchName}
|
||||||
title={
|
loading={searchRenameLoading}
|
||||||
<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">
|
title={<IconFont name="search" className="size-6"></IconFont>}
|
||||||
<Search size={14} className="font-bold m-auto" />
|
></RenameDialog>
|
||||||
</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>
|
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user