mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
perf: checkbox dom (#3149)
* perf: checkbox dom * perf: null check * perf: simple mode variables * perf: get csv encoding code * fix: dataset filter * perf: code editor ui
This commit is contained in:
@@ -39,6 +39,7 @@ weight: 811
|
|||||||
14. 优化 - Markdown 组件自动空格,避免分割 url 中的中文。
|
14. 优化 - Markdown 组件自动空格,避免分割 url 中的中文。
|
||||||
15. 优化 - 工作流上下文拆分,性能优化。
|
15. 优化 - 工作流上下文拆分,性能优化。
|
||||||
16. 优化 - 语音播报,不支持 mediaSource 的浏览器可等待完全生成语音后输出。
|
16. 优化 - 语音播报,不支持 mediaSource 的浏览器可等待完全生成语音后输出。
|
||||||
17. 修复 - Dockerfile pnpm install 支持代理。
|
17. 优化 - 对话引导 csv 读取,自动识别编码。
|
||||||
18. 修复 - BI 图表生成无法写入文件。同时优化其解析,支持数字类型数组。
|
18. 修复 - Dockerfile pnpm install 支持代理。
|
||||||
19. 修复 - 分享链接首次加载时,标题显示不正确。
|
19. 修复 - BI 图表生成无法写入文件。同时优化其解析,支持数字类型数组。
|
||||||
|
20. 修复 - 分享链接首次加载时,标题显示不正确。
|
||||||
|
@@ -16,7 +16,7 @@ export const bucketNameMap = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReadFileBaseUrl = `${process.env.FE_DOMAIN || ''}${process.env.NEXT_PUBLIC_BASE_URL}/api/common/file/read`;
|
export const ReadFileBaseUrl = `${process.env.FE_DOMAIN || ''}${process.env.NEXT_PUBLIC_BASE_URL || ''}/api/common/file/read`;
|
||||||
|
|
||||||
export const documentFileType = '.txt, .docx, .csv, .xlsx, .pdf, .md, .html, .pptx';
|
export const documentFileType = '.txt, .docx, .csv, .xlsx, .pdf, .md, .html, .pptx';
|
||||||
export const imageFileType =
|
export const imageFileType =
|
||||||
|
@@ -95,10 +95,10 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: NodeInputKeyEnum.collectionFilterMatch,
|
key: NodeInputKeyEnum.collectionFilterMatch,
|
||||||
renderTypeList: [FlowNodeInputTypeEnum.JSONEditor, FlowNodeInputTypeEnum.reference],
|
renderTypeList: [FlowNodeInputTypeEnum.textarea, FlowNodeInputTypeEnum.reference],
|
||||||
label: i18nT('workflow:collection_metadata_filter'),
|
label: i18nT('workflow:collection_metadata_filter'),
|
||||||
|
|
||||||
valueType: WorkflowIOValueTypeEnum.object,
|
valueType: WorkflowIOValueTypeEnum.string,
|
||||||
isPro: true,
|
isPro: true,
|
||||||
description: i18nT('workflow:filter_description')
|
description: i18nT('workflow:filter_description')
|
||||||
}
|
}
|
||||||
|
@@ -118,7 +118,10 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
let createTimeCollectionIdList: string[] | undefined = undefined;
|
let createTimeCollectionIdList: string[] | undefined = undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const jsonMatch = json5.parse(collectionFilterMatch);
|
const jsonMatch =
|
||||||
|
typeof collectionFilterMatch === 'object'
|
||||||
|
? collectionFilterMatch
|
||||||
|
: json5.parse(collectionFilterMatch);
|
||||||
|
|
||||||
// Tag
|
// Tag
|
||||||
let andTags = jsonMatch?.tags?.$and as (string | null)[] | undefined;
|
let andTags = jsonMatch?.tags?.$and as (string | null)[] | undefined;
|
||||||
@@ -347,7 +350,7 @@ export async function searchDatasetData(props: SearchDatasetDataProps) {
|
|||||||
teamId: new Types.ObjectId(teamId),
|
teamId: new Types.ObjectId(teamId),
|
||||||
datasetId: new Types.ObjectId(id),
|
datasetId: new Types.ObjectId(id),
|
||||||
$text: { $search: jiebaSplit({ text: query }) },
|
$text: { $search: jiebaSplit({ text: query }) },
|
||||||
...(filterCollectionIdList && filterCollectionIdList.length > 0
|
...(filterCollectionIdList
|
||||||
? {
|
? {
|
||||||
collectionId: {
|
collectionId: {
|
||||||
$in: filterCollectionIdList.map((id) => new Types.ObjectId(id))
|
$in: filterCollectionIdList.map((id) => new Types.ObjectId(id))
|
||||||
|
@@ -76,8 +76,6 @@ export async function dispatchDatasetSearch(
|
|||||||
nodeDispatchUsages: [],
|
nodeDispatchUsages: [],
|
||||||
[DispatchNodeResponseKeyEnum.toolResponses]: []
|
[DispatchNodeResponseKeyEnum.toolResponses]: []
|
||||||
};
|
};
|
||||||
|
|
||||||
return Promise.reject(i18nT('common:core.chat.error.User input empty'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// query extension
|
// query extension
|
||||||
|
@@ -81,26 +81,21 @@ export const readCsvRawText = async ({ file }: { file: File }) => {
|
|||||||
return csvArr;
|
return csvArr;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface EncodingDetectionResult {
|
|
||||||
encoding: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function detectEncoding(buffer: ArrayBuffer): EncodingDetectionResult {
|
|
||||||
const encodings = ['utf-8', 'iso-8859-1', 'windows-1252'];
|
|
||||||
for (let encoding of encodings) {
|
|
||||||
try {
|
|
||||||
const decoder = new TextDecoder(encoding, { fatal: true });
|
|
||||||
decoder.decode(buffer);
|
|
||||||
return { encoding }; // 如果解码成功,返回当前编码
|
|
||||||
} catch (e) {
|
|
||||||
// continue to try next encoding
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { encoding: null }; // 如果没有编码匹配,返回null
|
|
||||||
}
|
|
||||||
|
|
||||||
async function detectFileEncoding(file: File): Promise<string> {
|
async function detectFileEncoding(file: File): Promise<string> {
|
||||||
const buffer = await loadFile2Buffer({ file });
|
const buffer = await loadFile2Buffer({ file });
|
||||||
const { encoding } = detectEncoding(buffer);
|
const encoding = (() => {
|
||||||
return encoding || 'unknown';
|
const encodings = ['utf-8', 'iso-8859-1', 'windows-1252'];
|
||||||
|
for (let encoding of encodings) {
|
||||||
|
try {
|
||||||
|
const decoder = new TextDecoder(encoding, { fatal: true });
|
||||||
|
decoder.decode(buffer);
|
||||||
|
return encoding; // 如果解码成功,返回当前编码
|
||||||
|
} catch (e) {
|
||||||
|
// continue to try next encoding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null; // 如果没有编码匹配,返回null
|
||||||
|
})();
|
||||||
|
|
||||||
|
return encoding || 'utf-8';
|
||||||
}
|
}
|
||||||
|
@@ -245,13 +245,7 @@ export const MultipleRowArraySelect = ({
|
|||||||
onClick={() => handleSelect(item)}
|
onClick={() => handleSelect(item)}
|
||||||
{...(isSelected ? { color: 'primary.600' } : {})}
|
{...(isSelected ? { color: 'primary.600' } : {})}
|
||||||
>
|
>
|
||||||
{showCheckbox && (
|
{showCheckbox && <Checkbox isChecked={isChecked} mr={1} />}
|
||||||
<Checkbox
|
|
||||||
isChecked={isChecked}
|
|
||||||
icon={<MyIcon name={'common/check'} w={'12px'} />}
|
|
||||||
mr={1}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Box>{item.label}</Box>
|
<Box>{item.label}</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
@@ -14,7 +14,6 @@ type EditorVariablePickerType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type Props = Omit<BoxProps, 'resize' | 'onChange'> & {
|
export type Props = Omit<BoxProps, 'resize' | 'onChange'> & {
|
||||||
height?: number;
|
|
||||||
resize?: boolean;
|
resize?: boolean;
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
@@ -111,7 +110,7 @@ const MyEditor = ({
|
|||||||
borderWidth={'1px'}
|
borderWidth={'1px'}
|
||||||
borderRadius={'md'}
|
borderRadius={'md'}
|
||||||
borderColor={'myGray.200'}
|
borderColor={'myGray.200'}
|
||||||
py={2}
|
py={1}
|
||||||
height={height}
|
height={height}
|
||||||
position={'relative'}
|
position={'relative'}
|
||||||
pl={2}
|
pl={2}
|
||||||
@@ -132,8 +131,8 @@ const MyEditor = ({
|
|||||||
{resize && (
|
{resize && (
|
||||||
<Box
|
<Box
|
||||||
position={'absolute'}
|
position={'absolute'}
|
||||||
right={'-1'}
|
right={'-2.5'}
|
||||||
bottom={'-1'}
|
bottom={'-3.5'}
|
||||||
zIndex={10}
|
zIndex={10}
|
||||||
cursor={'ns-resize'}
|
cursor={'ns-resize'}
|
||||||
px={'4px'}
|
px={'4px'}
|
||||||
|
@@ -19,9 +19,11 @@ const CodeEditor = (props: Props) => {
|
|||||||
iconSrc="modal/edit"
|
iconSrc="modal/edit"
|
||||||
title={t('common:code_editor')}
|
title={t('common:code_editor')}
|
||||||
w={'full'}
|
w={'full'}
|
||||||
|
h={'85vh'}
|
||||||
|
isCentered
|
||||||
>
|
>
|
||||||
<ModalBody>
|
<ModalBody flex={'1 0 0'} overflow={'auto'}>
|
||||||
<MyEditor {...props} bg={'myGray.50'} defaultHeight={600} />
|
<MyEditor {...props} bg={'myGray.50'} height={'100%'} />
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button mr={2} onClick={onClose} px={6}>
|
<Button mr={2} onClick={onClose} px={6}>
|
||||||
|
@@ -12,25 +12,27 @@ const LANG_KEY = 'NEXT_LOCALE';
|
|||||||
|
|
||||||
export const useI18nLng = () => {
|
export const useI18nLng = () => {
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
|
const languageMap: Record<string, string> = {
|
||||||
|
zh: 'zh',
|
||||||
|
'zh-CN': 'zh',
|
||||||
|
'zh-Hans': 'zh',
|
||||||
|
en: 'en',
|
||||||
|
'en-US': 'en'
|
||||||
|
};
|
||||||
|
|
||||||
const onChangeLng = (lng: string) => {
|
const onChangeLng = (lng: string) => {
|
||||||
setCookie(LANG_KEY, lng, {
|
const lang = languageMap[lng] || 'en';
|
||||||
expires: 30,
|
|
||||||
sameSite: 'None',
|
setCookie(LANG_KEY, lang, {
|
||||||
secure: true
|
expires: 30
|
||||||
});
|
});
|
||||||
i18n?.changeLanguage(lng);
|
i18n?.changeLanguage(lang);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setUserDefaultLng = () => {
|
const setUserDefaultLng = () => {
|
||||||
if (!navigator || !localStorage) return;
|
if (!navigator || !localStorage) return;
|
||||||
if (getCookie(LANG_KEY)) return onChangeLng(getCookie(LANG_KEY) as string);
|
if (getCookie(LANG_KEY)) return onChangeLng(getCookie(LANG_KEY) as string);
|
||||||
|
|
||||||
const languageMap: Record<string, string> = {
|
|
||||||
zh: 'zh',
|
|
||||||
'zh-CN': 'zh'
|
|
||||||
};
|
|
||||||
|
|
||||||
const lang = languageMap[navigator.language] || 'en';
|
const lang = languageMap[navigator.language] || 'en';
|
||||||
|
|
||||||
// currentLng not in userLang
|
// currentLng not in userLang
|
||||||
|
@@ -206,12 +206,7 @@ const DatasetParamsModal = ({
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box position={'relative'} w={'18px'} h={'18px'}>
|
<Box position={'relative'} w={'18px'} h={'18px'}>
|
||||||
<Checkbox
|
<Checkbox colorScheme="primary" isChecked={getValues('usingReRank')} size="lg" />
|
||||||
colorScheme="primary"
|
|
||||||
isChecked={getValues('usingReRank')}
|
|
||||||
size="lg"
|
|
||||||
icon={<MyIcon name={'common/check'} w={'12px'} />}
|
|
||||||
/>
|
|
||||||
<Box position={'absolute'} top={0} right={0} bottom={0} left={0} zIndex={1}></Box>
|
<Box position={'absolute'} top={0} right={0} bottom={0} left={0} zIndex={1}></Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@@ -117,11 +117,12 @@ function AddMemberModal({ onClose, mode = 'member' }: AddModalPropsType) {
|
|||||||
<Flex flexDirection="column" mt="2" overflow={'auto'} maxH="400px">
|
<Flex flexDirection="column" mt="2" overflow={'auto'} maxH="400px">
|
||||||
{filterGroups.map((group) => {
|
{filterGroups.map((group) => {
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
if (selectedGroupIdList.includes(group._id)) {
|
setSelectedGroupIdList((state) => {
|
||||||
setSelectedGroupIdList(selectedGroupIdList.filter((v) => v !== group._id));
|
if (state.includes(group._id)) {
|
||||||
} else {
|
return state.filter((v) => v !== group._id);
|
||||||
setSelectedGroupIdList([...selectedGroupIdList, group._id]);
|
}
|
||||||
}
|
return [...state, group._id];
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const collaborator = collaboratorList.find((v) => v.groupId === group._id);
|
const collaborator = collaboratorList.find((v) => v.groupId === group._id);
|
||||||
return (
|
return (
|
||||||
@@ -141,10 +142,7 @@ function AddMemberModal({ onClose, mode = 'member' }: AddModalPropsType) {
|
|||||||
}}
|
}}
|
||||||
onClick={onChange}
|
onClick={onChange}
|
||||||
>
|
>
|
||||||
<Checkbox
|
<Checkbox isChecked={selectedGroupIdList.includes(group._id)} />
|
||||||
isChecked={selectedGroupIdList.includes(group._id)}
|
|
||||||
icon={<MyIcon name={'common/check'} w={'12px'} />}
|
|
||||||
/>
|
|
||||||
<MyAvatar src={group.avatar} w="1.5rem" borderRadius={'50%'} />
|
<MyAvatar src={group.avatar} w="1.5rem" borderRadius={'50%'} />
|
||||||
<Box ml="2" w="full">
|
<Box ml="2" w="full">
|
||||||
{group.name === DefaultGroupName ? userInfo?.team.teamName : group.name}
|
{group.name === DefaultGroupName ? userInfo?.team.teamName : group.name}
|
||||||
@@ -157,11 +155,12 @@ function AddMemberModal({ onClose, mode = 'member' }: AddModalPropsType) {
|
|||||||
})}
|
})}
|
||||||
{filterMembers.map((member) => {
|
{filterMembers.map((member) => {
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
if (selectedMemberIdList.includes(member.tmbId)) {
|
setSelectedMembers((state) => {
|
||||||
setSelectedMembers(selectedMemberIdList.filter((v) => v !== member.tmbId));
|
if (state.includes(member.tmbId)) {
|
||||||
} else {
|
return state.filter((v) => v !== member.tmbId);
|
||||||
setSelectedMembers([...selectedMemberIdList, member.tmbId]);
|
}
|
||||||
}
|
return [...state, member.tmbId];
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const collaborator = collaboratorList.find((v) => v.tmbId === member.tmbId);
|
const collaborator = collaboratorList.find((v) => v.tmbId === member.tmbId);
|
||||||
return (
|
return (
|
||||||
@@ -205,11 +204,12 @@ function AddMemberModal({ onClose, mode = 'member' }: AddModalPropsType) {
|
|||||||
<Flex flexDirection="column" mt="2" overflow={'auto'} maxH="400px">
|
<Flex flexDirection="column" mt="2" overflow={'auto'} maxH="400px">
|
||||||
{selectedGroupIdList.map((groupId) => {
|
{selectedGroupIdList.map((groupId) => {
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
if (selectedGroupIdList.includes(groupId)) {
|
setSelectedGroupIdList((state) => {
|
||||||
setSelectedGroupIdList(selectedGroupIdList.filter((v) => v !== groupId));
|
if (state.includes(groupId)) {
|
||||||
} else {
|
return state.filter((v) => v !== groupId);
|
||||||
setSelectedGroupIdList([...selectedGroupIdList, groupId]);
|
}
|
||||||
}
|
return [...state, groupId];
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const group = groups.find((v) => String(v._id) === groupId);
|
const group = groups.find((v) => String(v._id) === groupId);
|
||||||
return (
|
return (
|
||||||
|
@@ -106,7 +106,7 @@ const EditForm = ({
|
|||||||
formatEditorVariablePickerIcon([
|
formatEditorVariablePickerIcon([
|
||||||
...workflowSystemVariables.filter(
|
...workflowSystemVariables.filter(
|
||||||
(variable) =>
|
(variable) =>
|
||||||
!['userId', 'appId', 'chatId', 'responseChatItemId', 'histories'].includes(variable.key)
|
!['appId', 'chatId', 'responseChatItemId', 'histories'].includes(variable.key)
|
||||||
),
|
),
|
||||||
...(appForm.chatConfig.variables || [])
|
...(appForm.chatConfig.variables || [])
|
||||||
]).map((item) => ({
|
]).map((item) => ({
|
||||||
|
Reference in New Issue
Block a user