feat: Integrate OnlineDrive component into CreateFormPipeline and update related components

This commit is contained in:
twwu
2025-06-30 18:31:52 +08:00
parent ff511c6f31
commit 7b473bb5c9
7 changed files with 195 additions and 165 deletions

View File

@@ -27,6 +27,7 @@ import type { InitialDocumentDetail, PublishedPipelineRunPreviewResponse, Publis
import { DatasourceType } from '@/models/pipeline' import { DatasourceType } from '@/models/pipeline'
import { TransferMethod } from '@/types/app' import { TransferMethod } from '@/types/app'
import { useAddDocumentsSteps, useLocalFile, useOnlineDocuments, useWebsiteCrawl } from './hooks' import { useAddDocumentsSteps, useLocalFile, useOnlineDocuments, useWebsiteCrawl } from './hooks'
import OnlineDrive from '@/app/components/rag-pipeline/components/panel/test-run/data-source/online-drive'
const CreateFormPipeline = () => { const CreateFormPipeline = () => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -282,6 +283,11 @@ const CreateFormPipeline = () => {
previewIndex={previewIndex} previewIndex={previewIndex}
/> />
)} )}
{datasourceType === DatasourceType.onlineDrive && (
<OnlineDrive
nodeData={datasource!.nodeData}
/>
)}
{isShowVectorSpaceFull && ( {isShowVectorSpaceFull && (
<VectorSpaceFull /> <VectorSpaceFull />
)} )}

View File

@@ -1,7 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from 'react' import { useCallback, useEffect, useMemo, useState } from 'react'
import WorkspaceSelector from '@/app/components/base/notion-page-selector/workspace-selector' import WorkspaceSelector from '@/app/components/base/notion-page-selector/workspace-selector'
import SearchInput from '@/app/components/base/notion-page-selector/search-input' import SearchInput from '@/app/components/base/notion-page-selector/search-input'
import PageSelector from '@/app/components/base/notion-page-selector/page-selector' import PageSelector from './page-selector'
import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common' import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common'
import Header from '@/app/components/datasets/create/website/base/header' import Header from '@/app/components/datasets/create/website/base/header'
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'

View File

