From fb21efd77d44c7459bca440cccab5198150e4590 Mon Sep 17 00:00:00 2001 From: balibabu Date: Fri, 19 Jul 2024 09:07:36 +0800 Subject: [PATCH] fix: after logging out and entering the knowledge base page again, the data before still exists #1306 (#1597) ### What problem does this PR solve? fix: after logging out and entering the knowledge base page again, the data before still exists #1306 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) --- web/package-lock.json | 40 ++++++-- web/package.json | 1 + web/src/app.tsx | 9 +- web/src/components/knowledge-base-item.tsx | 4 +- web/src/hooks/flow-hooks.ts | 1 + web/src/hooks/knowledge-hooks.ts | 93 +++++++++++-------- web/src/locales/en.ts | 2 +- .../components/knowledge-setting/model.ts | 8 -- .../connect-to-knowledge-modal/index.tsx | 7 +- web/src/pages/knowledge/hooks.ts | 38 +++++++- web/src/pages/knowledge/index.tsx | 50 +++++----- .../pages/knowledge/knowledge-card/index.tsx | 13 +-- .../knowledge-creating-modal/index.tsx | 47 +++------- 13 files changed, 175 insertions(+), 138 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index ffcabf5cc..39e07f929 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -11,6 +11,7 @@ "@ant-design/pro-layout": "^7.17.16", "@js-preview/excel": "^1.7.8", "@tanstack/react-query": "^5.40.0", + "@tanstack/react-query-devtools": "^5.51.5", "ahooks": "^3.7.10", "antd": "^5.12.7", "axios": "^1.6.3", @@ -4257,12 +4258,21 @@ "integrity": "sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==", "dev": true }, + "node_modules/@tanstack/query-devtools": { + "version": "5.51.1", + "resolved": "https://registry.npmmirror.com/@tanstack/query-devtools/-/query-devtools-5.51.1.tgz", + "integrity": "sha512-rehG0WmL3EXER6MAI2uHQia/n0b5c3ZROohpYm7u3G7yg4q+HsfQy6nuAo6uy40NzHUe3FmnfWCZQ0Vb/3lE6g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/react-query": { - "version": "5.40.0", - "resolved": "https://registry.npmmirror.com/@tanstack/react-query/-/react-query-5.40.0.tgz", - "integrity": "sha512-iv/W0Axc4aXhFzkrByToE1JQqayxTPNotCoSCnarR/A1vDIHaoKpg7FTIfP3Ev2mbKn1yrxq0ZKYUdLEJxs6Tg==", + "version": "5.51.8", + "resolved": "https://registry.npmmirror.com/@tanstack/react-query/-/react-query-5.51.8.tgz", + "integrity": "sha512-MQ6LhvOabxtNfxv47IkbI6cQy5PUte2CWSv8GVBCoTLE3iBjw22Nkv2171m+vNkveL+udH7n+R7WDal6I95RCA==", "dependencies": { - "@tanstack/query-core": "5.40.0" + "@tanstack/query-core": "5.51.8" }, "funding": { "type": "github", @@ -4272,10 +4282,26 @@ "react": "^18.0.0" } }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.51.5", + "resolved": "https://registry.npmmirror.com/@tanstack/react-query-devtools/-/react-query-devtools-5.51.5.tgz", + "integrity": "sha512-Gu2jSgFuCGnD8tGCJpwpkmrQ3F2j13dgxjKRY+yGN7aN5W7Wxo9jEUctlKotGvXDn/iFE/uscTRsE1Au7wBWPQ==", + "dependencies": { + "@tanstack/query-devtools": "5.51.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.51.5", + "react": "^18 || ^19" + } + }, "node_modules/@tanstack/react-query/node_modules/@tanstack/query-core": { - "version": "5.40.0", - "resolved": "https://registry.npmmirror.com/@tanstack/query-core/-/query-core-5.40.0.tgz", - "integrity": "sha512-eD8K8jsOIq0Z5u/QbvOmfvKKE/XC39jA7yv4hgpl/1SRiU+J8QCIwgM/mEHuunQsL87dcvnHqSVLmf9pD4CiaA==", + "version": "5.51.8", + "resolved": "https://registry.npmmirror.com/@tanstack/query-core/-/query-core-5.51.8.tgz", + "integrity": "sha512-Gp9UmHMgewLrz9m7egdpPZDywftgXSSvcRRr2UKA1r0w/OJ0CrS556sj4bMNQs2m5hQOsj/7o8lSoGr5ce1D6Q==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" diff --git a/web/package.json b/web/package.json index 59ff53b83..31e477175 100644 --- a/web/package.json +++ b/web/package.json @@ -22,6 +22,7 @@ "@ant-design/pro-layout": "^7.17.16", "@js-preview/excel": "^1.7.8", "@tanstack/react-query": "^5.40.0", + "@tanstack/react-query-devtools": "^5.51.5", "ahooks": "^3.7.10", "antd": "^5.12.7", "axios": "^1.6.3", diff --git a/web/src/app.tsx b/web/src/app.tsx index 9cbacdae2..67e1844a5 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -1,12 +1,10 @@ import i18n from '@/locales/config'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { App, ConfigProvider, ConfigProviderProps } from 'antd'; import enUS from 'antd/locale/en_US'; import zhCN from 'antd/locale/zh_CN'; import zh_HK from 'antd/locale/zh_HK'; -import React, { ReactNode, useEffect, useState } from 'react'; -import storage from './utils/authorizationUtil'; - -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import dayjs from 'dayjs'; import advancedFormat from 'dayjs/plugin/advancedFormat'; import customParseFormat from 'dayjs/plugin/customParseFormat'; @@ -14,6 +12,8 @@ import localeData from 'dayjs/plugin/localeData'; import weekOfYear from 'dayjs/plugin/weekOfYear'; import weekYear from 'dayjs/plugin/weekYear'; import weekday from 'dayjs/plugin/weekday'; +import React, { ReactNode, useEffect, useState } from 'react'; +import storage from './utils/authorizationUtil'; dayjs.extend(customParseFormat); dayjs.extend(advancedFormat); @@ -63,6 +63,7 @@ const RootProvider = ({ children }: React.PropsWithChildren) => { > {children} + ); }; diff --git a/web/src/components/knowledge-base-item.tsx b/web/src/components/knowledge-base-item.tsx index 2da220a29..155b09af7 100644 --- a/web/src/components/knowledge-base-item.tsx +++ b/web/src/components/knowledge-base-item.tsx @@ -1,11 +1,11 @@ import { useTranslate } from '@/hooks/common-hooks'; -import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks'; +import { useNextFetchKnowledgeList } from '@/hooks/knowledge-hooks'; import { Form, Select } from 'antd'; const KnowledgeBaseItem = () => { const { t } = useTranslate('chat'); - const { list: knowledgeList } = useFetchKnowledgeList(true); + const { list: knowledgeList } = useNextFetchKnowledgeList(true); const knowledgeOptions = knowledgeList.map((x) => ({ label: x.name, diff --git a/web/src/hooks/flow-hooks.ts b/web/src/hooks/flow-hooks.ts index dc91fd49e..3b5736e0a 100644 --- a/web/src/hooks/flow-hooks.ts +++ b/web/src/hooks/flow-hooks.ts @@ -96,6 +96,7 @@ export const useFetchFlow = (): { refetchOnReconnect: false, refetchOnMount: false, refetchOnWindowFocus: false, + gcTime: 0, queryFn: async () => { const { data } = await flowService.getCanvas({}, id); diff --git a/web/src/hooks/knowledge-hooks.ts b/web/src/hooks/knowledge-hooks.ts index 0cb677cf4..ed311a08d 100644 --- a/web/src/hooks/knowledge-hooks.ts +++ b/web/src/hooks/knowledge-hooks.ts @@ -1,11 +1,12 @@ import { useShowDeleteConfirm } from '@/hooks/common-hooks'; import { IKnowledge } from '@/interfaces/database/knowledge'; +import i18n from '@/locales/config'; import kbService from '@/services/knowledge-service'; -import { useQuery } from '@tanstack/react-query'; -import { useCallback, useEffect, useMemo } from 'react'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { message } from 'antd'; +import { useCallback, useEffect } from 'react'; import { useDispatch, useSearchParams, useSelector } from 'umi'; import { useGetKnowledgeSearchParams } from './route-hook'; -import { useOneNamespaceEffectsLoading } from './store-hooks'; export const useKnowledgeBaseId = (): string => { const [searchParams] = useSearchParams(); @@ -127,54 +128,70 @@ export const useFetchKnowledgeBaseConfiguration = () => { }, [fetchKnowledgeBaseConfiguration]); }; -export const useSelectKnowledgeList = () => { - const knowledgeModel = useSelector((state) => state.knowledgeModel); - const { data = [] } = knowledgeModel; - return data; -}; - -export const useFetchKnowledgeList = ( +export const useNextFetchKnowledgeList = ( shouldFilterListWithoutDocument: boolean = false, -) => { - const dispatch = useDispatch(); - const loading = useOneNamespaceEffectsLoading('knowledgeModel', ['getList']); - - const knowledgeModel = useSelector((state) => state.knowledgeModel); - const { data = [] } = knowledgeModel; - const list: IKnowledge[] = useMemo(() => { - return shouldFilterListWithoutDocument - ? data.filter((x: IKnowledge) => x.chunk_num > 0) - : data; - }, [data, shouldFilterListWithoutDocument]); - - const fetchList = useCallback(() => { - dispatch({ - type: 'knowledgeModel/getList', - }); - }, [dispatch]); - - useEffect(() => { - fetchList(); - }, [fetchList]); - - return { list, loading, fetchList }; -}; - -export const useNextFetchKnowledgeList = (): { - data: any[]; +): { + list: any[]; loading: boolean; } => { const { data, isFetching: loading } = useQuery({ queryKey: ['fetchKnowledgeList'], initialData: [], + gcTime: 0, // https://tanstack.com/query/latest/docs/framework/react/guides/caching?from=reactQueryV3 queryFn: async () => { const { data } = await kbService.getList(); + const list = data?.data ?? []; + return shouldFilterListWithoutDocument + ? list.filter((x: IKnowledge) => x.chunk_num > 0) + : list; + }, + }); + return { list: data, loading }; +}; + +export const useCreateKnowledge = () => { + const queryClient = useQueryClient(); + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['createKnowledge'], + mutationFn: async (params: { id?: string; name: string }) => { + const { data = {} } = await kbService.createKb(params); + if (data.retcode === 0) { + message.success( + i18n.t(`message.${params?.id ? 'modified' : 'created'}`), + ); + queryClient.invalidateQueries({ queryKey: ['fetchKnowledgeList'] }); + } + return data; + }, + }); + + return { data, loading, createKnowledge: mutateAsync }; +}; + +export const useDeleteKnowledge = () => { + const queryClient = useQueryClient(); + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['deleteKnowledge'], + mutationFn: async (id: string) => { + const { data } = await kbService.rmKb({ kb_id: id }); + if (data.retcode === 0) { + message.success(i18n.t(`message.deleted`)); + queryClient.invalidateQueries({ queryKey: ['fetchKnowledgeList'] }); + } return data?.data ?? []; }, }); - return { data, loading }; + return { data, loading, deleteKnowledge: mutateAsync }; }; export const useSelectFileThumbnails = () => { diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 658f0e51b..2cad09673 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -124,7 +124,7 @@ export default { fromMessage: 'Missing start page number', toPlaceholder: 'to', toMessage: 'Missing end page number(excluded)', - layoutRecognize: 'Layout recognize', + layoutRecognize: 'Layout recognition', layoutRecognizeTip: 'Use visual models for layout analysis to better identify document structure, find where the titles, text blocks, images, and tables are. Without this feature, only the plain text of the PDF can be obtained.', taskPageSize: 'Task page size', diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/model.ts b/web/src/pages/add-knowledge/components/knowledge-setting/model.ts index a639172e4..d8706eaf6 100644 --- a/web/src/pages/add-knowledge/components/knowledge-setting/model.ts +++ b/web/src/pages/add-knowledge/components/knowledge-setting/model.ts @@ -29,14 +29,6 @@ const model: DvaModel = { }, }, effects: { - *createKb({ payload = {} }, { call }) { - const { data } = yield call(kbService.createKb, payload); - const { retcode } = data; - if (retcode === 0) { - message.success(i18n.t('message.created')); - } - return data; - }, *updateKb({ payload = {} }, { call, put }) { const { data } = yield call(kbService.updateKb, payload); const { retcode } = data; diff --git a/web/src/pages/file-manager/connect-to-knowledge-modal/index.tsx b/web/src/pages/file-manager/connect-to-knowledge-modal/index.tsx index 3c70862e4..9260c51df 100644 --- a/web/src/pages/file-manager/connect-to-knowledge-modal/index.tsx +++ b/web/src/pages/file-manager/connect-to-knowledge-modal/index.tsx @@ -1,5 +1,5 @@ import { useTranslate } from '@/hooks/common-hooks'; -import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks'; +import { useNextFetchKnowledgeList } from '@/hooks/knowledge-hooks'; import { IModalProps } from '@/interfaces/common'; import { filterOptionsByInput } from '@/utils/commonUtil'; import { Form, Modal, Select } from 'antd'; @@ -13,7 +13,7 @@ const ConnectToKnowledgeModal = ({ loading, }: IModalProps & { initialValue: string[] }) => { const [form] = Form.useForm(); - const { list, fetchList } = useFetchKnowledgeList(); + const { list } = useNextFetchKnowledgeList(); const { t } = useTranslate('fileManager'); const options = list?.map((item) => ({ @@ -30,9 +30,8 @@ const ConnectToKnowledgeModal = ({ useEffect(() => { if (visible) { form.setFieldValue('knowledgeIds', initialValue); - fetchList(); } - }, [visible, fetchList, initialValue, form]); + }, [visible, initialValue, form]); return ( { const [searchString, setSearchString] = useState(''); @@ -13,7 +16,32 @@ export const useSearchKnowledge = () => { }; }; -export const useSelectKnowledgeListByKeywords = (keywords: string) => { - const list = useSelectKnowledgeList(); - return list.filter((x) => x.name.includes(keywords)); +export const useSaveKnowledge = () => { + const { visible: visible, hideModal, showModal } = useSetModalState(); + const { loading, createKnowledge } = useCreateKnowledge(); + const navigate = useNavigate(); + + const onCreateOk = useCallback( + async (name: string) => { + const ret = await createKnowledge({ + name, + }); + + if (ret?.retcode === 0) { + hideModal(); + navigate( + `/knowledge/${KnowledgeRouteKey.Configuration}?id=${ret.data.kb_id}`, + ); + } + }, + [createKnowledge, hideModal, navigate], + ); + + return { + loading, + onCreateOk, + visible, + hideModal, + showModal, + }; }; diff --git a/web/src/pages/knowledge/index.tsx b/web/src/pages/knowledge/index.tsx index 4b034566a..f331b36b2 100644 --- a/web/src/pages/knowledge/index.tsx +++ b/web/src/pages/knowledge/index.tsx @@ -1,5 +1,4 @@ -import ModalManager from '@/components/modal-manager'; -import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks'; +import { useNextFetchKnowledgeList } from '@/hooks/knowledge-hooks'; import { useSelectUserInfo } from '@/hooks/user-setting-hooks'; import { PlusOutlined, SearchOutlined } from '@ant-design/icons'; import { Button, Empty, Flex, Input, Space, Spin } from 'antd'; @@ -7,15 +6,22 @@ import KnowledgeCard from './knowledge-card'; import KnowledgeCreatingModal from './knowledge-creating-modal'; import { useTranslation } from 'react-i18next'; -import { useSearchKnowledge, useSelectKnowledgeListByKeywords } from './hooks'; +import { useSaveKnowledge, useSearchKnowledge } from './hooks'; import styles from './index.less'; const KnowledgeList = () => { const { searchString, handleInputChange } = useSearchKnowledge(); - const { loading } = useFetchKnowledgeList(); - const list = useSelectKnowledgeListByKeywords(searchString); + const { loading, list: data } = useNextFetchKnowledgeList(); + const list = data.filter((x) => x.name.includes(searchString)); const userInfo = useSelectUserInfo(); const { t } = useTranslation('translation', { keyPrefix: 'knowledgeList' }); + const { + visible, + hideModal, + showModal, + onCreateOk, + loading: creatingLoading, + } = useSaveKnowledge(); return ( @@ -36,26 +42,14 @@ const KnowledgeList = () => { prefix={} /> - - {({ visible, hideModal, showModal }) => ( - <> - - - - )} - + @@ -75,6 +69,12 @@ const KnowledgeList = () => { )} + ); }; diff --git a/web/src/pages/knowledge/knowledge-card/index.tsx b/web/src/pages/knowledge/knowledge-card/index.tsx index 4fe3a99b8..fe3dfaee8 100644 --- a/web/src/pages/knowledge/knowledge-card/index.tsx +++ b/web/src/pages/knowledge/knowledge-card/index.tsx @@ -8,9 +8,10 @@ import { } from '@ant-design/icons'; import { Avatar, Card, Space } from 'antd'; import { useTranslation } from 'react-i18next'; -import { useDispatch, useNavigate } from 'umi'; +import { useNavigate } from 'umi'; import OperateDropdown from '@/components/operate-dropdown'; +import { useDeleteKnowledge } from '@/hooks/knowledge-hooks'; import styles from './index.less'; interface IProps { @@ -19,16 +20,12 @@ interface IProps { const KnowledgeCard = ({ item }: IProps) => { const navigate = useNavigate(); - const dispatch = useDispatch(); const { t } = useTranslation(); + const { deleteKnowledge } = useDeleteKnowledge(); + const removeKnowledge = async () => { - return dispatch({ - type: 'knowledgeModel/rmKb', - payload: { - kb_id: item.id, - }, - }); + return deleteKnowledge(item.id); }; const handleCardClick = () => { diff --git a/web/src/pages/knowledge/knowledge-creating-modal/index.tsx b/web/src/pages/knowledge/knowledge-creating-modal/index.tsx index 20eaa0668..0ec75d2e3 100644 --- a/web/src/pages/knowledge/knowledge-creating-modal/index.tsx +++ b/web/src/pages/knowledge/knowledge-creating-modal/index.tsx @@ -1,53 +1,30 @@ import { IModalManagerChildrenProps } from '@/components/modal-manager'; -import { KnowledgeRouteKey } from '@/constants/knowledge'; import { Form, Input, Modal } from 'antd'; import { useTranslation } from 'react-i18next'; -import { useDispatch, useNavigate, useSelector } from 'umi'; type FieldType = { name?: string; }; +interface IProps extends Omit { + loading: boolean; + onOk: (name: string) => void; +} + const KnowledgeCreatingModal = ({ visible, hideModal, -}: Omit) => { + loading, + onOk, +}: IProps) => { const [form] = Form.useForm(); - const dispatch = useDispatch(); - const loading = useSelector( - (state: any) => state.loading.effects['kSModel/createKb'], - ); - const navigate = useNavigate(); + const { t } = useTranslation('translation', { keyPrefix: 'knowledgeList' }); const handleOk = async () => { const ret = await form.validateFields(); - const data = await dispatch({ - type: 'kSModel/createKb', - payload: { - name: ret.name, - }, - }); - - if (data.retcode === 0) { - navigate( - `/knowledge/${KnowledgeRouteKey.Configuration}?id=${data.data.kb_id}`, - ); - hideModal(); - } - }; - - const handleCancel = () => { - hideModal(); - }; - - const onFinish = (values: any) => { - console.log('Success:', values); - }; - - const onFinishFailed = (errorInfo: any) => { - console.log('Failed:', errorInfo); + onOk(ret.name); }; return ( @@ -55,7 +32,7 @@ const KnowledgeCreatingModal = ({ title={t('createKnowledgeBase')} open={visible} onOk={handleOk} - onCancel={handleCancel} + onCancel={hideModal} okButtonProps={{ loading }} >