mirror of
https://github.com/langgenius/dify.git
synced 2026-05-13 08:57:28 +08:00
feat: Refactor NotionConnector integration and add Header component for improved UI in NotionPageSelector
This commit is contained in:
parent
de30e9278c
commit
f317ef2fe2
@ -2,11 +2,13 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { Notion } from '../icons/src/public/common'
|
import { Notion } from '../icons/src/public/common'
|
||||||
import { Icon3Dots } from '../icons/src/vender/line/others'
|
import { Icon3Dots } from '../icons/src/vender/line/others'
|
||||||
import Button from '../button'
|
import Button from '../button'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
type NotionConnectorProps = {
|
type NotionConnectorProps = {
|
||||||
onSetting: () => void
|
onSetting: () => void
|
||||||
}
|
}
|
||||||
export const NotionConnector = ({ onSetting }: NotionConnectorProps) => {
|
|
||||||
|
const NotionConnector = ({ onSetting }: NotionConnectorProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -25,3 +27,5 @@ export const NotionConnector = ({ onSetting }: NotionConnectorProps) => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default React.memo(NotionConnector)
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import useSWR from 'swr'
|
|
||||||
import { RiEqualizer2Line } from '@remixicon/react'
|
|
||||||
import WorkspaceSelector from './workspace-selector'
|
import WorkspaceSelector from './workspace-selector'
|
||||||
import SearchInput from './search-input'
|
import SearchInput from './search-input'
|
||||||
import PageSelector from './page-selector'
|
import PageSelector from './page-selector'
|
||||||
import { preImportNotionPages } from '@/service/datasets'
|
|
||||||
import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common'
|
import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common'
|
||||||
import { useModalContextSelector } from '@/context/modal-context'
|
import { useModalContextSelector } from '@/context/modal-context'
|
||||||
import { NotionConnector } from '../notion-connector'
|
import NotionConnector from '../notion-connector'
|
||||||
|
import { usePreImportNotionPages } from '@/service/knowledge/use-import'
|
||||||
|
import Header from './header'
|
||||||
|
|
||||||
type NotionPageSelectorProps = {
|
type NotionPageSelectorProps = {
|
||||||
value?: string[]
|
value?: string[]
|
||||||
@ -16,6 +15,7 @@ type NotionPageSelectorProps = {
|
|||||||
previewPageId?: string
|
previewPageId?: string
|
||||||
onPreview?: (selectedPage: NotionPage) => void
|
onPreview?: (selectedPage: NotionPage) => void
|
||||||
datasetId?: string
|
datasetId?: string
|
||||||
|
isInPipeline?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const NotionPageSelector = ({
|
const NotionPageSelector = ({
|
||||||
@ -25,8 +25,9 @@ const NotionPageSelector = ({
|
|||||||
previewPageId,
|
previewPageId,
|
||||||
onPreview,
|
onPreview,
|
||||||
datasetId = '',
|
datasetId = '',
|
||||||
|
isInPipeline = false,
|
||||||
}: NotionPageSelectorProps) => {
|
}: NotionPageSelectorProps) => {
|
||||||
const { data, mutate } = useSWR({ url: '/notion/pre-import/pages', datasetId }, preImportNotionPages)
|
const { data, refetch } = usePreImportNotionPages({ url: '/notion/pre-import/pages', datasetId })
|
||||||
const [prevData, setPrevData] = useState(data)
|
const [prevData, setPrevData] = useState(data)
|
||||||
const [searchValue, setSearchValue] = useState('')
|
const [searchValue, setSearchValue] = useState('')
|
||||||
const [currentWorkspaceId, setCurrentWorkspaceId] = useState('')
|
const [currentWorkspaceId, setCurrentWorkspaceId] = useState('')
|
||||||
@ -86,47 +87,52 @@ const NotionPageSelector = ({
|
|||||||
setCurrentWorkspaceId(firstWorkspaceId)
|
setCurrentWorkspaceId(firstWorkspaceId)
|
||||||
}, [firstWorkspaceId])
|
}, [firstWorkspaceId])
|
||||||
|
|
||||||
|
const handleConfigureNotion = useCallback(() => {
|
||||||
|
setShowAccountSettingModal({ payload: 'data-source', onCancelCallback: refetch })
|
||||||
|
}, [setShowAccountSettingModal, refetch])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{
|
{
|
||||||
data?.notion_info?.length
|
data?.notion_info?.length
|
||||||
? (
|
? (
|
||||||
<div className='rounded-xl border border-components-panel-border bg-background-default-subtle'>
|
<div className='flex flex-col gap-y-2'>
|
||||||
<div className='flex h-12 items-center gap-x-2 rounded-t-xl border-b border-b-divider-regular bg-components-panel-bg p-2'>
|
<Header
|
||||||
<div className='flex grow items-center gap-x-1'>
|
isInPipeline={isInPipeline}
|
||||||
<WorkspaceSelector
|
handleConfigureNotion={handleConfigureNotion}
|
||||||
value={currentWorkspaceId || firstWorkspaceId}
|
/>
|
||||||
items={notionWorkspaces}
|
<div className='rounded-xl border border-components-panel-border bg-background-default-subtle'>
|
||||||
onSelect={handleSelectWorkspace}
|
<div className='flex h-12 items-center gap-x-2 rounded-t-xl border-b border-b-divider-regular bg-components-panel-bg p-2'>
|
||||||
/>
|
<div className='flex grow items-center gap-x-1'>
|
||||||
<div className='mx-1 h-3 w-[1px] bg-divider-regular' />
|
<WorkspaceSelector
|
||||||
<RiEqualizer2Line
|
value={currentWorkspaceId || firstWorkspaceId}
|
||||||
className='h-4 w-4 cursor-pointer text-text-tertiary'
|
items={notionWorkspaces}
|
||||||
onClick={() => setShowAccountSettingModal({ payload: 'data-source', onCancelCallback: mutate })}
|
onSelect={handleSelectWorkspace}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<SearchInput
|
||||||
|
value={searchValue}
|
||||||
|
onChange={handleSearchValueChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='overflow-hidden rounded-b-xl'>
|
||||||
|
<PageSelector
|
||||||
|
value={selectedPagesId}
|
||||||
|
disabledValue={getPagesMapAndSelectedPagesId[2]}
|
||||||
|
searchValue={searchValue}
|
||||||
|
list={currentWorkspace?.pages || []}
|
||||||
|
pagesMap={getPagesMapAndSelectedPagesId[0]}
|
||||||
|
onSelect={handleSelectPages}
|
||||||
|
canPreview={canPreview}
|
||||||
|
previewPageId={previewPageId}
|
||||||
|
onPreview={handlePreviewPage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<SearchInput
|
|
||||||
value={searchValue}
|
|
||||||
onChange={handleSearchValueChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='overflow-hidden rounded-b-xl'>
|
|
||||||
<PageSelector
|
|
||||||
value={selectedPagesId}
|
|
||||||
disabledValue={getPagesMapAndSelectedPagesId[2]}
|
|
||||||
searchValue={searchValue}
|
|
||||||
list={currentWorkspace?.pages || []}
|
|
||||||
pagesMap={getPagesMapAndSelectedPagesId[0]}
|
|
||||||
onSelect={handleSelectPages}
|
|
||||||
canPreview={canPreview}
|
|
||||||
previewPageId={previewPageId}
|
|
||||||
onPreview={handlePreviewPage}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<NotionConnector onSetting={() => setShowAccountSettingModal({ payload: 'data-source', onCancelCallback: mutate })} />
|
<NotionConnector onSetting={handleConfigureNotion} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -0,0 +1,55 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Divider from '../../divider'
|
||||||
|
import Button from '../../button'
|
||||||
|
import cn from '@/utils/classnames'
|
||||||
|
import { RiBookOpenLine, RiEqualizer2Line } from '@remixicon/react'
|
||||||
|
|
||||||
|
type HeaderProps = {
|
||||||
|
isInPipeline?: boolean
|
||||||
|
handleConfigureNotion: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Header = ({
|
||||||
|
isInPipeline = false,
|
||||||
|
handleConfigureNotion,
|
||||||
|
}: HeaderProps) => {
|
||||||
|
return (
|
||||||
|
<div className='flex items-center gap-x-2'>
|
||||||
|
<div className='flex grow items-center gap-x-1'>
|
||||||
|
<div className={cn(
|
||||||
|
'text-text-secondary',
|
||||||
|
isInPipeline ? 'system-sm-semibold' : 'system-md-semibold',
|
||||||
|
)}>
|
||||||
|
Choose notion pages
|
||||||
|
</div>
|
||||||
|
<Divider type='vertical' className='mx-1 h-3.5' />
|
||||||
|
<Button
|
||||||
|
variant='secondary'
|
||||||
|
size='small'
|
||||||
|
className={cn(isInPipeline ? 'px-1' : 'px-1.5')}
|
||||||
|
>
|
||||||
|
<RiEqualizer2Line
|
||||||
|
className='h-4 w-4'
|
||||||
|
onClick={handleConfigureNotion}
|
||||||
|
/>
|
||||||
|
{!isInPipeline && (
|
||||||
|
<span className='system-xs-medium'>
|
||||||
|
Configure Notion
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
className='system-xs-medium flex items-center gap-x-1 text-text-accent'
|
||||||
|
href='https://www.notion.so/docs'
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
>
|
||||||
|
<RiBookOpenLine className='size-3.5' />
|
||||||
|
<span>Notion docs</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Header)
|
||||||
@ -31,7 +31,6 @@ export default function WorkspaceSelector({
|
|||||||
name={currentWorkspace?.workspace_name}
|
name={currentWorkspace?.workspace_name}
|
||||||
/>
|
/>
|
||||||
<div className='mr-1 w-[90px] truncate text-left text-sm font-medium text-text-secondary' title={currentWorkspace?.workspace_name}>{currentWorkspace?.workspace_name}</div>
|
<div className='mr-1 w-[90px] truncate text-left text-sm font-medium text-text-secondary' title={currentWorkspace?.workspace_name}>{currentWorkspace?.workspace_name}</div>
|
||||||
{/* <div className='mr-1 px-1 h-[18px] bg-primary-50 rounded-lg text-xs font-medium text-text-accent'>{currentWorkspace?.pages.length}</div> */}
|
|
||||||
<RiArrowDownSLine className='h-4 w-4 text-text-secondary' />
|
<RiArrowDownSLine className='h-4 w-4 text-text-secondary' />
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
<Transition
|
<Transition
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import { useProviderContext } from '@/context/provider-context'
|
|||||||
import VectorSpaceFull from '@/app/components/billing/vector-space-full'
|
import VectorSpaceFull from '@/app/components/billing/vector-space-full'
|
||||||
import classNames from '@/utils/classnames'
|
import classNames from '@/utils/classnames'
|
||||||
import { ENABLE_WEBSITE_FIRECRAWL, ENABLE_WEBSITE_JINAREADER, ENABLE_WEBSITE_WATERCRAWL } from '@/config'
|
import { ENABLE_WEBSITE_FIRECRAWL, ENABLE_WEBSITE_JINAREADER, ENABLE_WEBSITE_WATERCRAWL } from '@/config'
|
||||||
import { NotionConnector } from '@/app/components/base/notion-connector'
|
import NotionConnector from '@/app/components/base/notion-connector'
|
||||||
|
|
||||||
type IStepOneProps = {
|
type IStepOneProps = {
|
||||||
datasetId?: string
|
datasetId?: string
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { useDataSources } from '@/service/use-common'
|
|||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
import { NotionPageSelector } from '@/app/components/base/notion-page-selector'
|
import { NotionPageSelector } from '@/app/components/base/notion-page-selector'
|
||||||
import type { NotionPage } from '@/models/common'
|
import type { NotionPage } from '@/models/common'
|
||||||
import { NotionConnector } from '@/app/components/base/notion-connector'
|
import NotionConnector from '@/app/components/base/notion-connector'
|
||||||
import { useModalContextSelector } from '@/context/modal-context'
|
import { useModalContextSelector } from '@/context/modal-context'
|
||||||
|
|
||||||
type NotionProps = {
|
type NotionProps = {
|
||||||
@ -34,6 +34,7 @@ const Notion = ({
|
|||||||
value={notionPages.map(page => page.page_id)}
|
value={notionPages.map(page => page.page_id)}
|
||||||
onSelect={updateNotionPages}
|
onSelect={updateNotionPages}
|
||||||
canPreview={false}
|
canPreview={false}
|
||||||
|
isInPipeline
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
|
import { preImportNotionPages } from '../datasets'
|
||||||
|
|
||||||
|
type PreImportNotionPagesParams = {
|
||||||
|
url: string
|
||||||
|
datasetId?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const usePreImportNotionPages = ({ datasetId }: PreImportNotionPagesParams) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['notion-pre-import-pages'],
|
||||||
|
queryFn: async () => {
|
||||||
|
return preImportNotionPages({ url: '/notion/pre-import/pages', datasetId })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user