### What problem does this PR solve? Feat: Adjust the page header to breadcrumbs #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.20.0
| @@ -1,25 +1,8 @@ | |||
| import { ArrowLeft } from 'lucide-react'; | |||
| import { PropsWithChildren, ReactNode } from 'react'; | |||
| import { Button } from './ui/button'; | |||
| import { PropsWithChildren } from 'react'; | |||
| interface IPageHeaderProps extends PropsWithChildren { | |||
| back(): void; | |||
| title: ReactNode; | |||
| } | |||
| export function PageHeader({ back, title, children }: IPageHeaderProps) { | |||
| export function PageHeader({ children }: PropsWithChildren) { | |||
| return ( | |||
| <header className="flex justify-between items-center border-b pr-9"> | |||
| <div className="flex items-center "> | |||
| <div className="flex items-center border-r p-1.5"> | |||
| <Button variant="ghost" size="icon" onClick={back}> | |||
| <ArrowLeft className="w-5 h-5" /> | |||
| </Button> | |||
| </div> | |||
| <div className="p-4"> | |||
| <h1 className="text-2xl font-semibold tracking-tight">{title}</h1> | |||
| </div> | |||
| </div> | |||
| <header className="flex justify-between items-center border-b bg-background-header-bar p-5"> | |||
| {children} | |||
| </header> | |||
| ); | |||
| @@ -33,7 +33,10 @@ const BreadcrumbItem = React.forwardRef< | |||
| >(({ className, ...props }, ref) => ( | |||
| <li | |||
| ref={ref} | |||
| className={cn('inline-flex items-center gap-1.5', className)} | |||
| className={cn( | |||
| 'inline-flex items-center gap-1.5 text-text-sub-title', | |||
| className, | |||
| )} | |||
| {...props} | |||
| /> | |||
| )); | |||
| @@ -1302,6 +1302,10 @@ This delimiter is used to split the input text into several text pieces echo of | |||
| tavilySearchDescription: 'Search results via Tavily service.', | |||
| tavilyExtract: 'Tavily Extract', | |||
| tavilyExtractDescription: 'Tavily Extract', | |||
| log: 'Log', | |||
| management: 'Management', | |||
| import: 'Import', | |||
| export: 'Export', | |||
| }, | |||
| llmTools: { | |||
| bad_calculator: { | |||
| @@ -1255,6 +1255,10 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 | |||
| tavilySearchDescription: '通过 Tavily 服务搜索结果', | |||
| tavilyExtract: 'Tavily Extract', | |||
| tavilyExtractDescription: 'Tavily Extract', | |||
| log: '日志', | |||
| management: '管理', | |||
| import: '导入', | |||
| export: '导出', | |||
| }, | |||
| footer: { | |||
| profile: 'All rights reserved @ React', | |||
| @@ -1,4 +1,12 @@ | |||
| import { PageHeader } from '@/components/page-header'; | |||
| import { | |||
| Breadcrumb, | |||
| BreadcrumbItem, | |||
| BreadcrumbLink, | |||
| BreadcrumbList, | |||
| BreadcrumbPage, | |||
| BreadcrumbSeparator, | |||
| } from '@/components/ui/breadcrumb'; | |||
| import { Button, ButtonLoading } from '@/components/ui/button'; | |||
| import { | |||
| DropdownMenu, | |||
| @@ -89,32 +97,45 @@ export default function Agent() { | |||
| return ( | |||
| <section className="h-full"> | |||
| <PageHeader back={navigateToAgentList} title={flowDetail.title}> | |||
| <div className="flex items-center gap-2"> | |||
| <PageHeader> | |||
| <Breadcrumb> | |||
| <BreadcrumbList> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbLink onClick={navigateToAgentList}> | |||
| Agent | |||
| </BreadcrumbLink> | |||
| </BreadcrumbItem> | |||
| <BreadcrumbSeparator /> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbPage>{flowDetail.title}</BreadcrumbPage> | |||
| </BreadcrumbItem> | |||
| </BreadcrumbList> | |||
| </Breadcrumb> | |||
| <div className="flex items-center gap-5"> | |||
| <ButtonLoading | |||
| variant={'secondary'} | |||
| onClick={() => saveGraph()} | |||
| loading={loading} | |||
| > | |||
| <LaptopMinimalCheck /> Save | |||
| <LaptopMinimalCheck /> {t('flow.save')} | |||
| </ButtonLoading> | |||
| <Button variant={'secondary'} onClick={handleRunAgent}> | |||
| <CirclePlay /> | |||
| Run app | |||
| {t('flow.run')} | |||
| </Button> | |||
| <Button variant={'secondary'} onClick={showVersionDialog}> | |||
| <History /> | |||
| History version | |||
| {t('flow.historyversion')} | |||
| </Button> | |||
| <Button variant={'secondary'}> | |||
| <Logs /> | |||
| Log | |||
| {t('flow.log')} | |||
| </Button> | |||
| <DropdownMenu> | |||
| <DropdownMenuTrigger asChild> | |||
| <Button variant={'secondary'}> | |||
| <ChevronDown /> Management | |||
| <ChevronDown /> {t('flow.management')} | |||
| </Button> | |||
| </DropdownMenuTrigger> | |||
| <DropdownMenuContent> | |||
| @@ -125,12 +146,12 @@ export default function Agent() { | |||
| <DropdownMenuSeparator /> | |||
| <AgentDropdownMenuItem onClick={handleImportJson}> | |||
| <Download /> | |||
| Import | |||
| {t('flow.import')} | |||
| </AgentDropdownMenuItem> | |||
| <DropdownMenuSeparator /> | |||
| <AgentDropdownMenuItem onClick={handleExportJson}> | |||
| <Upload /> | |||
| Export | |||
| {t('flow.export')} | |||
| </AgentDropdownMenuItem> | |||
| <DropdownMenuSeparator /> | |||
| <AgentDropdownMenuItem onClick={showEmbedModal}> | |||
| @@ -1,68 +0,0 @@ | |||
| import { PageHeader } from '@/components/page-header'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { Segmented, SegmentedValue } from '@/components/ui/segmented'; | |||
| import { | |||
| QueryStringMap, | |||
| useNavigatePage, | |||
| } from '@/hooks/logic-hooks/navigate-hooks'; | |||
| import { Routes } from '@/routes'; | |||
| import { EllipsisVertical, Save } from 'lucide-react'; | |||
| import { useMemo } from 'react'; | |||
| import { Outlet, useLocation } from 'umi'; | |||
| export default function ChunkPage() { | |||
| const { navigateToDataset, getQueryString, navigateToChunk } = | |||
| useNavigatePage(); | |||
| const location = useLocation(); | |||
| const options = useMemo(() => { | |||
| return [ | |||
| { | |||
| label: 'Parsed results', | |||
| value: Routes.ParsedResult, | |||
| }, | |||
| { | |||
| label: 'Chunk result', | |||
| value: Routes.ChunkResult, | |||
| }, | |||
| { | |||
| label: 'Result view', | |||
| value: Routes.ResultView, | |||
| }, | |||
| ]; | |||
| }, []); | |||
| const path = useMemo(() => { | |||
| return location.pathname.split('/').slice(0, 3).join('/'); | |||
| }, [location.pathname]); | |||
| return ( | |||
| <section> | |||
| <PageHeader | |||
| title="Editing block" | |||
| back={navigateToDataset( | |||
| getQueryString(QueryStringMap.KnowledgeId) as string, | |||
| )} | |||
| > | |||
| <div> | |||
| <Segmented | |||
| options={options} | |||
| value={path} | |||
| onChange={navigateToChunk as (val: SegmentedValue) => void} | |||
| className="bg-colors-background-inverse-standard text-colors-text-neutral-standard" | |||
| ></Segmented> | |||
| </div> | |||
| <div className="flex items-center gap-2"> | |||
| <Button variant={'icon'} size={'icon'}> | |||
| <EllipsisVertical /> | |||
| </Button> | |||
| <Button variant={'tertiary'} size={'sm'}> | |||
| <Save /> | |||
| Save | |||
| </Button> | |||
| </div> | |||
| </PageHeader> | |||
| <Outlet /> | |||
| </section> | |||
| ); | |||
| } | |||
| @@ -1,4 +1,12 @@ | |||
| import { PageHeader } from '@/components/page-header'; | |||
| import { | |||
| Breadcrumb, | |||
| BreadcrumbItem, | |||
| BreadcrumbLink, | |||
| BreadcrumbList, | |||
| BreadcrumbPage, | |||
| BreadcrumbSeparator, | |||
| } from '@/components/ui/breadcrumb'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { Segmented, SegmentedValue } from '@/components/ui/segmented'; | |||
| import { | |||
| @@ -38,12 +46,24 @@ export default function ChunkPage() { | |||
| return ( | |||
| <section> | |||
| <PageHeader | |||
| title="Editing block" | |||
| back={navigateToDataset( | |||
| getQueryString(QueryStringMap.KnowledgeId) as string, | |||
| )} | |||
| > | |||
| <PageHeader> | |||
| <Breadcrumb> | |||
| <BreadcrumbList> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbLink | |||
| onClick={navigateToDataset( | |||
| getQueryString(QueryStringMap.KnowledgeId) as string, | |||
| )} | |||
| > | |||
| Agent | |||
| </BreadcrumbLink> | |||
| </BreadcrumbItem> | |||
| <BreadcrumbSeparator /> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbPage>xxx</BreadcrumbPage> | |||
| </BreadcrumbItem> | |||
| </BreadcrumbList> | |||
| </Breadcrumb> | |||
| <div> | |||
| <Segmented | |||
| options={options} | |||
| @@ -21,6 +21,14 @@ import CheckboxSets from './components/chunk-result-bar/checkbox-sets'; | |||
| import DocumentHeader from './components/document-preview/document-header'; | |||
| import { PageHeader } from '@/components/page-header'; | |||
| import { | |||
| Breadcrumb, | |||
| BreadcrumbItem, | |||
| BreadcrumbLink, | |||
| BreadcrumbList, | |||
| BreadcrumbPage, | |||
| BreadcrumbSeparator, | |||
| } from '@/components/ui/breadcrumb'; | |||
| import message from '@/components/ui/message'; | |||
| import { | |||
| RAGFlowPagination, | |||
| @@ -31,6 +39,7 @@ import { | |||
| QueryStringMap, | |||
| useNavigatePage, | |||
| } from '@/hooks/logic-hooks/navigate-hooks'; | |||
| import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request'; | |||
| import styles from './index.less'; | |||
| const Chunk = () => { | |||
| @@ -47,6 +56,7 @@ const Chunk = () => { | |||
| } = useFetchNextChunkList(); | |||
| const { handleChunkCardClick, selectedChunkId } = useHandleChunkCardClick(); | |||
| const isPdf = documentInfo?.type === 'pdf'; | |||
| const { data: dataset } = useFetchKnowledgeBaseConfiguration(); | |||
| const { t } = useTranslation(); | |||
| const { changeChunkTextMode, textMode } = useChangeChunkTextMode(); | |||
| @@ -61,7 +71,8 @@ const Chunk = () => { | |||
| chunkUpdatingVisible, | |||
| documentId, | |||
| } = useUpdateChunk(); | |||
| const { navigateToDataset, getQueryString } = useNavigatePage(); | |||
| const { navigateToDataset, getQueryString, navigateToDatasetList } = | |||
| useNavigatePage(); | |||
| useEffect(() => { | |||
| setChunkList(data); | |||
| }, [data]); | |||
| @@ -164,10 +175,31 @@ const Chunk = () => { | |||
| return ( | |||
| <> | |||
| <PageHeader | |||
| title="Back" | |||
| back={navigateToDataset(getQueryString(QueryStringMap.id) as string)} | |||
| ></PageHeader> | |||
| <PageHeader> | |||
| <Breadcrumb> | |||
| <BreadcrumbList> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbLink onClick={navigateToDatasetList}> | |||
| {t('knowledgeDetails.dataset')} | |||
| </BreadcrumbLink> | |||
| </BreadcrumbItem> | |||
| <BreadcrumbSeparator /> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbLink | |||
| onClick={navigateToDataset( | |||
| getQueryString(QueryStringMap.id) as string, | |||
| )} | |||
| > | |||
| {dataset.name} | |||
| </BreadcrumbLink> | |||
| </BreadcrumbItem> | |||
| <BreadcrumbSeparator /> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbPage>{documentInfo.name}</BreadcrumbPage> | |||
| </BreadcrumbItem> | |||
| </BreadcrumbList> | |||
| </Breadcrumb> | |||
| </PageHeader> | |||
| <div className={styles.chunkPage}> | |||
| <div className="flex flex-1 gap-8"> | |||
| <div className="w-2/5"> | |||
| @@ -1,10 +0,0 @@ | |||
| import ParsedResultPanel from '../parsed-result-panel'; | |||
| export default function ParsedResult() { | |||
| return ( | |||
| <section className="flex"> | |||
| <div className="flex-1"></div> | |||
| <ParsedResultPanel></ParsedResultPanel> | |||
| </section> | |||
| ); | |||
| } | |||
| @@ -1,17 +1,40 @@ | |||
| import { PageHeader } from '@/components/page-header'; | |||
| import { | |||
| Breadcrumb, | |||
| BreadcrumbItem, | |||
| BreadcrumbLink, | |||
| BreadcrumbList, | |||
| BreadcrumbPage, | |||
| BreadcrumbSeparator, | |||
| } from '@/components/ui/breadcrumb'; | |||
| import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; | |||
| import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { Outlet } from 'umi'; | |||
| import { SideBar } from './sidebar'; | |||
| export default function DatasetWrapper() { | |||
| const { navigateToDatasetList } = useNavigatePage(); | |||
| const { t } = useTranslation(); | |||
| const { data } = useFetchKnowledgeBaseConfiguration(); | |||
| return ( | |||
| <section> | |||
| <PageHeader | |||
| title="Dataset details" | |||
| back={navigateToDatasetList} | |||
| ></PageHeader> | |||
| <PageHeader> | |||
| <Breadcrumb> | |||
| <BreadcrumbList> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbLink onClick={navigateToDatasetList}> | |||
| {t('knowledgeDetails.dataset')} | |||
| </BreadcrumbLink> | |||
| </BreadcrumbItem> | |||
| <BreadcrumbSeparator /> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbPage>{data.name}</BreadcrumbPage> | |||
| </BreadcrumbItem> | |||
| </BreadcrumbList> | |||
| </Breadcrumb> | |||
| </PageHeader> | |||
| <div className="flex flex-1"> | |||
| <SideBar></SideBar> | |||
| <div className="flex-1"> | |||
| @@ -1,34 +1,45 @@ | |||
| import { PageHeader } from '@/components/page-header'; | |||
| import { | |||
| Breadcrumb, | |||
| BreadcrumbItem, | |||
| BreadcrumbLink, | |||
| BreadcrumbList, | |||
| BreadcrumbPage, | |||
| BreadcrumbSeparator, | |||
| } from '@/components/ui/breadcrumb'; | |||
| import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; | |||
| import { House } from 'lucide-react'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { Outlet } from 'umi'; | |||
| import { SideBar } from './sidebar'; | |||
| export default function ProfileSetting() { | |||
| const { navigateToHome } = useNavigatePage(); | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <div className="flex flex-col w-full h-screen bg-background text-foreground"> | |||
| {/* <header className="flex items-center border-b"> | |||
| <div className="flex items-center border-r p-1.5"> | |||
| <Button variant="ghost" size="icon" onClick={navigateToHome}> | |||
| <ArrowLeft className="w-5 h-5" /> | |||
| </Button> | |||
| </div> | |||
| <div className="p-4"> | |||
| <h1 className="text-2xl font-semibold tracking-tight"> | |||
| Profile & settings | |||
| </h1> | |||
| </div> | |||
| </header> */} | |||
| <PageHeader title="Profile & settings" back={navigateToHome}></PageHeader> | |||
| <PageHeader> | |||
| <Breadcrumb> | |||
| <BreadcrumbList> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbLink onClick={navigateToHome}> | |||
| <House className="size-4" /> | |||
| </BreadcrumbLink> | |||
| </BreadcrumbItem> | |||
| <BreadcrumbSeparator /> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbPage>{t('setting.profile')}</BreadcrumbPage> | |||
| </BreadcrumbItem> | |||
| </BreadcrumbList> | |||
| </Breadcrumb> | |||
| </PageHeader> | |||
| <div className="flex flex-1 bg-muted/50"> | |||
| <SideBar></SideBar> | |||
| <main className="flex-1 "> | |||
| <Outlet></Outlet> | |||
| {/* <h1 className="text-3xl font-bold mb-6"> {title}</h1> */} | |||
| </main> | |||
| </div> | |||
| </div> | |||