瀏覽代碼

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)
tags/v0.9.0
balibabu 1 年之前
父節點
當前提交
fb21efd77d
No account linked to committer's email address

+ 33
- 7
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"

+ 1
- 0
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",

+ 5
- 4
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) => {
>
<App> {children}</App>
</ConfigProvider>
<ReactQueryDevtools buttonPosition={'top-left'} />
</QueryClientProvider>
);
};

+ 2
- 2
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,

+ 1
- 0
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);


+ 55
- 38
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 = () => {

+ 1
- 1
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',

+ 0
- 8
web/src/pages/add-knowledge/components/knowledge-setting/model.ts 查看文件

@@ -29,14 +29,6 @@ const model: DvaModel<KSModelState> = {
},
},
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;

+ 3
- 4
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<string[]> & { 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 (
<Modal

+ 33
- 5
web/src/pages/knowledge/hooks.ts 查看文件

@@ -1,5 +1,8 @@
import { useSelectKnowledgeList } from '@/hooks/knowledge-hooks';
import { useState } from 'react';
import { KnowledgeRouteKey } from '@/constants/knowledge';
import { useSetModalState } from '@/hooks/common-hooks';
import { useCreateKnowledge } from '@/hooks/knowledge-hooks';
import { useCallback, useState } from 'react';
import { useNavigate } from 'umi';

export const useSearchKnowledge = () => {
const [searchString, setSearchString] = useState<string>('');
@@ -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,
};
};

+ 25
- 25
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 (
<Flex className={styles.knowledge} vertical flex={1}>
@@ -36,26 +42,14 @@ const KnowledgeList = () => {
prefix={<SearchOutlined />}
/>

<ModalManager>
{({ visible, hideModal, showModal }) => (
<>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() => {
showModal();
}}
className={styles.topButton}
>
{t('createKnowledgeBase')}
</Button>
<KnowledgeCreatingModal
visible={visible}
hideModal={hideModal}
></KnowledgeCreatingModal>
</>
)}
</ModalManager>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={showModal}
className={styles.topButton}
>
{t('createKnowledgeBase')}
</Button>
</Space>
</div>
<Spin spinning={loading}>
@@ -75,6 +69,12 @@ const KnowledgeList = () => {
)}
</Flex>
</Spin>
<KnowledgeCreatingModal
loading={creatingLoading}
visible={visible}
hideModal={hideModal}
onOk={onCreateOk}
></KnowledgeCreatingModal>
</Flex>
);
};

+ 5
- 8
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 = () => {

+ 11
- 36
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<IModalManagerChildrenProps, 'showModal'> {
loading: boolean;
onOk: (name: string) => void;
}

const KnowledgeCreatingModal = ({
visible,
hideModal,
}: Omit<IModalManagerChildrenProps, 'showModal'>) => {
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<any>({
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 }}
>
<Form
@@ -63,8 +40,6 @@ const KnowledgeCreatingModal = ({
labelCol={{ span: 4 }}
wrapperCol={{ span: 20 }}
style={{ maxWidth: 600 }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
form={form}
>

Loading…
取消
儲存