From 73c2f4d4183fa097b32b294f1cee96769d227cda Mon Sep 17 00:00:00 2001
From: balibabu <cike8899@users.noreply.github.com>
Date: Fri, 22 Mar 2024 11:35:25 +0800
Subject: [PATCH] feat: add hooks for document table and refactor
 document-related modal (#141)

* feat: add hooks for document table

* refactor: refactor document-related modal
---
 web/src/hooks/documentHooks.ts                | 142 ++++++++++-
 ...entSetModal.tsx => chunk-method-modal.tsx} | 155 +++++------
 .../knowledge-file/create-file-modal.tsx      |  49 ++++
 .../knowledge-file/createEFileModal.tsx       |  78 ------
 .../components/knowledge-file/hooks.ts        | 241 ++++++++++++++++++
 .../components/knowledge-file/index.tsx       | 229 ++++++-----------
 .../components/knowledge-file/model.ts        |  13 +-
 .../parsing-action-cell/index.tsx             |  53 +---
 .../knowledge-file/rename-modal/index.tsx     |  56 ++--
 .../knowledge-setting/category-panel.tsx      |   6 +-
 .../components/knowledge-setting/index.tsx    |   4 +-
 web/src/pages/chat/index.tsx                  |   2 +-
 12 files changed, 626 insertions(+), 402 deletions(-)
 rename web/src/pages/add-knowledge/components/knowledge-file/{segmentSetModal.tsx => chunk-method-modal.tsx} (55%)
 create mode 100644 web/src/pages/add-knowledge/components/knowledge-file/create-file-modal.tsx
 delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/createEFileModal.tsx
 create mode 100644 web/src/pages/add-knowledge/components/knowledge-file/hooks.ts

diff --git a/web/src/hooks/documentHooks.ts b/web/src/hooks/documentHooks.ts
index a79f9d1..536da8b 100644
--- a/web/src/hooks/documentHooks.ts
+++ b/web/src/hooks/documentHooks.ts
@@ -1,8 +1,10 @@
-import { IChunk } from '@/interfaces/database/knowledge';
+import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge';
 import { api_host } from '@/utils/api';
 import { buildChunkHighlights } from '@/utils/documentUtils';
