diff --git a/web/.umirc.ts b/web/.umirc.ts index 5cbf1c0aa7..c4c622f15d 100644 --- a/web/.umirc.ts +++ b/web/.umirc.ts @@ -27,7 +27,7 @@ export default defineConfig({ devtool: 'source-map', proxy: { '/v1': { - target: 'http://123.60.95.134:9380/', + target: 'http://192.168.200.233:9380/', changeOrigin: true, // pathRewrite: { '^/v1': '/v1' }, }, diff --git a/web/externals.d.ts b/web/externals.d.ts new file mode 100644 index 0000000000..9c5a8bc5ef --- /dev/null +++ b/web/externals.d.ts @@ -0,0 +1,138 @@ +// This file is generated by Umi automatically +// DO NOT CHANGE IT MANUALLY! +type CSSModuleClasses = { readonly [key: string]: string }; +declare module '*.css' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.scss' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.sass' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.less' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.styl' { + const classes: CSSModuleClasses; + export default classes; +} +declare module '*.stylus' { + const classes: CSSModuleClasses; + export default classes; +} + +// images +declare module '*.jpg' { + const src: string; + export default src; +} +declare module '*.jpeg' { + const src: string; + export default src; +} +declare module '*.png' { + const src: string; + export default src; +} +declare module '*.gif' { + const src: string; + export default src; +} +declare module '*.svg' { + import * as React from 'react'; + export const ReactComponent: React.FunctionComponent< + React.SVGProps & { title?: string } + >; + + const src: string; + export default src; +} +declare module '*.ico' { + const src: string; + export default src; +} +declare module '*.webp' { + const src: string; + export default src; +} +declare module '*.avif' { + const src: string; + export default src; +} + +// media +declare module '*.mp4' { + const src: string; + export default src; +} +declare module '*.webm' { + const src: string; + export default src; +} +declare module '*.ogg' { + const src: string; + export default src; +} +declare module '*.mp3' { + const src: string; + export default src; +} +declare module '*.wav' { + const src: string; + export default src; +} +declare module '*.flac' { + const src: string; + export default src; +} +declare module '*.aac' { + const src: string; + export default src; +} + +// fonts +declare module '*.woff' { + const src: string; + export default src; +} +declare module '*.woff2' { + const src: string; + export default src; +} +declare module '*.eot' { + const src: string; + export default src; +} +declare module '*.ttf' { + const src: string; + export default src; +} +declare module '*.otf' { + const src: string; + export default src; +} + +// other +declare module '*.wasm' { + const initWasm: ( + options: WebAssembly.Imports, + ) => Promise; + export default initWasm; +} +declare module '*.webmanifest' { + const src: string; + export default src; +} +declare module '*.pdf' { + const src: string; + export default src; +} +declare module '*.txt' { + const src: string; + export default src; +} diff --git a/web/src/hooks/fileManagerHooks.ts b/web/src/hooks/fileManagerHooks.ts new file mode 100644 index 0000000000..a9fd72c9b7 --- /dev/null +++ b/web/src/hooks/fileManagerHooks.ts @@ -0,0 +1,80 @@ +import { IFileListRequestBody } from '@/interfaces/request/file-manager'; +import { useCallback } from 'react'; +import { useDispatch, useSelector } from 'umi'; + +export const useFetchFileList = () => { + const dispatch = useDispatch(); + + const fetchFileList = useCallback( + (payload: IFileListRequestBody) => { + return dispatch({ + type: 'fileManager/listFile', + payload, + }); + }, + [dispatch], + ); + + return fetchFileList; +}; + +export const useRemoveFile = () => { + const dispatch = useDispatch(); + + const removeFile = useCallback( + (fileIds: string[]) => { + return dispatch({ + type: 'fileManager/removeFile', + payload: { fileIds }, + }); + }, + [dispatch], + ); + + return removeFile; +}; + +export const useRenameFile = () => { + const dispatch = useDispatch(); + + const renameFile = useCallback( + (fileId: string, name: string) => { + return dispatch({ + type: 'fileManager/renameFile', + payload: { fileId, name }, + }); + }, + [dispatch], + ); + + return renameFile; +}; + +export const useFetchParentFolderList = () => { + const dispatch = useDispatch(); + + const fetchParentFolderList = useCallback( + (fileId: string) => { + return dispatch({ + type: 'fileManager/getAllParentFolder', + payload: { fileId }, + }); + }, + [dispatch], + ); + + return fetchParentFolderList; +}; + +export const useSelectFileList = () => { + const fileList = useSelector((state) => state.fileManager.fileList); + + return fileList; +}; + +export const useSelectParentFolderList = () => { + const parentFolderList = useSelector( + (state) => state.fileManager.parentFolderList, + ); + return parentFolderList.toReversed(); +}; diff --git a/web/src/interfaces/database/file-manager.ts b/web/src/interfaces/database/file-manager.ts new file mode 100644 index 0000000000..d22df392ce --- /dev/null +++ b/web/src/interfaces/database/file-manager.ts @@ -0,0 +1,30 @@ +export interface IFile { + create_date: string; + create_time: number; + created_by: string; + id: string; + kb_ids: string[]; + location: string; + name: string; + parent_id: string; + size: number; + tenant_id: string; + type: string; + update_date: string; + update_time: number; +} + +export interface IFolder { + create_date: string; + create_time: number; + created_by: string; + id: string; + location: string; + name: string; + parent_id: string; + size: number; + tenant_id: string; + type: string; + update_date: string; + update_time: number; +} diff --git a/web/src/interfaces/request/base.ts b/web/src/interfaces/request/base.ts new file mode 100644 index 0000000000..b780abe8de --- /dev/null +++ b/web/src/interfaces/request/base.ts @@ -0,0 +1,7 @@ +export interface IPaginationRequestBody { + keywords?: string; + page?: number; + page_size?: number; // name|create|doc_num|create_time|update_time,default:create_time + orderby?: string; + desc?: string; +} diff --git a/web/src/interfaces/request/file-manager.ts b/web/src/interfaces/request/file-manager.ts new file mode 100644 index 0000000000..7e748ca9c7 --- /dev/null +++ b/web/src/interfaces/request/file-manager.ts @@ -0,0 +1,5 @@ +import { IPaginationRequestBody } from './base'; + +export interface IFileListRequestBody extends IPaginationRequestBody { + parent_id?: string; // folder id +} diff --git a/web/src/layouts/components/header/index.tsx b/web/src/layouts/components/header/index.tsx index 3affb2282c..2819f426c0 100644 --- a/web/src/layouts/components/header/index.tsx +++ b/web/src/layouts/components/header/index.tsx @@ -1,4 +1,5 @@ import { ReactComponent as StarIon } from '@/assets/svg/chat-star.svg'; +// import { ReactComponent as FileIcon } from '@/assets/svg/file-management.svg'; import { ReactComponent as KnowledgeBaseIcon } from '@/assets/svg/knowledge-base.svg'; import { ReactComponent as Logo } from '@/assets/svg/logo.svg'; import { useTranslate } from '@/hooks/commonHooks'; diff --git a/web/src/pages/add-knowledge/components/knowledge-file/document-toolbar.tsx b/web/src/pages/add-knowledge/components/knowledge-file/document-toolbar.tsx index f6fb5bef23..b5f594069e 100644 --- a/web/src/pages/add-knowledge/components/knowledge-file/document-toolbar.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-file/document-toolbar.tsx @@ -182,7 +182,14 @@ const DocumentToolbar = ({ selectedRowKeys, showCreateModal }: IProps) => { ), }, ]; - }, [handleDelete, handleRunClick, handleCancelClick, t]); + }, [ + handleDelete, + handleRunClick, + handleCancelClick, + t, + handleDisableClick, + handleEnableClick, + ]); return (
diff --git a/web/src/pages/file-manager/action-cell/index.less b/web/src/pages/file-manager/action-cell/index.less new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web/src/pages/file-manager/action-cell/index.tsx b/web/src/pages/file-manager/action-cell/index.tsx new file mode 100644 index 0000000000..b6e44a28fd --- /dev/null +++ b/web/src/pages/file-manager/action-cell/index.tsx @@ -0,0 +1,91 @@ +import { useShowDeleteConfirm, useTranslate } from '@/hooks/commonHooks'; +import { api_host } from '@/utils/api'; +import { downloadFile } from '@/utils/fileUtil'; +import { + DeleteOutlined, + DownloadOutlined, + EditOutlined, + ToolOutlined, +} from '@ant-design/icons'; +import { Button, Space, Tooltip } from 'antd'; + +import { useRemoveFile } from '@/hooks/fileManagerHooks'; +import { IFile } from '@/interfaces/database/file-manager'; +import styles from './index.less'; + +interface IProps { + record: IFile; + setCurrentRecord: (record: any) => void; + showRenameModal: (record: IFile) => void; +} + +const ActionCell = ({ record, setCurrentRecord, showRenameModal }: IProps) => { + const documentId = record.id; + const beingUsed = false; + const { t } = useTranslate('knowledgeDetails'); + const removeDocument = useRemoveFile(); + const showDeleteConfirm = useShowDeleteConfirm(); + + const onRmDocument = () => { + if (!beingUsed) { + showDeleteConfirm({ + onOk: () => { + return removeDocument([documentId]); + }, + }); + } + }; + + const onDownloadDocument = () => { + downloadFile({ + url: `${api_host}/document/get/${documentId}`, + filename: record.name, + }); + }; + + const setRecord = () => { + setCurrentRecord(record); + }; + + const onShowRenameModal = () => { + setRecord(); + showRenameModal(record); + }; + + return ( + + + + + + + + + + ); +}; + +export default ActionCell; diff --git a/web/src/pages/file-manager/file-toolbar.tsx b/web/src/pages/file-manager/file-toolbar.tsx new file mode 100644 index 0000000000..cd01e62207 --- /dev/null +++ b/web/src/pages/file-manager/file-toolbar.tsx @@ -0,0 +1,153 @@ +import { ReactComponent as DeleteIcon } from '@/assets/svg/delete.svg'; +import { useShowDeleteConfirm, useTranslate } from '@/hooks/commonHooks'; +import { + DownOutlined, + FileOutlined, + FileTextOutlined, + PlusOutlined, + SearchOutlined, +} from '@ant-design/icons'; +import { + Breadcrumb, + BreadcrumbProps, + Button, + Dropdown, + Flex, + Input, + MenuProps, + Space, +} from 'antd'; +import { useCallback, useMemo } from 'react'; +import { + useFetchDocumentListOnMount, + useGetPagination, + useHandleSearchChange, + useSelectBreadcrumbItems, +} from './hooks'; + +import { useRemoveFile } from '@/hooks/fileManagerHooks'; +import { Link } from 'umi'; +import styles from './index.less'; + +interface IProps { + selectedRowKeys: string[]; +} + +const itemRender: BreadcrumbProps['itemRender'] = ( + currentRoute, + params, + items, +) => { + const isLast = currentRoute?.path === items[items.length - 1]?.path; + + return isLast ? ( + {currentRoute.title} + ) : ( + {currentRoute.title} + ); +}; + +const FileToolbar = ({ selectedRowKeys }: IProps) => { + const { t } = useTranslate('knowledgeDetails'); + const { fetchDocumentList } = useFetchDocumentListOnMount(); + const { setPagination, searchString } = useGetPagination(fetchDocumentList); + const { handleInputChange } = useHandleSearchChange(setPagination); + const removeDocument = useRemoveFile(); + const showDeleteConfirm = useShowDeleteConfirm(); + const breadcrumbItems = useSelectBreadcrumbItems(); + + const actionItems: MenuProps['items'] = useMemo(() => { + return [ + { + key: '1', + label: ( +
+ +
+ ), + }, + { type: 'divider' }, + { + key: '2', + label: ( +
+ +
+ ), + // disabled: true, + }, + ]; + }, [t]); + + const handleDelete = useCallback(() => { + showDeleteConfirm({ + onOk: () => { + return removeDocument(selectedRowKeys); + }, + }); + }, [removeDocument, showDeleteConfirm, selectedRowKeys]); + + const disabled = selectedRowKeys.length === 0; + + const items: MenuProps['items'] = useMemo(() => { + return [ + { + key: '4', + onClick: handleDelete, + label: ( + + + + + {t('delete', { keyPrefix: 'common' })} + + ), + }, + ]; + }, [handleDelete, t]); + + return ( +
+ + + + + + } + /> + + + + + +
+ ); +}; + +export default FileToolbar; diff --git a/web/src/pages/file-manager/hooks.ts b/web/src/pages/file-manager/hooks.ts new file mode 100644 index 0000000000..6a43c33645 --- /dev/null +++ b/web/src/pages/file-manager/hooks.ts @@ -0,0 +1,193 @@ +import { useSetModalState, useTranslate } from '@/hooks/commonHooks'; +import { + useFetchFileList, + useFetchParentFolderList, + useRenameFile, + useSelectFileList, + useSelectParentFolderList, +} from '@/hooks/fileManagerHooks'; +import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; +import { Pagination } from '@/interfaces/common'; +import { IFile } from '@/interfaces/database/file-manager'; +import { PaginationProps } from 'antd'; +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useDispatch, useNavigate, useSearchParams, useSelector } from 'umi'; + +export const useGetFolderId = () => { + const [searchParams] = useSearchParams(); + const id = searchParams.get('folderId') as string; + + return id; +}; + +export const useFetchDocumentListOnMount = () => { + const fetchDocumentList = useFetchFileList(); + const fileList = useSelectFileList(); + const id = useGetFolderId(); + + const dispatch = useDispatch(); + + useEffect(() => { + fetchDocumentList({ parent_id: id }); + }, [dispatch, fetchDocumentList, id]); + + return { fetchDocumentList, fileList }; +}; + +export const useGetPagination = ( + fetchDocumentList: (payload: IFile) => any, +) => { + const dispatch = useDispatch(); + const kFModel = useSelector((state: any) => state.kFModel); + const { t } = useTranslate('common'); + + 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.current, + pageSize: kFModel.pagination.pageSize, + pageSizeOptions: [1, 2, 10, 20, 50, 100], + onChange: onPageChange, + showTotal: (total) => `${t('total')} ${total}`, + }; + }, [kFModel, onPageChange, t]); + + return { + pagination, + setPagination, + total: kFModel.total, + searchString: kFModel.searchString, + }; +}; + +export const useHandleSearchChange = (setPagination: () => void) => { + const dispatch = useDispatch(); + + const throttledGetDocumentList = useCallback(() => { + dispatch({ + type: 'kFModel/throttledGetDocumentList', + }); + }, [dispatch]); + + const handleInputChange = useCallback( + (e: React.ChangeEvent) => { + const value = e.target.value; + dispatch({ type: 'kFModel/setSearchString', payload: value }); + setPagination(); + throttledGetDocumentList(); + }, + [setPagination, throttledGetDocumentList, dispatch], + ); + + return { handleInputChange }; +}; + +export const useGetRowSelection = () => { + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + + const rowSelection = { + selectedRowKeys, + onChange: (newSelectedRowKeys: React.Key[]) => { + setSelectedRowKeys(newSelectedRowKeys); + }, + }; + + return rowSelection; +}; + +export const useNavigateToOtherFolder = () => { + const navigate = useNavigate(); + const navigateToOtherFolder = useCallback( + (folderId: string) => { + navigate(`/file?folderId=${folderId}`); + }, + [navigate], + ); + + return navigateToOtherFolder; +}; + +export const useRenameCurrentFile = () => { + const [file, setFile] = useState({} as IFile); + const { + visible: fileRenameVisible, + hideModal: hideFileRenameModal, + showModal: showFileRenameModal, + } = useSetModalState(); + const renameFile = useRenameFile(); + + const onFileRenameOk = useCallback( + async (name: string) => { + const ret = await renameFile(file.id, name); + + if (ret === 0) { + hideFileRenameModal(); + } + }, + [renameFile, file, hideFileRenameModal], + ); + + const loading = useOneNamespaceEffectsLoading('fileManager', ['renameFile']); + + const handleShowFileRenameModal = useCallback( + async (record: IFile) => { + setFile(record); + showFileRenameModal(); + }, + [showFileRenameModal], + ); + + return { + fileRenameLoading: loading, + initialFileName: file.name, + onFileRenameOk, + fileRenameVisible, + hideFileRenameModal, + showFileRenameModal: handleShowFileRenameModal, + }; +}; + +export const useSelectBreadcrumbItems = () => { + const parentFolderList = useSelectParentFolderList(); + const id = useGetFolderId(); + const fetchParentFolderList = useFetchParentFolderList(); + + useEffect(() => { + if (id) { + fetchParentFolderList(id); + } + }, [id, fetchParentFolderList]); + + return parentFolderList.length === 1 + ? [] + : parentFolderList.map((x) => ({ + title: x.name === '/' ? 'root' : x.name, + path: `/file?folderId=${x.id}`, + })); +}; diff --git a/web/src/pages/file-manager/index.less b/web/src/pages/file-manager/index.less new file mode 100644 index 0000000000..566c63a947 --- /dev/null +++ b/web/src/pages/file-manager/index.less @@ -0,0 +1,18 @@ +.fileManagerWrapper { + flex-basis: 100%; + padding: 32px; +} + +.filter { + height: 32px; + display: flex; + margin: 10px 0; + justify-content: space-between; + padding: 24px 0; + align-items: center; +} + +.deleteIconWrapper { + width: 22px; + text-align: center; +} diff --git a/web/src/pages/file-manager/index.tsx b/web/src/pages/file-manager/index.tsx new file mode 100644 index 0000000000..83dee7a634 --- /dev/null +++ b/web/src/pages/file-manager/index.tsx @@ -0,0 +1,99 @@ +import { useSelectFileList } from '@/hooks/fileManagerHooks'; +import { IFile } from '@/interfaces/database/file-manager'; +import { formatDate } from '@/utils/date'; +import { Button, Table } from 'antd'; +import { ColumnsType } from 'antd/es/table'; +import ActionCell from './action-cell'; +import FileToolbar from './file-toolbar'; +import { + useGetRowSelection, + useNavigateToOtherFolder, + useRenameCurrentFile, +} from './hooks'; + +import RenameModal from '@/components/rename-modal'; +import styles from './index.less'; + +const FileManager = () => { + const fileList = useSelectFileList(); + const rowSelection = useGetRowSelection(); + const navigateToOtherFolder = useNavigateToOtherFolder(); + const { + fileRenameVisible, + fileRenameLoading, + hideFileRenameModal, + showFileRenameModal, + initialFileName, + onFileRenameOk, + } = useRenameCurrentFile(); + + const columns: ColumnsType = [ + { + title: 'Name', + dataIndex: 'name', + key: 'name', + render(value, record) { + return record.type === 'folder' ? ( + + ) : ( + value + ); + }, + }, + { + title: 'Upload Date', + dataIndex: 'create_date', + key: 'create_date', + render(text) { + return formatDate(text); + }, + }, + { + title: 'Location', + dataIndex: 'location', + key: 'location', + }, + { + title: 'Action', + dataIndex: 'action', + key: 'action', + render: (text, record) => ( + { + console.info(record); + }} + showRenameModal={showFileRenameModal} + > + ), + }, + ]; + + return ( +
+ + + + + ); +}; + +export default FileManager; diff --git a/web/src/pages/file-manager/model.ts b/web/src/pages/file-manager/model.ts new file mode 100644 index 0000000000..e58faa9d5f --- /dev/null +++ b/web/src/pages/file-manager/model.ts @@ -0,0 +1,65 @@ +import { IFile, IFolder } from '@/interfaces/database/file-manager'; +import fileManagerService from '@/services/fileManagerService'; +import { DvaModel } from 'umi'; + +export interface FileManagerModelState { + fileList: IFile[]; + parentFolderList: IFolder[]; +} + +const model: DvaModel = { + namespace: 'fileManager', + state: { fileList: [], parentFolderList: [] }, + reducers: { + setFileList(state, { payload }) { + return { ...state, fileList: payload }; + }, + setParentFolderList(state, { payload }) { + return { ...state, parentFolderList: payload }; + }, + }, + effects: { + *removeFile({ payload = {} }, { call, put }) { + const { data } = yield call(fileManagerService.removeFile, payload); + const { retcode } = data; + if (retcode === 0) { + yield put({ + type: 'listFile', + payload: data.data?.files ?? [], + }); + } + }, + *listFile({ payload = {} }, { call, put }) { + const { data } = yield call(fileManagerService.listFile, payload); + const { retcode, data: res } = data; + + if (retcode === 0 && Array.isArray(res.files)) { + yield put({ + type: 'setFileList', + payload: res.files, + }); + } + }, + *renameFile({ payload = {} }, { call, put }) { + const { data } = yield call(fileManagerService.renameFile, payload); + if (data.retcode === 0) { + yield put({ type: 'listFile' }); + } + return data.retcode; + }, + *getAllParentFolder({ payload = {} }, { call, put }) { + const { data } = yield call( + fileManagerService.getAllParentFolder, + payload, + ); + if (data.retcode === 0) { + yield put({ + type: 'setParentFolderList', + payload: data.data?.parent_folders ?? [], + }); + } + return data.retcode; + }, + }, +}; +export default model; diff --git a/web/src/pages/file/index.tsx b/web/src/pages/file/index.tsx deleted file mode 100644 index be7eada21b..0000000000 --- a/web/src/pages/file/index.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { UploadOutlined } from '@ant-design/icons'; -import { Button, Upload } from 'antd'; -import React, { useEffect, useState } from 'react'; - -const File: React.FC = () => { - const [fileList, setFileList] = useState([ - { - uid: '0', - name: 'xxx.png', - status: 'uploading', - percent: 10, - }, - ]); - const obj = { - uid: '-1', - name: 'yyy.png', - status: 'done', - url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - thumbUrl: - 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - }; - useEffect(() => { - const timer = setInterval(() => { - setFileList((fileList: any) => { - const percent = fileList[0]?.percent; - if (percent + 10 >= 100) { - clearInterval(timer); - return [obj]; - } - const list = [{ ...fileList[0], percent: percent + 10 }]; - console.log(list); - return list; - }); - }, 300); - }, []); - return ( - <> - - - - - ); -}; - -export default File; diff --git a/web/src/pages/login/index.tsx b/web/src/pages/login/index.tsx index 98700dc9af..406bed0c8f 100644 --- a/web/src/pages/login/index.tsx +++ b/web/src/pages/login/index.tsx @@ -167,20 +167,22 @@ const Login = () => { Sign in with Google */} - + {location.host === 'demo.ragflow.io' && ( + + )} )} diff --git a/web/src/routes.ts b/web/src/routes.ts index ff61870520..5900f98954 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -82,7 +82,7 @@ const routes = [ }, { path: '/file', - component: '@/pages/file', + component: '@/pages/file-manager', }, ], }, diff --git a/web/src/services/fileManagerService.ts b/web/src/services/fileManagerService.ts new file mode 100644 index 0000000000..9edcc2f797 --- /dev/null +++ b/web/src/services/fileManagerService.ts @@ -0,0 +1,36 @@ +import api from '@/utils/api'; +import registerServer from '@/utils/registerServer'; +import request from '@/utils/request'; + +const { listFile, removeFile, uploadFile, renameFile, getAllParentFolder } = + api; + +const methods = { + listFile: { + url: listFile, + method: 'get', + }, + removeFile: { + url: removeFile, + method: 'post', + }, + uploadFile: { + url: uploadFile, + method: 'post', + }, + renameFile: { + url: renameFile, + method: 'post', + }, + getAllParentFolder: { + url: getAllParentFolder, + method: 'get', + }, +} as const; + +const fileManagerService = registerServer( + methods, + request, +); + +export default fileManagerService; diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts index f404eceeae..f449f932c8 100644 --- a/web/src/utils/api.ts +++ b/web/src/utils/api.ts @@ -66,4 +66,11 @@ export default { createExternalConversation: `${api_host}/api/new_conversation`, getExternalConversation: `${api_host}/api/conversation`, completeExternalConversation: `${api_host}/api/completion`, + + // file manager + listFile: `${api_host}/file/list`, + uploadFile: `${api_host}/file/upload`, + removeFile: `${api_host}/file/rm`, + renameFile: `${api_host}/file/rename`, + getAllParentFolder: `${api_host}/file/all_parent_folder`, }; diff --git a/web/src/utils/commonUtil.ts b/web/src/utils/commonUtil.ts index 9cda1a9958..cd6c0d5c74 100644 --- a/web/src/utils/commonUtil.ts +++ b/web/src/utils/commonUtil.ts @@ -5,11 +5,18 @@ export const isFormData = (data: unknown): data is FormData => { return data instanceof FormData; }; +const excludedFields = ['img2txt_id']; + +const isExcludedField = (key: string) => { + return excludedFields.includes(key); +}; + export const convertTheKeysOfTheObjectToSnake = (data: unknown) => { if (isObject(data) && !isFormData(data)) { return Object.keys(data).reduce>((pre, cur) => { const value = (data as Record)[cur]; - pre[isFormData(value) ? cur : snakeCase(cur)] = value; + pre[isFormData(value) || isExcludedField(cur) ? cur : snakeCase(cur)] = + value; return pre; }, {}); } diff --git a/web/typings.d.ts b/web/typings.d.ts index cbe06bea1f..682c112a36 100644 --- a/web/typings.d.ts +++ b/web/typings.d.ts @@ -1,8 +1,39 @@ -import 'umi/typings'; +import { ChunkModelState } from '@/pages/add-knowledge/components/knowledge-chunk/model'; +import { KFModelState } from '@/pages/add-knowledge/components/knowledge-file/model'; +import { KSModelState } from '@/pages/add-knowledge/components/knowledge-setting/model'; +import { TestingModelState } from '@/pages/add-knowledge/components/knowledge-testing/model'; +import { kAModelState } from '@/pages/add-knowledge/model'; +import { ChatModelState } from '@/pages/chat/model'; +import { FileManagerModelState } from '@/pages/file-manager/model'; +import { KnowledgeModelState } from '@/pages/knowledge/model'; +import { LoginModelState } from '@/pages/login/model'; +import { SettingModelState } from '@/pages/user-setting/model'; + declare module 'lodash'; -// declare type Nullable = T | null; invalid +function useSelector( + selector: (state: TState) => TSelected, + equalityFn?: (left: TSelected, right: TSelected) => boolean, +): TSelected; + +export interface RootState { + // loading: Loading; + fileManager: FileManagerModelState; + chatModel: ChatModelState; + loginModel: LoginModelState; + knowledgeModel: KnowledgeModelState; + settingModel: SettingModelState; + kFModel: KFModelState; + kAModel: kAModelState; + chunkModel: ChunkModelState; + kSModel: KSModelState; + testingModel: TestingModelState; +} declare global { type Nullable = T | null; } + +declare module 'umi' { + export { useSelector }; +}