Refactor: UmiJs -> Vite (#12410)

### What problem does this PR solve?

Refactor: UmiJs -> Vite+React

### Type of change

- [x] Refactoring

---------

Co-authored-by: Liu An <asiro@qq.com>
This commit is contained in:
chanx
2026-01-04 19:14:20 +08:00
committed by GitHub
parent 2c10ccd622
commit a8a060676a
168 changed files with 12808 additions and 23476 deletions

View File

@ -18,11 +18,14 @@ 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 React, { useEffect, useState } from 'react';
import { RouterProvider } from 'react-router';
import { ThemeProvider, useTheme } from './components/theme-provider';
import { SidebarProvider } from './components/ui/sidebar';
import { TooltipProvider } from './components/ui/tooltip';
import { ThemeEnum } from './constants/common';
// import { getRouter } from './routes';
import { routers } from './routes';
import storage from './utils/authorization-util';
import 'react-photo-view/dist/react-photo-view.css';
@ -54,15 +57,26 @@ const AntLanguageMap = {
de: deDE,
};
// if (process.env.NODE_ENV === 'development') {
// const whyDidYouRender = require('@welldone-software/why-did-you-render');
// whyDidYouRender(React, {
// trackAllPureComponents: true,
// trackExtraHooks: [],
// logOnDifferentValues: true,
// });
// }
if (process.env.NODE_ENV === 'development') {
const whyDidYouRender = require('@welldone-software/why-did-you-render');
whyDidYouRender(React, {
trackAllPureComponents: true,
trackExtraHooks: [],
logOnDifferentValues: true,
});
import('@welldone-software/why-did-you-render').then(
(whyDidYouRenderModule) => {
const whyDidYouRender = whyDidYouRenderModule.default;
whyDidYouRender(React, {
trackAllPureComponents: true,
trackExtraHooks: [],
logOnDifferentValues: true,
});
},
);
}
const queryClient = new QueryClient();
type Locale = ConfigProviderProps['locale'];
@ -94,7 +108,7 @@ function Root({ children }: React.PropsWithChildren) {
locale={locale}
>
<SidebarProvider className="h-full">
<App>{children}</App>
<App className="w-full h-dvh relative">{children}</App>
</SidebarProvider>
<Sonner position={'top-right'} expand richColors closeButton></Sonner>
<Toaster />
@ -126,6 +140,22 @@ const RootProvider = ({ children }: React.PropsWithChildren) => {
</TooltipProvider>
);
};
export function rootContainer(container: ReactNode) {
return <RootProvider>{container}</RootProvider>;
export default function AppContainer() {
// const [router, setRouter] = useState<any>(null);
// useEffect(() => {
// getRouter().then(setRouter);
// }, []);
// if (!router) {
// return <div>Loading...</div>;
// }
return (
<RootProvider>
<RouterProvider router={routers}></RouterProvider>
{/* <RouterProvider router={router}></RouterProvider> */}
</RootProvider>
);
}

View File

@ -1,7 +1,7 @@
import { useIsDarkTheme } from '@/components/theme-provider';
import { useSetModalState } from '@/hooks/common-hooks';
import { LangfuseCard } from '@/pages/user-setting/setting-model/langfuse';
import apiDoc from '@parent/docs/references/http_api_reference.md';
import apiDoc from '@parent/docs/references/http_api_reference.md?raw';
import MarkdownPreview from '@uiw/react-markdown-preview';
import ChatApiKeyModal from '../chat-api-key-modal';
import BackendServiceApi from './backend-service-api';

View File

@ -5,7 +5,7 @@ import { formatDate } from '@/utils/date';
import camelCase from 'lodash/camelCase';
import { useSelectChartStatsList } from '../hooks';
import styles from './index.less';
import styles from './index.module.less';
const StatsLineChart = ({ statsType }: { statsType: keyof IStats }) => {
const { t } = useTranslate('chat');

View File

@ -2,11 +2,10 @@ import { cn } from '@/lib/utils';
import { t } from 'i18next';
import { ArrowBigLeft } from 'lucide-react';
import React from 'react';
import { useNavigate } from 'umi';
import { useNavigate } from 'react-router';
import { Button } from '../ui/button';
interface BackButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
interface BackButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
to?: string;
}

View File

@ -57,11 +57,10 @@ import {
const FormId = 'ChunkMethodDialogForm';
interface IProps
extends IModalProps<{
parserId: string;
parserConfig: IChangeParserConfigRequestBody;
}> {
interface IProps extends IModalProps<{
parserId: string;
parserConfig: IChangeParserConfigRequestBody;
}> {
loading: boolean;
parserId: string;
pipelineId?: string;

View File

@ -14,7 +14,7 @@ import { Spin } from '@/components/ui/spin';
import { Authorization } from '@/constants/authorization';
import FileError from '@/pages/document-viewer/file-error';
import { getAuthorization } from '@/utils/authorization-util';
import styles from './index.less';
import styles from './index.module.less';
type PdfLoaderProps = React.ComponentProps<typeof PdfLoader> & {
httpHeaders?: Record<string, string>;
};

View File

@ -952,8 +952,8 @@ const DynamicForm = {
onClick={() => {
(async () => {
try {
let beValid = await form.formControl.trigger();
console.log('form valid', beValid, form, form.formControl);
let beValid = await form.trigger();
console.log('form valid', beValid, form);
// if (beValid) {
// form.handleSubmit(async (values) => {
// console.log('form values', values);

View File

@ -0,0 +1,65 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
interface FallbackComponentProps {
error?: Error;
reset?: () => void;
}
const FallbackComponent: React.FC<FallbackComponentProps> = ({
error,
reset,
}) => {
const { t } = useTranslation();
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h2>{t('error_boundary.title', 'Something went wrong')}</h2>
<p>
{t(
'error_boundary.description',
'Sorry, an error occurred while loading the page.',
)}
</p>
{error && (
<details style={{ whiteSpace: 'pre-wrap', marginTop: '16px' }}>
<summary>{t('error_boundary.details', 'Error details')}</summary>
{error.toString()}
</details>
)}
<div style={{ marginTop: '16px' }}>
<button
onClick={() => window.location.reload()}
style={{
marginRight: '12px',
padding: '8px 16px',
backgroundColor: '#1890ff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
}}
>
{t('error_boundary.reload', 'Reload Page')}
</button>
{reset && (
<button
onClick={reset}
style={{
padding: '8px 16px',
backgroundColor: '#52c41a',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
}}
>
{t('error_boundary.retry', 'Retry')}
</button>
)}
</div>
</div>
);
};
export default FallbackComponent;

View File

@ -3,7 +3,7 @@ import SvgIcon from '../svg-icon';
import { useFetchDocumentThumbnailsByIds } from '@/hooks/use-document-request';
import { useEffect } from 'react';
import styles from './index.less';
import styles from './index.module.less';
interface IProps {
name: string;

View File

@ -287,11 +287,10 @@ function useFileUploadContext(consumerName: string) {
return context;
}
interface FileUploadRootProps
extends Omit<
React.ComponentPropsWithoutRef<'div'>,
'defaultValue' | 'onChange'
> {
interface FileUploadRootProps extends Omit<
React.ComponentPropsWithoutRef<'div'>,
'defaultValue' | 'onChange'
> {
value?: File[];
defaultValue?: File[];
onValueChange?: (files: File[]) => void;
@ -639,8 +638,7 @@ function FileUploadRoot(props: FileUploadRootProps) {
);
}
interface FileUploadDropzoneProps
extends React.ComponentPropsWithoutRef<'div'> {
interface FileUploadDropzoneProps extends React.ComponentPropsWithoutRef<'div'> {
asChild?: boolean;
}
@ -836,8 +834,7 @@ function FileUploadDropzone(props: FileUploadDropzoneProps) {
);
}
interface FileUploadTriggerProps
extends React.ComponentPropsWithoutRef<'button'> {
interface FileUploadTriggerProps extends React.ComponentPropsWithoutRef<'button'> {
asChild?: boolean;
}
@ -1069,8 +1066,7 @@ function getFileIcon(file: File) {
return <FileIcon />;
}
interface FileUploadItemPreviewProps
extends React.ComponentPropsWithoutRef<'div'> {
interface FileUploadItemPreviewProps extends React.ComponentPropsWithoutRef<'div'> {
render?: (file: File) => React.ReactNode;
asChild?: boolean;
}
@ -1122,8 +1118,7 @@ function FileUploadItemPreview(props: FileUploadItemPreviewProps) {
);
}
interface FileUploadItemMetadataProps
extends React.ComponentPropsWithoutRef<'div'> {
interface FileUploadItemMetadataProps extends React.ComponentPropsWithoutRef<'div'> {
asChild?: boolean;
size?: 'default' | 'sm';
}
@ -1184,8 +1179,7 @@ function FileUploadItemMetadata(props: FileUploadItemMetadataProps) {
</ItemMetadataPrimitive>
);
}
interface FileUploadItemProgressProps
extends React.ComponentPropsWithoutRef<'div'> {
interface FileUploadItemProgressProps extends React.ComponentPropsWithoutRef<'div'> {
variant?: 'linear' | 'circular' | 'fill';
size?: number;
asChild?: boolean;
@ -1315,8 +1309,7 @@ function FileUploadItemProgress(props: FileUploadItemProgressProps) {
}
}
interface FileUploadItemDeleteProps
extends React.ComponentPropsWithoutRef<'button'> {
interface FileUploadItemDeleteProps extends React.ComponentPropsWithoutRef<'button'> {
asChild?: boolean;
}
@ -1356,8 +1349,7 @@ function FileUploadItemDelete(props: FileUploadItemDeleteProps) {
);
}
interface FileUploadClearProps
extends React.ComponentPropsWithoutRef<'button'> {
interface FileUploadClearProps extends React.ComponentPropsWithoutRef<'button'> {
forceMount?: boolean;
asChild?: boolean;
}

View File

@ -92,8 +92,10 @@ function FileCard({ file, progress, onRemove }: FileCardProps) {
);
}
interface FileUploaderProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
interface FileUploaderProps extends Omit<
React.HTMLAttributes<HTMLDivElement>,
'title'
> {
/**
* Value of the uploader.
* @type File[]

View File

@ -23,7 +23,6 @@
}
.widget-citation-content {
p,
div,
span,
@ -35,7 +34,6 @@
}
.floating-chat-widget {
/* General styles for markdown content within the widget */
p,
div,
@ -55,4 +53,4 @@
margin: 8px 0 !important;
display: inline-block !important;
}
}
}

View File

@ -35,7 +35,7 @@ import rehypeRaw from 'rehype-raw';
import remarkGfm from 'remark-gfm';
import remarkMath from 'remark-math';
import { visitParents } from 'unist-util-visit-parents';
import styles from './floating-chat-widget-markdown.less';
import styles from './floating-chat-widget-markdown.module.less';
import { useIsDarkTheme } from './theme-provider';
const getChunkIndex = (match: string) => Number(match.replace(/\[|\]/g, ''));

View File

@ -14,7 +14,7 @@ import 'katex/dist/katex.min.css'; // `rehype-katex` does not import the CSS for
import { preprocessLaTeX } from '@/utils/chat';
import { useIsDarkTheme } from '../theme-provider';
import styles from './index.less';
import styles from './index.module.less';
const HighLightMarkdown = ({
children,

View File

@ -11,7 +11,7 @@ import { useComposeLlmOptionsByModelTypes } from '@/hooks/use-llm-request';
import { setChatVariableEnabledFieldValuePage } from '@/utils/chat';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { useCallback, useMemo } from 'react';
import styles from './index.less';
import styles from './index.module.less';
interface IProps {
prefix?: string;

View File

@ -33,7 +33,7 @@ import {
HoverCardContent,
HoverCardTrigger,
} from '../ui/hover-card';
import styles from './index.less';
import styles from './index.module.less';
const getChunkIndex = (match: string) => Number(match);

View File

@ -1,4 +1,3 @@
import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg';
import { MessageType } from '@/constants/chat';
import {
IMessage,
@ -21,9 +20,10 @@ import {
removePDFDownloadInfo,
} from '../pdf-download-button';
import { RAGFlowAvatar } from '../ragflow-avatar';
import SvgIcon from '../svg-icon';
import { useTheme } from '../theme-provider';
import { AssistantGroupButton, UserGroupButton } from './group-button';
import styles from './index.less';
import styles from './index.module.less';
interface IProps extends Partial<IRemoveMessageById>, IRegenerateMessage {
item: IMessage;
@ -117,7 +117,11 @@ const MessageItem = ({
isPerson
/>
) : (
<AssistantIcon />
<SvgIcon
name={'assistant'}
width={'100%'}
className={cn('size-10 fill-current')}
></SvgIcon>
))}
<section className="flex gap-2 flex-1 flex-col">

View File

@ -35,7 +35,7 @@ import {
HoverCardContent,
HoverCardTrigger,
} from '../ui/hover-card';
import styles from './index.less';
import styles from './index.module.less';
const getChunkIndex = (match: string) => Number(match);
// TODO: The display of the table is inconsistent with the display previously placed in the MessageItem.

View File

@ -1,4 +1,3 @@
import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg';
import { MessageType } from '@/constants/chat';
import {
IMessage,
@ -31,18 +30,17 @@ import {
removePDFDownloadInfo,
} from '../pdf-download-button';
import { RAGFlowAvatar } from '../ragflow-avatar';
import SvgIcon from '../svg-icon';
import { useTheme } from '../theme-provider';
import { Button } from '../ui/button';
import { AssistantGroupButton, UserGroupButton } from './group-button';
import styles from './index.less';
import styles from './index.module.less';
import { ReferenceDocumentList } from './reference-document-list';
import { ReferenceImageList } from './reference-image-list';
import { UploadedMessageFiles } from './uploaded-message-files';
interface IProps
extends Partial<IRemoveMessageById>,
IRegenerateMessage,
PropsWithChildren {
extends Partial<IRemoveMessageById>, IRegenerateMessage, PropsWithChildren {
item: IMessage;
conversationId?: string;
currentEventListWithoutMessageById?: (messageId: string) => INodeEvent[];
@ -208,7 +206,11 @@ function MessageItem({
isPerson
/>
) : (
<AssistantIcon />
<SvgIcon
name={'assistant'}
width={'100%'}
className={cn('size-10 fill-current')}
></SvgIcon>
))}
<section className="flex-col gap-2 flex-1">
<div className="flex justify-between items-center">

View File

@ -17,7 +17,7 @@ import {
useGetChunkHighlights,
useGetDocumentUrl,
} from '@/hooks/use-document-request';
import styles from './index.less';
import styles from './index.module.less';
interface IProps {
chunk: IChunk | IReferenceChunk;

View File

@ -61,8 +61,8 @@ export function RAGFlowFormItem({
)}
<div
className={cn('flex flex-col', {
'w-3/4': horizontal,
'w-full': !horizontal,
'w-3/4': horizontal,
})}
>
<FormControl>

View File

@ -4,26 +4,39 @@ import Icon, { UserOutlined } from '@ant-design/icons';
import { IconComponentProps } from '@ant-design/icons/lib/components/Icon';
import { Avatar } from 'antd';
import { AvatarSize } from 'antd/es/avatar/AvatarContext';
import { useMemo } from 'react';
import { memo, useMemo } from 'react';
import { IconFontFill } from './icon-font';
import { useIsDarkTheme } from './theme-provider';
const importAll = (requireContext: __WebpackModuleApi.RequireContext) => {
const list = requireContext.keys().map((key) => {
const name = key.replace(/\.\/(.*)\.\w+$/, '$1');
return { name, value: requireContext(key) };
});
return list;
};
// const importAll = (requireContext: __WebpackModuleApi.RequireContext) => {
// const list = requireContext.keys().map((key) => {
// const name = key.replace(/\.\/(.*)\.\w+$/, '$1');
// return { name, value: requireContext(key) };
// });
// return list;
// };
let routeList: { name: string; value: string }[] = [];
// let routeList: { name: string; value: string }[] = [];
try {
routeList = importAll(require.context('@/assets/svg', true, /\.svg$/));
} catch (error) {
console.warn(error);
routeList = [];
}
// try {
// routeList = importAll(require.context('@/assets/svg', true, /\.svg$/));
// } catch (error) {
// console.warn(error);
// routeList = [];
// }
const svgModules = import.meta.glob('@/assets/svg/**/*.svg', {
eager: true,
query: '?url',
});
const routeList: { name: string; value: string }[] = Object.entries(
svgModules,
).map(([path, module]) => {
const name = path.replace(/^.*\/assets\/svg\//, '').replace(/\.[^/.]+$/, '');
// @ts-ignore
return { name, value: module.default || module };
});
interface IProps extends IconComponentProps {
name: string;
@ -32,23 +45,25 @@ interface IProps extends IconComponentProps {
imgClass?: string;
}
const SvgIcon = ({ name, width, height, imgClass, ...restProps }: IProps) => {
const ListItem = routeList.find((item) => item.name === name);
return (
<Icon
component={() => (
<img
src={ListItem?.value}
alt=""
width={width}
height={height}
className={cn(imgClass, 'max-w-full')}
/>
)}
{...(restProps as any)}
/>
);
};
const SvgIcon = memo(
({ name, width, height, imgClass, ...restProps }: IProps) => {
const ListItem = routeList.find((item) => item.name === name);
return (
<Icon
component={() => (
<img
src={ListItem?.value}
alt=""
width={width}
height={height}
className={cn(imgClass, 'max-w-full')}
/>
)}
{...(restProps as any)}
/>
);
},
);
export const LlmIcon = ({
name,

View File

@ -40,8 +40,10 @@ const segmentedVariants = {
xl: 'px-6 py-2',
},
};
export interface SegmentedProps
extends Omit<React.HTMLProps<HTMLDivElement>, 'onChange'> {
export interface SegmentedProps extends Omit<
React.HTMLProps<HTMLDivElement>,
'onChange'
> {
options: SegmentedOptions;
defaultValue?: SegmentedValue;
value?: SegmentedValue;

View File

@ -1,7 +1,7 @@
import message from '@/components/ui/message';
import authorizationUtil from '@/utils/authorization-util';
import { useEffect, useMemo, useState } from 'react';
import { useNavigate, useSearchParams } from 'umi';
import { useNavigate, useSearchParams } from 'react-router';
export const useOAuthCallback = () => {
const [currentQueryParameters, setSearchParams] = useSearchParams();

View File

@ -60,7 +60,9 @@ export function useDynamicSVGImport(
setLoading(true);
const importIcon = async (): Promise<void> => {
try {
ImportedIconRef.current = (await import(name)).ReactComponent;
ImportedIconRef.current = (
await import(/* @vite-ignore */ name)
).ReactComponent;
onCompleted?.(name, ImportedIconRef.current);
} catch (err: any) {
onError?.(err);

View File

@ -2,7 +2,7 @@ import { AgentCategory, AgentQuery } from '@/constants/agent';
import { NavigateToDataflowResultProps } from '@/pages/dataflow-result/interface';
import { Routes } from '@/routes';
import { useCallback } from 'react';
import { useNavigate, useParams, useSearchParams } from 'umi';
import { useNavigate, useParams, useSearchParams } from 'react-router';
export enum QueryStringMap {
KnowledgeId = 'knowledgeId',

View File

@ -3,7 +3,7 @@ import {
KnowledgeSearchParams,
} from '@/constants/knowledge';
import { useCallback } from 'react';
import { useLocation, useNavigate, useSearchParams } from 'umi';
import { useLocation, useNavigate, useSearchParams } from 'react-router';
export enum SegmentIndex {
Second = '2',

View File

@ -31,7 +31,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useDebounce } from 'ahooks';
import { get, set } from 'lodash';
import { useCallback, useState } from 'react';
import { useParams, useSearchParams } from 'umi';
import { useParams, useSearchParams } from 'react-router';
import {
useGetPaginationWithRouter,
useHandleSearchChange,

View File

@ -22,7 +22,7 @@ import { useDebounce } from 'ahooks';
import { has } from 'lodash';
import { useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams, useSearchParams } from 'umi';
import { useParams, useSearchParams } from 'react-router';
import {
useGetPaginationWithRouter,
useHandleSearchChange,

View File

@ -3,7 +3,7 @@ import { IFlow } from '@/interfaces/database/agent';
import dataflowService from '@/services/dataflow-service';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { useParams } from 'umi';
import { useParams } from 'react-router';
export const enum DataflowApiAction {
ListDataflow = 'listDataflow',

View File

@ -23,7 +23,7 @@ import { useDebounce } from 'ahooks';
import { get } from 'lodash';
import { useCallback, useMemo, useState } from 'react';
import { IHighlight } from 'react-pdf-highlighter';
import { useParams } from 'umi';
import { useParams } from 'react-router';
import {
useGetPaginationWithRouter,
useHandleSearchChange,

View File

@ -11,7 +11,7 @@ import { useDebounce } from 'ahooks';
import { PaginationProps } from 'antd';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useSearchParams } from 'umi';
import { useSearchParams } from 'react-router';
import {
useGetPaginationWithRouter,
useHandleSearchChange,

View File

@ -28,7 +28,7 @@ import {
} from '@tanstack/react-query';
import { useDebounce } from 'ahooks';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useParams, useSearchParams } from 'umi';
import { useParams, useSearchParams } from 'react-router';
import {
useGetPaginationWithRouter,
useHandleSearchChange,

View File

@ -18,13 +18,13 @@ import userService, {
listTenant,
listTenantUser,
} from '@/services/user-service';
import { history } from '@/utils/simple-history-util';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { Modal } from 'antd';
import DOMPurify from 'dompurify';
import { isEmpty } from 'lodash';
import { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { history } from 'umi';
export const enum UserSettingApiAction {
UserInfo = 'userInfo',

View File

@ -1,17 +1,17 @@
import { ReactComponent as FileIcon } from '@/assets/svg/file-management.svg';
import { ReactComponent as GraphIcon } from '@/assets/svg/graph.svg';
import { ReactComponent as KnowledgeBaseIcon } from '@/assets/svg/knowledge-base.svg';
import FileIcon from '@/assets/svg/file-management.svg';
import GraphIcon from '@/assets/svg/graph.svg';
import KnowledgeBaseIcon from '@/assets/svg/knowledge-base.svg';
import { useTranslate } from '@/hooks/common-hooks';
import { useFetchAppConf } from '@/hooks/logic-hooks';
import { useNavigateWithFromState } from '@/hooks/route-hook';
import { MessageOutlined, SearchOutlined } from '@ant-design/icons';
import { Flex, Layout, Radio, Space, theme } from 'antd';
import { MouseEventHandler, useCallback, useMemo } from 'react';
import { useLocation } from 'umi';
import { useLocation } from 'react-router';
import Toolbar from '../right-toolbar';
import { useTheme } from '@/components/theme-provider';
import styles from './index.less';
import styles from './index.module.less';
const { Header } = Layout;

View File

@ -14,7 +14,7 @@ import {
} from '@/hooks/use-user-setting-request';
import { TenantRole } from '@/pages/user-setting/constants';
import { BellRing, CircleHelp, MoonIcon, SunIcon } from 'lucide-react';
import { useNavigate } from 'umi';
import { useNavigate } from 'react-router';
import styled from './index.less';
const Circle = ({ children, ...restProps }: React.PropsWithChildren) => {

View File

@ -1,9 +1,9 @@
import { useFetchUserInfo } from '@/hooks/use-user-setting-request';
import { history } from '@/utils/simple-history-util';
import { Avatar } from 'antd';
import React from 'react';
import { history } from 'umi';
import styles from '../../index.less';
import styles from '../../index.module.less';
const App: React.FC = () => {
const { data: userInfo } = useFetchUserInfo();

View File

@ -1,10 +1,10 @@
import { Divider, Layout, theme } from 'antd';
import React from 'react';
import { Outlet } from 'umi';
import { Outlet } from 'react-router';
import '../locales/config';
import Header from './components/header';
import styles from './index.less';
import styles from './index.module.less';
const { Content } = Layout;

View File

@ -30,7 +30,7 @@ import {
} from 'lucide-react';
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'umi';
import { useLocation } from 'react-router';
import { BellButton } from './bell-button';
const handleDocHelpCLick = () => {

View File

@ -1,4 +1,4 @@
import { Outlet } from 'umi';
import { Outlet } from 'react-router';
import { Header } from './next-header';
export default function NextLayout() {

13
web/src/main.tsx Normal file
View File

@ -0,0 +1,13 @@
import React from 'react';
import { gotoVSCode, Inspector } from 'react-dev-inspector';
import ReactDOM from 'react-dom/client';
import '../tailwind.css';
import App from './app';
import './global.less';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<Inspector keys={['alt', 'c']} onInspectElement={gotoVSCode} />
<App />
</React.StrictMode>,
);

View File

@ -1,7 +1,7 @@
import { Routes } from '@/routes';
import { history } from '@/utils/simple-history-util';
import { Button, Result } from 'antd';
import { history, useLocation } from 'umi';
import { useLocation } from 'react-router';
const NoFoundPage = () => {
const location = useLocation();

View File

@ -1,6 +1,6 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { NavLink, Outlet, useNavigate } from 'umi';
import { NavLink, Outlet, useNavigate } from 'react-router';
import { useMutation, useQuery } from '@tanstack/react-query';

View File

@ -1,4 +1,4 @@
import { Outlet } from 'umi';
import { Outlet } from 'react-router';
const AdminRootLayout = () => {
return <Outlet />;

View File

@ -2,7 +2,7 @@ import { type AxiosResponseHeaders } from 'axios';
import { useEffect, useId } from 'react';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'umi';
import { useNavigate } from 'react-router';
import { useMutation } from '@tanstack/react-query';

View File

@ -1,6 +1,6 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate, useParams } from 'umi';
import { useNavigate, useParams } from 'react-router';
import { LucideArrowLeft, LucideDot } from 'lucide-react';

View File

@ -1,6 +1,6 @@
import { useLayoutEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'umi';
import { useNavigate } from 'react-router';
import {
createColumnHelper,

View File

@ -1,6 +1,6 @@
import { Routes } from '@/routes';
import authorizationUtil from '@/utils/authorization-util';
import { Navigate, Outlet } from 'umi';
import { Navigate, Outlet } from 'react-router';
export default function AuthorizedAdminWrapper() {
const isLogin = !!authorizationUtil.getAuthorization();

View File

@ -1,7 +1,7 @@
import { NodeMouseHandler, useReactFlow } from '@xyflow/react';
import { useCallback, useRef, useState } from 'react';
import styles from './index.less';
import styles from './index.module.less';
export interface INodeContextMenu {
id: string;

View File

@ -50,7 +50,7 @@ import { useStopMessageUnmount } from '../hooks/use-stop-message';
import { LogSheet } from '../log-sheet';
import RunSheet from '../run-sheet';
import { ButtonEdge } from './edge';
import styles from './index.less';
import styles from './index.module.less';
import { RagNode } from './node';
import { AgentNode } from './node/agent-node';
import { BeginNode } from './node/begin-node';

View File

@ -18,7 +18,7 @@ import OperatorIcon from '../../operator-icon';
import { LabelCard } from './card';
import { CommonHandle } from './handle';
import { RightHandleStyle } from './handle-icon';
import styles from './index.less';
import styles from './index.module.less';
import { NodeWrapper } from './node-wrapper';
function InnerBeginNode({

View File

@ -14,7 +14,7 @@ import { BeginQuery } from '../../interface';
import OperatorIcon from '../../operator-icon';
import { CommonHandle } from './handle';
import { RightHandleStyle } from './handle-icon';
import styles from './index.less';
import styles from './index.module.less';
import { NodeWrapper } from './node-wrapper';
// TODO: do not allow other nodes to connect to this node

View File

@ -6,7 +6,7 @@ import { get } from 'lodash';
import { memo } from 'react';
import { LLMLabelCard } from './card';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less';
import styles from './index.module.less';
import NodeHeader from './node-header';
export function InnerKeywordNode({

View File

@ -8,7 +8,7 @@ import { get } from 'lodash';
import { memo } from 'react';
import { LabelCard } from './card';
import { LeftEndHandle } from './handle';
import styles from './index.less';
import styles from './index.module.less';
import NodeHeader from './node-header';
import { NodeWrapper } from './node-wrapper';
import { ToolBar } from './toolbar';
@ -17,7 +17,6 @@ import { VariableDisplay } from './variable-display';
function InnerMessageNode({ id, data, selected }: NodeProps<IMessageNode>) {
const messages: string[] = get(data, 'form.content', []);
const { getLabel } = useGetVariableLabelOrTypeByValue({ nodeId: id });
return (
<ToolBar selected={selected} id={id} label={data.label}>
<NodeWrapper selected={selected} id={id}>

View File

@ -12,7 +12,7 @@ import { RetrievalFormSchemaType } from '../../form/retrieval-form/next';
import { useGetVariableLabelOrTypeByValue } from '../../hooks/use-get-begin-query';
import { LabelCard } from './card';
import { CommonHandle, LeftEndHandle } from './handle';
import styles from './index.less';
import styles from './index.module.less';
import NodeHeader from './node-header';
import { NodeWrapper } from './node-wrapper';
import { ToolBar } from './toolbar';

View File

@ -6,7 +6,7 @@ import { get } from 'lodash';
import { memo } from 'react';
import { LLMLabelCard } from './card';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less';
import styles from './index.module.less';
import NodeHeader from './node-header';
function InnerRewriteNode({

View File

@ -15,7 +15,7 @@ import {
import { useFetchUserInfo } from '@/hooks/use-user-setting-request';
import { buildMessageUuidWithRole } from '@/utils/chat';
import { memo, useCallback, useContext } from 'react';
import { useParams } from 'umi';
import { useParams } from 'react-router';
import { AgentChatContext } from '../context';
import DebugContent from '../debug-content';
import { useAwaitCompentData } from '../hooks/use-chat-logic';

View File

@ -26,7 +26,7 @@ import {
useRef,
useState,
} from 'react';
import { useParams } from 'umi';
import { useParams } from 'react-router';
import { v4 as uuid } from 'uuid';
import { BeginId } from '../constant';
import { AgentChatLogContext } from '../context';

View File

@ -1,4 +1,4 @@
import { useParams } from 'umi';
import { useParams } from 'react-router';
export function useBuildWebhookUrl() {
const { id } = useParams();

View File

@ -1,5 +1,5 @@
import { AgentCategory, AgentQuery } from '@/constants/agent';
import { useSearchParams } from 'umi';
import { useSearchParams } from 'react-router';
export function useIsPipeline() {
const [queryParameters] = useSearchParams();

View File

@ -3,7 +3,7 @@ import { useSendMessageBySSE } from '@/hooks/use-send-message';
import api from '@/utils/api';
import { get } from 'lodash';
import { useCallback, useState } from 'react';
import { useParams } from 'umi';
import { useParams } from 'react-router';
import { UseFetchLogReturnType } from './use-fetch-pipeline-log';
import { useSaveGraph } from './use-save-graph';

View File

@ -8,7 +8,7 @@ import { RAGFlowNodeType } from '@/interfaces/database/flow';
import { formatDate } from '@/utils/date';
import { useDebounceEffect } from 'ahooks';
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'umi';
import { useParams } from 'react-router';
import useGraphStore from '../store';
import { useBuildDslData } from './use-build-dsl';

View File

@ -9,7 +9,7 @@ import {
import { isEmpty } from 'lodash';
import trim from 'lodash/trim';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useSearchParams } from 'umi';
import { useSearchParams } from 'react-router';
import { AgentDialogueMode } from '../constant';
export const useSendButtonDisabled = (value: string) => {

View File

@ -35,7 +35,7 @@ import {
} from 'lucide-react';
import { ComponentPropsWithoutRef, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'umi';
import { useParams } from 'react-router';
import AgentCanvas from './canvas';
import { DropdownProvider } from './canvas/context';
import { Operator } from './constant';

View File

@ -1,18 +1,5 @@
import { ReactComponent as ArxivIcon } from '@/assets/svg/arxiv.svg';
import { ReactComponent as BingIcon } from '@/assets/svg/bing.svg';
import { ReactComponent as CrawlerIcon } from '@/assets/svg/crawler.svg';
import { ReactComponent as DuckIcon } from '@/assets/svg/duck.svg';
import { ReactComponent as GithubIcon } from '@/assets/svg/github.svg';
import { ReactComponent as GoogleScholarIcon } from '@/assets/svg/google-scholar.svg';
import { ReactComponent as GoogleIcon } from '@/assets/svg/google.svg';
import { ReactComponent as PubMedIcon } from '@/assets/svg/pubmed.svg';
import { ReactComponent as SearXNGIcon } from '@/assets/svg/searxng.svg';
import { ReactComponent as TavilyIcon } from '@/assets/svg/tavily.svg';
import { ReactComponent as WenCaiIcon } from '@/assets/svg/wencai.svg';
import { ReactComponent as WikipediaIcon } from '@/assets/svg/wikipedia.svg';
import { ReactComponent as YahooFinanceIcon } from '@/assets/svg/yahoo-finance.svg';
import { IconFontFill } from '@/components/icon-font';
import SvgIcon from '@/components/svg-icon';
import { cn } from '@/lib/utils';
import {
FileCode,
@ -21,6 +8,7 @@ import {
Infinity as InfinityIcon,
LogOut,
} from 'lucide-react';
import { Component } from 'react';
import { Operator } from './constant';
interface IProps {
@ -49,20 +37,20 @@ export const OperatorIconMap = {
};
export const SVGIconMap = {
[Operator.ArXiv]: ArxivIcon,
[Operator.GitHub]: GithubIcon,
[Operator.Bing]: BingIcon,
[Operator.DuckDuckGo]: DuckIcon,
[Operator.Google]: GoogleIcon,
[Operator.GoogleScholar]: GoogleScholarIcon,
[Operator.PubMed]: PubMedIcon,
[Operator.SearXNG]: SearXNGIcon,
[Operator.TavilyExtract]: TavilyIcon,
[Operator.TavilySearch]: TavilyIcon,
[Operator.Wikipedia]: WikipediaIcon,
[Operator.YahooFinance]: YahooFinanceIcon,
[Operator.WenCai]: WenCaiIcon,
[Operator.Crawler]: CrawlerIcon,
[Operator.ArXiv]: 'arxiv',
[Operator.GitHub]: 'github',
[Operator.Bing]: 'bing',
[Operator.DuckDuckGo]: 'duck',
[Operator.Google]: 'google',
[Operator.GoogleScholar]: 'google-scholar',
[Operator.PubMed]: 'pubmed',
[Operator.SearXNG]: 'searxng',
[Operator.TavilyExtract]: 'tavily',
[Operator.TavilySearch]: 'tavily',
[Operator.Wikipedia]: 'wikipedia',
[Operator.YahooFinance]: 'yahoo-finance',
[Operator.WenCai]: 'wencai',
[Operator.Crawler]: 'crawler',
};
export const LucideIconMap = {
[Operator.DataOperations]: FileCode,
@ -75,9 +63,28 @@ const Empty = () => {
return <div className="hidden"></div>;
};
class SvgErrorBoundary extends Component<{
children: React.ReactNode;
fallback?: React.ReactNode;
}> {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return this.props.fallback || <Empty />;
}
return this.props.children;
}
}
const OperatorIcon = ({ name, className }: IProps) => {
const Icon = OperatorIconMap[name as keyof typeof OperatorIconMap];
const SvgIcon = SVGIconMap[name as keyof typeof SVGIconMap];
const svgIcon = SVGIconMap[name as keyof typeof SVGIconMap];
const LucideIcon = LucideIconMap[name as keyof typeof LucideIconMap];
if (name === Operator.Begin) {
@ -95,19 +102,33 @@ const OperatorIcon = ({ name, className }: IProps) => {
if (Icon) {
return (
<IconFontFill
name={Icon}
className={cn('size-5 ', className)}
></IconFontFill>
<SvgErrorBoundary fallback={<Empty />}>
<IconFontFill
name={Icon}
className={cn('size-5 ', className)}
></IconFontFill>
</SvgErrorBoundary>
);
}
if (LucideIcon) {
return <LucideIcon className={cn('size-5', className)} />;
return (
<SvgErrorBoundary fallback={<Empty />}>
<LucideIcon className={cn('size-5', className)} />
</SvgErrorBoundary>
);
}
if (SvgIcon) {
return <SvgIcon className={cn('size-5 fill-current', className)}></SvgIcon>;
if (svgIcon) {
return (
<SvgErrorBoundary fallback={<Empty />}>
<SvgIcon
name={svgIcon}
width={'100%'}
className={cn('size-5 fill-current', className)}
></SvgIcon>
</SvgErrorBoundary>
);
}
return <Empty></Empty>;

View File

@ -18,8 +18,8 @@ import {
SquareArrowOutUpRight,
} from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router';
import 'react18-json-view/src/style.css';
import { useParams } from 'umi';
import {
isEndOutputEmpty,
useDownloadOutput,

View File

@ -540,13 +540,13 @@ const useGraphStore = create<RFState>()(
(x) => x.component_name === name,
);
const lastIndex = tools.length
? tools
? (tools
.map((x) => {
const idx = x.name.match(/(\d+)$/)?.[1];
return idx && isNaN(idx) ? -1 : Number(idx);
})
.sort((a, b) => a - b)
.at(-1) ?? -1
.at(-1) ?? -1)
: -1;
return `${name}_${lastIndex + 1}`;

View File

@ -836,7 +836,7 @@ export function buildBeginQueryWithObject(
}
export function getArrayElementType(type: string) {
return typeof type === 'string' ? type.match(/<([^>]+)>/)?.at(1) ?? '' : '';
return typeof type === 'string' ? (type.match(/<([^>]+)>/)?.at(1) ?? '') : '';
}
export function buildConversationVariableSelectOptions() {

View File

@ -13,7 +13,7 @@ import { cn } from '@/lib/utils';
import { upperFirst } from 'lodash';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'umi';
import { useParams } from 'react-router';
import { BeginId } from '../constant';
import { JsonViewer } from '../form/components/json-viewer';
import { WorkFlowTimeline } from './timeline';

View File

@ -20,7 +20,7 @@ import {
import { IReferenceObject } from '@/interfaces/database/chat';
import { useQueryClient } from '@tanstack/react-query';
import React, { useEffect, useState } from 'react';
import { useParams } from 'umi';
import { useParams } from 'react-router';
import { DateRange } from '../../components/originui/calendar/index';
import {
Table,

View File

@ -17,7 +17,7 @@ import { t } from 'i18next';
import { pick } from 'lodash';
import { Clipboard, ClipboardPlus, FileInput, Plus } from 'lucide-react';
import { useCallback, useEffect } from 'react';
import { useSearchParams } from 'umi';
import { useSearchParams } from 'react-router';
import { AgentCard } from './agent-card';
import { CreateAgentDialog } from './create-agent-dialog';
import { useCreateAgentOrPipeline } from './hooks/use-create-agent';

View File

@ -16,7 +16,7 @@ import {
import { Routes } from '@/routes';
import { EllipsisVertical, Save } from 'lucide-react';
import { useMemo } from 'react';
import { Outlet, useLocation } from 'umi';
import { Outlet, useLocation } from 'react-router';
export default function ChunkPage() {
const { navigateToDataset, getQueryString, navigateToChunk } =

View File

@ -16,7 +16,7 @@ import DOMPurify from 'dompurify';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ChunkTextMode } from '../../constant';
import styles from './index.less';
import styles from './index.module.less';
interface IProps {
item: IChunk;

View File

@ -1,4 +1,4 @@
import { ReactComponent as FilterIcon } from '@/assets/filter.svg';
import FilterIcon from '@/assets/filter.svg';
import { KnowledgeRouteKey } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import {
@ -32,16 +32,15 @@ import {
Typography,
} from 'antd';
import { useCallback, useMemo, useState } from 'react';
import { Link } from 'umi';
import { Link } from 'react-router';
import { ChunkTextMode } from '../../constant';
const { Text } = Typography;
interface IProps
extends Pick<
IChunkListResult,
'searchString' | 'handleInputChange' | 'available' | 'handleSetAvailable'
> {
interface IProps extends Pick<
IChunkListResult,
'searchString' | 'handleInputChange' | 'available' | 'handleSetAvailable'
> {
checked: boolean;
selectAllChunk: (checked: boolean) => void;
createChunk: () => void;

View File

@ -42,7 +42,7 @@ import {
useNavigatePage,
} from '@/hooks/logic-hooks/navigate-hooks';
import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request';
import styles from './index.less';
import styles from './index.module.less';
const Chunk = () => {
const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]);

View File

@ -8,10 +8,10 @@ import { Breadcrumb } from 'antd';
import { ItemType } from 'antd/es/breadcrumb/Breadcrumb';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Link, Outlet } from 'umi';
import { Link, Outlet } from 'react-router';
import Siderbar from './components/knowledge-sidebar';
import { KnowledgeDatasetRouteKey, KnowledgeRouteKey } from './constant';
import styles from './index.less';
import styles from './index.module.less';
const KnowledgeAdding = () => {
const knowledgeBaseId = useKnowledgeBaseId();

View File

@ -23,7 +23,7 @@ import {
useHandleChunkCardClick,
useUpdateChunk,
} from './hooks';
import styles from './index.less';
import styles from './index.module.less';
interface IProps {
isChange: boolean;

View File

@ -14,7 +14,7 @@ import classNames from 'classnames';
import DOMPurify from 'dompurify';
import { useEffect, useState } from 'react';
import { ChunkTextMode } from '../../constant';
import styles from './index.less';
import styles from './index.module.less';
interface IProps {
item: IChunk;

View File

@ -1,4 +1,4 @@
import { ReactComponent as FilterIcon } from '@/assets/filter.svg';
import FilterIcon from '@/assets/filter.svg';
import { KnowledgeRouteKey } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks';
import {
@ -32,16 +32,15 @@ import {
Typography,
} from 'antd';
import { useCallback, useMemo, useState } from 'react';
import { Link } from 'umi';
import { Link } from 'react-router';
import { ChunkTextMode } from '../../constant';
const { Text } = Typography;
interface IProps
extends Pick<
IChunkListResult,
'searchString' | 'handleInputChange' | 'available' | 'handleSetAvailable'
> {
interface IProps extends Pick<
IChunkListResult,
'searchString' | 'handleInputChange' | 'available' | 'handleSetAvailable'
> {
checked: boolean;
selectAllChunk: (checked: boolean) => void;
createChunk: () => void;

View File

@ -3,7 +3,7 @@ import { cn } from '@/lib/utils';
import { isArray } from 'lodash';
import { useCallback, useEffect, useMemo } from 'react';
import { ChunkTextMode } from '../../constant';
import styles from '../../index.less';
import styles from '../../index.module.less';
import { IChunk } from '../../interface';
import { useParserInit } from './hook';
import { IJsonContainerProps } from './interface';

View File

@ -1,7 +1,7 @@
import { cn } from '@/lib/utils';
import { useCallback, useEffect } from 'react';
import { ChunkTextMode } from '../../constant';
import styles from '../../index.less';
import styles from '../../index.module.less';
import { IChunk } from '../../interface';
import { useParserInit } from './hook';
import { IObjContainerProps } from './interface';

Some files were not shown because too many files have changed in this diff Show More