base.tsx 5.1 KB

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