-import { useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
 import { IHighlight } from 'react-pdf-highlighter';
+import { useDispatch, useSelector } from 'umi';
+import { useGetKnowledgeSearchParams } from './routeHook';
 
 export const useGetDocumentUrl = (documentId: string) => {
   const url = useMemo(() => {
@@ -19,3 +21,139 @@ export const useGetChunkHighlights = (selectedChunk: IChunk): IHighlight[] => {
 
   return highlights;
 };
+
+export const useFetchDocumentList = () => {
+  const { knowledgeId } = useGetKnowledgeSearchParams();
+
+  const dispatch = useDispatch();
+
+  const fetchKfList = useCallback(() => {
+    return dispatch<any>({
+      type: 'kFModel/getKfList',
+      payload: {
+        kb_id: knowledgeId,
+      },
+    });
+  }, [dispatch, knowledgeId]);
+
+  return fetchKfList;
+};
+
+export const useSetDocumentStatus = () => {
+  const dispatch = useDispatch();
+  const { knowledgeId } = useGetKnowledgeSearchParams();
+
+  const setDocumentStatus = useCallback(
+    (status: boolean, documentId: string) => {
+      dispatch({
+        type: 'kFModel/updateDocumentStatus',
+        payload: {
+          doc_id: documentId,
+          status: Number(status),
+          kb_id: knowledgeId,
+        },
+      });
+    },
+    [dispatch, knowledgeId],
+  );
+
+  return setDocumentStatus;
+};
+
+export const useSelectDocumentList = () => {
+  const list: IKnowledgeFile[] = useSelector(
+    (state: any) => state.kFModel.data,
+  );
+  return list;
+};
+
+export const useSaveDocumentName = () => {
+  const dispatch = useDispatch();
+  const { knowledgeId } = useGetKnowledgeSearchParams();
+
+  const saveName = useCallback(
+    (documentId: string, name: string) => {
+      return dispatch<any>({
+        type: 'kFModel/document_rename',
+        payload: {
+          doc_id: documentId,
+          name: name,
+          kb_id: knowledgeId,
+        },
+      });
+    },
+    [dispatch, knowledgeId],
+  );
+
+  return saveName;
+};
+
+export const useCreateDocument = () => {
+  const dispatch = useDispatch();
+  const { knowledgeId } = useGetKnowledgeSearchParams();
+
+  const createDocument = useCallback(
+    (name: string) => {
+      try {
+        return dispatch<any>({
+          type: 'kFModel/document_create',
+          payload: {
+            name,
+            kb_id: knowledgeId,
+          },
+        });
+      } catch (errorInfo) {
+        console.log('Failed:', errorInfo);
+      }
+    },
+    [dispatch, knowledgeId],
+  );
+
+  return createDocument;
+};
+
+export const useSetDocumentParser = () => {
+  const dispatch = useDispatch();
+  const { knowledgeId } = useGetKnowledgeSearchParams();
+
+  const setDocumentParser = useCallback(
+    (parserId: string, documentId: string) => {
+      try {
+        return dispatch<any>({
+          type: 'kFModel/document_change_parser',
+          payload: {
+            parser_id: parserId,
+            doc_id: documentId,
+            kb_id: knowledgeId,
+          },
+        });
+      } catch (errorInfo) {
+        console.log('Failed:', errorInfo);
+      }
+    },
+    [dispatch, knowledgeId],
+  );
+
+  return setDocumentParser;
+};
+
+export const useRemoveDocument = (documentId: string) => {
+  const dispatch = useDispatch();
+  const { knowledgeId } = useGetKnowledgeSearchParams();
+
+  const removeDocument = useCallback(() => {
+    try {
+      return dispatch<any>({
+        type: 'kFModel/document_rm',
+        payload: {
+          doc_id: documentId,
+          kb_id: knowledgeId,
+        },
+      });
+    } catch (errorInfo) {
+      console.log('Failed:', errorInfo);
+    }
+  }, [dispatch, knowledgeId, documentId]);
+
+  return removeDocument;
+};
diff --git a/web/src/pages/add-knowledge/components/knowledge-file/segmentSetModal.tsx b/web/src/pages/add-knowledge/components/knowledge-file/chunk-method-modal.tsx
similarity index 55%
rename from web/src/pages/add-knowledge/components/knowledge-file/segmentSetModal.tsx
rename to web/src/pages/add-knowledge/components/knowledge-file/chunk-method-modal.tsx
index ea7a9e8..69d5e91 100644
--- a/web/src/pages/add-knowledge/components/knowledge-file/segmentSetModal.tsx
+++ b/web/src/pages/add-knowledge/components/knowledge-file/chunk-method-modal.tsx
@@ -1,86 +1,69 @@
-import {
-  useFetchTenantInfo,
-  useSelectParserList,
-} from '@/hooks/userSettingHook';
-import { Modal, Space, Tag } from 'antd';
-import React, { useEffect, useState } from 'react';
-import { useDispatch, useSelector } from 'umi';
-import styles from './index.less';
-const { CheckableTag } = Tag;
-interface kFProps {
-  getKfList: () => void;
-  parser_id: string;
-  doc_id: string;
-}
-const SegmentSetModal: React.FC<kFProps> = ({
-  getKfList,
-  parser_id,
-  doc_id,
-}) => {
-  const dispatch = useDispatch();
-  const kFModel = useSelector((state: any) => state.kFModel);
-  const [selectedTag, setSelectedTag] = useState('');
-  const { isShowSegmentSetModal } = kFModel;
-  const parserList = useSelectParserList();
-
-  useFetchTenantInfo();
-
-  useEffect(() => {
-    setSelectedTag(parser_id);
-  }, [parser_id]);
-
-  const handleCancel = () => {
-    dispatch({
-      type: 'kFModel/updateState',
-      payload: {
-        isShowSegmentSetModal: false,
-      },
-    });
-  };
-
-  const handleOk = async () => {
-    const retcode = await dispatch<any>({
-      type: 'kFModel/document_change_parser',
-      payload: {
-        parser_id: selectedTag,
-        doc_id,
-      },
-    });
-
-    if (retcode === 0 && getKfList) {
-      getKfList();
-      handleCancel();
-    }
-  };
-
-  const handleChange = (tag: string, checked: boolean) => {
-    const nextSelectedTag = checked ? tag : selectedTag;
-    setSelectedTag(nextSelectedTag);
-  };
-
-  return (
-    <Modal
-      title="Category"
-      open={isShowSegmentSetModal}
-      onOk={handleOk}
-      onCancel={handleCancel}
-    >
-      <Space size={[0, 8]} wrap>
-        <div className={styles.tags}>
-          {parserList.map((x) => {
-            return (
-              <CheckableTag
-                key={x.value}
-                checked={selectedTag === x.value}
-                onChange={(checked) => handleChange(x.value, checked)}
-              >
-                {x.label}
-              </CheckableTag>
-            );
-          })}
-        </div>
-      </Space>
-    </Modal>
-  );
-};
-export default SegmentSetModal;
+import { IModalManagerChildrenProps } from '@/components/modal-manager';
+import {
+  useFetchTenantInfo,
+  useSelectParserList,
+} from '@/hooks/userSettingHook';
+import { Modal, Space, Tag } from 'antd';
+import React, { useEffect, useState } from 'react';
+
+import styles from './index.less';
+
+const { CheckableTag } = Tag;
+
+interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
+  loading: boolean;
+  onOk: (parserId: string) => void;
+  showModal?(): void;
+  parser_id: string;
+}
+
+const ChunkMethodModal: React.FC<IProps> = ({
+  parser_id,
+  onOk,
+  hideModal,
+  visible,
+}) => {
+  const [selectedTag, setSelectedTag] = useState('');
+  const parserList = useSelectParserList();
+
+  useFetchTenantInfo();
+
+  useEffect(() => {
+    setSelectedTag(parser_id);
+  }, [parser_id]);
+
+  const handleOk = async () => {
+    onOk(selectedTag);
+  };
+
+  const handleChange = (tag: string, checked: boolean) => {
+    const nextSelectedTag = checked ? tag : selectedTag;
+    setSelectedTag(nextSelectedTag);
+  };
+
+  return (
+    <Modal
+      title="Chunk Method"
+      open={visible}
+      onOk={handleOk}
+      onCancel={hideModal}
+    >
+      <Space size={[0, 8]} wrap>
+        <div className={styles.tags}>
+          {parserList.map((x) => {
+            return (
+              <CheckableTag
+                key={x.value}
+                checked={selectedTag === x.value}
+                onChange={(checked) => handleChange(x.value, checked)}
+              >
+                {x.label}
+              </CheckableTag>
+            );
+          })}
+        </div>
+      </Space>
+    </Modal>
+  );
+};
+export default ChunkMethodModal;
diff --git a/web/src/pages/add-knowledge/components/knowledge-file/create-file-modal.tsx b/web/src/pages/add-knowledge/components/knowledge-file/create-file-modal.tsx
new file mode 100644
index 0000000..8e23d42
--- /dev/null
+++ b/web/src/pages/add-knowledge/components/knowledge-file/create-file-modal.tsx
@@ -0,0 +1,49 @@
+import { IModalManagerChildrenProps } from '@/components/modal-manager';
+import { Form, Input, Modal } from 'antd';
+import React from 'react';
+
+type FieldType = {
+  name?: string;
+};
+
+interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
+  loading: boolean;
+  onOk: (name: string) => void;
+  showModal?(): void;
+}
+
+const FileCreatingModal: React.FC<IProps> = ({ visible, hideModal, onOk }) => {
+  const [form] = Form.useForm();
+
+  const handleOk = async () => {
+    const values = await form.validateFields();
+    onOk(values.name);
+  };
+
+  return (
+    <Modal
+      title="File Name"
+      open={visible}
+      onOk={handleOk}
+      onCancel={hideModal}
+    >
+      <Form
+        form={form}
+        name="validateOnly"
+        labelCol={{ span: 4 }}
+        wrapperCol={{ span: 20 }}
+        style={{ maxWidth: 600 }}
+        autoComplete="off"
+      >
+        <Form.Item<FieldType>
+          label="File Name"
+          name="name"
+          rules={[{ required: true, message: 'Please input name!' }]}
+        >
+          <Input />
+        </Form.Item>
+      </Form>
+    </Modal>
+  );
+};
+export default FileCreatingModal;
diff --git a/web/src/pages/add-knowledge/components/knowledge-file/createEFileModal.tsx b/web/src/pages/add-knowledge/components/knowledge-file/createEFileModal.tsx
deleted file mode 100644
index 3447f20..0000000
--- a/web/src/pages/add-knowledge/components/knowledge-file/createEFileModal.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import { Form, Input, Modal } from 'antd';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import { useDispatch, useSelector } from 'umi';
-
-type FieldType = {
-  name?: string;
-};
-interface kFProps {
-  getKfList: () => void;
-  kb_id: string;
-}
-
-const FileCreatingModal: React.FC<kFProps> = ({ getKfList, kb_id }) => {
-  const dispatch = useDispatch();
-  const [form] = Form.useForm();
-  const kFModel = useSelector((state: any) => state.kFModel);
-  const { isShowCEFwModal } = kFModel;
-  const { t } = useTranslation();
-
-  const handleCancel = () => {
-    dispatch({
-      type: 'kFModel/updateState',
-      payload: {
-        isShowCEFwModal: false,
-      },
-    });
-  };
-
-  const createDocument = async () => {
-    try {
-      const values = await form.validateFields();
-      const retcode = await dispatch<any>({
-        type: 'kFModel/document_create',
-        payload: {
-          name: values.name,
-          kb_id,
-        },
-      });
-      if (retcode === 0) {
-        getKfList && getKfList();
-      }
-    } catch (errorInfo) {
-      console.log('Failed:', errorInfo);
-    }
-  };
-
-  const handleOk = async () => {
-    createDocument();
-  };
-
-  return (
-    <Modal
-      title="File Name"
-      open={isShowCEFwModal}
-      onOk={handleOk}
-      onCancel={handleCancel}
-    >
-      <Form
-        form={form}
-        name="validateOnly"
-        labelCol={{ span: 4 }}
-        wrapperCol={{ span: 20 }}
-        style={{ maxWidth: 600 }}
-        autoComplete="off"
-      >
-        <Form.Item<FieldType>
-          label="File Name"
-          name="name"
-          rules={[{ required: true, message: 'Please input name!' }]}
-        >
-          <Input />
-        </Form.Item>
-      </Form>
-    </Modal>
-  );
-};
-export default FileCreatingModal;
diff --git a/web/src/pages/add-knowledge/components/knowledge-file/hooks.ts b/web/src/pages/add-knowledge/components/knowledge-file/hooks.ts
new file mode 100644
index 0000000..3618908
--- /dev/null
+++ b/web/src/pages/add-knowledge/components/knowledge-file/hooks.ts
@@ -0,0 +1,241 @@
+import { useSetModalState } from '@/hooks/commonHooks';
+import {
+  useCreateDocument,
+  useFetchDocumentList,
+  useSaveDocumentName,
+  useSetDocumentParser,
+} from '@/hooks/documentHooks';
+import { useGetKnowledgeSearchParams } from '@/hooks/routeHook';
+import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
+import { useFetchTenantInfo } from '@/hooks/userSettingHook';
+import { Pagination } from '@/interfaces/common';
+import { IKnowledgeFile } from '@/interfaces/database/knowledge';
+import { PaginationProps } from 'antd';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import { useDispatch, useNavigate, useSelector } from 'umi';
+import { KnowledgeRouteKey } from './constant';
+
+export const useFetchDocumentListOnMount = () => {
+  const { knowledgeId } = useGetKnowledgeSearchParams();
+  const fetchDocumentList = useFetchDocumentList();
+  const dispatch = useDispatch();
+
+  useFetchTenantInfo();
+
+  useEffect(() => {
+    if (knowledgeId) {
+      fetchDocumentList();
+      dispatch({
+        type: 'kFModel/pollGetDocumentList-start',
+        payload: knowledgeId,
+      });
+    }
+    return () => {
+      dispatch({
+        type: 'kFModel/pollGetDocumentList-stop',
+      });
+    };
+  }, [knowledgeId, dispatch, fetchDocumentList]);
+
+  return { fetchDocumentList };
+};
+
+export const useGetPagination = (fetchDocumentList: () => void) => {
+  const dispatch = useDispatch();
+  const kFModel = useSelector((state: any) => state.kFModel);
+
+  const setPagination = useCallback(
+    (pageNumber = 1, pageSize?: number) => {
+      const pagination: Pagination = {
+        current: pageNumber,
+      } as Pagination;
+      if (pageSize) {
+        pagination.pageSize = pageSize;
+      }
+      dispatch({
+        type: 'kFModel/setPagination',
+        payload: pagination,
+      });
+    },
+    [dispatch],
+  );
+
+  const onPageChange: PaginationProps['onChange'] = useCallback(
+    (pageNumber: number, pageSize: number) => {
+      setPagination(pageNumber, pageSize);
+      fetchDocumentList();
+    },
+    [fetchDocumentList, setPagination],
+  );
+
+  const pagination: PaginationProps = useMemo(() => {
+    return {
+      showQuickJumper: true,
+      total: kFModel.total,
+      showSizeChanger: true,
+      current: kFModel.pagination.currentPage,
+      pageSize: kFModel.pagination.pageSize,
+      pageSizeOptions: [1, 2, 10, 20, 50, 100],
+      onChange: onPageChange,
+    };
+  }, [kFModel, onPageChange]);
+
+  return {
+    pagination,
+    setPagination,
+    total: kFModel.total,
+    searchString: kFModel.searchString,
+  };
+};
+
+export const useSelectDocumentListLoading = () => {
+  return useOneNamespaceEffectsLoading('kFModel', [
+    'getKfList',
+    'updateDocumentStatus',
+  ]);
+};
+
+export const useNavigateToOtherPage = () => {
+  const navigate = useNavigate();
+  const { knowledgeId } = useGetKnowledgeSearchParams();
+
+  const linkToUploadPage = useCallback(() => {
+    navigate(`/knowledge/dataset/upload?id=${knowledgeId}`);
+  }, [navigate, knowledgeId]);
+
+  const toChunk = useCallback(
+    (id: string) => {
+      navigate(
+        `/knowledge/${KnowledgeRouteKey.Dataset}/chunk?id=${knowledgeId}&doc_id=${id}`,
+      );
+    },
+    [navigate, knowledgeId],
+  );
+
+  return { linkToUploadPage, toChunk };
+};
+
+export const useHandleSearchChange = (setPagination: () => void) => {
+  const dispatch = useDispatch();
+  const { knowledgeId } = useGetKnowledgeSearchParams();
+
+  const throttledGetDocumentList = useCallback(() => {
+    dispatch({
+      type: 'kFModel/throttledGetDocumentList',
+      payload: knowledgeId,
+    });
+  }, [dispatch, knowledgeId]);
+
+  const handleInputChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
+      const value = e.target.value;
+      dispatch({ type: 'kFModel/setSearchString', payload: value });
+      setPagination();
+      throttledGetDocumentList();
+    },
+    [setPagination, throttledGetDocumentList, dispatch],
+  );
+
+  return { handleInputChange };
+};
+
+export const useSetSelectedRecord = () => {
+  const [currentRecord, setCurrentRecord] = useState<IKnowledgeFile>(
+    {} as IKnowledgeFile,
+  );
+
+  const setRecord = (record: IKnowledgeFile) => () => {
+    setCurrentRecord(record);
+  };
+
+  return { currentRecord, setRecord };
+};
+
+export const useRenameDocument = (documentId: string) => {
+  const saveName = useSaveDocumentName();
+
+  const {
+    visible: renameVisible,
+    hideModal: hideRenameModal,
+    showModal: showRenameModal,
+  } = useSetModalState();
+  const loading = useOneNamespaceEffectsLoading('kFModel', ['document_rename']);
+
+  const onRenameOk = useCallback(
+    async (name: string) => {
+      const ret = await saveName(documentId, name);
+      if (ret === 0) {
+        hideRenameModal();
+      }
+    },
+    [hideRenameModal, saveName, documentId],
+  );
+
+  return {
+    renameLoading: loading,
+    onRenameOk,
+    renameVisible,
+    hideRenameModal,
+    showRenameModal,
+  };
+};
+
+export const useCreateEmptyDocument = () => {
+  const createDocument = useCreateDocument();
+
+  const {
+    visible: createVisible,
+    hideModal: hideCreateModal,
+    showModal: showCreateModal,
+  } = useSetModalState();
+  const loading = useOneNamespaceEffectsLoading('kFModel', ['document_create']);
+
+  const onCreateOk = useCallback(
+    async (name: string) => {
+      const ret = await createDocument(name);
+      if (ret === 0) {
+        hideCreateModal();
+      }
+    },
+    [hideCreateModal, createDocument],
+  );
+
+  return {
+    createLoading: loading,
+    onCreateOk,
+    createVisible,
+    hideCreateModal,
+    showCreateModal,
+  };
+};
+
+export const useChangeDocumentParser = (documentId: string) => {
+  const setDocumentParser = useSetDocumentParser();
+
+  const {
+    visible: changeParserVisible,
+    hideModal: hideChangeParserModal,
+    showModal: showChangeParserModal,
+  } = useSetModalState();
+  const loading = useOneNamespaceEffectsLoading('kFModel', [
+    'document_change_parser',
+  ]);
+
+  const onChangeParserOk = useCallback(
+    async (parserId: string) => {
+      const ret = await setDocumentParser(parserId, documentId);
+      if (ret === 0) {
+        hideChangeParserModal();
+      }
+    },
+    [hideChangeParserModal, setDocumentParser, documentId],
+  );
+
+  return {
+    changeParserLoading: loading,
+    onChangeParserOk,
+    changeParserVisible,
+    hideChangeParserModal,
+    showChangeParserModal,
+  };
+};
diff --git a/web/src/pages/add-knowledge/components/knowledge-file/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/index.tsx
index 02a159c..7c36b6c 100644
--- a/web/src/pages/add-knowledge/components/knowledge-file/index.tsx
+++ b/web/src/pages/add-knowledge/components/knowledge-file/index.tsx
@@ -1,12 +1,9 @@
-import { KnowledgeRouteKey } from '@/constants/knowledge';
-import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
 import {
-  useFetchTenantInfo,
-  useSelectParserList,
-} from '@/hooks/userSettingHook';
-import { Pagination } from '@/interfaces/common';
+  useSelectDocumentList,
+  useSetDocumentStatus,
+} from '@/hooks/documentHooks';
+import { useSelectParserList } from '@/hooks/userSettingHook';
 import { IKnowledgeFile } from '@/interfaces/database/knowledge';
