From a430284aa21e3ae1f0d5654e55b2ad2852519cc2 Mon Sep 17 00:00:00 2001 From: wwf <yearningwang@iqtogether.com> Date: 星期三, 04 六月 2025 15:17:49 +0800 Subject: [PATCH] 初始化 --- app/components/datasets/documents/index.tsx | 124 +++++++++++++---------------------------- 1 files changed, 40 insertions(+), 84 deletions(-) diff --git a/app/components/datasets/documents/index.tsx b/app/components/datasets/documents/index.tsx index 32980ee..c9df2f2 100644 --- a/app/components/datasets/documents/index.tsx +++ b/app/components/datasets/documents/index.tsx @@ -1,12 +1,13 @@ 'use client' import type { FC } from 'react' import React, { useCallback, useEffect, useMemo, useState } from 'react' +import useSWR from 'swr' import { useTranslation } from 'react-i18next' import { useRouter } from 'next/navigation' import { useDebounce, useDebounceFn } from 'ahooks' -import { groupBy } from 'lodash-es' +import { groupBy, omit } from 'lodash-es' import { PlusIcon } from '@heroicons/react/24/solid' -import { RiDraftLine, RiExternalLinkLine } from '@remixicon/react' +import { RiExternalLinkLine } from '@remixicon/react' import AutoDisabledDocument from '../common/document-status-with-action/auto-disabled-document' import List from './list' import s from './style.module.css' @@ -14,23 +15,18 @@ import Button from '@/app/components/base/button' import Input from '@/app/components/base/input' import { get } from '@/service/base' -import { createDocument } from '@/service/datasets' +import { createDocument, fetchDocuments } from '@/service/datasets' import { useDatasetDetailContext } from '@/context/dataset-detail' import { NotionPageSelectorModal } from '@/app/components/base/notion-page-selector' import type { NotionPage } from '@/models/common' import type { CreateDocumentReq } from '@/models/datasets' -import { DataSourceType, ProcessMode } from '@/models/datasets' +import { DataSourceType } from '@/models/datasets' import IndexFailed from '@/app/components/datasets/common/document-status-with-action/index-failed' import { useProviderContext } from '@/context/provider-context' import cn from '@/utils/classnames' -import { useDocumentList, useInvalidDocumentDetailKey, useInvalidDocumentList } from '@/service/knowledge/use-document' +import { useInvalidDocumentDetailKey } from '@/service/knowledge/use-document' import { useInvalid } from '@/service/use-base' import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/use-segment' -import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata' -import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer' -import StatusWithAction from '../common/document-status-with-action/status-with-action' -import { LanguagesSupported } from '@/i18n/language' -import { getLocaleOnClient } from '@/i18n' const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => { return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}> @@ -66,7 +62,7 @@ <div className={s.emptySymbolIconWrapper}> {type === 'upload' ? <FolderPlusIcon /> : <NotionIcon />} </div> - <span className={s.emptyTitle}>{t('datasetDocuments.list.empty.title')}<ThreeDotsIcon className='relative -left-1.5 -top-3 inline' /></span> + <span className={s.emptyTitle}>{t('datasetDocuments.list.empty.title')}<ThreeDotsIcon className='inline relative -top-3 -left-1.5' /></span> <div className={s.emptyTip}> {t(`datasetDocuments.list.empty.${type}.tip`)} </div> @@ -82,7 +78,7 @@ } export const fetcher = (url: string) => get(url, {}, {}) -const DEFAULT_LIMIT = 10 +const DEFAULT_LIMIT = 15 const Documents: FC<IDocumentsProps> = ({ datasetId }) => { const { t } = useTranslation() @@ -100,36 +96,36 @@ const isDataSourceWeb = dataset?.data_source_type === DataSourceType.WEB const isDataSourceFile = dataset?.data_source_type === DataSourceType.FILE const embeddingAvailable = !!dataset?.embedding_available - const locale = getLocaleOnClient() + const debouncedSearchValue = useDebounce(searchValue, { wait: 500 }) - const { data: documentsRes, isFetching: isListLoading } = useDocumentList({ - datasetId, - query: { - page: currPage + 1, - limit, - keyword: debouncedSearchValue, + const query = useMemo(() => { + return { page: currPage + 1, limit, keyword: debouncedSearchValue, fetch: isDataSourceNotion ? true : '' } + }, [currPage, debouncedSearchValue, isDataSourceNotion, limit]) + + const { data: documentsRes, mutate, isLoading: isListLoading } = useSWR( + { + action: 'fetchDocuments', + datasetId, + params: query, }, - refetchInterval: (isDataSourceNotion && timerCanRun) ? 2500 : 0, - }) + apiParams => fetchDocuments(omit(apiParams, 'action')), + { refreshInterval: (isDataSourceNotion && timerCanRun) ? 2500 : 0 }, + ) - const invalidDocumentList = useInvalidDocumentList(datasetId) - + const [isMuting, setIsMuting] = useState(false) useEffect(() => { - if (documentsRes) { - const totalPages = Math.ceil(documentsRes.total / limit) - if (totalPages < currPage + 1) - setCurrPage(totalPages === 0 ? 0 : totalPages - 1) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [documentsRes]) + if (!isListLoading && isMuting) + setIsMuting(false) + }, [isListLoading, isMuting]) const invalidDocumentDetail = useInvalidDocumentDetailKey() const invalidChunkList = useInvalid(useSegmentListKey) const invalidChildChunkList = useInvalid(useChildSegmentListKey) const handleUpdate = useCallback(() => { - invalidDocumentList() + setIsMuting(true) + mutate() invalidDocumentDetail() setTimeout(() => { invalidChunkList() @@ -179,6 +175,8 @@ router.push(`/datasets/${datasetId}/documents/create`) } + const isLoading = isListLoading // !documentsRes && !error + const handleSaveNotionPageSelected = async (selectedPages: NotionPage[]) => { const workspacesMap = groupBy(selectedPages, 'workspace_id') const workspaces = Object.keys(workspacesMap).map((workspaceId) => { @@ -211,7 +209,7 @@ indexing_technique: dataset?.indexing_technique, process_rule: { rules: {}, - mode: ProcessMode.general, + mode: 'automatic', }, } as CreateDocumentReq @@ -219,7 +217,7 @@ datasetId, body: params, }) - invalidDocumentList() + mutate() setTimerCanRun(true) // mutateDatasetIndexingStatus(undefined, { revalidate: true }) setNotionPageSelectorModalVisible(false) @@ -236,45 +234,23 @@ handleSearch() } - const { - isShowEditModal: isShowEditMetadataModal, - showEditModal: showEditMetadataModal, - hideEditModal: hideEditMetadataModal, - datasetMetaData, - handleAddMetaData, - handleRename, - handleDeleteMetaData, - builtInEnabled, - setBuiltInEnabled, - builtInMetaData, - } = useEditDocumentMetadata({ - datasetId, - dataset, - onUpdateDocList: invalidDocumentList, - }) - return ( - <div className='flex h-full flex-col overflow-y-auto'> + <div className='flex flex-col h-full overflow-y-auto'> <div className='flex flex-col justify-center gap-1 px-6 pt-4'> <h1 className='text-base font-semibold text-text-primary'>{t('datasetDocuments.list.title')}</h1> - <div className='flex items-center space-x-0.5 text-sm font-normal text-text-tertiary'> + <div className='flex items-center text-sm font-normal text-text-tertiary space-x-0.5'> <span>{t('datasetDocuments.list.desc')}</span> <a className='flex items-center text-text-accent' target='_blank' - href={ - locale === LanguagesSupported[1] - ? 'https://docs.dify.ai/zh-hans/guides/knowledge-base/integrate-knowledge-within-application' - : 'https://docs.dify.ai/en/guides/knowledge-base/integrate-knowledge-within-application' - } - > + href='https://docs.dify.ai/guides/knowledge-base/integrate-knowledge-within-application'> <span>{t('datasetDocuments.list.learnMore')}</span> - <RiExternalLinkLine className='h-3 w-3' /> + <RiExternalLinkLine className='w-3 h-3' /> </a> </div> </div> - <div className='flex flex-1 flex-col px-6 py-4'> - <div className='flex flex-wrap items-center justify-between'> + <div className='flex flex-col px-6 py-4 flex-1'> + <div className='flex items-center justify-between flex-wrap'> <Input showLeftIcon showClearIcon @@ -283,31 +259,12 @@ onChange={e => handleInputChange(e.target.value)} onClear={() => handleInputChange('')} /> - <div className='flex !h-8 items-center justify-center gap-2'> + <div className='flex gap-2 justify-center items-center !h-8'> {!isFreePlan && <AutoDisabledDocument datasetId={datasetId} />} <IndexFailed datasetId={datasetId} /> - {!embeddingAvailable && <StatusWithAction type='warning' description={t('dataset.embeddingModelNotAvailable')} />} - {embeddingAvailable && ( - <Button variant='secondary' className='shrink-0' onClick={showEditMetadataModal}> - <RiDraftLine className='mr-1 size-4' /> - {t('dataset.metadata.metadata')} - </Button> - )} - {isShowEditMetadataModal && ( - <DatasetMetadataDrawer - userMetadata={datasetMetaData || []} - onClose={hideEditMetadataModal} - onAdd={handleAddMetaData} - onRename={handleRename} - onRemove={handleDeleteMetaData} - builtInMetadata={builtInMetaData || []} - isBuiltInEnabled={!!builtInEnabled} - onIsBuiltInEnabledChange={setBuiltInEnabled} - /> - )} {embeddingAvailable && ( <Button variant='primary' onClick={routeToDocCreate} className='shrink-0'> - <PlusIcon className={cn('mr-2 h-4 w-4 stroke-current')} /> + <PlusIcon className={cn('h-4 w-4 mr-2 stroke-current')} /> {isDataSourceNotion && t('datasetDocuments.list.addPages')} {isDataSourceWeb && t('datasetDocuments.list.addUrl')} {(!dataset?.data_source_type || isDataSourceFile) && t('datasetDocuments.list.addFile')} @@ -315,7 +272,7 @@ )} </div> </div> - {isListLoading + {(isLoading && !isMuting) ? <Loading type='app' /> : total > 0 ? <List @@ -332,7 +289,6 @@ current: currPage, onChange: setCurrPage, }} - onManageMetadata={showEditMetadataModal} /> : <EmptyElement canAdd={embeddingAvailable} onClick={routeToDocCreate} type={isDataSourceNotion ? 'sync' : 'upload'} /> } -- Gitblit v1.8.0