mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 21:13:50 +00:00
4.8 test fix (#1385)
* fix: tool name cannot startwith number * fix: chatbox update * fix: chatbox * perf: drag ui * perf: drag component * drag component
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 'V4.8(进行中)'
|
title: 'V4.8(开发中)'
|
||||||
description: 'FastGPT V4.8 更新说明'
|
description: 'FastGPT V4.8 更新说明'
|
||||||
icon: 'upgrade'
|
icon: 'upgrade'
|
||||||
draft: false
|
draft: false
|
||||||
@@ -18,10 +18,14 @@ FastGPT workflow V2上线,支持更加简洁的工作流模式。
|
|||||||
## V4.8 更新说明
|
## V4.8 更新说明
|
||||||
|
|
||||||
1. 重构 - 工作流
|
1. 重构 - 工作流
|
||||||
2. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流。
|
2. 新增 - 判断器。支持 if elseIf else 判断。
|
||||||
3. 新增 - 定时执行应用。可轻松实现定时任务。
|
3. 新增 - 变量更新节点。支持更新运行中工作流输出变量,或更新全局变量。
|
||||||
4. 新增 - 插件自定义输入优化,可以渲染输入组件。
|
4. 新增 - 工作流 Debug 模式,可以调试单个节点或者逐步调试工作流。
|
||||||
6. 优化 - 工作流连线,可以四向连接,方便构建循环工作流。
|
5. 新增 - 定时执行应用。可轻松实现定时任务。
|
||||||
7. 优化 - 工作流上下文传递,性能🚀。
|
6. 新增 - 插件自定义输入优化,可以渲染输入组件。
|
||||||
8. 优化 - 简易模式,更新配置后自动更新调试框内容,无需保存。
|
7. 优化 - 工作流连线,可以四向连接,方便构建循环工作流。
|
||||||
9. 优化 - worker进程管理,并将计算 Token 任务分配给 worker 进程。
|
8. 优化 - 工作流上下文传递,性能🚀。
|
||||||
|
9. 优化 - 简易模式,更新配置后自动更新调试框内容,无需保存。
|
||||||
|
10. 优化 - worker进程管理,并将计算 Token 任务分配给 worker 进程。
|
||||||
|
11. 修复 - 工具调用时候,name不能是数字开头(随机数有概率数字开头)
|
||||||
|
12. 修复 - 分享链接, query 全局变量会被缓存。
|
@@ -50,8 +50,18 @@ export const replaceSensitiveText = (text: string) => {
|
|||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Make sure the first letter is definitely lowercase */
|
||||||
export const getNanoid = (size = 12) => {
|
export const getNanoid = (size = 12) => {
|
||||||
return customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890', size)();
|
const firstChar = customAlphabet('abcdefghijklmnopqrstuvwxyz', 1)();
|
||||||
|
|
||||||
|
if (size === 1) return firstChar;
|
||||||
|
|
||||||
|
const randomsStr = customAlphabet(
|
||||||
|
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
|
||||||
|
size - 1
|
||||||
|
)();
|
||||||
|
|
||||||
|
return `${firstChar}${randomsStr}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const replaceRegChars = (text: string) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
export const replaceRegChars = (text: string) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
@@ -9,9 +9,10 @@ export const Input_Template_History: FlowNodeInputItemType = {
|
|||||||
renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference],
|
renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference],
|
||||||
valueType: WorkflowIOValueTypeEnum.chatHistory,
|
valueType: WorkflowIOValueTypeEnum.chatHistory,
|
||||||
label: 'core.module.input.label.chat history',
|
label: 'core.module.input.label.chat history',
|
||||||
|
description: '最多携带多少轮对话记录',
|
||||||
required: true,
|
required: true,
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 30,
|
max: 50,
|
||||||
value: 6
|
value: 6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
14
packages/web/components/common/DndDrag/DragIcon.tsx
Normal file
14
packages/web/components/common/DndDrag/DragIcon.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { DragHandleIcon } from '@chakra-ui/icons';
|
||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { DraggableProvided } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
|
const DragIcon = ({ provided }: { provided: DraggableProvided }) => {
|
||||||
|
return (
|
||||||
|
<Box {...provided.dragHandleProps}>
|
||||||
|
<DragHandleIcon color={'myGray.500'} _hover={{ color: 'primary.600' }} />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DragIcon;
|
61
packages/web/components/common/DndDrag/index.tsx
Normal file
61
packages/web/components/common/DndDrag/index.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { Box } from '@chakra-ui/react';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
DragDropContext,
|
||||||
|
DroppableProps,
|
||||||
|
Droppable,
|
||||||
|
DraggableChildrenFn,
|
||||||
|
DragStart,
|
||||||
|
DropResult
|
||||||
|
} from 'react-beautiful-dnd';
|
||||||
|
|
||||||
|
type Props<T = any> = {
|
||||||
|
onDragEndCb: (result: T[]) => void;
|
||||||
|
renderClone?: DraggableChildrenFn;
|
||||||
|
children: DroppableProps['children'];
|
||||||
|
dataList: T[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function DndDrag<T>({ children, renderClone, onDragEndCb, dataList }: Props<T>) {
|
||||||
|
const [draggingItemHeight, setDraggingItemHeight] = useState(0);
|
||||||
|
|
||||||
|
const onDragStart = (start: DragStart) => {
|
||||||
|
const draggingNode = document.querySelector(`[data-rbd-draggable-id="${start.draggableId}"]`);
|
||||||
|
setDraggingItemHeight(draggingNode?.getBoundingClientRect().height || 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDragEnd = (result: DropResult) => {
|
||||||
|
if (!result.destination) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setDraggingItemHeight(0);
|
||||||
|
|
||||||
|
const startIndex = result.source.index;
|
||||||
|
const endIndex = result.destination.index;
|
||||||
|
|
||||||
|
const list = Array.from(dataList);
|
||||||
|
const [removed] = list.splice(startIndex, 1);
|
||||||
|
list.splice(endIndex, 0, removed);
|
||||||
|
|
||||||
|
onDragEndCb(list);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
|
||||||
|
<Droppable droppableId="droppable" renderClone={renderClone}>
|
||||||
|
{(provided, snapshot) => {
|
||||||
|
return (
|
||||||
|
<Box {...provided.droppableProps} ref={provided.innerRef}>
|
||||||
|
{children(provided, snapshot)}
|
||||||
|
{snapshot.isDraggingOver && <Box height={draggingItemHeight} />}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Droppable>
|
||||||
|
</DragDropContext>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DndDrag;
|
||||||
|
|
||||||
|
export * from 'react-beautiful-dnd';
|
@@ -31,12 +31,14 @@
|
|||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-day-picker": "^8.7.1",
|
"react-day-picker": "^8.7.1",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-i18next": "13.5.0"
|
"react-i18next": "13.5.0",
|
||||||
|
"react-beautiful-dnd": "^13.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash": "^4.14.191",
|
"@types/lodash": "^4.14.191",
|
||||||
"@types/papaparse": "^5.3.7",
|
"@types/papaparse": "^5.3.7",
|
||||||
"@types/react": "18.2.0",
|
"@types/react": "18.2.0",
|
||||||
"@types/react-dom": "18.2.0"
|
"@types/react-dom": "18.2.0",
|
||||||
|
"@types/react-beautiful-dnd": "^13.1.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -292,6 +292,9 @@ importers:
|
|||||||
react:
|
react:
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
|
react-beautiful-dnd:
|
||||||
|
specifier: ^13.1.1
|
||||||
|
version: 13.1.1(react-dom@18.2.0)(react@18.2.0)
|
||||||
react-day-picker:
|
react-day-picker:
|
||||||
specifier: ^8.7.1
|
specifier: ^8.7.1
|
||||||
version: 8.7.1(date-fns@2.30.0)(react@18.2.0)
|
version: 8.7.1(date-fns@2.30.0)(react@18.2.0)
|
||||||
@@ -311,6 +314,9 @@ importers:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
|
'@types/react-beautiful-dnd':
|
||||||
|
specifier: ^13.1.8
|
||||||
|
version: 13.1.8
|
||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
@@ -431,9 +437,6 @@ importers:
|
|||||||
react:
|
react:
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
react-beautiful-dnd:
|
|
||||||
specifier: ^13.1.1
|
|
||||||
version: 13.1.1(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
react-day-picker:
|
react-day-picker:
|
||||||
specifier: ^8.7.1
|
specifier: ^8.7.1
|
||||||
version: 8.7.1(date-fns@2.30.0)(react@18.2.0)
|
version: 8.7.1(date-fns@2.30.0)(react@18.2.0)
|
||||||
@@ -504,9 +507,6 @@ importers:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
'@types/react-beautiful-dnd':
|
|
||||||
specifier: ^13.1.8
|
|
||||||
version: 13.1.8
|
|
||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0
|
version: 18.2.0
|
||||||
|
@@ -644,8 +644,7 @@
|
|||||||
"success": "开始同步"
|
"success": "开始同步"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"training": {
|
"training": {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"Auxiliary Data": "辅助数据",
|
"Auxiliary Data": "辅助数据",
|
||||||
@@ -920,7 +919,7 @@
|
|||||||
"AppId": "应用的ID",
|
"AppId": "应用的ID",
|
||||||
"ChatId": "当前对话ID",
|
"ChatId": "当前对话ID",
|
||||||
"Current time": "当前时间",
|
"Current time": "当前时间",
|
||||||
"Histories": "历史记录,最多取10条",
|
"Histories": "最近10条聊天记录",
|
||||||
"Key already exists": "Key 已经存在",
|
"Key already exists": "Key 已经存在",
|
||||||
"Key cannot be empty": "参数名不能为空",
|
"Key cannot be empty": "参数名不能为空",
|
||||||
"Props name": "参数名",
|
"Props name": "参数名",
|
||||||
|
@@ -47,7 +47,6 @@
|
|||||||
"nextjs-node-loader": "^1.1.5",
|
"nextjs-node-loader": "^1.1.5",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
|
||||||
"react-day-picker": "^8.7.1",
|
"react-day-picker": "^8.7.1",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-hook-form": "7.43.1",
|
"react-hook-form": "7.43.1",
|
||||||
@@ -73,7 +72,6 @@
|
|||||||
"@types/lodash": "^4.14.191",
|
"@types/lodash": "^4.14.191",
|
||||||
"@types/node": "^20.8.5",
|
"@types/node": "^20.8.5",
|
||||||
"@types/react": "18.2.0",
|
"@types/react": "18.2.0",
|
||||||
"@types/react-beautiful-dnd": "^13.1.8",
|
|
||||||
"@types/react-dom": "18.2.0",
|
"@types/react-dom": "18.2.0",
|
||||||
"@types/react-syntax-highlighter": "^15.5.6",
|
"@types/react-syntax-highlighter": "^15.5.6",
|
||||||
"@types/request-ip": "^0.0.37",
|
"@types/request-ip": "^0.0.37",
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
import { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
||||||
import React, { useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { UseFormReturn } from 'react-hook-form';
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { Box, Button, Card, Input, Textarea } from '@chakra-ui/react';
|
import { Box, Button, Card, Input, Textarea } from '@chakra-ui/react';
|
||||||
@@ -24,10 +24,23 @@ const VariableInput = ({
|
|||||||
chatForm: UseFormReturn<ChatBoxInputFormType>;
|
chatForm: UseFormReturn<ChatBoxInputFormType>;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [refresh, setRefresh] = useState(false);
|
const { register, unregister, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
|
||||||
const { register, setValue, handleSubmit: handleSubmitChat, watch } = chatForm;
|
|
||||||
const variables = watch('variables');
|
const variables = watch('variables');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// 重新注册所有字段
|
||||||
|
variableModules.forEach((item) => {
|
||||||
|
register(`variables.${item.key}`, { required: item.required });
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// 组件卸载时注销所有字段
|
||||||
|
variableModules.forEach((item) => {
|
||||||
|
unregister(`variables.${item.key}`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, [register, unregister, variableModules]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={3}>
|
<Box py={3}>
|
||||||
{/* avatar */}
|
{/* avatar */}
|
||||||
@@ -92,7 +105,6 @@ const VariableInput = ({
|
|||||||
value={variables[item.key]}
|
value={variables[item.key]}
|
||||||
onchange={(e) => {
|
onchange={(e) => {
|
||||||
setValue(`variables.${item.key}`, e);
|
setValue(`variables.${item.key}`, e);
|
||||||
setRefresh((state) => !state);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -116,4 +128,4 @@ const VariableInput = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(VariableInput);
|
export default VariableInput;
|
||||||
|
@@ -158,12 +158,6 @@ const ChatBox = (
|
|||||||
isChatting
|
isChatting
|
||||||
} = useChatProviderStore();
|
} = useChatProviderStore();
|
||||||
|
|
||||||
/* variable */
|
|
||||||
const filterVariableModules = useMemo(
|
|
||||||
() => variableModules.filter((item) => item.type !== VariableInputEnum.custom),
|
|
||||||
[variableModules]
|
|
||||||
);
|
|
||||||
|
|
||||||
// compute variable input is finish.
|
// compute variable input is finish.
|
||||||
const chatForm = useForm<ChatBoxInputFormType>({
|
const chatForm = useForm<ChatBoxInputFormType>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -174,9 +168,15 @@ const ChatBox = (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
const { setValue, watch, handleSubmit } = chatForm;
|
const { setValue, watch, handleSubmit } = chatForm;
|
||||||
const variables = watch('variables');
|
|
||||||
const chatStarted = watch('chatStarted');
|
const chatStarted = watch('chatStarted');
|
||||||
const variableIsFinish = useMemo(() => {
|
|
||||||
|
/* variable */
|
||||||
|
const variables = watch('variables');
|
||||||
|
const filterVariableModules = useMemo(
|
||||||
|
() => variableModules.filter((item) => item.type !== VariableInputEnum.custom),
|
||||||
|
[variableModules]
|
||||||
|
);
|
||||||
|
const variableIsFinish = (() => {
|
||||||
if (!filterVariableModules || filterVariableModules.length === 0 || chatHistories.length > 0)
|
if (!filterVariableModules || filterVariableModules.length === 0 || chatHistories.length > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ const ChatBox = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
return chatStarted;
|
return chatStarted;
|
||||||
}, [filterVariableModules, chatHistories.length, chatStarted, variables]);
|
})();
|
||||||
|
|
||||||
// 滚动到底部
|
// 滚动到底部
|
||||||
const scrollToBottom = (behavior: 'smooth' | 'auto' = 'smooth') => {
|
const scrollToBottom = (behavior: 'smooth' | 'auto' = 'smooth') => {
|
||||||
@@ -360,6 +360,12 @@ const ChatBox = (
|
|||||||
[questionGuide, shareId, outLinkUid, teamId, teamToken]
|
[questionGuide, shareId, outLinkUid, teamId, teamToken]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* Abort chat completions, questionGuide */
|
||||||
|
const abortRequest = useCallback(() => {
|
||||||
|
chatController.current?.abort('stop');
|
||||||
|
questionGuideController.current?.abort('stop');
|
||||||
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* user confirm send prompt
|
* user confirm send prompt
|
||||||
*/
|
*/
|
||||||
@@ -383,6 +389,8 @@ const ChatBox = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abortRequest();
|
||||||
|
|
||||||
text = text.trim();
|
text = text.trim();
|
||||||
|
|
||||||
if (!text && files.length === 0) {
|
if (!text && files.length === 0) {
|
||||||
@@ -472,7 +480,8 @@ const ChatBox = (
|
|||||||
generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }),
|
generatingMessage: (e) => generatingMessage({ ...e, autoTTSResponse }),
|
||||||
variables
|
variables
|
||||||
});
|
});
|
||||||
setValue('variables', newVariables || []);
|
|
||||||
|
newVariables && setValue('variables', newVariables);
|
||||||
|
|
||||||
isNewChatReplace.current = isNewChat;
|
isNewChatReplace.current = isNewChat;
|
||||||
|
|
||||||
@@ -540,6 +549,7 @@ const ChatBox = (
|
|||||||
})();
|
})();
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
abortRequest,
|
||||||
chatHistories,
|
chatHistories,
|
||||||
createQuestionGuide,
|
createQuestionGuide,
|
||||||
finishSegmentedAudio,
|
finishSegmentedAudio,
|
||||||
@@ -710,7 +720,7 @@ const ChatBox = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[appId, chatId, feedbackType, teamId, teamToken]
|
[appId, chatId, feedbackType, setChatHistories, teamId, teamToken]
|
||||||
);
|
);
|
||||||
const onADdUserDislike = useCallback(
|
const onADdUserDislike = useCallback(
|
||||||
(chat: ChatSiteItemType) => {
|
(chat: ChatSiteItemType) => {
|
||||||
@@ -747,7 +757,7 @@ const ChatBox = (
|
|||||||
return () => setFeedbackId(chat.dataId);
|
return () => setFeedbackId(chat.dataId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[appId, chatId, feedbackType, outLinkUid, shareId, teamId, teamToken]
|
[appId, chatId, feedbackType, outLinkUid, setChatHistories, shareId, teamId, teamToken]
|
||||||
);
|
);
|
||||||
const onReadUserDislike = useCallback(
|
const onReadUserDislike = useCallback(
|
||||||
(chat: ChatSiteItemType) => {
|
(chat: ChatSiteItemType) => {
|
||||||
@@ -868,6 +878,7 @@ const ChatBox = (
|
|||||||
setValue('variables', e || defaultVal);
|
setValue('variables', e || defaultVal);
|
||||||
},
|
},
|
||||||
resetHistory(e) {
|
resetHistory(e) {
|
||||||
|
abortRequest();
|
||||||
setValue('chatStarted', e.length > 0);
|
setValue('chatStarted', e.length > 0);
|
||||||
setChatHistories(e);
|
setChatHistories(e);
|
||||||
},
|
},
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
import { Box, Button, Flex } from '@chakra-ui/react';
|
import { Box, Button, Flex } from '@chakra-ui/react';
|
||||||
import { DraggableProvided, DraggableStateSnapshot } from 'react-beautiful-dnd';
|
import {
|
||||||
|
DraggableProvided,
|
||||||
|
DraggableStateSnapshot
|
||||||
|
} from '@fastgpt/web/components/common/DndDrag/index';
|
||||||
import Container from '../../components/Container';
|
import Container from '../../components/Container';
|
||||||
import { DragHandleIcon, MinusIcon, SmallAddIcon } from '@chakra-ui/icons';
|
import { DragHandleIcon, MinusIcon, SmallAddIcon } from '@chakra-ui/icons';
|
||||||
import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type';
|
import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type';
|
||||||
@@ -25,6 +28,7 @@ import { getElseIFLabel, getHandleId } from '@fastgpt/global/core/workflow/utils
|
|||||||
import { SourceHandle } from '../render/Handle';
|
import { SourceHandle } from '../render/Handle';
|
||||||
import { Position, useReactFlow } from 'reactflow';
|
import { Position, useReactFlow } from 'reactflow';
|
||||||
import { getReferenceDataValueType } from '@/web/core/workflow/utils';
|
import { getReferenceDataValueType } from '@/web/core/workflow/utils';
|
||||||
|
import DragIcon from '@fastgpt/web/components/common/DndDrag/DragIcon';
|
||||||
|
|
||||||
const ListItem = ({
|
const ListItem = ({
|
||||||
provided,
|
provided,
|
||||||
@@ -63,11 +67,7 @@ const ListItem = ({
|
|||||||
>
|
>
|
||||||
<Container w={snapshot.isDragging ? '' : 'full'} className="nodrag">
|
<Container w={snapshot.isDragging ? '' : 'full'} className="nodrag">
|
||||||
<Flex mb={4} alignItems={'center'}>
|
<Flex mb={4} alignItems={'center'}>
|
||||||
{ifElseList.length > 1 && (
|
{ifElseList.length > 1 && <DragIcon provided={provided} />}
|
||||||
<Box {...provided.dragHandleProps}>
|
|
||||||
<DragHandleIcon color={'blackAlpha.600'} />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<Box color={'black'} fontSize={'lg'} ml={2}>
|
<Box color={'black'} fontSize={'lg'} ml={2}>
|
||||||
{getElseIFLabel(conditionIndex)}
|
{getElseIFLabel(conditionIndex)}
|
||||||
</Box>
|
</Box>
|
||||||
|
@@ -9,7 +9,7 @@ import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/syste
|
|||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext } from '../../../context';
|
import { WorkflowContext } from '../../../context';
|
||||||
import Container from '../../components/Container';
|
import Container from '../../components/Container';
|
||||||
import { DragDropContext, DragStart, Draggable, DropResult, Droppable } from 'react-beautiful-dnd';
|
import DndDrag, { Draggable, DropResult } from '@fastgpt/web/components/common/DndDrag/index';
|
||||||
import { SourceHandle } from '../render/Handle';
|
import { SourceHandle } from '../render/Handle';
|
||||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||||
import ListItem from './ListItem';
|
import ListItem from './ListItem';
|
||||||
@@ -20,8 +20,6 @@ const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
const { nodeId, inputs = [] } = data;
|
const { nodeId, inputs = [] } = data;
|
||||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||||
|
|
||||||
const [draggingItemHeight, setDraggingItemHeight] = useState(0);
|
|
||||||
|
|
||||||
const ifElseList = useMemo(
|
const ifElseList = useMemo(
|
||||||
() =>
|
() =>
|
||||||
(inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList)
|
(inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList)
|
||||||
@@ -47,73 +45,49 @@ const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
|||||||
[inputs, nodeId, onChangeNode]
|
[inputs, nodeId, onChangeNode]
|
||||||
);
|
);
|
||||||
|
|
||||||
const reorder = (list: IfElseListItemType[], startIndex: number, endIndex: number) => {
|
|
||||||
const result = Array.from(list);
|
|
||||||
const [removed] = result.splice(startIndex, 1);
|
|
||||||
result.splice(endIndex, 0, removed);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDragStart = (start: DragStart) => {
|
|
||||||
const draggingNode = document.querySelector(`[data-rbd-draggable-id="${start.draggableId}"]`);
|
|
||||||
setDraggingItemHeight(draggingNode?.getBoundingClientRect().height || 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDragEnd = (result: DropResult) => {
|
|
||||||
if (!result.destination) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const newList = reorder(ifElseList, result.source.index, result.destination.index);
|
|
||||||
|
|
||||||
onUpdateIfElseList(newList);
|
|
||||||
setDraggingItemHeight(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeCard selected={selected} maxW={'1000px'} {...data}>
|
<NodeCard selected={selected} maxW={'1000px'} {...data}>
|
||||||
<Box px={4}>
|
<Box px={4} cursor={'default'}>
|
||||||
<DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
|
<DndDrag<IfElseListItemType>
|
||||||
<Droppable
|
onDragEndCb={(list) => onUpdateIfElseList(list)}
|
||||||
droppableId="droppable"
|
dataList={ifElseList}
|
||||||
renderClone={(provided, snapshot, rubric) => (
|
renderClone={(provided, snapshot, rubric) => (
|
||||||
<ListItem
|
<ListItem
|
||||||
provided={provided}
|
provided={provided}
|
||||||
snapshot={snapshot}
|
snapshot={snapshot}
|
||||||
conditionItem={ifElseList[rubric.source.index]}
|
conditionItem={ifElseList[rubric.source.index]}
|
||||||
conditionIndex={rubric.source.index}
|
conditionIndex={rubric.source.index}
|
||||||
ifElseList={ifElseList}
|
ifElseList={ifElseList}
|
||||||
onUpdateIfElseList={onUpdateIfElseList}
|
onUpdateIfElseList={onUpdateIfElseList}
|
||||||
nodeId={nodeId}
|
nodeId={nodeId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{(provided, snapshot) => (
|
{(provided) => (
|
||||||
<Box {...provided.droppableProps} ref={provided.innerRef}>
|
<Box {...provided.droppableProps} ref={provided.innerRef}>
|
||||||
{ifElseList.map((conditionItem, conditionIndex) => (
|
{ifElseList.map((conditionItem, conditionIndex) => (
|
||||||
<Draggable
|
<Draggable
|
||||||
key={conditionIndex}
|
key={conditionIndex}
|
||||||
draggableId={conditionIndex.toString()}
|
draggableId={conditionIndex.toString()}
|
||||||
index={conditionIndex}
|
index={conditionIndex}
|
||||||
>
|
>
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
<ListItem
|
<ListItem
|
||||||
provided={provided}
|
provided={provided}
|
||||||
snapshot={snapshot}
|
snapshot={snapshot}
|
||||||
conditionItem={conditionItem}
|
conditionItem={conditionItem}
|
||||||
conditionIndex={conditionIndex}
|
conditionIndex={conditionIndex}
|
||||||
ifElseList={ifElseList}
|
ifElseList={ifElseList}
|
||||||
onUpdateIfElseList={onUpdateIfElseList}
|
onUpdateIfElseList={onUpdateIfElseList}
|
||||||
nodeId={nodeId}
|
nodeId={nodeId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Draggable>
|
</Draggable>
|
||||||
))}
|
))}
|
||||||
{snapshot.isDraggingOver && <Box height={draggingItemHeight} />}
|
</Box>
|
||||||
</Box>
|
)}
|
||||||
)}
|
</DndDrag>
|
||||||
</Droppable>
|
|
||||||
</DragDropContext>
|
|
||||||
<Container position={'relative'}>
|
<Container position={'relative'}>
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
<Box color={'black'} fontSize={'lg'} ml={2}>
|
<Box color={'black'} fontSize={'lg'} ml={2}>
|
||||||
|
@@ -45,7 +45,6 @@ import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runti
|
|||||||
import { dispatchWorkFlowV1 } from '@fastgpt/service/core/workflow/dispatchV1';
|
import { dispatchWorkFlowV1 } from '@fastgpt/service/core/workflow/dispatchV1';
|
||||||
import { setEntryEntries } from '@fastgpt/service/core/workflow/dispatchV1/utils';
|
import { setEntryEntries } from '@fastgpt/service/core/workflow/dispatchV1/utils';
|
||||||
import { NextAPI } from '@/service/middle/entry';
|
import { NextAPI } from '@/service/middle/entry';
|
||||||
import { MongoAppVersion } from '@fastgpt/service/core/app/versionSchema';
|
|
||||||
import { getAppLatestVersion } from '@fastgpt/service/core/app/controller';
|
import { getAppLatestVersion } from '@fastgpt/service/core/app/controller';
|
||||||
|
|
||||||
type FastGptWebChatProps = {
|
type FastGptWebChatProps = {
|
||||||
|
@@ -28,7 +28,7 @@ const Render = ({ app, onClose }: Props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isV2Workflow) return;
|
if (!isV2Workflow) return;
|
||||||
initData(JSON.parse(workflowStringData));
|
initData(JSON.parse(workflowStringData));
|
||||||
}, [isV2Workflow, initData, workflowStringData]);
|
}, [isV2Workflow, initData, app._id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isV2Workflow) {
|
if (!isV2Workflow) {
|
||||||
|
@@ -99,8 +99,8 @@ const OutLink = ({
|
|||||||
data: {
|
data: {
|
||||||
messages: prompts,
|
messages: prompts,
|
||||||
variables: {
|
variables: {
|
||||||
...customVariables,
|
...variables,
|
||||||
...variables
|
...customVariables
|
||||||
},
|
},
|
||||||
shareId,
|
shareId,
|
||||||
chatId: completionChatId,
|
chatId: completionChatId,
|
||||||
|
Reference in New Issue
Block a user