-import { getOneNamespaceEffectsLoading } from '@/utils/storeUtil';
 import {
   FileOutlined,
   FileTextOutlined,
@@ -25,133 +22,57 @@ import {
   Tag,
 } from 'antd';
 import type { ColumnsType } from 'antd/es/table';
-import { PaginationProps } from 'antd/lib';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import { useDispatch, useNavigate, useSelector } from 'umi';
-import CreateEPModal from './createEFileModal';
-import styles from './index.less';
+import { useMemo } from 'react';
+import ChunkMethodModal from './chunk-method-modal';
+import CreateFileModal from './create-file-modal';
+import {
+  useChangeDocumentParser,
+  useCreateEmptyDocument,
+  useFetchDocumentListOnMount,
+  useGetPagination,
+  useHandleSearchChange,
+  useNavigateToOtherPage,
+  useRenameDocument,
+  useSetSelectedRecord,
+} from './hooks';
 import ParsingActionCell from './parsing-action-cell';
 import ParsingStatusCell from './parsing-status-cell';
 import RenameModal from './rename-modal';
-import SegmentSetModal from './segmentSetModal';
 
-const KnowledgeFile = () => {
-  const dispatch = useDispatch();
-  const kFModel = useSelector((state: any) => state.kFModel);
-  const effects = useSelector((state: any) => state.loading.effects);
-  const { data, total } = kFModel;
-  const knowledgeBaseId = useKnowledgeBaseId();
+import styles from './index.less';
 
-  const loading = getOneNamespaceEffectsLoading('kFModel', effects, [
-    'getKfList',
-    'updateDocumentStatus',
-  ]);
-  const [doc_id, setDocId] = useState('0');
-  const [parser_id, setParserId] = useState('0');
-  let navigate = useNavigate();
+const KnowledgeFile = () => {
+  const data = useSelectDocumentList();
+  const { fetchDocumentList } = useFetchDocumentListOnMount();
   const parserList = useSelectParserList();
-
-  const getKfList = useCallback(() => {
-    const payload = {
-      kb_id: knowledgeBaseId,
-    };
-
-    dispatch({
-      type: 'kFModel/getKfList',
-      payload,
-    });
-  }, [dispatch, knowledgeBaseId]);
-
-  const throttledGetDocumentList = () => {
-    dispatch({
-      type: 'kFModel/throttledGetDocumentList',
-      payload: knowledgeBaseId,
-    });
-  };
-
-  const setPagination = useCallback(
-    (pageNumber = 1, pageSize?: number) => {
-      const pagination: Pagination = {
-        current: pageNumber,
-      } as Pagination;
-      if (pageSize) {
-        pagination.pageSize = pageSize;
-      }
-      dispatch({
-        type: 'kFModel/setPagination',
-        payload: pagination,
-      });
-    },
-    [dispatch],
-  );
-
-  const onPageChange: PaginationProps['onChange'] = useCallback(
-    (pageNumber: number, pageSize: number) => {
-      setPagination(pageNumber, pageSize);
-      getKfList();
-    },
-    [getKfList, setPagination],
-  );
-
-  const pagination: PaginationProps = useMemo(() => {
-    return {
-      showQuickJumper: true,
-      total,
-      showSizeChanger: true,
-      current: kFModel.pagination.currentPage,
-      pageSize: kFModel.pagination.pageSize,
-      pageSizeOptions: [1, 2, 10, 20, 50, 100],
-      onChange: onPageChange,
-    };
-  }, [total, kFModel.pagination, onPageChange]);
-
-  useEffect(() => {
-    if (knowledgeBaseId) {
-      getKfList();
-      dispatch({
-        type: 'kFModel/pollGetDocumentList-start',
-        payload: knowledgeBaseId,
-      });
-    }
-    return () => {
-      dispatch({
-        type: 'kFModel/pollGetDocumentList-stop',
-      });
-    };
-  }, [knowledgeBaseId, dispatch, getKfList]);
-
-  const handleInputChange = (
-    e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
-  ) => {
-    const value = e.target.value;
-    dispatch({ type: 'kFModel/setSearchString', payload: value });
-    setPagination();
-    throttledGetDocumentList();
-  };
-
-  const onChangeStatus = (e: boolean, doc_id: string) => {
-    dispatch({
-      type: 'kFModel/updateDocumentStatus',
-      payload: {
-        doc_id,
-        status: Number(e),
-        kb_id: knowledgeBaseId,
-      },
-    });
-  };
-
-  const showCEFModal = useCallback(() => {
-    dispatch({
-      type: 'kFModel/updateState',
-      payload: {
-        isShowCEFwModal: true,
-      },
-    });
-  }, [dispatch]);
-
-  const linkToUploadPage = useCallback(() => {
-    navigate(`/knowledge/dataset/upload?id=${knowledgeBaseId}`);
-  }, [navigate, knowledgeBaseId]);
+  const { pagination, setPagination, total, searchString } =
+    useGetPagination(fetchDocumentList);
+  const onChangeStatus = useSetDocumentStatus();
+  const { linkToUploadPage, toChunk } = useNavigateToOtherPage();
+
+  const { handleInputChange } = useHandleSearchChange(setPagination);
+  const { currentRecord, setRecord } = useSetSelectedRecord();
+  const {
+    renameLoading,
+    onRenameOk,
+    renameVisible,
+    hideRenameModal,
+    showRenameModal,
+  } = useRenameDocument(currentRecord.id);
+  const {
+    createLoading,
+    onCreateOk,
+    createVisible,
+    hideCreateModal,
+    showCreateModal,
+  } = useCreateEmptyDocument();
+  const {
+    changeParserLoading,
+    onChangeParserOk,
+    changeParserVisible,
+    hideChangeParserModal,
+    showChangeParserModal,
+  } = useChangeDocumentParser(currentRecord.id);
 
   const actionItems: MenuProps['items'] = useMemo(() => {
     return [
@@ -172,7 +93,7 @@ const KnowledgeFile = () => {
       { type: 'divider' },
       {
         key: '2',
-        onClick: showCEFModal,
+        onClick: showCreateModal,
         label: (
           <div>
             <Button type="link">
@@ -184,18 +105,7 @@ const KnowledgeFile = () => {
         // disabled: true,
       },
     ];
-  }, [linkToUploadPage, showCEFModal]);
-
-  const toChunk = (id: string) => {
-    navigate(
-      `/knowledge/${KnowledgeRouteKey.Dataset}/chunk?id=${knowledgeBaseId}&doc_id=${id}`,
-    );
-  };
-
-  const setDocumentAndParserId = (record: IKnowledgeFile) => () => {
-    setDocId(record.id);
-    setParserId(record.parser_id);
-  };
+  }, [linkToUploadPage, showCreateModal]);
 
   const columns: ColumnsType<IKnowledgeFile> = [
     {
@@ -255,8 +165,12 @@ const KnowledgeFile = () => {
       key: 'action',
       render: (_, record) => (
         <ParsingActionCell
-          knowledgeBaseId={knowledgeBaseId}
-          setDocumentAndParserId={setDocumentAndParserId(record)}
+          setDocumentAndParserId={setRecord(record)}
+          showRenameModal={() => {
+            setRecord(record)();
+            showRenameModal();
+          }}
+          showChangeParserModal={showChangeParserModal}
           record={record}
         ></ParsingActionCell>
       ),
@@ -268,8 +182,6 @@ const KnowledgeFile = () => {
     className: `${styles.column}`,
   }));
 
-  useFetchTenantInfo();
-
   return (
     <div className={styles.datasetWrapper}>
       <h3>Dataset</h3>
@@ -283,7 +195,7 @@ const KnowledgeFile = () => {
         <Space>
           <Input
             placeholder="Seach your files"
-            value={kFModel.searchString}
+            value={searchString}
             style={{ width: 220 }}
             allowClear
             onChange={handleInputChange}
@@ -305,13 +217,26 @@ const KnowledgeFile = () => {
         pagination={pagination}
         scroll={{ scrollToFirstRowOnChange: true, x: 1300, y: 'fill' }}
       />
-      <CreateEPModal getKfList={getKfList} kb_id={knowledgeBaseId} />
-      <SegmentSetModal
-        getKfList={getKfList}
-        parser_id={parser_id}
-        doc_id={doc_id}
+      <CreateFileModal
+        visible={createVisible}
+        hideModal={hideCreateModal}
+        loading={createLoading}
+        onOk={onCreateOk}
+      />
+      <ChunkMethodModal
+        parser_id={currentRecord.parser_id}
+        onOk={onChangeParserOk}
+        visible={changeParserVisible}
+        hideModal={hideChangeParserModal}
+        loading={changeParserLoading}
       />
-      <RenameModal></RenameModal>
+      <RenameModal
+        visible={renameVisible}
+        onOk={onRenameOk}
+        loading={renameLoading}
+        hideModal={hideRenameModal}
+        initialName={currentRecord.name}
+      ></RenameModal>
     </div>
   );
 };
diff --git a/web/src/pages/add-knowledge/components/knowledge-file/model.ts b/web/src/pages/add-knowledge/components/knowledge-file/model.ts
index a2a40d4..6644647 100644
--- a/web/src/pages/add-knowledge/components/knowledge-file/model.ts
+++ b/web/src/pages/add-knowledge/components/knowledge-file/model.ts
@@ -164,6 +164,10 @@ const model: DvaModel<KFModelState> = {
       const { data } = yield call(kbService.document_create, payload);
       const { retcode } = data;
       if (retcode === 0) {
+        put({
+          type: 'getKfList',
+          payload: { kb_id: payload.kb_id },
+        });
         put({
           type: 'kFModel/updateState',
           payload: {
@@ -192,9 +196,16 @@ const model: DvaModel<KFModelState> = {
       return retcode;
     },
     *document_change_parser({ payload = {} }, { call, put }) {
-      const { data } = yield call(kbService.document_change_parser, payload);
+      const { data } = yield call(
+        kbService.document_change_parser,
+        omit(payload, ['kb_id']),
+      );
       const { retcode } = data;
       if (retcode === 0) {
+        put({
+          type: 'getKfList',
+          payload: { kb_id: payload.kb_id },
+        });
         put({
           type: 'updateState',
           payload: {
diff --git a/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx
index 49cb0b1..4bb04d6 100644
--- a/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx
+++ b/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx
@@ -1,5 +1,8 @@
 import showDeleteConfirm from '@/components/deleting-confirm';
+import { useRemoveDocument } from '@/hooks/documentHooks';
 import { IKnowledgeFile } from '@/interfaces/database/knowledge';
+import { api_host } from '@/utils/api';
+import { downloadFile } from '@/utils/fileUtil';
 import {
   DeleteOutlined,
   DownloadOutlined,
@@ -7,37 +10,27 @@ import {
   ToolOutlined,
 } from '@ant-design/icons';
 import { Button, Dropdown, MenuProps, Space, Tooltip } from 'antd';
-import { useDispatch } from 'umi';
 import { isParserRunning } from '../utils';
 
-import { api_host } from '@/utils/api';
-import { downloadFile } from '@/utils/fileUtil';
 import styles from './index.less';
 
 interface IProps {
-  knowledgeBaseId: string;
   record: IKnowledgeFile;
   setDocumentAndParserId: () => void;
+  showRenameModal: () => void;
+  showChangeParserModal: () => void;
 }
 
 const ParsingActionCell = ({
-  knowledgeBaseId,
   record,
   setDocumentAndParserId,
+  showRenameModal,
+  showChangeParserModal,
 }: IProps) => {
-  const dispatch = useDispatch();
   const documentId = record.id;
   const isRunning = isParserRunning(record.run);
 
-  const removeDocument = () => {
-    dispatch({
-      type: 'kFModel/document_rm',
-      payload: {
-        doc_id: documentId,
-        kb_id: knowledgeBaseId,
-      },
-    });
-  };
+  const removeDocument = useRemoveDocument(documentId);
 
   const onRmDocument = () => {
     if (!isRunning) {
@@ -52,39 +45,13 @@ const ParsingActionCell = ({
     });
   };
 
-  const setCurrentRecord = () => {
-    dispatch({
-      type: 'kFModel/setCurrentRecord',
-      payload: record,
-    });
-  };
-
-  const showSegmentSetModal = () => {
-    dispatch({
-      type: 'kFModel/updateState',
-      payload: {
-        isShowSegmentSetModal: true,
-      },
-    });
-  };
-
-  const showRenameModal = () => {
-    if (!isRunning) {
-      setCurrentRecord();
-      dispatch({
-        type: 'kFModel/setIsShowRenameModal',
-        payload: true,
-      });
-    }
-  };
-
   const chunkItems: MenuProps['items'] = [
     {
       key: '1',
       label: (
         <div>
-          <Button type="link" onClick={showSegmentSetModal}>
-            Category
+          <Button type="link" onClick={showChangeParserModal}>
+            Chunk Method
           </Button>
         </div>
       ),
diff --git a/web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx
index a80d7f4..b93a179 100644
--- a/web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx
+++ b/web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx
@@ -1,46 +1,30 @@
-import { useKnowledgeBaseId } from '@/hooks/knowledgeHook';
+import { IModalManagerChildrenProps } from '@/components/modal-manager';
 import { Form, Input, Modal } from 'antd';
 import { useEffect } from 'react';
-import { useDispatch, useSelector } from 'umi';
 
-const RenameModal = () => {
+interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
+  loading: boolean;
+  initialName: string;
+  onOk: (name: string) => void;
+  showModal?(): void;
+}
+
+const RenameModal = ({
+  visible,
+  onOk,
+  loading,
+  initialName,
+  hideModal,
+}: IProps) => {
   const [form] = Form.useForm();
-  const dispatch = useDispatch();
-  const kFModel = useSelector((state: any) => state.kFModel);
-  const loading = useSelector(
-    (state: any) => state.loading.effects['kFModel/document_rename'],
-  );
-  const knowledgeBaseId = useKnowledgeBaseId();
-  const isModalOpen = kFModel.isShowRenameModal;
-  const initialName = kFModel.currentRecord?.name;
-  const documentId = kFModel.currentRecord?.id;
 
   type FieldType = {
     name?: string;
   };
 
-  const closeModal = () => {
-    dispatch({
-      type: 'kFModel/setIsShowRenameModal',
-      payload: false,
-    });
-  };
-
   const handleOk = async () => {
     const ret = await form.validateFields();
-
-    dispatch({
-      type: 'kFModel/document_rename',
-      payload: {
-        doc_id: documentId,
-        name: ret.name,
-        kb_id: knowledgeBaseId,
-      },
-    });
-  };
-
-  const handleCancel = () => {
-    closeModal();
+    onOk(ret.name);
   };
 
   const onFinish = (values: any) => {
@@ -52,17 +36,17 @@ const RenameModal = () => {
   };
 
   useEffect(() => {
-    if (isModalOpen) {
+    if (visible) {
       form.setFieldValue('name', initialName);
     }
-  }, [initialName, documentId, form, isModalOpen]);
+  }, [initialName, form, visible]);
 
   return (
     <Modal
       title="Rename"
-      open={isModalOpen}
+      open={visible}
       onOk={handleOk}
-      onCancel={handleCancel}
+      onCancel={hideModal}
       okButtonProps={{ loading }}
     >
       <Form
diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx
index 1d0b7e0..84af184 100644
--- a/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx
+++ b/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx
@@ -35,7 +35,11 @@ const CategoryPanel = ({ chunkMethod }: { chunkMethod: string }) => {
           <Title level={5} className={styles.topTitle}>
             {item.title} Category
           </Title>
-          <Text>{item.description}</Text>
+          <p
+            dangerouslySetInnerHTML={{
+              __html: item.description,
+            }}
+          ></p>
           <Title level={5}>{item.title} Image Examples</Title>
           <Text>
             We've prepared detailed visual guides to make understanding easier
diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/index.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/index.tsx
index fa2c377..0ef3ff6 100644
--- a/web/src/pages/add-knowledge/components/knowledge-setting/index.tsx
+++ b/web/src/pages/add-knowledge/components/knowledge-setting/index.tsx
@@ -21,10 +21,10 @@ const Configuration = () => {
       <Divider></Divider>
       <Spin spinning={loading}>
         <Row gutter={32}>
-          <Col span={12}>
+          <Col span={8}>
             <ConfigurationForm form={form}></ConfigurationForm>
           </Col>
-          <Col span={12}>
+          <Col span={16}>
             <CategoryPanel chunkMethod={chunkMethod}></CategoryPanel>
           </Col>
         </Row>
diff --git a/web/src/pages/chat/index.tsx b/web/src/pages/chat/index.tsx
index 88c3bca..1839140 100644
--- a/web/src/pages/chat/index.tsx
+++ b/web/src/pages/chat/index.tsx
@@ -1,4 +1,5 @@
 import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg';
+import RenameModal from '@/components/rename-modal';
 import { DeleteOutlined, EditOutlined, FormOutlined } from '@ant-design/icons';
 import {
   Avatar,
@@ -34,7 +35,6 @@ import {
   useSelectFirstDialogOnMount,
 } from './hooks';
 
-import RenameModal from '@/components/rename-modal';
 import styles from './index.less';
 
 const Chat = () => {
-- 
GitLab