From fdab383b26abda807b7f4900d3787c676ac326f3 Mon Sep 17 00:00:00 2001 From: papapatrick <109422393+Patrickill@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:00:55 +0800 Subject: [PATCH] Style-dataset-2.5 (#2580) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * style: dataset detail page 2.5 * fix merge error * fix: flash bug * fix: build error * revert: 滚动变回分页 --- .../web/components/common/Icon/constants.ts | 1 + .../web/components/common/Icon/icons/book.svg | 4 +- .../components/common/Icon/icons/visible.svg | 3 + packages/web/i18n/en/common.json | 7 +- packages/web/i18n/zh/common.json | 7 +- .../components/common/ParentPaths/index.tsx | 2 +- .../components/core/app/InputGuideConfig.tsx | 2 +- .../src/components/core/dataset/QuoteItem.tsx | 3 - .../dataset/detail/components/DataCard.tsx | 17 +- .../detail/components/InputDataModal.tsx | 555 +++++++++++------- .../detail/components/MetaDataCard.tsx | 38 +- .../dataset/detail/components/NavBar.tsx | 104 ++-- .../detail/components/styles.module.scss | 11 + .../dataset/context/datasetPageContext.tsx | 30 +- 14 files changed, 473 insertions(+), 311 deletions(-) create mode 100644 packages/web/components/common/Icon/icons/visible.svg create mode 100644 projects/app/src/pages/dataset/detail/components/styles.module.scss diff --git a/packages/web/components/common/Icon/constants.ts b/packages/web/components/common/Icon/constants.ts index 7c307c635..8375960e9 100644 --- a/packages/web/components/common/Icon/constants.ts +++ b/packages/web/components/common/Icon/constants.ts @@ -2,6 +2,7 @@ export const iconPaths = { book: () => import('./icons/book.svg'), + visible: () => import('./icons/visible.svg'), change: () => import('./icons/change.svg'), chatSend: () => import('./icons/chatSend.svg'), closeSolid: () => import('./icons/closeSolid.svg'), diff --git a/packages/web/components/common/Icon/icons/book.svg b/packages/web/components/common/Icon/icons/book.svg index 9e45d5e20..043acdc65 100644 --- a/packages/web/components/common/Icon/icons/book.svg +++ b/packages/web/components/common/Icon/icons/book.svg @@ -1,3 +1,3 @@ - - + + diff --git a/packages/web/components/common/Icon/icons/visible.svg b/packages/web/components/common/Icon/icons/visible.svg new file mode 100644 index 000000000..74a44b850 --- /dev/null +++ b/packages/web/components/common/Icon/icons/visible.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index 23aa62856..9332a4001 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -443,7 +443,8 @@ "tool_label": { "doc": "Use documentation", "github": "GitHub address", - "price": "Billing instructions" + "price": "Billing instructions", + "view_doc": "View documentation" }, "tts": { "Close": "Do not use", @@ -659,6 +660,7 @@ "Search data placeholder": "Search related data", "Too Long": "Total length too long", "Total Amount": "{{total}} sets", + "empty_index": "No custom index", "group": "Group", "unit": "items" }, @@ -1062,7 +1064,8 @@ "Content": "Data content", "Course": "Documentation", "Delete": "Delete data", - "Index": "Data Index ({{amount}})" + "Index": "Data Index ({{amount}})", + "divide_content": "Chunked content" }, "input is empty": "Data content cannot be empty" }, diff --git a/packages/web/i18n/zh/common.json b/packages/web/i18n/zh/common.json index f0d9cf466..ad65373e0 100644 --- a/packages/web/i18n/zh/common.json +++ b/packages/web/i18n/zh/common.json @@ -443,7 +443,8 @@ "tool_label": { "doc": "使用文档", "github": "GitHub地址", - "price": "计费说明" + "price": "计费说明", + "view_doc": "查看说明文档" }, "tts": { "Close": "不使用", @@ -658,6 +659,7 @@ "Search data placeholder": "搜索相关数据", "Too Long": "总长度超长了", "Total Amount": "{{total}} 组", + "empty_index": "无自定义索引", "group": "组", "unit": "条" }, @@ -1061,7 +1063,8 @@ "Content": "数据内容", "Course": "说明文档", "Delete": "删除数据", - "Index": "数据索引({{amount}})" + "Index": "数据索引({{amount}})", + "divide_content": "分块内容" }, "input is empty": "数据内容不能为空 " }, diff --git a/projects/app/src/components/common/ParentPaths/index.tsx b/projects/app/src/components/common/ParentPaths/index.tsx index 6f751eae5..bd9d83708 100644 --- a/projects/app/src/components/common/ParentPaths/index.tsx +++ b/projects/app/src/components/common/ParentPaths/index.tsx @@ -60,7 +60,7 @@ const ParentPaths = (props: { {item.parentName} {i !== concatPaths.length - 1 && ( - + / )} diff --git a/projects/app/src/components/core/app/InputGuideConfig.tsx b/projects/app/src/components/core/app/InputGuideConfig.tsx index 9668901c5..0965f14af 100644 --- a/projects/app/src/components/core/app/InputGuideConfig.tsx +++ b/projects/app/src/components/core/app/InputGuideConfig.tsx @@ -150,7 +150,7 @@ const InputGuideConfig = ({ alignItems={'center'} cursor={'pointer'} > - + {commonT('common.Documents')} diff --git a/projects/app/src/components/core/dataset/QuoteItem.tsx b/projects/app/src/components/core/dataset/QuoteItem.tsx index 57f589c9f..2a6b8f563 100644 --- a/projects/app/src/components/core/dataset/QuoteItem.tsx +++ b/projects/app/src/components/core/dataset/QuoteItem.tsx @@ -275,9 +275,6 @@ const QuoteItem = ({ onSuccess={() => { console.log('更新引用成功'); }} - onDelete={() => { - console.log('删除引用成功'); - }} dataId={editInputData.dataId} collectionId={editInputData.collectionId} /> diff --git a/projects/app/src/pages/dataset/detail/components/DataCard.tsx b/projects/app/src/pages/dataset/detail/components/DataCard.tsx index 769a02cfd..50844077b 100644 --- a/projects/app/src/pages/dataset/detail/components/DataCard.tsx +++ b/projects/app/src/pages/dataset/detail/components/DataCard.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, useMemo } from 'react'; +import React, { useState, useRef, useMemo, useCallback } from 'react'; import { Box, Card, @@ -69,8 +69,6 @@ const DataCard = () => { content: t('common:dataset.Confirm to delete the data'), type: 'delete' }); - const { isOpen, onOpen, onClose } = useDisclosure(); - const readSource = getCollectionSourceAndOpen(collectionId); const { data: datasetDataList, @@ -136,10 +134,10 @@ const DataCard = () => { const isLoading = isRequesting || loading; return ( - + {/* Header */} - + @@ -174,10 +172,10 @@ const DataCard = () => { )} - + - + @@ -227,7 +225,7 @@ const DataCard = () => { '& .forbid-switch': { display: 'flex' }, bg: index % 2 === 1 ? 'myGray.200' : 'blue.100' }} - onClickCapture={(e) => { + onClick={(e) => { e.stopPropagation(); if (!collection) return; setEditDataId(item._id); @@ -316,7 +314,7 @@ const DataCard = () => { display={'flex'} p={1} boxShadow={'1'} - icon={} + icon={} variant={'whiteDanger'} size={'xsSquare'} aria-label={'delete'} @@ -355,7 +353,6 @@ const DataCard = () => { dataId={editDataId} onClose={() => setEditDataId(undefined)} onSuccess={() => getData(pageNum)} - onDelete={() => getData(pageNum)} /> )} diff --git a/projects/app/src/pages/dataset/detail/components/InputDataModal.tsx b/projects/app/src/pages/dataset/detail/components/InputDataModal.tsx index ced3c489a..7ea9ccacc 100644 --- a/projects/app/src/pages/dataset/detail/components/InputDataModal.tsx +++ b/projects/app/src/pages/dataset/detail/components/InputDataModal.tsx @@ -1,6 +1,14 @@ -import React, { useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Box, Flex, Button, Textarea, useTheme, Grid, HStack } from '@chakra-ui/react'; -import { UseFormRegister, useFieldArray, useForm } from 'react-hook-form'; +import { + Control, + FieldArrayWithId, + UseFieldArrayAppend, + UseFieldArrayRemove, + UseFormRegister, + useFieldArray, + useForm +} from 'react-hook-form'; import { postInsertData2Dataset, putDatasetDataById, @@ -16,7 +24,7 @@ import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { useRequest, useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; -import { getDefaultIndex } from '@fastgpt/global/core/dataset/utils'; +import { getDefaultIndex, getSourceNameIcon } from '@fastgpt/global/core/dataset/utils'; import { DatasetDataIndexItemType } from '@fastgpt/global/core/dataset/type'; import SideTabs from '@/components/SideTabs'; import DeleteIcon from '@fastgpt/web/components/common/Icon/delete'; @@ -27,6 +35,9 @@ import MyBox from '@fastgpt/web/components/common/MyBox'; import { getErrText } from '@fastgpt/global/common/error/utils'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; +import { useSystem } from '@fastgpt/web/hooks/useSystem'; +import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs'; +import styles from './styles.module.scss'; export type InputDataType = { q: string; @@ -38,9 +49,7 @@ export type InputDataType = { enum TabEnum { content = 'content', - index = 'index', - delete = 'delete', - doc = 'doc' + index = 'index' } const InputDataModal = ({ @@ -48,22 +57,20 @@ const InputDataModal = ({ dataId, defaultValue, onClose, - onSuccess, - onDelete + onSuccess }: { collectionId: string; dataId?: string; defaultValue?: { q: string; a?: string }; onClose: () => void; onSuccess: (data: InputDataType & { dataId: string }) => void; - onDelete?: () => void; }) => { const { t } = useTranslation(); const theme = useTheme(); const { toast } = useToast(); const [currentTab, setCurrentTab] = useState(TabEnum.content); const { vectorModelList } = useSystemStore(); - + const { isPc } = useSystem(); const { register, handleSubmit, reset, control } = useForm(); const { fields: indexes, @@ -76,19 +83,35 @@ const InputDataModal = ({ const tabList = [ { - label: t('common:dataset.data.edit.Content'), - value: TabEnum.content, - icon: 'common/overviewLight' + label: ( + + {t('common:dataset.data.edit.divide_content')} + + ), + value: TabEnum.content }, { - label: t('common:dataset.data.edit.Index', { amount: indexes.length }), - value: TabEnum.index, - icon: 'kbTest' - }, - ...(dataId - ? [{ label: t('common:dataset.data.edit.Delete'), value: TabEnum.delete, icon: 'delete' }] - : []), - { label: t('common:dataset.data.edit.Course'), value: TabEnum.doc, icon: 'common/courseLight' } + label: ( + + {t('common:dataset.data.edit.Index', { amount: indexes.length })} + + window.open(getDocPath('/docs/course/dataset_engine'), '_blank')} + _hover={{ + color: 'primary.600', + cursor: 'pointer' + }} + /> + + + ), + value: TabEnum.index + } ]; const { ConfirmModal, openConfirm } = useConfirm({ @@ -181,7 +204,7 @@ const InputDataModal = ({ a: '', indexes: [] }); - + console.log('执行onSuccess'); onSuccess(e); }, errorToast: t('common:common.error.unKnow') @@ -215,176 +238,101 @@ const InputDataModal = ({ } } ); - // delete - const { mutate: onDeleteData, isLoading: isDeleting } = useRequest({ - mutationFn: () => { - if (!onDelete || !dataId) return Promise.resolve(null); - return delOneDatasetDataById(dataId); - }, - onSuccess() { - if (!onDelete) return; - onDelete(); - onClose(); - }, - successToast: t('common:common.Delete Success'), - errorToast: t('common:common.error.unKnow') - }); - const isLoading = isFetchingData || isDeleting; + const isLoading = isFetchingData; + const icon = useMemo( + () => getSourceNameIcon({ sourceName: collection.sourceName, sourceId: collection.sourceId }), + [collection] + ); return ( - - - - - - list={tabList} - value={currentTab} - onChange={async (e) => { - if (e === TabEnum.delete) { - return openConfirm(onDeleteData)(); - } - if (e === TabEnum.doc) { - return window.open(getDocPath('/docs/course/dataset_engine'), '_blank'); - } - setCurrentTab(e); - }} - /> - - - - {currentTab === TabEnum.content && ( - <> - {dataId - ? t('common:dataset.data.Update Data') - : t('common:dataset.data.Input Data')} - - )} - {currentTab === TabEnum.index && <> {t('common:dataset.data.Index Edit')}} + onClose()} + closeOnOverlayClick={false} + maxW={'1440px'} + h={'46.25rem'} + title={ + + + + {collection.sourceName || t('common:common.UnKnow Source')} - - {currentTab === TabEnum.content && } - {currentTab === TabEnum.index && ( - - {indexes?.map((index, i) => ( - - - - {index.defaultIndex - ? t('common:dataset.data.Default Index') - : t('dataset.data.Custom Index Number', { number: i })} - - { - if (indexes.length <= 1) { - appendIndexes(getDefaultIndex({ dataId: `${Date.now()}` })); - } - removeIndexes(i); - }} - /> - - {index.defaultIndex ? ( - - {t('common:core.dataset.data.Default Index Tip')} - - ) : ( - - )} - - ))} - - appendIndexes({ - defaultIndex: false, - text: '', - dataId: `${Date.now()}` - }) - } - > - - {t('common:dataset.data.Add Index')} - - - )} - - {/* footer */} - - - - - + + } + > + + + + + list={tabList} + p={0} + value={currentTab} + onChange={(e: TabEnum) => setCurrentTab(e)} + /> + {currentTab === TabEnum.index && ( + + )} + + + {currentTab === TabEnum.content && } + {currentTab === TabEnum.index && ( + + )} + + + + + + @@ -404,44 +352,205 @@ const InputTab = ({ const { t } = useTranslation(); return ( - - - - * - {t('common:core.dataset.data.Main Content')} - + <> + + + + * + {t('common:core.dataset.data.Main Content')} + + + + + - - - - - - - {t('common:core.dataset.data.Auxiliary Data')} - + + + {t('common:core.dataset.data.Auxiliary Data')} + + + + + - - - - + + ); +}; + +const DataIndex = ({ + maxToken, + register, + indexes, + appendIndexes, + removeIndexes +}: { + maxToken: number; + register: UseFormRegister; + indexes: FieldArrayWithId[]; + appendIndexes: UseFieldArrayAppend; + removeIndexes: UseFieldArrayRemove; +}) => { + const { t } = useTranslation(); + + return ( + <> + + + + + {t('common:dataset.data.Default Index')} + + + + {t('common:core.dataset.data.Default Index Tip')} + + + {indexes?.map((index, i) => { + return ( + !index.defaultIndex && ( + + + + {t('dataset.data.Custom Index Number', { number: i })} + + { + if (indexes.length <= 1) { + appendIndexes(getDefaultIndex({ dataId: `${Date.now()}` })); + } + removeIndexes(i); + }} + /> + + + + ) + ); + })} + + + ); +}; + +const DataIndexTextArea = ({ + index, + maxToken, + register +}: { + index: number; + maxToken: number; + register: UseFormRegister; +}) => { + const { t } = useTranslation(); + const TextareaDom = useRef(null); + const { + ref: TextareaRef, + required, + name, + onChange: onTextChange, + onBlur + } = register(`indexes.${index}.text`, { required: true }); + const textareaMinH = '40px'; + useEffect(() => { + if (TextareaDom.current) { + TextareaDom.current.style.height = textareaMinH; + TextareaDom.current.style.height = `${TextareaDom.current.scrollHeight + 5}px`; + } + }, []); + const autoHeight = useCallback((e: React.ChangeEvent) => { + if (e.target) { + e.target.style.height = textareaMinH; + e.target.style.height = `${e.target.scrollHeight + 5}px`; + } + }, []); + return ( + + {metadataList.map( + (item, i) => + item.label && + item.value && ( + + + {item.label} + + {item.value} + + ) + )} {collection?.sourceId && ( )} diff --git a/projects/app/src/pages/dataset/detail/components/NavBar.tsx b/projects/app/src/pages/dataset/detail/components/NavBar.tsx index 4fd981e5c..ffd1f6c77 100644 --- a/projects/app/src/pages/dataset/detail/components/NavBar.tsx +++ b/projects/app/src/pages/dataset/detail/components/NavBar.tsx @@ -9,6 +9,7 @@ import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs'; import { useI18n } from '@/web/context/I18n'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; import MyPopover from '@fastgpt/web/components/common/MyPopover'; +import ParentPaths from '@/components/common/ParentPaths'; export enum TabEnum { dataCard = 'dataCard', @@ -25,7 +26,7 @@ const NavBar = ({ currentTab }: { currentTab: TabEnum }) => { const router = useRouter(); const query = router.query; const { isPc } = useSystem(); - const { datasetDetail, vectorTrainingMap, agentTrainingMap, rebuildingCount } = + const { datasetDetail, vectorTrainingMap, agentTrainingMap, rebuildingCount, paths } = useContextSelector(DatasetPageContext, (v) => v); const tabList = [ @@ -55,56 +56,67 @@ const NavBar = ({ currentTab }: { currentTab: TabEnum }) => { <> {isPc ? ( - { - if (currentTab !== TabEnum.dataCard) router.replace('/dataset/list'); - else - router.replace({ - query: { - datasetId: router.query.datasetId, - parentId: router.query.parentId, - currentTab: TabEnum.collectionCard - } - }); - }} - > - } - bg={'white'} - size={'smSquare'} - borderRadius={'50%'} - aria-label={''} - _hover={'none'} - /> - - {currentTab !== TabEnum.dataCard - ? t('common:core.dataset.All Dataset') - : datasetDetail.name} - - + {currentTab === TabEnum.dataCard ? ( + <> + { + router.replace({ + query: { + datasetId: router.query.datasetId, + parentId: router.query.parentId, + currentTab: TabEnum.collectionCard + } + }); + }} + > + } + bg={'white'} + size={'smSquare'} + borderRadius={'50%'} + aria-label={''} + _hover={'none'} + /> + + {datasetDetail.name} + + + + ) : ( + + { + router.push(`/dataset/list?parentId=${e}`); + }} + /> + + )} + px={4} diff --git a/projects/app/src/pages/dataset/detail/components/styles.module.scss b/projects/app/src/pages/dataset/detail/components/styles.module.scss new file mode 100644 index 000000000..c54428da5 --- /dev/null +++ b/projects/app/src/pages/dataset/detail/components/styles.module.scss @@ -0,0 +1,11 @@ +.scrollbar { + &::-webkit-scrollbar-thumb { + background: var(--chakra-colors-myGray-150) !important; + transition: background 1s; + margin-left: 5px; + } + + &::-webkit-scrollbar-thumb:hover { + background: var(--chakra-colors-myGray-250) !important; + } +} diff --git a/projects/app/src/web/core/dataset/context/datasetPageContext.tsx b/projects/app/src/web/core/dataset/context/datasetPageContext.tsx index 0c9a59092..1529bb3bf 100644 --- a/projects/app/src/web/core/dataset/context/datasetPageContext.tsx +++ b/projects/app/src/web/core/dataset/context/datasetPageContext.tsx @@ -6,6 +6,7 @@ import { getAllTags, getDatasetById, getDatasetCollectionTags, + getDatasetPaths, getDatasetTrainingQueue, getTrainingQueueLen, postCreateDatasetCollectionTag, @@ -15,6 +16,7 @@ import { defaultDatasetDetail } from '../constants'; import { DatasetUpdateBody } from '@fastgpt/global/core/dataset/api'; import { DatasetItemType, DatasetTagType } from '@fastgpt/global/core/dataset/type'; import { useSystemStore } from '@/web/common/system/useSystemStore'; +import { ParentTreePathItemType } from '@fastgpt/global/common/parentFolder/type'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; type DatasetPageContextType = { @@ -32,7 +34,8 @@ type DatasetPageContextType = { isCreateCollectionTagLoading: boolean; searchTagKey: string; setSearchTagKey: Dispatch>; - + paths: ParentTreePathItemType[]; + refetchPaths: () => void; vectorTrainingMap: { colorSchema: string; tip: string; @@ -84,7 +87,9 @@ export const DatasetPageContext = createContext({ searchTagKey: '', setSearchTagKey: function (value: SetStateAction): void { throw new Error('Function not implemented.'); - } + }, + paths: [], + refetchPaths: () => {} }); export const DatasetPageContextProvider = ({ @@ -99,12 +104,9 @@ export const DatasetPageContextProvider = ({ // dataset detail const [datasetDetail, setDatasetDetail] = useState(defaultDatasetDetail); - const loadDatasetDetail = async (id: string) => { const data = await getDatasetById(id); - setDatasetDetail(data); - return data; }; const updateDataset = async (data: DatasetUpdateBody) => { @@ -224,12 +226,28 @@ export const DatasetPageContextProvider = ({ refetchInterval: 10000 }); + const { data: paths = [], runAsync: refetchPaths } = useRequest2( + () => + getDatasetPaths(datasetDetail.parentId).then((res) => { + res.push({ + parentId: '', + parentName: datasetDetail.name + }); + return res; + }), + { + manual: false, + refreshDeps: [datasetDetail.parentId] + } + ); + const contextValue: DatasetPageContextType = { datasetId, datasetDetail, loadDatasetDetail, updateDataset, - + paths, + refetchPaths, vectorTrainingMap, agentTrainingMap, rebuildingCount,