mirror of
https://github.com/langgenius/dify.git
synced 2025-11-23 00:13:22 +00:00
feat: Update selection handling to support multiple choice in OnlineDocuments and PageSelector components
This commit is contained in:
parent
55d7d7ef76
commit
2d0d448667
@ -265,7 +265,6 @@ const CreateFormPipeline = () => {
|
|||||||
nodeData={datasource!.nodeData}
|
nodeData={datasource!.nodeData}
|
||||||
pageIdList={onlineDocuments.map(doc => doc.page_id)}
|
pageIdList={onlineDocuments.map(doc => doc.page_id)}
|
||||||
onSelect={updateOnlineDocuments}
|
onSelect={updateOnlineDocuments}
|
||||||
canPreview
|
|
||||||
onPreview={updateCurrentPage}
|
onPreview={updateCurrentPage}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import type { DataSourceNodeType } from '@/app/components/workflow/nodes/data-so
|
|||||||
type OnlineDocumentsProps = {
|
type OnlineDocumentsProps = {
|
||||||
pageIdList?: string[]
|
pageIdList?: string[]
|
||||||
onSelect: (selectedPages: NotionPage[]) => void
|
onSelect: (selectedPages: NotionPage[]) => void
|
||||||
canPreview?: boolean
|
|
||||||
previewPageId?: string
|
previewPageId?: string
|
||||||
onPreview?: (selectedPage: NotionPage) => void
|
onPreview?: (selectedPage: NotionPage) => void
|
||||||
isInPipeline?: boolean
|
isInPipeline?: boolean
|
||||||
@ -25,7 +24,6 @@ type OnlineDocumentsProps = {
|
|||||||
const OnlineDocuments = ({
|
const OnlineDocuments = ({
|
||||||
pageIdList,
|
pageIdList,
|
||||||
onSelect,
|
onSelect,
|
||||||
canPreview,
|
|
||||||
previewPageId,
|
previewPageId,
|
||||||
onPreview,
|
onPreview,
|
||||||
isInPipeline = false,
|
isInPipeline = false,
|
||||||
@ -97,19 +95,22 @@ const OnlineDocuments = ({
|
|||||||
const handleSearchValueChange = useCallback((value: string) => {
|
const handleSearchValueChange = useCallback((value: string) => {
|
||||||
setSearchValue(value)
|
setSearchValue(value)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleSelectWorkspace = useCallback((workspaceId: string) => {
|
const handleSelectWorkspace = useCallback((workspaceId: string) => {
|
||||||
setCurrentWorkspaceId(workspaceId)
|
setCurrentWorkspaceId(workspaceId)
|
||||||
}, [])
|
}, [])
|
||||||
const handleSelectPages = (newSelectedPagesId: Set<string>) => {
|
|
||||||
|
const handleSelectPages = useCallback((newSelectedPagesId: Set<string>) => {
|
||||||
const selectedPages = Array.from(newSelectedPagesId).map(pageId => PagesMapAndSelectedPagesId[0][pageId])
|
const selectedPages = Array.from(newSelectedPagesId).map(pageId => PagesMapAndSelectedPagesId[0][pageId])
|
||||||
|
|
||||||
setSelectedPagesId(new Set(Array.from(newSelectedPagesId)))
|
setSelectedPagesId(new Set(Array.from(newSelectedPagesId)))
|
||||||
onSelect(selectedPages)
|
onSelect(selectedPages)
|
||||||
}
|
}, [onSelect, PagesMapAndSelectedPagesId])
|
||||||
const handlePreviewPage = (previewPageId: string) => {
|
|
||||||
|
const handlePreviewPage = useCallback((previewPageId: string) => {
|
||||||
if (onPreview)
|
if (onPreview)
|
||||||
onPreview(PagesMapAndSelectedPagesId[0][previewPageId])
|
onPreview(PagesMapAndSelectedPagesId[0][previewPageId])
|
||||||
}
|
}, [PagesMapAndSelectedPagesId, onPreview])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrentWorkspaceId(firstWorkspaceId)
|
setCurrentWorkspaceId(firstWorkspaceId)
|
||||||
@ -154,9 +155,10 @@ const OnlineDocuments = ({
|
|||||||
list={currentWorkspace?.pages || []}
|
list={currentWorkspace?.pages || []}
|
||||||
pagesMap={PagesMapAndSelectedPagesId[0]}
|
pagesMap={PagesMapAndSelectedPagesId[0]}
|
||||||
onSelect={handleSelectPages}
|
onSelect={handleSelectPages}
|
||||||
canPreview={canPreview}
|
canPreview={!isInPipeline}
|
||||||
previewPageId={previewPageId}
|
previewPageId={previewPageId}
|
||||||
onPreview={handlePreviewPage}
|
onPreview={handlePreviewPage}
|
||||||
|
isMultipleChoice={!isInPipeline}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useMemo, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FixedSizeList as List } from 'react-window'
|
import { FixedSizeList as List } from 'react-window'
|
||||||
import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common'
|
import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common'
|
||||||
@ -15,6 +15,7 @@ type PageSelectorProps = {
|
|||||||
canPreview?: boolean
|
canPreview?: boolean
|
||||||
previewPageId?: string
|
previewPageId?: string
|
||||||
onPreview?: (selectedPageId: string) => void
|
onPreview?: (selectedPageId: string) => void
|
||||||
|
isMultipleChoice?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NotionPageTreeItem = {
|
export type NotionPageTreeItem = {
|
||||||
@ -41,11 +42,14 @@ const PageSelector = ({
|
|||||||
canPreview = true,
|
canPreview = true,
|
||||||
previewPageId,
|
previewPageId,
|
||||||
onPreview,
|
onPreview,
|
||||||
|
isMultipleChoice = true,
|
||||||
}: PageSelectorProps) => {
|
}: PageSelectorProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [prevDataList, setPrevDataList] = useState(list)
|
const [prevDataList, setPrevDataList] = useState(list)
|
||||||
const [dataList, setDataList] = useState<NotionPageItem[]>([])
|
const [dataList, setDataList] = useState<NotionPageItem[]>([])
|
||||||
const [localPreviewPageId, setLocalPreviewPageId] = useState('')
|
const [localPreviewPageId, setLocalPreviewPageId] = useState('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
if (prevDataList !== list) {
|
if (prevDataList !== list) {
|
||||||
setPrevDataList(list)
|
setPrevDataList(list)
|
||||||
setDataList(list.filter(item => item.parent_id === 'root' || !pagesMap[item.parent_id]).map((item) => {
|
setDataList(list.filter(item => item.parent_id === 'root' || !pagesMap[item.parent_id]).map((item) => {
|
||||||
@ -56,6 +60,8 @@ const PageSelector = ({
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
}, [prevDataList, list, pagesMap])
|
||||||
|
|
||||||
const searchDataList = list.filter((item) => {
|
const searchDataList = list.filter((item) => {
|
||||||
return item.page_name.includes(searchValue)
|
return item.page_name.includes(searchValue)
|
||||||
}).map((item) => {
|
}).map((item) => {
|
||||||
@ -79,7 +85,7 @@ const PageSelector = ({
|
|||||||
}, {})
|
}, {})
|
||||||
}, [list, pagesMap])
|
}, [list, pagesMap])
|
||||||
|
|
||||||
const handleToggle = (index: number) => {
|
const handleToggle = useCallback((index: number) => {
|
||||||
const current = dataList[index]
|
const current = dataList[index]
|
||||||
const pageId = current.page_id
|
const pageId = current.page_id
|
||||||
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[pageId]
|
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[pageId]
|
||||||
@ -105,16 +111,16 @@ const PageSelector = ({
|
|||||||
...dataList.slice(index + 1)]
|
...dataList.slice(index + 1)]
|
||||||
}
|
}
|
||||||
setDataList(newDataList)
|
setDataList(newDataList)
|
||||||
}
|
}, [dataList, listMapWithChildrenAndDescendants, pagesMap])
|
||||||
|
|
||||||
|
const handleCheck = useCallback((index: number) => {
|
||||||
const copyValue = new Set([...value])
|
const copyValue = new Set([...value])
|
||||||
const handleCheck = (index: number) => {
|
|
||||||
const current = currentDataList[index]
|
const current = currentDataList[index]
|
||||||
const pageId = current.page_id
|
const pageId = current.page_id
|
||||||
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[pageId]
|
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[pageId]
|
||||||
|
|
||||||
if (copyValue.has(pageId)) {
|
if (copyValue.has(pageId)) {
|
||||||
if (!searchValue) {
|
if (!searchValue && isMultipleChoice) {
|
||||||
for (const item of currentWithChildrenAndDescendants.descendants)
|
for (const item of currentWithChildrenAndDescendants.descendants)
|
||||||
copyValue.delete(item)
|
copyValue.delete(item)
|
||||||
}
|
}
|
||||||
@ -122,18 +128,24 @@ const PageSelector = ({
|
|||||||
copyValue.delete(pageId)
|
copyValue.delete(pageId)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!searchValue) {
|
if (!searchValue && isMultipleChoice) {
|
||||||
for (const item of currentWithChildrenAndDescendants.descendants)
|
for (const item of currentWithChildrenAndDescendants.descendants)
|
||||||
copyValue.add(item)
|
copyValue.add(item)
|
||||||
}
|
}
|
||||||
|
// Single choice mode, clear previous selection
|
||||||
|
if (!isMultipleChoice && copyValue.size > 0) {
|
||||||
|
copyValue.clear()
|
||||||
copyValue.add(pageId)
|
copyValue.add(pageId)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
copyValue.add(pageId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onSelect(new Set([...copyValue]))
|
onSelect(new Set([...copyValue]))
|
||||||
}
|
}, [currentDataList, isMultipleChoice, listMapWithChildrenAndDescendants, onSelect, searchValue, value])
|
||||||
|
|
||||||
const handlePreview = (index: number) => {
|
const handlePreview = useCallback((index: number) => {
|
||||||
const current = currentDataList[index]
|
const current = currentDataList[index]
|
||||||
const pageId = current.page_id
|
const pageId = current.page_id
|
||||||
|
|
||||||
@ -141,7 +153,7 @@ const PageSelector = ({
|
|||||||
|
|
||||||
if (onPreview)
|
if (onPreview)
|
||||||
onPreview(pageId)
|
onPreview(pageId)
|
||||||
}
|
}, [currentDataList, onPreview])
|
||||||
|
|
||||||
if (!currentDataList.length) {
|
if (!currentDataList.length) {
|
||||||
return (
|
return (
|
||||||
@ -171,6 +183,7 @@ const PageSelector = ({
|
|||||||
searchValue,
|
searchValue,
|
||||||
previewPageId: currentPreviewPageId,
|
previewPageId: currentPreviewPageId,
|
||||||
pagesMap,
|
pagesMap,
|
||||||
|
isMultipleChoice,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Item}
|
{Item}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import Checkbox from '@/app/components/base/checkbox'
|
|||||||
import NotionIcon from '@/app/components/base/notion-icon'
|
import NotionIcon from '@/app/components/base/notion-icon'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common'
|
import type { DataSourceNotionPage, DataSourceNotionPageMap } from '@/models/common'
|
||||||
|
import Radio from '@/app/components/base/radio/ui'
|
||||||
|
|
||||||
type NotionPageTreeItem = {
|
type NotionPageTreeItem = {
|
||||||
children: Set<string>
|
children: Set<string>
|
||||||
@ -34,6 +35,7 @@ const Item = ({ index, style, data }: ListChildComponentProps<{
|
|||||||
searchValue: string
|
searchValue: string
|
||||||
previewPageId: string
|
previewPageId: string
|
||||||
pagesMap: DataSourceNotionPageMap
|
pagesMap: DataSourceNotionPageMap
|
||||||
|
isMultipleChoice?: boolean
|
||||||
}>) => {
|
}>) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const {
|
const {
|
||||||
@ -48,6 +50,7 @@ const Item = ({ index, style, data }: ListChildComponentProps<{
|
|||||||
searchValue,
|
searchValue,
|
||||||
previewPageId,
|
previewPageId,
|
||||||
pagesMap,
|
pagesMap,
|
||||||
|
isMultipleChoice,
|
||||||
} = data
|
} = data
|
||||||
const current = dataList[index]
|
const current = dataList[index]
|
||||||
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[current.page_id]
|
const currentWithChildrenAndDescendants = listMapWithChildrenAndDescendants[current.page_id]
|
||||||
@ -88,16 +91,24 @@ const Item = ({ index, style, data }: ListChildComponentProps<{
|
|||||||
previewPageId === current.page_id && '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)' }}
|
style={{ ...style, top: style.top as number + 8, left: 8, right: 8, width: 'calc(100% - 16px)' }}
|
||||||
>
|
>
|
||||||
|
{isMultipleChoice ? (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className='mr-2 shrink-0'
|
className='mr-2 shrink-0'
|
||||||
checked={checkedIds.has(current.page_id)}
|
checked={checkedIds.has(current.page_id)}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onCheck={() => {
|
onCheck={() => {
|
||||||
if (disabled)
|
handleCheck(index)
|
||||||
return
|
}}
|
||||||
|
/>) : (
|
||||||
|
<Radio
|
||||||
|
className='mr-2 shrink-0'
|
||||||
|
isChecked={checkedIds.has(current.page_id)}
|
||||||
|
disabled={disabled}
|
||||||
|
onCheck={() => {
|
||||||
handleCheck(index)
|
handleCheck(index)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
{!searchValue && renderArrow()}
|
{!searchValue && renderArrow()}
|
||||||
<NotionIcon
|
<NotionIcon
|
||||||
className='mr-1 shrink-0'
|
className='mr-1 shrink-0'
|
||||||
|
|||||||
@ -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={isInPipeline} // only support single choice in test run
|
isMultipleChoice={!isInPipeline} // only support single choice in test run
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user