Perf input guide (#1557)

* perf: input guide code

* perf: input guide ui

* Chat input guide api

* Update app chat config store

* perf: app chat config field

* perf: app context

* perf: params

* fix: ts

* perf: filter private config

* perf: filter private config

* perf: import workflow

* perf: limit max tip amount
This commit is contained in:
Archer
2024-05-21 17:52:04 +08:00
committed by GitHub
parent 8e8ceb7439
commit fb368a581c
123 changed files with 2124 additions and 1805 deletions

View File

@@ -1,4 +1,5 @@
import { getErrText } from '@fastgpt/global/common/error/utils';
import Papa from 'papaparse';
export const loadFile2Buffer = ({ file, onError }: { file: File; onError?: (err: any) => void }) =>
new Promise<ArrayBuffer>((resolve, reject) => {
@@ -29,3 +30,47 @@ export const loadFile2Buffer = ({ file, onError }: { file: File; onError?: (err:
reject('The browser does not support file content reading');
}
});
export const readFileRawText = ({
file,
onError
}: {
file: File;
onError?: (err: any) => void;
}) => {
return new Promise<string>((resolve, reject) => {
try {
let reader = new FileReader();
reader.onload = async ({ target }) => {
if (!target?.result) {
onError?.('Load file error');
return reject('Load file error');
}
try {
resolve(target.result as string);
} catch (err) {
console.log(err, 'Load file error');
onError?.(err);
reject(getErrText(err, 'Load file error'));
}
};
reader.onerror = (err) => {
console.log(err, 'Load file error');
onError?.(err);
reject(getErrText(err, 'Load file error'));
};
reader.readAsText(file);
} catch (error) {
reject('The browser does not support file content reading');
}
});
};
export const readCsvRawText = async ({ file }: { file: File }) => {
const rawText = await readFileRawText({ file });
const csvArr = Papa.parse(rawText).data as string[][];
return csvArr;
};

View File

@@ -10,7 +10,7 @@ type Props = FlexProps & {
const EmptyTip = ({ text, ...props }: Props) => {
const { t } = useTranslation();
return (
<Flex mt={5} flexDirection={'column'} alignItems={'center'} pt={'10vh'} {...props}>
<Flex mt={5} flexDirection={'column'} alignItems={'center'} py={'10vh'} {...props}>
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
<Box mt={2} color={'myGray.500'}>
{text || t('common.empty.Common Tip')}

View File

@@ -15,7 +15,7 @@ const MyIcon = ({ name, w = 'auto', h = 'auto', ...props }: { name: IconNameType
.catch((error) => console.log(error));
}, [name]);
return !!name && !!iconPaths[name] ? (
return !!IconComponent ? (
<Icon
{...IconComponent}
w={w}

View File

@@ -9,7 +9,7 @@ type Props = BoxProps & {
const MyBox = ({ text, isLoading, children, ...props }: Props, ref: any) => {
return (
<Box ref={ref} position={'relative'} {...props}>
<Box ref={ref} position={isLoading ? 'relative' : 'unset'} {...props}>
{isLoading && <Loading fixed={false} text={text} />}
{children}
</Box>

View File

@@ -11,11 +11,13 @@ import {
useMediaQuery
} from '@chakra-ui/react';
import MyIcon from '../Icon';
import MyBox from '../MyBox';
export interface MyModalProps extends ModalContentProps {
iconSrc?: string;
title?: any;
isCentered?: boolean;
isLoading?: boolean;
isOpen: boolean;
onClose?: () => void;
}
@@ -27,6 +29,7 @@ const MyModal = ({
title,
children,
isCentered,
isLoading,
w = 'auto',
maxW = ['90vw', '600px'],
...props
@@ -39,6 +42,7 @@ const MyModal = ({
onClose={() => onClose && onClose()}
autoFocus={false}
isCentered={isPc ? isCentered : true}
blockScrollOnMount={false}
>
<ModalOverlay />
<ModalContent
@@ -78,14 +82,15 @@ const MyModal = ({
</ModalHeader>
)}
<Box
<MyBox
isLoading={isLoading}
overflow={props.overflow || 'overlay'}
h={'100%'}
display={'flex'}
flexDirection={'column'}
>
{children}
</Box>
</MyBox>
</ModalContent>
</Modal>
);

View File

@@ -0,0 +1,40 @@
import { Box } from '@chakra-ui/react';
import React from 'react';
const HighlightText = ({
rawText,
matchText,
color = 'primary.600'
}: {
rawText: string;
matchText: string;
color?: string;
}) => {
const regex = new RegExp(`(${matchText})`, 'gi');
const parts = rawText.split(regex);
return (
<Box>
{parts.map((part, index) => {
let highLight = part.toLowerCase() === matchText.toLowerCase();
if (highLight) {
parts.find((item, i) => {
if (i >= index) return;
if (item.toLowerCase() === matchText.toLowerCase()) {
highLight = false;
}
});
}
return (
<Box as="span" key={index} color={highLight ? color : 'inherit'}>
{part}
</Box>
);
})}
</Box>
);
};
export default HighlightText;

View File

@@ -3,6 +3,7 @@ import { useMutation } from '@tanstack/react-query';
import type { UseMutationOptions } from '@tanstack/react-query';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { useTranslation } from 'next-i18next';
import { useRequest as ahooksUseRequest } from 'ahooks';
interface Props extends UseMutationOptions<any, any, any, any> {
successToast?: string | null;
@@ -39,3 +40,50 @@ export const useRequest = ({ successToast, errorToast, onSuccess, onError, ...pr
return mutation;
};
type UseRequestFunProps<TData, TParams extends any[]> = Parameters<
typeof ahooksUseRequest<TData, TParams>
>;
export const useRequest2 = <TData, TParams extends any[]>(
server: UseRequestFunProps<TData, TParams>[0],
options: UseRequestFunProps<TData, TParams>[1] & {
errorToast?: string;
successToast?: string;
} = {},
plugin?: UseRequestFunProps<TData, TParams>[2]
) => {
const { t } = useTranslation();
const { errorToast, successToast, ...rest } = options || {};
const { toast } = useToast();
const res = ahooksUseRequest<TData, TParams>(
server,
{
...rest,
onError: (err, params) => {
rest?.onError?.(err, params);
if (errorToast !== undefined) {
const errText = t(getErrText(err, errorToast || ''));
if (errText) {
toast({
title: errText,
status: 'error'
});
}
}
},
onSuccess: (res, params) => {
rest?.onSuccess?.(res, params);
if (successToast) {
toast({
title: successToast,
status: 'success'
});
}
}
},
plugin
);
return res;
};

View File

@@ -1,9 +1,17 @@
import { useRef, useState, useEffect } from 'react';
import React, { useRef, useState, useEffect } from 'react';
import { Box, BoxProps } from '@chakra-ui/react';
import { useToast } from './useToast';
import { getErrText } from '@fastgpt/global/common/error/utils';
import { PaginationProps, PaginationResponse } from '../common/fetch/type';
import { useBoolean, useLockFn, useMemoizedFn, useMount, useScroll, useVirtualList } from 'ahooks';
import {
useBoolean,
useLockFn,
useMemoizedFn,
useMount,
useScroll,
useVirtualList,
useRequest
} from 'ahooks';
import MyBox from '../components/common/MyBox';
import { useTranslation } from 'next-i18next';
@@ -13,12 +21,19 @@ export function useScrollPagination<
>(
api: (data: TParams) => Promise<TData>,
{
debounceWait,
throttleWait,
refreshDeps,
itemHeight = 50,
overscan = 10,
pageSize = 10,
defaultParams = {}
}: {
debounceWait?: number;
throttleWait?: number;
refreshDeps?: any[];
itemHeight: number;
overscan?: number;
@@ -45,7 +60,7 @@ export function useScrollPagination<
});
const loadData = useLockFn(async (num: number = current) => {
if (noMore.current) return;
if (noMore.current && num !== 1) return;
setTrue();
@@ -59,7 +74,7 @@ export function useScrollPagination<
setCurrent(num);
if (num === 1) {
// reload
// init or reload
setData(res.list);
noMore.current = res.list.length >= res.total;
} else {
@@ -78,34 +93,48 @@ export function useScrollPagination<
setFalse();
});
const scroll2Top = () => {
if (containerRef.current) {
containerRef.current.scrollTop = 0;
}
};
const ScrollList = useMemoizedFn(
({
children,
EmptyChildren,
isLoading,
...props
}: { children: React.ReactNode; isLoading?: boolean } & BoxProps) => {
}: {
children: React.ReactNode;
EmptyChildren?: React.ReactNode;
isLoading?: boolean;
} & BoxProps) => {
return (
<>
<MyBox isLoading={isLoading} ref={containerRef} overflow={'overlay'} {...props}>
<Box ref={wrapperRef}>{children}</Box>
{noMore.current && list.length > 0 && (
<Box py={4} textAlign={'center'} color={'myGray.600'} fontSize={'sm'}>
{t('common.No more data')}
</Box>
)}
{list.length === 0 && !isLoading && EmptyChildren && <>{EmptyChildren}</>}
</MyBox>
{noMore.current && (
<Box pb={2} textAlign={'center'} color={'myGray.600'} fontSize={'sm'}>
{t('common.No more data')}
</Box>
)}
</>
);
}
);
useMount(() => {
loadData(1);
useRequest(() => loadData(1), {
refreshDeps,
debounceWait: data.length === 0 ? 0 : debounceWait,
throttleWait
});
const scroll = useScroll(containerRef);
useEffect(() => {
if (!containerRef.current) return;
if (!containerRef.current || list.length === 0) return;
const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
@@ -118,8 +147,10 @@ export function useScrollPagination<
containerRef,
list,
data,
setData,
isLoading,
ScrollList,
fetchData: loadData
fetchData: loadData,
scroll2Top
};
}

View File

@@ -26,7 +26,6 @@
"lodash": "^4.17.21",
"next-i18next": "15.2.0",
"papaparse": "^5.4.1",
"pdfjs-dist": "4.0.269",
"react": "18.3.1",
"use-context-selector": "^1.4.4",
"react-day-picker": "^8.7.1",