You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

base.tsx 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import { useCallback, useEffect, useMemo, useState } from 'react'
  2. import type { NotionCredential } from './credential-selector'
  3. import WorkspaceSelector from './credential-selector'
  4. import SearchInput from './search-input'
  5. import PageSelector from './page-selector'
  6. import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common'
  7. import { useModalContextSelector } from '@/context/modal-context'
  8. import NotionConnector from '../notion-connector'
  9. import { useInvalidPreImportNotionPages, usePreImportNotionPages } from '@/service/knowledge/use-import'
  10. import Header from '../../datasets/create/website/base/header'
  11. import type { DataSourceCredential } from '../../header/account-setting/data-source-page-new/types'
  12. import Loading from '../loading'
  13. type NotionPageSelectorProps = {
  14. value?: string[]
  15. onSelect: (selectedPages: NotionPage[]) => void
  16. canPreview?: boolean
  17. previewPageId?: string
  18. onPreview?: (selectedPage: NotionPage) => void
  19. datasetId?: string
  20. credentialList: DataSourceCredential[]
  21. onSelectCredential?: (credentialId: string) => void
  22. }
  23. const NotionPageSelector = ({
  24. value,
  25. onSelect,
  26. canPreview,
  27. previewPageId,
  28. onPreview,
  29. datasetId = '',
  30. credentialList,
  31. onSelectCredential,
  32. }: NotionPageSelectorProps) => {
  33. const [searchValue, setSearchValue] = useState('')
  34. const setShowAccountSettingModal = useModalContextSelector(s => s.setShowAccountSettingModal)
  35. const invalidPreImportNotionPages = useInvalidPreImportNotionPages()
  36. const notionCredentials = useMemo((): NotionCredential[] => {
  37. return credentialList.map((item) => {
  38. return {
  39. credentialId: item.id,
  40. credentialName: item.name,
  41. workspaceIcon: item.credential.workspace_icon,
  42. workspaceName: item.credential.workspace_name,
  43. }
  44. })
  45. }, [credentialList])
  46. const [currentCredential, setCurrentCredential] = useState(notionCredentials[0])
  47. useEffect(() => {
  48. const credential = notionCredentials.find(item => item.credentialId === currentCredential?.credentialId)
  49. if (!credential) {
  50. const firstCredential = notionCredentials[0]
  51. invalidPreImportNotionPages({ datasetId, credentialId: firstCredential.credentialId })
  52. setCurrentCredential(notionCredentials[0])
  53. onSelect([]) // Clear selected pages when changing credential
  54. onSelectCredential?.(firstCredential.credentialId)
  55. }
  56. else {
  57. onSelectCredential?.(credential?.credentialId || '')
  58. }
  59. }, [notionCredentials])
  60. const {
  61. data: notionsPages,
  62. isFetching: isFetchingNotionPages,
  63. isError: isFetchingNotionPagesError,
  64. } = usePreImportNotionPages({ datasetId, credentialId: currentCredential.credentialId || '' })
  65. const pagesMapAndSelectedPagesId: [DataSourceNotionPageMap, Set<string>, Set<string>] = useMemo(() => {
  66. const selectedPagesId = new Set<string>()
  67. const boundPagesId = new Set<string>()
  68. const notionWorkspaces = notionsPages?.notion_info || []
  69. const pagesMap = notionWorkspaces.reduce((prev: DataSourceNotionPageMap, cur: DataSourceNotionWorkspace) => {
  70. cur.pages.forEach((page) => {
  71. if (page.is_bound) {
  72. selectedPagesId.add(page.page_id)
  73. boundPagesId.add(page.page_id)
  74. }
  75. prev[page.page_id] = {
  76. ...page,
  77. workspace_id: cur.workspace_id,
  78. }
  79. })
  80. return prev
  81. }, {})
  82. return [pagesMap, selectedPagesId, boundPagesId]
  83. }, [notionsPages?.notion_info])
  84. const defaultSelectedPagesId = useMemo(() => {
  85. return [...Array.from(pagesMapAndSelectedPagesId[1]), ...(value || [])]
  86. }, [pagesMapAndSelectedPagesId, value])
  87. const [selectedPagesId, setSelectedPagesId] = useState<Set<string>>(new Set(defaultSelectedPagesId))
  88. useEffect(() => {
  89. setSelectedPagesId(new Set(defaultSelectedPagesId))
  90. }, [defaultSelectedPagesId])
  91. const handleSearchValueChange = useCallback((value: string) => {
  92. setSearchValue(value)
  93. }, [])
  94. const handleSelectCredential = useCallback((credentialId: string) => {
  95. const credential = notionCredentials.find(item => item.credentialId === credentialId)!
  96. invalidPreImportNotionPages({ datasetId, credentialId: credential.credentialId })
  97. setCurrentCredential(credential)
  98. onSelect([]) // Clear selected pages when changing credential
  99. onSelectCredential?.(credential.credentialId)
  100. }, [invalidPreImportNotionPages, onSelect, onSelectCredential])
  101. const handleSelectPages = useCallback((newSelectedPagesId: Set<string>) => {
  102. const selectedPages = Array.from(newSelectedPagesId).map(pageId => pagesMapAndSelectedPagesId[0][pageId])
  103. setSelectedPagesId(new Set(Array.from(newSelectedPagesId)))
  104. onSelect(selectedPages)
  105. }, [pagesMapAndSelectedPagesId, onSelect])
  106. const handlePreviewPage = useCallback((previewPageId: string) => {
  107. if (onPreview)
  108. onPreview(pagesMapAndSelectedPagesId[0][previewPageId])
  109. }, [pagesMapAndSelectedPagesId, onPreview])
  110. const handleConfigureNotion = useCallback(() => {
  111. setShowAccountSettingModal({ payload: 'data-source' })
  112. }, [setShowAccountSettingModal])
  113. if (isFetchingNotionPagesError) {
  114. return (
  115. <NotionConnector
  116. onSetting={handleConfigureNotion}
  117. />
  118. )
  119. }
  120. return (
  121. <div className='flex flex-col gap-y-2'>
  122. <Header
  123. onClickConfiguration={handleConfigureNotion}
  124. title={'Choose notion pages'}
  125. buttonText={'Configure Notion'}
  126. docTitle={'Notion docs'}
  127. docLink={'https://www.notion.so/docs'}
  128. />
  129. <div className='rounded-xl border border-components-panel-border bg-background-default-subtle'>
  130. <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'>
  131. <div className='flex grow items-center gap-x-1'>
  132. <WorkspaceSelector
  133. value={currentCredential.credentialId}
  134. items={notionCredentials}
  135. onSelect={handleSelectCredential}
  136. />
  137. </div>
  138. <SearchInput
  139. value={searchValue}
  140. onChange={handleSearchValueChange}
  141. />
  142. </div>
  143. <div className='overflow-hidden rounded-b-xl'>
  144. {isFetchingNotionPages ? (
  145. <div className='flex h-[296px] items-center justify-center'>
  146. <Loading />
  147. </div>
  148. ) : (
  149. <PageSelector
  150. value={selectedPagesId}
  151. disabledValue={pagesMapAndSelectedPagesId[2]}
  152. searchValue={searchValue}
  153. list={notionsPages!.notion_info?.[0].pages || []}
  154. pagesMap={pagesMapAndSelectedPagesId[0]}
  155. onSelect={handleSelectPages}
  156. canPreview={canPreview}
  157. previewPageId={previewPageId}
  158. onPreview={handlePreviewPage}
  159. />
  160. )}
  161. </div>
  162. </div>
  163. </div>
  164. )
  165. }
  166. export default NotionPageSelector