@@ -1,14 +1,10 @@
import { memo, useMemo, useState } from 'react' import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { FixedSizeList as List, areEqual } from 'react-window' import { FixedSizeList as List } from 'react-window'
import type { ListChildComponentProps } from 'react-window'
import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react'
import Checkbox from '@/app/components/base/checkbox'
import NotionIcon from '@/app/components/base/notion-icon'
import cn from '@/utils/classnames'
import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common' import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common'
import Item from './item'
import { recursivePushInParentDescendants } from './utils'
// todo: refactor this component to use the new OnlineDocumentSelector component
type PageSelectorProps = { type PageSelectorProps = {
value: Set<string> value: Set<string>
disabledValue: Set<string> disabledValue: Set<string>
@@ -20,169 +16,21 @@ type PageSelectorProps = {
previewPageId?: string previewPageId?: string
onPreview?: (selectedPageId: string) => void onPreview?: (selectedPageId: string) => void
} }
type NotionPageTreeItem = {
export type NotionPageTreeItem = {
children: Set<string> children: Set<string>
descendants: Set<string> descendants: Set<string>
depth: number depth: number
ancestors: string[] ancestors: string[]
} & DataSourceNotionPage } & DataSourceNotionPage
type NotionPageTreeMap = Record<string, NotionPageTreeItem>
export type NotionPageTreeMap = Record<string, NotionPageTreeItem>
type NotionPageItem = { type NotionPageItem = {
expand: boolean expand: boolean
depth: number depth: number
} & DataSourceNotionPage } & DataSourceNotionPage
const recursivePushInParentDescendants = (
pagesMap: DataSourceNotionPageMap,
listTreeMap: NotionPageTreeMap,
current: NotionPageTreeItem,
leafItem: NotionPageTreeItem,
) => {
const parentId = current.parent_id
const pageId = current.page_id
if (!parentId || !pageId)
return
if (parentId !== 'root' && pagesMap[parentId]) {
if (!listTreeMap[parentId]) {
const children = new Set([pageId])
const descendants = new Set([pageId, leafItem.page_id])
listTreeMap[parentId] = {
...pagesMap[parentId],
children,
descendants,
depth: 0,
ancestors: [],
}
}
else {
listTreeMap[parentId].children.add(pageId)
listTreeMap[parentId].descendants.add(pageId)
listTreeMap[parentId].descendants.add(leafItem.page_id)
}
leafItem.depth++
leafItem.ancestors.unshift(listTreeMap[parentId].page_name)
if (listTreeMap[parentId].parent_id !== 'root')
recursivePushInParentDescendants(pagesMap, listTreeMap, listTreeMap[parentId], leafItem)
}
}
const ItemComponent = ({ index, style, data }: ListChildComponentProps<{
dataList: NotionPageItem[]
handleToggle: (index: number) => void
checkedIds: Set<string>
disabledCheckedIds: Set<string>
handleCheck: (index: number) => void
canPreview?: boolean
handlePreview: (index: number) => void
listMapWithChildrenAndDescendants: NotionPageTreeMap
searchValue: string
previewPageId: string
pagesMap: DataSourceNotionPageMap
}>) => {
const { t } = useTranslation()
const {
dataList,
handleToggle,
checkedIds,
disabledCheckedIds,
handleCheck,
canPreview,
handlePreview,
listMapWithChildrenAndDescendants,
searchValue,
previewPageId,
pagesMap,
} = data
const current = dataList[index]
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[current.page_id]
const hasChild = currentWithChildrenAndDescendants.descendants.size > 0
const ancestors = currentWithChildrenAndDescendants.ancestors
const breadCrumbs = ancestors.length ? [...ancestors, current.page_name] : [current.page_name]
const disabled = disabledCheckedIds.has(current.page_id)
const renderArrow = () => {
if (hasChild) {
return (
<div
className='mr-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-md hover:bg-components-button-ghost-bg-hover'
style={{ marginLeft: current.depth * 8 }}
onClick={() => handleToggle(index)}
>
{
current.expand
? <RiArrowDownSLine className='h-4 w-4 text-text-tertiary' />
: <RiArrowRightSLine className='h-4 w-4 text-text-tertiary' />
}
</div>
)
}
if (current.parent_id === 'root' || !pagesMap[current.parent_id]) {
return (
<div></div>
)
}
return (
<div className='mr-1 h-5 w-5 shrink-0' style={{ marginLeft: current.depth * 8 }} />
)
}
return (
<div
className={cn('group flex cursor-pointer items-center rounded-md pl-2 pr-[2px] hover:bg-state-base-hover',
previewPageId === current.page_id && 'bg-state-base-hover')}
style={{ ...style, top: style.top as number + 8, left: 8, right: 8, width: 'calc(100% - 16px)' }}
>
<Checkbox
className='mr-2 shrink-0'
checked={checkedIds.has(current.page_id)}
disabled={disabled}
onCheck={() => {
if (disabled)
return
handleCheck(index)
}}
/>
{!searchValue && renderArrow()}
<NotionIcon
className='mr-1 shrink-0'
type='page'
src={current.page_icon}
/>
<div
className='grow truncate text-[13px] font-medium leading-4 text-text-secondary'
title={current.page_name}
>
{current.page_name}
</div>
{
canPreview && (
<div
className='ml-1 hidden h-6 shrink-0 cursor-pointer items-center rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-2 text-xs
font-medium leading-4 text-components-button-secondary-text shadow-xs shadow-shadow-shadow-3 backdrop-blur-[10px]
hover:border-components-button-secondary-border-hover hover:bg-components-button-secondary-bg-hover group-hover:flex'
onClick={() => handlePreview(index)}>
{t('common.dataSource.notion.selector.preview')}
</div>
)
}
{
searchValue && (
<div
className='ml-1 max-w-[120px] shrink-0 truncate text-xs text-text-quaternary'
title={breadCrumbs.join(' / ')}
>
{breadCrumbs.join(' / ')}
</div>
)
}
</div>
)
}
const Item = memo(ItemComponent, areEqual)
const PageSelector = ({ const PageSelector = ({
value, value,
disabledValue, disabledValue,

View File

@@ -0,0 +1,138 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import { areEqual } from 'react-window'
import type { ListChildComponentProps } from 'react-window'
import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react'
import Checkbox from '@/app/components/base/checkbox'
import NotionIcon from '@/app/components/base/notion-icon'
import cn from '@/utils/classnames'
import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common'
type NotionPageTreeItem = {
children: Set<string>
descendants: Set<string>
depth: number
ancestors: string[]
} & DataSourceNotionPage
type NotionPageTreeMap = Record<string, NotionPageTreeItem>
type NotionPageItem = {
expand: boolean
depth: number
} & DataSourceNotionPage
const Item = ({ index, style, data }: ListChildComponentProps<{
dataList: NotionPageItem[]
handleToggle: (index: number) => void
checkedIds: Set<string>
disabledCheckedIds: Set<string>
handleCheck: (index: number) => void
canPreview?: boolean
handlePreview: (index: number) => void
listMapWithChildrenAndDescendants: NotionPageTreeMap
searchValue: string
previewPageId: string
pagesMap: DataSourceNotionPageMap
}>) => {
const { t } = useTranslation()
const {
dataList,
handleToggle,
checkedIds,
disabledCheckedIds,
handleCheck,
canPreview,
handlePreview,
listMapWithChildrenAndDescendants,
searchValue,
previewPageId,
pagesMap,
} = data
const current = dataList[index]
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[current.page_id]
const hasChild = currentWithChildrenAndDescendants.descendants.size > 0
const ancestors = currentWithChildrenAndDescendants.ancestors
const breadCrumbs = ancestors.length ? [...ancestors, current.page_name] : [current.page_name]
const disabled = disabledCheckedIds.has(current.page_id)
const renderArrow = () => {
if (hasChild) {
return (
<div
className='mr-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-md hover:bg-components-button-ghost-bg-hover'
style={{ marginLeft: current.depth * 8 }}
onClick={() => handleToggle(index)}
>
{
current.expand
? <RiArrowDownSLine className='h-4 w-4 text-text-tertiary' />
: <RiArrowRightSLine className='h-4 w-4 text-text-tertiary' />
}
</div>
)
}
if (current.parent_id === 'root' || !pagesMap[current.parent_id]) {
return (
<div></div>
)
}
return (
<div className='mr-1 h-5 w-5 shrink-0' style={{ marginLeft: current.depth * 8 }} />
)
}
return (
<div
className={cn('group flex cursor-pointer items-center rounded-md pl-2 pr-[2px] hover:bg-state-base-hover',
previewPageId === current.page_id && 'bg-state-base-hover')}
style={{ ...style, top: style.top as number + 8, left: 8, right: 8, width: 'calc(100% - 16px)' }}
>
<Checkbox
className='mr-2 shrink-0'
checked={checkedIds.has(current.page_id)}
disabled={disabled}
onCheck={() => {
if (disabled)
return
handleCheck(index)
}}
/>
{!searchValue && renderArrow()}
<NotionIcon
className='mr-1 shrink-0'
type='page'
src={current.page_icon}
/>
<div
className='grow truncate text-[13px] font-medium leading-4 text-text-secondary'
title={current.page_name}
>
{current.page_name}
</div>
{
canPreview && (
<div
className='ml-1 hidden h-6 shrink-0 cursor-pointer items-center rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-2 text-xs
font-medium leading-4 text-components-button-secondary-text shadow-xs shadow-shadow-shadow-3 backdrop-blur-[10px]
hover:border-components-button-secondary-border-hover hover:bg-components-button-secondary-bg-hover group-hover:flex'
onClick={() => handlePreview(index)}>
{t('common.dataSource.notion.selector.preview')}
</div>
)
}
{
searchValue && (
<div
className='ml-1 max-w-[120px] shrink-0 truncate text-xs text-text-quaternary'
title={breadCrumbs.join(' / ')}
>
{breadCrumbs.join(' / ')}
</div>
)
}
</div>
)
}
export default React.memo(Item, areEqual)

View File

@@ -0,0 +1,39 @@
import type { DataSourceNotionPageMap } from '@/models/common'
import type { NotionPageTreeItem, NotionPageTreeMap } from './index'
export const recursivePushInParentDescendants = (
pagesMap: DataSourceNotionPageMap,
listTreeMap: NotionPageTreeMap,
current: NotionPageTreeItem,
leafItem: NotionPageTreeItem,
) => {
const parentId = current.parent_id
const pageId = current.page_id
if (!parentId || !pageId)
return
if (parentId !== 'root' && pagesMap[parentId]) {
if (!listTreeMap[parentId]) {
const children = new Set([pageId])
const descendants = new Set([pageId, leafItem.page_id])
listTreeMap[parentId] = {
...pagesMap[parentId],
children,
descendants,
depth: 0,
ancestors: [],
}
}
else {
listTreeMap[parentId].children.add(pageId)
listTreeMap[parentId].descendants.add(pageId)
listTreeMap[parentId].descendants.add(leafItem.page_id)
}
leafItem.depth++
leafItem.ancestors.unshift(listTreeMap[parentId].page_name)
if (listTreeMap[parentId].parent_id !== 'root')
recursivePushInParentDescendants(pagesMap, listTreeMap, listTreeMap[parentId], leafItem)
}
}

View File

@@ -169,7 +169,7 @@ const WebsiteCrawl = ({
usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0} usedTime={Number.parseFloat(crawlResult?.time_consuming as string) || 0}
previewIndex={previewIndex} previewIndex={previewIndex}
onPreview={onPreview} onPreview={onPreview}
isMultipleChoice={false} // only support single choice in test run isMultipleChoice={isInPipeline} // only support single choice in test run
/> />
)} )}
</div> </div>

View File

@@ -149,8 +149,7 @@ const TestRunPanel = () => {
<OnlineDrive <OnlineDrive
nodeData={datasource!.nodeData} nodeData={datasource!.nodeData}
/> />
) )}
}
</div> </div>
<Actions disabled={nextBtnDisabled} handleNextStep={handleNextStep} /> <Actions disabled={nextBtnDisabled} handleNextStep={handleNextStep} />
<FooterTips /> <FooterTips />