base.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import { useCallback, useEffect, useMemo, useState } from 'react'
  2. import useSWR from 'swr'
  3. import cn from 'classnames'
  4. import s from './base.module.css'
  5. import WorkspaceSelector from './workspace-selector'
  6. import SearchInput from './search-input'
  7. import PageSelector from './page-selector'
  8. import { preImportNotionPages } from '@/service/datasets'
  9. import { NotionConnector } from '@/app/components/datasets/create/step-one'
  10. import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common'
  11. import { useModalContext } from '@/context/modal-context'
  12. type NotionPageSelectorProps = {
  13. value?: string[]
  14. onSelect: (selectedPages: NotionPage[]) => void
  15. canPreview?: boolean
  16. previewPageId?: string
  17. onPreview?: (selectedPage: NotionPage) => void
  18. datasetId?: string
  19. }
  20. const NotionPageSelector = ({
  21. value,
  22. onSelect,
  23. canPreview,
  24. previewPageId,
  25. onPreview,
  26. datasetId = '',
  27. }: NotionPageSelectorProps) => {
  28. const { data, mutate } = useSWR({ url: '/notion/pre-import/pages', datasetId }, preImportNotionPages)
  29. const [prevData, setPrevData] = useState(data)
  30. const [searchValue, setSearchValue] = useState('')
  31. const [currentWorkspaceId, setCurrentWorkspaceId] = useState('')
  32. const { setShowAccountSettingModal } = useModalContext()
  33. const notionWorkspaces = useMemo(() => {
  34. return data?.notion_info || []
  35. }, [data?.notion_info])
  36. const firstWorkspaceId = notionWorkspaces[0]?.workspace_id
  37. const currentWorkspace = notionWorkspaces.find(workspace => workspace.workspace_id === currentWorkspaceId)
  38. const getPagesMapAndSelectedPagesId: [DataSourceNotionPageMap, Set<string>] = useMemo(() => {
  39. const selectedPagesId = new Set<string>()
  40. const pagesMap = notionWorkspaces.reduce((prev: DataSourceNotionPageMap, next: DataSourceNotionWorkspace) => {
  41. next.pages.forEach((page) => {
  42. if (page.is_bound)
  43. selectedPagesId.add(page.page_id)
  44. prev[page.page_id] = {
  45. ...page,
  46. workspace_id: next.workspace_id,
  47. }
  48. })
  49. return prev
  50. }, {})
  51. return [pagesMap, selectedPagesId]
  52. }, [notionWorkspaces])
  53. const defaultSelectedPagesId = [...Array.from(getPagesMapAndSelectedPagesId[1]), ...(value || [])]
  54. const [selectedPagesId, setSelectedPagesId] = useState<Set<string>>(new Set(defaultSelectedPagesId))
  55. if (prevData !== data) {
  56. setPrevData(data)
  57. setSelectedPagesId(new Set(defaultSelectedPagesId))
  58. }
  59. const handleSearchValueChange = useCallback((value: string) => {
  60. setSearchValue(value)
  61. }, [])
  62. const handleSelectWorkspace = useCallback((workspaceId: string) => {
  63. setCurrentWorkspaceId(workspaceId)
  64. }, [])
  65. const handleSelecPages = (newSelectedPagesId: Set<string>) => {
  66. const selectedPages = Array.from(newSelectedPagesId).map(pageId => getPagesMapAndSelectedPagesId[0][pageId])
  67. setSelectedPagesId(new Set(Array.from(newSelectedPagesId)))
  68. onSelect(selectedPages)
  69. }
  70. const handlePreviewPage = (previewPageId: string) => {
  71. if (onPreview)
  72. onPreview(getPagesMapAndSelectedPagesId[0][previewPageId])
  73. }
  74. useEffect(() => {
  75. setCurrentWorkspaceId(firstWorkspaceId)
  76. }, [firstWorkspaceId])
  77. return (
  78. <div className='bg-gray-25 border border-gray-200 rounded-xl'>
  79. {
  80. data?.notion_info?.length
  81. ? (
  82. <>
  83. <div className='flex items-center pl-[10px] pr-2 h-11 bg-white border-b border-b-gray-200 rounded-t-xl'>
  84. <WorkspaceSelector
  85. value={currentWorkspaceId || firstWorkspaceId}
  86. items={notionWorkspaces}
  87. onSelect={handleSelectWorkspace}
  88. />
  89. <div className='mx-1 w-[1px] h-3 bg-gray-200' />
  90. <div
  91. className={cn(s['setting-icon'], 'w-6 h-6 cursor-pointer')}
  92. onClick={() => setShowAccountSettingModal({ payload: 'data-source', onCancelCallback: mutate })}
  93. />
  94. <div className='grow' />
  95. <SearchInput
  96. value={searchValue}
  97. onChange={handleSearchValueChange}
  98. />
  99. </div>
  100. <div className='rounded-b-xl overflow-hidden'>
  101. <PageSelector
  102. value={selectedPagesId}
  103. searchValue={searchValue}
  104. list={currentWorkspace?.pages || []}
  105. pagesMap={getPagesMapAndSelectedPagesId[0]}
  106. onSelect={handleSelecPages}
  107. canPreview={canPreview}
  108. previewPageId={previewPageId}
  109. onPreview={handlePreviewPage}
  110. />
  111. </div>
  112. </>
  113. )
  114. : (
  115. <NotionConnector onSetting={() => setShowAccountSettingModal({ payload: 'data-source', onCancelCallback: mutate })} />
  116. )
  117. }
  118. </div>
  119. )
  120. }
  121. export default NotionPageSelector