4.8-preview fix (#1324)
* feishu app release (#85) * Revert "lafAccount add pat & re request when token invalid (#76)" (#77) This reverts commit 83d85dfe37adcaef4833385ea52ee79fd84720be. * perf: workflow ux * system config * feat: feishu app release * chore: sovle the conflicts files; fix the feishu entry * fix: rename Feishu interface to FeishuType * fix: fix type problem in app.ts * fix: type problem * fix: style problem --------- Co-authored-by: Archer <545436317@qq.com> * perf: publish channel code * change system variable position (#94) * perf: workflow context * perf: variable select * hide publish * perf: simple edit auto refresh * perf: simple edit data refresh * fix: target handle --------- Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com> Co-authored-by: heheer <71265218+newfish-cmyk@users.noreply.github.com>
This commit is contained in:
@@ -13,7 +13,6 @@ import {
|
||||
Switch,
|
||||
Input,
|
||||
FormControl,
|
||||
Image,
|
||||
Table,
|
||||
Thead,
|
||||
Tbody,
|
||||
@@ -21,7 +20,6 @@ import {
|
||||
Th,
|
||||
Td,
|
||||
TableContainer,
|
||||
BoxProps,
|
||||
useDisclosure
|
||||
} from '@chakra-ui/react';
|
||||
import { QuestionOutlineIcon, SmallAddIcon } from '@chakra-ui/icons';
|
||||
|
||||
@@ -3,7 +3,8 @@ import { Textarea, Button, ModalBody, ModalFooter } from '@chakra-ui/react';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useFlowProviderStore } from './FlowProvider';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../context';
|
||||
|
||||
type Props = {
|
||||
onClose: () => void;
|
||||
@@ -12,7 +13,8 @@ type Props = {
|
||||
const ImportSettings = ({ onClose }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const { setNodes, setEdges, initData } = useFlowProviderStore();
|
||||
|
||||
const initData = useContextSelector(WorkflowContext, (v) => v.initData);
|
||||
const [value, setValue] = useState('');
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
Flex,
|
||||
IconButton,
|
||||
Input,
|
||||
InputGroup,
|
||||
InputLeftElement,
|
||||
css
|
||||
} from '@chakra-ui/react';
|
||||
import { Box, Flex, IconButton, Input, InputGroup, InputLeftElement, css } from '@chakra-ui/react';
|
||||
import type {
|
||||
FlowNodeTemplateType,
|
||||
nodeTemplateListType
|
||||
@@ -16,8 +7,6 @@ import type {
|
||||
import { useViewport, XYPosition } from 'reactflow';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import { useFlowProviderStore } from './FlowProvider';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { nodeTemplate2FlowNode } from '@/web/core/workflow/utils';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
||||
@@ -36,6 +25,9 @@ import { PluginTypeEnum } from '@fastgpt/global/core/plugin/constants';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { debounce } from 'lodash';
|
||||
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../context';
|
||||
import { useCreation } from 'ahooks';
|
||||
|
||||
type ModuleTemplateListProps = {
|
||||
isOpen: boolean;
|
||||
@@ -62,7 +54,9 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
||||
const [currentParent, setCurrentParent] = useState<RenderListProps['currentParent']>();
|
||||
const [searchKey, setSearchKey] = useState('');
|
||||
const { feConfigs } = useSystemStore();
|
||||
const { nodes, basicNodeTemplates, hasToolNode } = useFlowProviderStore();
|
||||
const basicNodeTemplates = useContextSelector(WorkflowContext, (v) => v.basicNodeTemplates);
|
||||
const hasToolNode = useContextSelector(WorkflowContext, (v) => v.hasToolNode);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
const {
|
||||
systemNodeTemplates,
|
||||
@@ -72,12 +66,12 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
||||
} = useWorkflowStore();
|
||||
const [templateType, setTemplateType] = useState(TemplateTypeEnum.basic);
|
||||
|
||||
const templatesString = useMemo(() => {
|
||||
const templates = useCreation(() => {
|
||||
const map = {
|
||||
[TemplateTypeEnum.basic]: basicNodeTemplates.filter((item) => {
|
||||
// unique node filter
|
||||
if (item.unique) {
|
||||
const nodeExist = nodes.some((node) => node.data.flowNodeType === item.flowNodeType);
|
||||
const nodeExist = nodeList.some((node) => node.flowNodeType === item.flowNodeType);
|
||||
if (nodeExist) {
|
||||
return false;
|
||||
}
|
||||
@@ -97,12 +91,12 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
||||
searchKey ? item.pluginType !== PluginTypeEnum.folder : true
|
||||
)
|
||||
};
|
||||
return JSON.stringify(map[templateType]);
|
||||
return map[templateType];
|
||||
}, [
|
||||
basicNodeTemplates,
|
||||
feConfigs.lafEnv,
|
||||
hasToolNode,
|
||||
nodes,
|
||||
nodeList,
|
||||
searchKey,
|
||||
systemNodeTemplates,
|
||||
teamPluginNodeTemplates,
|
||||
@@ -132,135 +126,120 @@ const NodeTemplatesModal = ({ isOpen, onClose }: ModuleTemplateListProps) => {
|
||||
})
|
||||
);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
const parseTemplates = JSON.parse(templatesString) as FlowNodeTemplateType[];
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
zIndex={2}
|
||||
display={isOpen ? 'block' : 'none'}
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
w={`${sliderWidth}px`}
|
||||
onClick={onClose}
|
||||
/>
|
||||
<Flex
|
||||
zIndex={3}
|
||||
flexDirection={'column'}
|
||||
position={'absolute'}
|
||||
top={'10px'}
|
||||
left={0}
|
||||
pt={'20px'}
|
||||
pb={4}
|
||||
h={isOpen ? 'calc(100% - 20px)' : '0'}
|
||||
w={isOpen ? ['100%', `${sliderWidth}px`] : '0'}
|
||||
bg={'white'}
|
||||
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
|
||||
borderRadius={'0 20px 20px 0'}
|
||||
transition={'.2s ease'}
|
||||
userSelect={'none'}
|
||||
overflow={isOpen ? 'none' : 'hidden'}
|
||||
>
|
||||
<Box mb={2} pl={'20px'} pr={'10px'} whiteSpace={'nowrap'} overflow={'hidden'}>
|
||||
<Flex flex={'1 0 0'} alignItems={'center'} gap={3}>
|
||||
<RowTabs
|
||||
list={[
|
||||
{
|
||||
icon: 'core/modules/basicNode',
|
||||
label: t('core.module.template.Basic Node'),
|
||||
value: TemplateTypeEnum.basic
|
||||
},
|
||||
{
|
||||
icon: 'core/modules/systemPlugin',
|
||||
label: t('core.module.template.System Plugin'),
|
||||
value: TemplateTypeEnum.systemPlugin
|
||||
},
|
||||
{
|
||||
icon: 'core/modules/teamPlugin',
|
||||
label: t('core.module.template.Team Plugin'),
|
||||
value: TemplateTypeEnum.teamPlugin
|
||||
}
|
||||
]}
|
||||
py={'5px'}
|
||||
value={templateType}
|
||||
onChange={onChangeTab}
|
||||
/>
|
||||
{/* close icon */}
|
||||
<IconButton
|
||||
size={'sm'}
|
||||
icon={<MyIcon name={'common/backFill'} w={'14px'} color={'myGray.700'} />}
|
||||
w={'26px'}
|
||||
h={'26px'}
|
||||
borderColor={'myGray.300'}
|
||||
variant={'grayBase'}
|
||||
aria-label={''}
|
||||
onClick={onClose}
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
zIndex={2}
|
||||
display={isOpen ? 'block' : 'none'}
|
||||
position={'absolute'}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
w={`${sliderWidth}px`}
|
||||
onClick={onClose}
|
||||
/>
|
||||
<Flex
|
||||
zIndex={3}
|
||||
flexDirection={'column'}
|
||||
position={'absolute'}
|
||||
top={'10px'}
|
||||
left={0}
|
||||
pt={'20px'}
|
||||
pb={4}
|
||||
h={isOpen ? 'calc(100% - 20px)' : '0'}
|
||||
w={isOpen ? ['100%', `${sliderWidth}px`] : '0'}
|
||||
bg={'white'}
|
||||
boxShadow={'3px 0 20px rgba(0,0,0,0.2)'}
|
||||
borderRadius={'0 20px 20px 0'}
|
||||
transition={'.2s ease'}
|
||||
userSelect={'none'}
|
||||
overflow={isOpen ? 'none' : 'hidden'}
|
||||
>
|
||||
<Box mb={2} pl={'20px'} pr={'10px'} whiteSpace={'nowrap'} overflow={'hidden'}>
|
||||
<Flex flex={'1 0 0'} alignItems={'center'} gap={3}>
|
||||
<RowTabs
|
||||
list={[
|
||||
{
|
||||
icon: 'core/modules/basicNode',
|
||||
label: t('core.module.template.Basic Node'),
|
||||
value: TemplateTypeEnum.basic
|
||||
},
|
||||
{
|
||||
icon: 'core/modules/systemPlugin',
|
||||
label: t('core.module.template.System Plugin'),
|
||||
value: TemplateTypeEnum.systemPlugin
|
||||
},
|
||||
{
|
||||
icon: 'core/modules/teamPlugin',
|
||||
label: t('core.module.template.Team Plugin'),
|
||||
value: TemplateTypeEnum.teamPlugin
|
||||
}
|
||||
]}
|
||||
py={'5px'}
|
||||
value={templateType}
|
||||
onChange={onChangeTab}
|
||||
/>
|
||||
{/* close icon */}
|
||||
<IconButton
|
||||
size={'sm'}
|
||||
icon={<MyIcon name={'common/backFill'} w={'14px'} color={'myGray.700'} />}
|
||||
w={'26px'}
|
||||
h={'26px'}
|
||||
borderColor={'myGray.300'}
|
||||
variant={'grayBase'}
|
||||
aria-label={''}
|
||||
onClick={onClose}
|
||||
/>
|
||||
</Flex>
|
||||
{templateType === TemplateTypeEnum.teamPlugin && (
|
||||
<Flex mt={2} alignItems={'center'} h={10}>
|
||||
<InputGroup mr={4} h={'full'}>
|
||||
<InputLeftElement h={'full'} alignItems={'center'} display={'flex'}>
|
||||
<MyIcon name={'common/searchLight'} w={'16px'} color={'myGray.500'} ml={3} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
h={'full'}
|
||||
bg={'myGray.50'}
|
||||
placeholder={t('plugin.Search plugin')}
|
||||
onChange={debounce((e) => setSearchKey(e.target.value), 200)}
|
||||
/>
|
||||
</InputGroup>
|
||||
<Box flex={1} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'primary.600'
|
||||
}}
|
||||
onClick={() => router.push('/plugin/list')}
|
||||
>
|
||||
<Box>去创建</Box>
|
||||
<MyIcon name={'common/rightArrowLight'} w={'14px'} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
{templateType === TemplateTypeEnum.teamPlugin && !searchKey && currentParent && (
|
||||
<Flex alignItems={'center'} mt={2}>
|
||||
<ParentPaths
|
||||
paths={[currentParent]}
|
||||
FirstPathDom={null}
|
||||
onClick={() => {
|
||||
setCurrentParent(undefined);
|
||||
}}
|
||||
fontSize="md"
|
||||
/>
|
||||
</Flex>
|
||||
{templateType === TemplateTypeEnum.teamPlugin && (
|
||||
<Flex mt={2} alignItems={'center'} h={10}>
|
||||
<InputGroup mr={4} h={'full'}>
|
||||
<InputLeftElement h={'full'} alignItems={'center'} display={'flex'}>
|
||||
<MyIcon name={'common/searchLight'} w={'16px'} color={'myGray.500'} ml={3} />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
h={'full'}
|
||||
bg={'myGray.50'}
|
||||
placeholder={t('plugin.Search plugin')}
|
||||
onChange={debounce((e) => setSearchKey(e.target.value), 200)}
|
||||
/>
|
||||
</InputGroup>
|
||||
<Box flex={1} />
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
_hover={{
|
||||
color: 'primary.600'
|
||||
}}
|
||||
onClick={() => router.push('/plugin/list')}
|
||||
>
|
||||
<Box>去创建</Box>
|
||||
<MyIcon name={'common/rightArrowLight'} w={'14px'} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
{templateType === TemplateTypeEnum.teamPlugin && !searchKey && currentParent && (
|
||||
<Flex alignItems={'center'} mt={2}>
|
||||
<ParentPaths
|
||||
paths={[currentParent]}
|
||||
FirstPathDom={null}
|
||||
onClick={() => {
|
||||
setCurrentParent(undefined);
|
||||
}}
|
||||
fontSize="md"
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
<RenderList
|
||||
templates={parseTemplates}
|
||||
onClose={onClose}
|
||||
currentParent={currentParent}
|
||||
setCurrentParent={setCurrentParent}
|
||||
/>
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
}, [
|
||||
currentParent,
|
||||
isOpen,
|
||||
onChangeTab,
|
||||
onClose,
|
||||
router,
|
||||
searchKey,
|
||||
t,
|
||||
templateType,
|
||||
templatesString
|
||||
]);
|
||||
|
||||
return Render;
|
||||
)}
|
||||
</Box>
|
||||
<RenderList
|
||||
templates={templates}
|
||||
onClose={onClose}
|
||||
currentParent={currentParent}
|
||||
setCurrentParent={setCurrentParent}
|
||||
/>
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(NodeTemplatesModal);
|
||||
@@ -276,7 +255,8 @@ const RenderList = React.memo(function RenderList({
|
||||
const { x, y, zoom } = useViewport();
|
||||
const { setLoading } = useSystemStore();
|
||||
const { toast } = useToast();
|
||||
const { reactFlowWrapper, setNodes } = useFlowProviderStore();
|
||||
const reactFlowWrapper = useContextSelector(WorkflowContext, (v) => v.reactFlowWrapper);
|
||||
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||
|
||||
const formatTemplates = useMemo<nodeTemplateListType>(() => {
|
||||
const copy: nodeTemplateListType = JSON.parse(JSON.stringify(moduleTemplatesList));
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { BezierEdge, getBezierPath, EdgeLabelRenderer, EdgeProps } from 'reactflow';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { NodeOutputKeyEnum, RuntimeEdgeStatusEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
|
||||
const ButtonEdge = (props: EdgeProps) => {
|
||||
const { nodes, setEdges, workflowDebugData } = useFlowProviderStore();
|
||||
const nodes = useContextSelector(WorkflowContext, (v) => v.nodes);
|
||||
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||
const workflowDebugData = useContextSelector(WorkflowContext, (v) => v.workflowDebugData);
|
||||
|
||||
const {
|
||||
id,
|
||||
sourceX,
|
||||
|
||||
@@ -2,7 +2,6 @@ import { storeNodes2RuntimeNodes } from '@fastgpt/global/core/workflow/runtime/u
|
||||
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import { RuntimeEdgeItemType, StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { getWorkflowStore, useFlowProviderStore } from '../FlowProvider';
|
||||
import { checkWorkflowNodeAndConnection } from '@/web/core/workflow/utils';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
@@ -25,6 +24,8 @@ import {
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { checkInputIsReference } from '@fastgpt/global/core/workflow/utils';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext, getWorkflowStore } from '../../context';
|
||||
|
||||
const MyRightDrawer = dynamic(
|
||||
() => import('@fastgpt/web/components/common/MyDrawer/MyRightDrawer')
|
||||
@@ -35,7 +36,10 @@ export const useDebug = () => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { edges, setNodes, onStartNodeDebug, onUpdateNodeError } = useFlowProviderStore();
|
||||
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||
const onStartNodeDebug = useContextSelector(WorkflowContext, (v) => v.onStartNodeDebug);
|
||||
|
||||
const [runtimeNodeId, setRuntimeNodeId] = useState<string>();
|
||||
const [runtimeNodes, setRuntimeNodes] = useState<RuntimeNodeItemType[]>();
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { getWorkflowStore, useFlowProviderStore } from '../FlowProvider';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { useCopyData } from '@/web/common/hooks/useCopyData';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Node } from 'reactflow';
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext, getWorkflowStore } from '../../context';
|
||||
|
||||
export const useKeyboard = () => {
|
||||
const { t } = useTranslation();
|
||||
const { setNodes } = useFlowProviderStore();
|
||||
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||
const { copyData } = useCopyData();
|
||||
|
||||
const [isDowningCtrl, setIsDowningCtrl] = useState(false);
|
||||
@@ -29,6 +30,7 @@ export const useKeyboard = () => {
|
||||
const onCopy = useCallback(async () => {
|
||||
if (hasInputtingElement()) return;
|
||||
const { nodes } = await getWorkflowStore();
|
||||
|
||||
const selectedNodes = nodes.filter(
|
||||
(node) => node.selected && !node.data?.isError && node.data?.unique !== true
|
||||
);
|
||||
|
||||
@@ -21,7 +21,6 @@ import dynamic from 'next/dynamic';
|
||||
|
||||
import ButtonEdge from './components/ButtonEdge';
|
||||
import NodeTemplatesModal from './NodeTemplatesModal';
|
||||
import { useFlowProviderStore } from './FlowProvider';
|
||||
|
||||
import 'reactflow/dist/style.css';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
@@ -32,6 +31,8 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import { connectionLineStyle, defaultEdgeOptions } from '../constants';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useKeyboard } from './hooks/useKeyboard';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../context';
|
||||
|
||||
const NodeSimple = dynamic(() => import('./nodes/NodeSimple'));
|
||||
const nodeTypes: Record<`${FlowNodeTypeEnum}`, any> = {
|
||||
@@ -71,16 +72,13 @@ const Container = React.memo(function Container() {
|
||||
});
|
||||
|
||||
const { isDowningCtrl } = useKeyboard();
|
||||
|
||||
const {
|
||||
reactFlowWrapper,
|
||||
nodes,
|
||||
onNodesChange,
|
||||
edges,
|
||||
setEdges,
|
||||
onEdgesChange,
|
||||
setConnectingEdge
|
||||
} = useFlowProviderStore();
|
||||
const setConnectingEdge = useContextSelector(WorkflowContext, (v) => v.setConnectingEdge);
|
||||
const reactFlowWrapper = useContextSelector(WorkflowContext, (v) => v.reactFlowWrapper);
|
||||
const nodes = useContextSelector(WorkflowContext, (v) => v.nodes);
|
||||
const onNodesChange = useContextSelector(WorkflowContext, (v) => v.onNodesChange);
|
||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||
const onEdgesChange = useContextSelector(WorkflowContext, (v) => v.onEdgesChange);
|
||||
|
||||
/* node */
|
||||
const handleNodesChange = useCallback(
|
||||
|
||||
@@ -4,15 +4,16 @@ import NodeCard from './render/NodeCard';
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import Container from '../components/Container';
|
||||
import RenderInput from './render/RenderInput';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import RenderToolInput from './render/RenderToolInput';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import IOTitle from '../components/IOTitle';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
|
||||
const NodeAnswer = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
const { splitToolInputs } = useFlowProviderStore();
|
||||
const { nodeId, inputs } = data;
|
||||
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||
|
||||
return (
|
||||
|
||||
@@ -11,16 +11,16 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { SourceHandle } from './render/Handle';
|
||||
import IOTitle from '../components/IOTitle';
|
||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
|
||||
const NodeCQNode = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, inputs } = data;
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const CustomComponent = useMemo(
|
||||
() => ({
|
||||
|
||||
@@ -9,19 +9,21 @@ import { useTranslation } from 'next-i18next';
|
||||
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||
import { WorkflowIOValueTypeEnum, NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { getOneQuoteInputTemplate } from '@fastgpt/global/core/workflow/template/system/datasetConcat';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MySlider from '@/components/Slider';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import RenderOutput from './render/RenderOutput';
|
||||
import IOTitle from '../components/IOTitle';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
|
||||
const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { llmModelList } = useSystemStore();
|
||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const quotes = useMemo(
|
||||
() => inputs.filter((item) => item.valueType === WorkflowIOValueTypeEnum.datasetQuote),
|
||||
|
||||
@@ -26,7 +26,6 @@ import ExtractFieldModal, { defaultField } from './ExtractFieldModal';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useFlowProviderStore } from '../../FlowProvider';
|
||||
import RenderToolInput from '../render/RenderToolInput';
|
||||
import {
|
||||
FlowNodeInputItemType,
|
||||
@@ -34,12 +33,17 @@ import {
|
||||
} from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import IOTitle from '../../components/IOTitle';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../../context';
|
||||
|
||||
const NodeExtract = ({ data }: NodeProps<FlowNodeItemType>) => {
|
||||
const { inputs, outputs, nodeId } = data;
|
||||
const { splitToolInputs, onChangeNode } = useFlowProviderStore();
|
||||
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||
const [editExtractFiled, setEditExtractField] = useState<ContextExtractAgentItemType>();
|
||||
|
||||
const CustomComponent = useMemo(
|
||||
|
||||
@@ -7,7 +7,8 @@ import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import parse from '@bany/curl-to-json';
|
||||
import { useFlowProviderStore } from '../../FlowProvider';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../../context';
|
||||
|
||||
type RequestMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
|
||||
const methodMap: { [K in RequestMethod]: string } = {
|
||||
@@ -28,7 +29,8 @@ const CurlImportModal = ({
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const { register, handleSubmit } = useForm({
|
||||
defaultValues: {
|
||||
curlContent: ''
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
useDisclosure
|
||||
} from '@chakra-ui/react';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useFlowProviderStore } from '../../FlowProvider';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
@@ -41,6 +40,9 @@ import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
import RenderToolInput from '../render/RenderToolInput';
|
||||
import IOTitle from '../../components/IOTitle';
|
||||
import { getSystemVariables } from '@/web/core/app/utils';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../../context';
|
||||
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||
const CurlImportModal = dynamic(() => import('./CurlImportModal'));
|
||||
|
||||
export const HttpHeaders = [
|
||||
@@ -105,7 +107,7 @@ const RenderHttpMethodAndUrl = React.memo(function RenderHttpMethodAndUrl({
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const [_, startSts] = useTransition();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const { isOpen: isOpenCurl, onOpen: onOpenCurl, onClose: onCloseCurl } = useDisclosure();
|
||||
|
||||
@@ -277,7 +279,7 @@ export function RenderHttpProps({
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [selectedTab, setSelectedTab] = useState(TabEnum.params);
|
||||
const { nodeList } = useFlowProviderStore();
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
const requestMethods = inputs.find((item) => item.key === NodeInputKeyEnum.httpMethod)?.value;
|
||||
const params = inputs.find((item) => item.key === NodeInputKeyEnum.httpParams);
|
||||
@@ -289,11 +291,7 @@ export function RenderHttpProps({
|
||||
|
||||
// get variable
|
||||
const variables = useMemo(() => {
|
||||
const globalVariables = formatEditorVariablePickerIcon(
|
||||
splitGuideModule(getGuideModule(nodeList))?.variableModules || []
|
||||
);
|
||||
|
||||
const systemVariables = getSystemVariables(t);
|
||||
const globalVariables = getWorkflowGlobalVariables(nodeList, t);
|
||||
|
||||
const moduleVariables = formatEditorVariablePickerIcon(
|
||||
inputs
|
||||
@@ -304,7 +302,7 @@ export function RenderHttpProps({
|
||||
}))
|
||||
);
|
||||
|
||||
return [...moduleVariables, ...globalVariables, ...systemVariables];
|
||||
return [...moduleVariables, ...globalVariables];
|
||||
}, [inputs, nodeList, t]);
|
||||
|
||||
const variableText = useMemo(() => {
|
||||
@@ -407,7 +405,7 @@ const RenderForm = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const [list, setList] = useState<PropsArrType[]>(input.value || []);
|
||||
const [updateTrigger, setUpdateTrigger] = useState(false);
|
||||
@@ -601,7 +599,7 @@ const RenderJson = ({
|
||||
variables: EditorVariablePickerType[];
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const [_, startSts] = useTransition();
|
||||
|
||||
const Render = useMemo(() => {
|
||||
@@ -650,7 +648,7 @@ const RenderPropsItem = ({ text, num }: { text: string; num: number }) => {
|
||||
const NodeHttp = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
const { splitToolInputs } = useFlowProviderStore();
|
||||
const splitToolInputs = useContextSelector(WorkflowContext, (v) => v.splitToolInputs);
|
||||
const { toolInputs, commonInputs, isTool } = splitToolInputs(inputs, nodeId);
|
||||
|
||||
const CustomComponents = useMemo(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import NodeCard from './render/NodeCard';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import { Box, Button, Flex, background } from '@chakra-ui/react';
|
||||
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
@@ -25,11 +24,13 @@ import {
|
||||
import { stringConditionList } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
import MyInput from '@/components/MyInput';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
|
||||
const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, inputs = [], outputs } = data;
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const condition = useMemo(
|
||||
() =>
|
||||
@@ -274,7 +275,7 @@ const ConditionSelect = ({
|
||||
variable?: ReferenceValueProps;
|
||||
onSelect: (e: VariableConditionEnum) => void;
|
||||
}) => {
|
||||
const { nodeList } = useFlowProviderStore();
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
// get condition type
|
||||
const valueType = useMemo(() => {
|
||||
@@ -337,7 +338,7 @@ const ConditionValueInput = ({
|
||||
condition?: VariableConditionEnum;
|
||||
onChange: (e: string) => void;
|
||||
}) => {
|
||||
const { nodeList } = useFlowProviderStore();
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
// get value type
|
||||
const valueType = useMemo(() => {
|
||||
|
||||
@@ -5,7 +5,6 @@ import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import Container from '../components/Container';
|
||||
import { Box, Button, Center, Flex, useDisclosure } from '@chakra-ui/react';
|
||||
import { WorkflowIOValueTypeEnum, NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { getLafAppDetail } from '@/web/support/laf/api';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
@@ -32,6 +31,8 @@ import {
|
||||
} from '@fastgpt/global/core/workflow/type/io';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import IOTitle from '../components/IOTitle';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
|
||||
const LafAccountModal = dynamic(() => import('@/components/support/laf/LafAccountModal'));
|
||||
|
||||
@@ -42,7 +43,7 @@ const NodeLaf = (props: NodeProps<FlowNodeItemType>) => {
|
||||
const { data, selected } = props;
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const requestUrl = inputs.find((item) => item.key === NodeInputKeyEnum.httpReqUrl);
|
||||
|
||||
@@ -293,7 +294,7 @@ const ConfigLaf = () => {
|
||||
const RenderIO = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
const { splitToolInputs } = useFlowProviderStore();
|
||||
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||
const { commonInputs, toolInputs, isTool } = splitToolInputs(inputs, nodeId);
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useMemo, useState } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from './render/NodeCard';
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { Box, Button, Flex } from '@chakra-ui/react';
|
||||
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
@@ -17,7 +16,6 @@ import type {
|
||||
EditNodeFieldType
|
||||
} from '@fastgpt/global/core/workflow/node/type.d';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import {
|
||||
FlowNodeInputMap,
|
||||
@@ -26,6 +24,8 @@ import {
|
||||
} from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { FlowValueTypeMap } from '@/web/core/workflow/constants/dataType';
|
||||
import VariableTable from '../nodes/render/VariableTable';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
|
||||
const defaultCreateField: EditNodeFieldType = {
|
||||
label: '',
|
||||
@@ -50,7 +50,7 @@ const NodePluginInput = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const [createField, setCreateField] = useState<EditNodeFieldType>();
|
||||
const [editField, setEditField] = useState<EditNodeFieldType>();
|
||||
|
||||
@@ -11,8 +11,9 @@ import { EditInputFieldMapType, EditNodeFieldType } from '@fastgpt/global/core/w
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import RenderInput from './render/RenderInput';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
|
||||
const FieldEditModal = dynamic(() => import('./render/FieldEditModal'));
|
||||
|
||||
@@ -31,7 +32,7 @@ const createEditField: EditInputFieldMapType = {
|
||||
const NodePluginOutput = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, inputs } = data;
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const [createField, setCreateField] = useState<EditNodeFieldType>();
|
||||
|
||||
|
||||
@@ -7,9 +7,10 @@ import RenderInput from './render/RenderInput';
|
||||
import RenderOutput from './render/RenderOutput';
|
||||
import RenderToolInput from './render/RenderToolInput';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import IOTitle from '../components/IOTitle';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
|
||||
const NodeSimple = ({
|
||||
data,
|
||||
@@ -18,7 +19,7 @@ const NodeSimple = ({
|
||||
maxW
|
||||
}: NodeProps<FlowNodeItemType> & { minW?: string | number; maxW?: string | number }) => {
|
||||
const { t } = useTranslation();
|
||||
const { splitToolInputs } = useFlowProviderStore();
|
||||
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||
const { nodeId, inputs, outputs } = data;
|
||||
const { toolInputs, commonInputs } = splitToolInputs(inputs, nodeId);
|
||||
|
||||
|
||||
@@ -1,24 +1,31 @@
|
||||
import React, { useCallback, useMemo, useTransition } from 'react';
|
||||
import React, { useMemo, useTransition } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import { Box, Flex, Textarea, useTheme } from '@chakra-ui/react';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { FlowNodeItemType, StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { welcomeTextTip } from '@fastgpt/global/core/workflow/template/tip';
|
||||
|
||||
import type { VariableItemType } from '@fastgpt/global/core/app/type.d';
|
||||
import QGSwitch from '@/components/core/app/QGSwitch';
|
||||
import TTSSelect from '@/components/core/app/TTSSelect';
|
||||
import WhisperConfig from '@/components/core/app/WhisperConfig';
|
||||
import { splitGuideModule } from '@fastgpt/global/core/workflow/utils';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { TTSTypeEnum } from '@/constants/app';
|
||||
import { useFlowProviderStore } from '../FlowProvider';
|
||||
import VariableEdit from '../../../app/VariableEdit';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import NodeCard from './render/NodeCard';
|
||||
import ScheduledTriggerConfig from '@/components/core/app/ScheduledTriggerConfig';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
import { VariableItemType } from '@fastgpt/global/core/app/type';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import VariableEdit from '@/components/core/app/VariableEdit';
|
||||
import {
|
||||
FlowNodeOutputTypeEnum,
|
||||
FlowNodeTypeEnum
|
||||
} from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { FlowNodeOutputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||
|
||||
const NodeUserGuide = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const theme = useTheme();
|
||||
@@ -38,10 +45,10 @@ const NodeUserGuide = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
>
|
||||
<Box px={4} py={'10px'} position={'relative'} borderRadius={'md'} className="nodrag">
|
||||
<WelcomeText data={data} />
|
||||
<Box pt={4} pb={2}>
|
||||
<Box pt={4}>
|
||||
<ChatStartVariable data={data} />
|
||||
</Box>
|
||||
<Box pt={3} borderTop={theme.borders.base}>
|
||||
<Box mt={3} pt={3} borderTop={theme.borders.base}>
|
||||
<TTSGuide data={data} />
|
||||
</Box>
|
||||
<Box mt={3} pt={3} borderTop={theme.borders.base}>
|
||||
@@ -65,7 +72,7 @@ function WelcomeText({ data }: { data: FlowNodeItemType }) {
|
||||
const { t } = useTranslation();
|
||||
const { inputs, nodeId } = data;
|
||||
const [, startTst] = useTransition();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const welcomeText = inputs.find((item) => item.key === NodeInputKeyEnum.welcomeText);
|
||||
|
||||
@@ -108,7 +115,7 @@ function WelcomeText({ data }: { data: FlowNodeItemType }) {
|
||||
|
||||
function ChatStartVariable({ data }: { data: FlowNodeItemType }) {
|
||||
const { inputs, nodeId } = data;
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const variables = useMemo(
|
||||
() =>
|
||||
@@ -117,27 +124,25 @@ function ChatStartVariable({ data }: { data: FlowNodeItemType }) {
|
||||
[inputs]
|
||||
);
|
||||
|
||||
const updateVariables = useCallback(
|
||||
(value: VariableItemType[]) => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
key: NodeInputKeyEnum.variables,
|
||||
type: 'updateInput',
|
||||
value: {
|
||||
...inputs.find((item) => item.key === NodeInputKeyEnum.variables),
|
||||
value
|
||||
}
|
||||
});
|
||||
},
|
||||
[inputs, nodeId, onChangeNode]
|
||||
);
|
||||
const updateVariables = useMemoizedFn((value: VariableItemType[]) => {
|
||||
// update system config node
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
key: NodeInputKeyEnum.variables,
|
||||
type: 'updateInput',
|
||||
value: {
|
||||
...inputs.find((item) => item.key === NodeInputKeyEnum.variables),
|
||||
value
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return <VariableEdit variables={variables} onChange={(e) => updateVariables(e)} />;
|
||||
}
|
||||
|
||||
function QuestionGuide({ data }: { data: FlowNodeItemType }) {
|
||||
const { inputs, nodeId } = data;
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const questionGuide = useMemo(
|
||||
() =>
|
||||
@@ -168,7 +173,7 @@ function QuestionGuide({ data }: { data: FlowNodeItemType }) {
|
||||
|
||||
function TTSGuide({ data }: { data: FlowNodeItemType }) {
|
||||
const { inputs, nodeId } = data;
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const { ttsConfig } = splitGuideModule({ inputs } as StoreNodeItemType);
|
||||
|
||||
return (
|
||||
@@ -191,7 +196,7 @@ function TTSGuide({ data }: { data: FlowNodeItemType }) {
|
||||
|
||||
function WhisperGuide({ data }: { data: FlowNodeItemType }) {
|
||||
const { inputs, nodeId } = data;
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const { ttsConfig, whisperConfig } = splitGuideModule({ inputs } as StoreNodeItemType);
|
||||
|
||||
return (
|
||||
@@ -215,7 +220,7 @@ function WhisperGuide({ data }: { data: FlowNodeItemType }) {
|
||||
|
||||
function ScheduledTrigger({ data }: { data: FlowNodeItemType }) {
|
||||
const { inputs, nodeId } = data;
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const { scheduledTriggerConfig } = splitGuideModule({ inputs } as StoreNodeItemType);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeCard from './render/NodeCard';
|
||||
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
@@ -6,10 +6,30 @@ import Container from '../components/Container';
|
||||
import RenderOutput from './render/RenderOutput';
|
||||
import IOTitle from '../components/IOTitle';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../context';
|
||||
import { useCreation } from 'ahooks';
|
||||
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||
import { FlowNodeOutputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
|
||||
const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeId, outputs } = data;
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
const variablesOutputs = useCreation(() => {
|
||||
const variables = getWorkflowGlobalVariables(nodeList, t);
|
||||
|
||||
return variables.map<FlowNodeOutputItemType>((item) => ({
|
||||
id: item.key,
|
||||
type: FlowNodeOutputTypeEnum.static,
|
||||
key: item.key,
|
||||
valueType: item.valueType || WorkflowIOValueTypeEnum.any,
|
||||
label: item.label
|
||||
}));
|
||||
}, [nodeList, t]);
|
||||
|
||||
return (
|
||||
<NodeCard
|
||||
@@ -26,6 +46,10 @@ const NodeStart = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
|
||||
<IOTitle text={t('common.Output')} />
|
||||
<RenderOutput nodeId={nodeId} flowOutputList={outputs} />
|
||||
</Container>
|
||||
<Container>
|
||||
<IOTitle text={t('core.module.Variable')} />
|
||||
<RenderOutput nodeId={nodeId} flowOutputList={variablesOutputs} />
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Position } from 'reactflow';
|
||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
||||
import { SourceHandle, TargetHandle } from '.';
|
||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
|
||||
const { nodeList, edges, connectingEdge } = useFlowProviderStore();
|
||||
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||
|
||||
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
|
||||
|
||||
@@ -102,7 +105,8 @@ export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
|
||||
};
|
||||
|
||||
export const ConnectionTargetHandle = ({ nodeId }: { nodeId: string }) => {
|
||||
const { nodeList, connectingEdge } = useFlowProviderStore();
|
||||
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { FlowValueTypeMap } from '@/web/core/workflow/constants/dataType';
|
||||
import { Box, BoxProps } from '@chakra-ui/react';
|
||||
import {
|
||||
WorkflowIOValueTypeEnum,
|
||||
NodeOutputKeyEnum
|
||||
} from '@fastgpt/global/core/workflow/constants';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Connection, Handle, Position } from 'reactflow';
|
||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
const handleSize = '14px';
|
||||
|
||||
type ToolHandleProps = BoxProps & {
|
||||
@@ -17,7 +14,9 @@ type ToolHandleProps = BoxProps & {
|
||||
};
|
||||
export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { connectingEdge, edges } = useFlowProviderStore();
|
||||
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||
|
||||
const handleId = NodeOutputKeyEnum.selectedTools;
|
||||
|
||||
const connected = edges.some((edge) => edge.target === nodeId && edge.targetHandle === handleId);
|
||||
@@ -62,7 +61,7 @@ export const ToolTargetHandle = ({ nodeId }: ToolHandleProps) => {
|
||||
|
||||
export const ToolSourceHandle = ({ nodeId }: ToolHandleProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { setEdges } = useFlowProviderStore();
|
||||
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||
|
||||
/* onConnect edge, delete tool input and switch */
|
||||
const onConnect = useCallback(
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Handle, Position } from 'reactflow';
|
||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
||||
import { SmallAddIcon } from '@chakra-ui/icons';
|
||||
import { handleHighLightStyle, sourceCommonStyle, handleConnectedStyle, handleSize } from './style';
|
||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
type Props = {
|
||||
nodeId: string;
|
||||
@@ -23,7 +24,11 @@ const MySourceHandle = React.memo(function MySourceHandle({
|
||||
highlightStyle: Record<string, any>;
|
||||
connectedStyle: Record<string, any>;
|
||||
}) {
|
||||
const { nodes, hoverNodeId, edges, connectingEdge } = useFlowProviderStore();
|
||||
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||
|
||||
const nodes = useContextSelector(WorkflowContext, (v) => v.nodes);
|
||||
const hoverNodeId = useContextSelector(WorkflowContext, (v) => v.hoverNodeId);
|
||||
|
||||
const node = useMemo(() => nodes.find((node) => node.data.nodeId === nodeId), [nodes, nodeId]);
|
||||
const connected = edges.some((edge) => edge.sourceHandle === handleId);
|
||||
@@ -136,8 +141,10 @@ const MyTargetHandle = React.memo(function MyTargetHandle({
|
||||
highlightStyle: Record<string, any>;
|
||||
connectedStyle: Record<string, any>;
|
||||
}) {
|
||||
const { nodeList, edges, connectingEdge } = useFlowProviderStore();
|
||||
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
|
||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
|
||||
const connected = edges.some((edge) => edge.targetHandle === handleId);
|
||||
const connectedEdges = edges.filter((edge) => edge.target === nodeId);
|
||||
@@ -194,12 +201,13 @@ const MyTargetHandle = React.memo(function MyTargetHandle({
|
||||
return false;
|
||||
}
|
||||
if (connectingEdge?.handleId && !connectingEdge.handleId?.includes('source')) return false;
|
||||
// Same source node
|
||||
|
||||
if (connectedEdges.some((item) => item.sourceHandle === connectingEdge?.handleId)) return false;
|
||||
// Same source node
|
||||
if (connectedEdges.some((item) => item.target === nodeId && item.targetHandle !== handleId))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}, [connectedEdges, connectingEdge?.handleId, edges, node, nodeId]);
|
||||
}, [connectedEdges, connectingEdge?.handleId, edges, handleId, node, nodeId]);
|
||||
|
||||
const RenderHandle = useMemo(() => {
|
||||
return (
|
||||
|
||||
@@ -6,7 +6,6 @@ import type { FlowNodeItemType } from '@fastgpt/global/core/workflow/type/index.
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useEditTitle } from '@/web/common/hooks/useEditTitle';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useFlowProviderStore } from '../../FlowProvider';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
@@ -21,6 +20,8 @@ import { getPreviewPluginModule } from '@/web/core/plugin/api';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { storeNode2FlowNode } from '@/web/core/workflow/utils';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '../../../context';
|
||||
|
||||
type Props = FlowNodeItemType & {
|
||||
children?: React.ReactNode | React.ReactNode[] | string;
|
||||
@@ -55,7 +56,9 @@ const NodeCard = (props: Props) => {
|
||||
pluginId
|
||||
} = props;
|
||||
|
||||
const { nodeList, setHoverNodeId, onUpdateNodeError } = useFlowProviderStore();
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const setHoverNodeId = useContextSelector(WorkflowContext, (v) => v.setHoverNodeId);
|
||||
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
||||
|
||||
const showToolHandle = useMemo(
|
||||
() => isTool && !!nodeList.find((item) => item?.flowNodeType === FlowNodeTypeEnum.tools),
|
||||
@@ -105,44 +108,40 @@ const NodeCard = (props: Props) => {
|
||||
intro
|
||||
]);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
<Box
|
||||
minW={minW}
|
||||
maxW={maxW}
|
||||
bg={'white'}
|
||||
borderWidth={'1px'}
|
||||
borderRadius={'md'}
|
||||
boxShadow={'1'}
|
||||
_hover={{
|
||||
boxShadow: '4',
|
||||
'& .controller-menu': {
|
||||
display: 'flex'
|
||||
},
|
||||
'& .controller-debug': {
|
||||
display: 'block'
|
||||
return (
|
||||
<Box
|
||||
minW={minW}
|
||||
maxW={maxW}
|
||||
bg={'white'}
|
||||
borderWidth={'1px'}
|
||||
borderRadius={'md'}
|
||||
boxShadow={'1'}
|
||||
_hover={{
|
||||
boxShadow: '4',
|
||||
'& .controller-menu': {
|
||||
display: 'flex'
|
||||
},
|
||||
'& .controller-debug': {
|
||||
display: 'block'
|
||||
}
|
||||
}}
|
||||
onMouseEnter={() => setHoverNodeId(nodeId)}
|
||||
onMouseLeave={() => setHoverNodeId(undefined)}
|
||||
{...(isError
|
||||
? {
|
||||
borderColor: 'red.500',
|
||||
onMouseDownCapture: () => onUpdateNodeError(nodeId, false)
|
||||
}
|
||||
}}
|
||||
onMouseEnter={() => setHoverNodeId(nodeId)}
|
||||
onMouseLeave={() => setHoverNodeId(undefined)}
|
||||
{...(isError
|
||||
? {
|
||||
borderColor: 'red.500',
|
||||
onMouseDownCapture: () => onUpdateNodeError(nodeId, false)
|
||||
}
|
||||
: {
|
||||
borderColor: selected ? 'primary.600' : 'borderColor.base'
|
||||
})}
|
||||
>
|
||||
{Header}
|
||||
{children}
|
||||
<ConnectionSourceHandle nodeId={nodeId} />
|
||||
<ConnectionTargetHandle nodeId={nodeId} />
|
||||
</Box>
|
||||
);
|
||||
}, [Header, children, isError, maxW, minW, nodeId, onUpdateNodeError, selected, setHoverNodeId]);
|
||||
|
||||
return Render;
|
||||
: {
|
||||
borderColor: selected ? 'primary.600' : 'borderColor.base'
|
||||
})}
|
||||
>
|
||||
{Header}
|
||||
{children}
|
||||
<ConnectionSourceHandle nodeId={nodeId} />
|
||||
<ConnectionTargetHandle nodeId={nodeId} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(NodeCard);
|
||||
@@ -180,7 +179,10 @@ const MenuRender = React.memo(function MenuRender({
|
||||
type: 'delete'
|
||||
});
|
||||
|
||||
const { setNodes, setEdges, onResetNode, onChangeNode } = useFlowProviderStore();
|
||||
const setNodes = useContextSelector(WorkflowContext, (v) => v.setNodes);
|
||||
const onResetNode = useContextSelector(WorkflowContext, (v) => v.onResetNode);
|
||||
const setEdges = useContextSelector(WorkflowContext, (v) => v.setEdges);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const onCopyNode = useCallback(
|
||||
(nodeId: string) => {
|
||||
@@ -383,7 +385,8 @@ const NodeIntro = React.memo(function NodeIntro({
|
||||
intro?: string;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode, splitToolInputs } = useFlowProviderStore();
|
||||
const splitToolInputs = useContextSelector(WorkflowContext, (ctx) => ctx.splitToolInputs);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const moduleIsTool = useMemo(() => {
|
||||
const { isTool } = splitToolInputs([], nodeId);
|
||||
@@ -442,8 +445,12 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
||||
debugResult: FlowNodeItemType['debugResult'];
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode, onStopNodeDebug, onNextNodeDebug, workflowDebugData } =
|
||||
useFlowProviderStore();
|
||||
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const onStopNodeDebug = useContextSelector(WorkflowContext, (v) => v.onStopNodeDebug);
|
||||
const onNextNodeDebug = useContextSelector(WorkflowContext, (v) => v.onNextNodeDebug);
|
||||
const workflowDebugData = useContextSelector(WorkflowContext, (v) => v.workflowDebugData);
|
||||
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: t('core.workflow.Confirm stop debug')
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
@@ -13,17 +12,20 @@ import dynamic from 'next/dynamic';
|
||||
import { EditNodeFieldType } from '@fastgpt/global/core/workflow/node/type';
|
||||
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import ValueTypeLabel from '../ValueTypeLabel';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
const FieldEditModal = dynamic(() => import('../FieldEditModal'));
|
||||
|
||||
type Props = {
|
||||
nodeId: string;
|
||||
input: FlowNodeInputItemType;
|
||||
mode?: 'app' | 'plugin';
|
||||
};
|
||||
|
||||
const InputLabel = ({ nodeId, input }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const {
|
||||
description,
|
||||
toolDescription,
|
||||
|
||||
@@ -5,18 +5,21 @@ import { SmallAddIcon } from '@chakra-ui/icons';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { EditNodeFieldType } from '@fastgpt/global/core/workflow/node/type';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
|
||||
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||
import Reference from './Reference';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const FieldEditModal = dynamic(() => import('../../FieldEditModal'));
|
||||
|
||||
const AddInputParam = (props: RenderInputProps) => {
|
||||
const { item, inputs, nodeId } = props;
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode, mode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const mode = useContextSelector(WorkflowContext, (ctx) => ctx.mode);
|
||||
|
||||
const inputValue = useMemo(() => (item.value || []) as FlowNodeInputItemType[], [item.value]);
|
||||
|
||||
const [editField, setEditField] = useState<EditNodeFieldType>();
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import JSONEditor from '@fastgpt/web/components/common/Textarea/JsonEditor';
|
||||
import {
|
||||
formatEditorVariablePickerIcon,
|
||||
getGuideModule,
|
||||
splitGuideModule
|
||||
} from '@fastgpt/global/core/workflow/utils';
|
||||
import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/workflow/utils';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||
import { useCreation } from 'ahooks';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
const JsonEditor = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
||||
const { t } = useTranslation();
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
// get variable
|
||||
const variables = useMemo(() => {
|
||||
const globalVariables = formatEditorVariablePickerIcon(
|
||||
splitGuideModule(getGuideModule(nodeList))?.variableModules || []
|
||||
);
|
||||
const variables = useCreation(() => {
|
||||
const globalVariables = getWorkflowGlobalVariables(nodeList, t);
|
||||
|
||||
const moduleVariables = formatEditorVariablePickerIcon(
|
||||
inputs
|
||||
.filter((input) => input.canEdit)
|
||||
|
||||
@@ -7,10 +7,11 @@ import {
|
||||
NumberInputField,
|
||||
NumberInputStepper
|
||||
} from '@chakra-ui/react';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const NumberInputRender = ({ item, nodeId }: RenderInputProps) => {
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { Flex, Box, ButtonProps } from '@chakra-ui/react';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { computedNodeInputReference } from '@/web/core/workflow/utils';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import {
|
||||
NodeOutputKeyEnum,
|
||||
VARIABLE_NODE_ID,
|
||||
WorkflowIOValueTypeEnum
|
||||
} from '@fastgpt/global/core/workflow/constants';
|
||||
import type { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
|
||||
const MultipleRowSelect = dynamic(
|
||||
() => import('@fastgpt/web/components/common/MySelect/MultipleRowSelect')
|
||||
@@ -34,21 +37,37 @@ type SelectProps = {
|
||||
|
||||
const Reference = ({ item, nodeId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
const onSelect = useCallback(
|
||||
(e: any) => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
const workflowStartNode = nodeList.find(
|
||||
(node) => node.flowNodeType === FlowNodeTypeEnum.workflowStart
|
||||
);
|
||||
if (e[0] === workflowStartNode?.id && e[1] !== NodeOutputKeyEnum.userChatInput) {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: [VARIABLE_NODE_ID, e[1]]
|
||||
}
|
||||
});
|
||||
} else {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'updateInput',
|
||||
key: item.key,
|
||||
value: {
|
||||
...item,
|
||||
value: e
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
[item, nodeId, onChangeNode]
|
||||
[item, nodeId, nodeList, onChangeNode]
|
||||
);
|
||||
|
||||
const { referenceList, formatValue } = useReference({
|
||||
@@ -79,13 +98,15 @@ export const useReference = ({
|
||||
value?: any;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeList, edges } = useFlowProviderStore();
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
|
||||
|
||||
const referenceList = useMemo(() => {
|
||||
const sourceNodes = computedNodeInputReference({
|
||||
nodeId,
|
||||
nodes: nodeList,
|
||||
edges: edges
|
||||
edges: edges,
|
||||
t
|
||||
});
|
||||
|
||||
if (!sourceNodes) return [];
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
|
||||
const SelectRender = ({ item, nodeId }: RenderInputProps) => {
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { Box, Button, Flex, useDisclosure, useTheme } from '@chakra-ui/react';
|
||||
import { SelectAppItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import SelectAppModal from '../../../../SelectAppModal';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const SelectAppRender = ({ item, nodeId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { filterAppIds, onChangeNode } = useFlowProviderStore();
|
||||
const filterAppIds = useContextSelector(WorkflowContext, (ctx) => ctx.filterAppIds);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const {
|
||||
isOpen: isOpenSelectApp,
|
||||
@@ -20,7 +22,7 @@ const SelectAppRender = ({ item, nodeId }: RenderInputProps) => {
|
||||
|
||||
const value = item.value as SelectAppItemType | undefined;
|
||||
|
||||
const filterAppString = useMemo(() => filterAppIds.join(','), [filterAppIds]);
|
||||
const filterAppString = useMemo(() => filterAppIds?.join(',') || '', [filterAppIds]);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { Box, Button, Flex, Grid, useDisclosure, useTheme } from '@chakra-ui/react';
|
||||
import { useDatasetStore } from '@/web/core/dataset/store/dataset';
|
||||
import { SelectedDatasetType } from '@fastgpt/global/core/workflow/api';
|
||||
@@ -8,19 +7,19 @@ import Avatar from '@/components/Avatar';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
|
||||
|
||||
const SelectDatasetRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const [data, setData] = useState({
|
||||
searchMode: DatasetSearchModeEnum.embedding,
|
||||
limit: 5,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { Box, Button, Flex, useDisclosure } from '@chakra-ui/react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { DatasetSearchModeEnum } from '@fastgpt/global/core/dataset/constants';
|
||||
@@ -10,9 +9,13 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import DatasetParamsModal, { DatasetParamsProps } from '@/components/core/app/DatasetParamsModal';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import SearchParamsTip from '@/components/core/dataset/SearchParamsTip';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const SelectDatasetParam = ({ inputs = [], nodeId }: RenderInputProps) => {
|
||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { llmModelList } = useSystemStore();
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@ import type { RenderInputProps } from '../type';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import { llmModelTypeFilterMap } from '@fastgpt/global/core/ai/constants';
|
||||
import AIModelSelector from '@/components/Select/AIModelSelector';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const SelectAiModelRender = ({ item, nodeId }: RenderInputProps) => {
|
||||
const { llmModelList } = useSystemStore();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const modelList = useMemo(
|
||||
() =>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import type { SettingAIDataType } from '@fastgpt/global/core/app/type.d';
|
||||
import SettingLLMModel from '@/components/core/ai/SettingLLMModel';
|
||||
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const SelectAiModelRender = ({ item, inputs = [], nodeId }: RenderInputProps) => {
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const onChangeModel = useCallback(
|
||||
(e: SettingAIDataType) => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { Box, BoxProps, Button, Flex, ModalFooter, useDisclosure } from '@chakra-ui/react';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import MyModal from '@fastgpt/web/components/common/MyModal';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { PromptTemplateItem } from '@fastgpt/global/core/ai/type';
|
||||
@@ -25,6 +24,10 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import Reference from './Reference';
|
||||
import { getSystemVariables } from '@/web/core/app/utils';
|
||||
import ValueTypeLabel from '../../ValueTypeLabel';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||
import { useCreation } from 'ahooks';
|
||||
|
||||
const LabelStyles: BoxProps = {
|
||||
fontSize: ['sm', 'md']
|
||||
@@ -38,7 +41,9 @@ const SettingQuotePrompt = (props: RenderInputProps) => {
|
||||
const { inputs = [], nodeId } = props;
|
||||
const { t } = useTranslation();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
|
||||
const { watch, setValue, handleSubmit } = useForm({
|
||||
defaultValues: {
|
||||
quoteTemplate: inputs.find((input) => input.key === 'quoteTemplate')?.value || '',
|
||||
@@ -48,14 +53,10 @@ const SettingQuotePrompt = (props: RenderInputProps) => {
|
||||
const aiChatQuoteTemplate = watch('quoteTemplate');
|
||||
const aiChatQuotePrompt = watch('quotePrompt');
|
||||
|
||||
const variables = useMemo(() => {
|
||||
const globalVariables = formatEditorVariablePickerIcon(
|
||||
splitGuideModule(getGuideModule(nodeList))?.variableModules || []
|
||||
);
|
||||
const variables = useCreation(() => {
|
||||
const globalVariables = getWorkflowGlobalVariables(nodeList, t);
|
||||
|
||||
const systemVariables = getSystemVariables(t);
|
||||
|
||||
return [...globalVariables, ...systemVariables];
|
||||
return globalVariables;
|
||||
}, [nodeList, t]);
|
||||
|
||||
const [selectTemplateData, setSelectTemplateData] = useState<{
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import MySlider from '@/components/Slider';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const SliderRender = ({ item, nodeId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { Switch } from '@chakra-ui/react';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const SwitchRender = ({ item, nodeId }: RenderInputProps) => {
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { Input } from '@chakra-ui/react';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const TextInput = ({ item, nodeId }: RenderInputProps) => {
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const Render = useMemo(() => {
|
||||
return (
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import type { RenderInputProps } from '../type';
|
||||
import { useFlowProviderStore } from '../../../../FlowProvider';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
|
||||
import {
|
||||
formatEditorVariablePickerIcon,
|
||||
getGuideModule,
|
||||
splitGuideModule
|
||||
} from '@fastgpt/global/core/workflow/utils';
|
||||
import { getSystemVariables } from '@/web/core/app/utils';
|
||||
import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/workflow/utils';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
import { getWorkflowGlobalVariables } from '@/web/core/workflow/utils';
|
||||
import { useCreation } from 'ahooks';
|
||||
|
||||
const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { nodeList, onChangeNode } = useFlowProviderStore();
|
||||
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
// get variable
|
||||
const variables = useMemo(() => {
|
||||
const globalVariables = formatEditorVariablePickerIcon(
|
||||
splitGuideModule(getGuideModule(nodeList))?.variableModules || []
|
||||
);
|
||||
const variables = useCreation(() => {
|
||||
const globalVariables = getWorkflowGlobalVariables(nodeList, t);
|
||||
|
||||
const moduleVariables = formatEditorVariablePickerIcon(
|
||||
inputs
|
||||
.filter((input) => input.canEdit)
|
||||
@@ -28,9 +26,7 @@ const TextareaRender = ({ inputs = [], item, nodeId }: RenderInputProps) => {
|
||||
}))
|
||||
);
|
||||
|
||||
const systemVariables = getSystemVariables(t);
|
||||
|
||||
return [...globalVariables, ...moduleVariables, ...systemVariables];
|
||||
return [...globalVariables, ...moduleVariables];
|
||||
}, [nodeList, inputs, t]);
|
||||
|
||||
const onChange = useCallback(
|
||||
|
||||
@@ -11,7 +11,8 @@ import VariableTable from '../VariableTable';
|
||||
import { EditNodeFieldType } from '@fastgpt/global/core/workflow/node/type';
|
||||
import { FlowValueTypeMap } from '@/web/core/workflow/constants/dataType';
|
||||
import { getNanoid } from '@fastgpt/global/common/string/tools';
|
||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const RenderList: {
|
||||
types: `${FlowNodeOutputTypeEnum}`[];
|
||||
@@ -26,7 +27,7 @@ const RenderOutput = ({
|
||||
flowOutputList: FlowNodeOutputItemType[];
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const outputString = useMemo(() => JSON.stringify(flowOutputList), [flowOutputList]);
|
||||
const copyOutputs = useMemo(() => {
|
||||
|
||||
@@ -17,8 +17,9 @@ import { defaultEditFormData } from './constants';
|
||||
import MySelect from '@fastgpt/web/components/common/MySelect';
|
||||
import { useRequest } from '@fastgpt/web/hooks/useRequest';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
|
||||
const EditFieldModal = ({
|
||||
defaultValue = defaultEditFormData,
|
||||
@@ -27,7 +28,7 @@ const EditFieldModal = ({
|
||||
}: EditFieldModalProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const { register, setValue, handleSubmit, watch } = useForm<FlowNodeInputItemType>({
|
||||
defaultValues: defaultValue
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import type {
|
||||
FlowNodeInputItemType,
|
||||
FlowNodeOutputItemType
|
||||
@@ -19,7 +19,8 @@ import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { defaultEditFormData } from './constants';
|
||||
import { useFlowProviderStore } from '../../../FlowProvider';
|
||||
import { useContextSelector } from 'use-context-selector';
|
||||
import { WorkflowContext } from '@/components/core/workflow/context';
|
||||
const EditFieldModal = dynamic(() => import('./EditFieldModal'));
|
||||
|
||||
const RenderToolInput = ({
|
||||
@@ -32,8 +33,9 @@ const RenderToolInput = ({
|
||||
canEdit?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { onChangeNode } = useFlowProviderStore();
|
||||
const [editField, setEditField] = React.useState<FlowNodeInputItemType>();
|
||||
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
|
||||
|
||||
const [editField, setEditField] = useState<FlowNodeInputItemType>();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,58 +1,89 @@
|
||||
import {
|
||||
type Node,
|
||||
type NodeChange,
|
||||
type Edge,
|
||||
type EdgeChange,
|
||||
useNodesState,
|
||||
useEdgesState,
|
||||
OnConnectStartParams
|
||||
} from 'reactflow';
|
||||
import type {
|
||||
FlowNodeItemType,
|
||||
FlowNodeTemplateType
|
||||
} from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import type { FlowNodeChangeProps } from '@fastgpt/global/core/workflow/type/fe.d';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io.d';
|
||||
import React, {
|
||||
type SetStateAction,
|
||||
type Dispatch,
|
||||
useContext,
|
||||
useCallback,
|
||||
createContext,
|
||||
useRef,
|
||||
useMemo,
|
||||
useState,
|
||||
useEffect
|
||||
} from 'react';
|
||||
import { storeEdgesRenderEdge, storeNode2FlowNode } from '@/web/core/workflow/utils';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { NodeOutputKeyEnum, RuntimeEdgeStatusEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/index.d';
|
||||
import { RuntimeEdgeItemType, StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||
import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import { defaultRunningStatus } from '../constants';
|
||||
import { postWorkflowDebug } from '@/web/core/workflow/api';
|
||||
import { storeEdgesRenderEdge, storeNode2FlowNode } from '@/web/core/workflow/utils';
|
||||
import { getErrText } from '@fastgpt/global/common/error/utils';
|
||||
import { NodeOutputKeyEnum, RuntimeEdgeStatusEnum } from '@fastgpt/global/core/workflow/constants';
|
||||
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
|
||||
import { RuntimeNodeItemType } from '@fastgpt/global/core/workflow/runtime/type';
|
||||
import {
|
||||
FlowNodeItemType,
|
||||
FlowNodeTemplateType,
|
||||
StoreNodeItemType
|
||||
} from '@fastgpt/global/core/workflow/type';
|
||||
import { RuntimeEdgeItemType, StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||
import { FlowNodeChangeProps } from '@fastgpt/global/core/workflow/type/fe';
|
||||
import { FlowNodeInputItemType } from '@fastgpt/global/core/workflow/type/io';
|
||||
import { useToast } from '@fastgpt/web/hooks/useToast';
|
||||
import { useCreation, useMemoizedFn } from 'ahooks';
|
||||
import React, {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState
|
||||
} from 'react';
|
||||
import {
|
||||
Edge,
|
||||
EdgeChange,
|
||||
Node,
|
||||
NodeChange,
|
||||
OnConnectStartParams,
|
||||
useEdgesState,
|
||||
useNodesState
|
||||
} from 'reactflow';
|
||||
import { createContext } from 'use-context-selector';
|
||||
import { defaultRunningStatus } from './constants';
|
||||
import { checkNodeRunStatus } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||
import { EventNameEnum, eventBus } from '@/web/common/utils/eventbus';
|
||||
import { delay } from '@fastgpt/global/common/system/utils';
|
||||
|
||||
type OnChange<ChangesType> = (changes: ChangesType[]) => void;
|
||||
|
||||
export type useFlowProviderStoreType = {
|
||||
// connect
|
||||
connectingEdge: OnConnectStartParams | undefined;
|
||||
setConnectingEdge: React.Dispatch<React.SetStateAction<OnConnectStartParams | undefined>>;
|
||||
// nodes
|
||||
basicNodeTemplates: FlowNodeTemplateType[];
|
||||
reactFlowWrapper: null | React.RefObject<HTMLDivElement>;
|
||||
type WorkflowContextType = {
|
||||
mode: 'app' | 'plugin';
|
||||
filterAppIds: string[];
|
||||
basicNodeTemplates: FlowNodeTemplateType[];
|
||||
filterAppIds?: string[];
|
||||
reactFlowWrapper: React.RefObject<HTMLDivElement> | null;
|
||||
|
||||
// nodes
|
||||
nodes: Node<FlowNodeItemType, string | undefined>[];
|
||||
nodeList: FlowNodeItemType[];
|
||||
setNodes: Dispatch<SetStateAction<Node<FlowNodeItemType, string | undefined>[]>>;
|
||||
onNodesChange: OnChange<NodeChange>;
|
||||
hasToolNode: boolean;
|
||||
hoverNodeId?: string;
|
||||
setHoverNodeId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
onUpdateNodeError: (node: string, isError: Boolean) => void;
|
||||
onResetNode: (e: { id: string; module: FlowNodeTemplateType }) => void;
|
||||
onChangeNode: (e: FlowNodeChangeProps) => void;
|
||||
|
||||
// edges
|
||||
edges: Edge<any>[];
|
||||
setEdges: Dispatch<SetStateAction<Edge<any>[]>>;
|
||||
onEdgesChange: OnChange<EdgeChange>;
|
||||
onDelEdge: (e: {
|
||||
nodeId: string;
|
||||
sourceHandle?: string | undefined;
|
||||
targetHandle?: string | undefined;
|
||||
}) => void;
|
||||
|
||||
// connect
|
||||
connectingEdge?: OnConnectStartParams;
|
||||
setConnectingEdge: React.Dispatch<React.SetStateAction<OnConnectStartParams | undefined>>;
|
||||
|
||||
// common function
|
||||
onFixView: () => void;
|
||||
splitToolInputs: (
|
||||
inputs: FlowNodeInputItemType[],
|
||||
nodeId: string
|
||||
) => {
|
||||
isTool: boolean;
|
||||
toolInputs: FlowNodeInputItemType[];
|
||||
commonInputs: FlowNodeInputItemType[];
|
||||
};
|
||||
initData: (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => Promise<void>;
|
||||
|
||||
// debug
|
||||
// debug
|
||||
workflowDebugData:
|
||||
| {
|
||||
@@ -72,67 +103,66 @@ export type useFlowProviderStoreType = {
|
||||
runtimeEdges: RuntimeEdgeItemType[];
|
||||
}) => Promise<void>;
|
||||
onStopNodeDebug: () => void;
|
||||
|
||||
edges: Edge<any>[];
|
||||
setEdges: Dispatch<SetStateAction<Edge<any>[]>>;
|
||||
onEdgesChange: OnChange<EdgeChange>;
|
||||
onFixView: () => void;
|
||||
onChangeNode: (e: FlowNodeChangeProps) => void;
|
||||
onResetNode: (e: { id: string; module: FlowNodeTemplateType }) => void;
|
||||
onDelEdge: (e: {
|
||||
nodeId: string;
|
||||
sourceHandle?: string | undefined;
|
||||
targetHandle?: string | undefined;
|
||||
}) => void;
|
||||
initData: (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => Promise<void>;
|
||||
splitToolInputs: (
|
||||
inputs: FlowNodeInputItemType[],
|
||||
nodeId: string
|
||||
) => {
|
||||
isTool: boolean;
|
||||
toolInputs: FlowNodeInputItemType[];
|
||||
commonInputs: FlowNodeInputItemType[];
|
||||
};
|
||||
hasToolNode: boolean;
|
||||
hoverNodeId: string | undefined;
|
||||
setHoverNodeId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
onUpdateNodeError: (node: string, isError: Boolean) => void;
|
||||
};
|
||||
|
||||
const StateContext = createContext<useFlowProviderStoreType>({
|
||||
reactFlowWrapper: null,
|
||||
type ContextValueProps = Pick<
|
||||
WorkflowContextType,
|
||||
'mode' | 'basicNodeTemplates' | 'filterAppIds'
|
||||
> & {
|
||||
appId?: string;
|
||||
pluginId?: string;
|
||||
};
|
||||
|
||||
type DebugDataType = {
|
||||
runtimeNodes: RuntimeNodeItemType[];
|
||||
runtimeEdges: RuntimeEdgeItemType[];
|
||||
nextRunNodes: RuntimeNodeItemType[];
|
||||
};
|
||||
|
||||
export const WorkflowContext = createContext<WorkflowContextType>({
|
||||
mode: 'app',
|
||||
filterAppIds: [],
|
||||
setConnectingEdge: function (
|
||||
value: React.SetStateAction<OnConnectStartParams | undefined>
|
||||
): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
onFixView: function (): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
basicNodeTemplates: [],
|
||||
reactFlowWrapper: null,
|
||||
nodes: [],
|
||||
nodeList: [],
|
||||
setNodes: function (
|
||||
value: React.SetStateAction<Node<FlowNodeItemType, string | undefined>[]>
|
||||
): void {
|
||||
return;
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
onNodesChange: function (changes: NodeChange[]): void {
|
||||
return;
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
hasToolNode: false,
|
||||
setHoverNodeId: function (value: React.SetStateAction<string | undefined>): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
onUpdateNodeError: function (node: string, isError: Boolean): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
edges: [],
|
||||
setEdges: function (value: React.SetStateAction<Edge<any>[]>): void {
|
||||
return;
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
onEdgesChange: function (changes: EdgeChange[]): void {
|
||||
return;
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
onFixView: function (): void {
|
||||
return;
|
||||
},
|
||||
onChangeNode: function (e: FlowNodeChangeProps): void {
|
||||
return;
|
||||
onResetNode: function (e: { id: string; module: FlowNodeTemplateType }): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
onDelEdge: function (e: {
|
||||
nodeId: string;
|
||||
sourceHandle?: string | undefined;
|
||||
targetHandle?: string | undefined;
|
||||
}): void {
|
||||
return;
|
||||
},
|
||||
onResetNode: function (e): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
splitToolInputs: function (
|
||||
@@ -145,23 +175,12 @@ const StateContext = createContext<useFlowProviderStoreType>({
|
||||
} {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
hasToolNode: false,
|
||||
connectingEdge: undefined,
|
||||
basicNodeTemplates: [],
|
||||
initData: function (e: {
|
||||
nodes: StoreNodeItemType[];
|
||||
edges: StoreEdgeItemType[];
|
||||
}): Promise<void> {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
hoverNodeId: undefined,
|
||||
setHoverNodeId: function (value: React.SetStateAction<string | undefined>): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
onUpdateNodeError: function (nodeId: string, isError: Boolean): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
nodeList: [],
|
||||
workflowDebugData: undefined,
|
||||
onNextNodeDebug: function (): Promise<void> {
|
||||
throw new Error('Function not implemented.');
|
||||
@@ -180,55 +199,24 @@ const StateContext = createContext<useFlowProviderStoreType>({
|
||||
onStopNodeDebug: function (): void {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
setConnectingEdge: function (
|
||||
value: React.SetStateAction<OnConnectStartParams | undefined>
|
||||
): void {
|
||||
onChangeNode: function (e: FlowNodeChangeProps): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}
|
||||
});
|
||||
export const useFlowProviderStore = () => useContext(StateContext);
|
||||
|
||||
export const FlowProvider = ({
|
||||
mode,
|
||||
basicNodeTemplates = [],
|
||||
filterAppIds = [],
|
||||
const WorkflowContextProvider = ({
|
||||
children,
|
||||
appId,
|
||||
pluginId
|
||||
value
|
||||
}: {
|
||||
mode: useFlowProviderStoreType['mode'];
|
||||
basicNodeTemplates: FlowNodeTemplateType[];
|
||||
filterAppIds?: string[];
|
||||
children: React.ReactNode;
|
||||
appId?: string;
|
||||
pluginId?: string;
|
||||
value: ContextValueProps;
|
||||
}) => {
|
||||
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
||||
const { appId, pluginId } = value;
|
||||
const { toast } = useToast();
|
||||
const [nodes = [], setNodes, onNodesChange] = useNodesState<FlowNodeItemType>([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
const [hoverNodeId, setHoverNodeId] = useState<string>();
|
||||
const [connectingEdge, setConnectingEdge] = useState<OnConnectStartParams>();
|
||||
|
||||
const stringifyNodes = useMemo(() => JSON.stringify(nodes.map((node) => node.data)), [nodes]);
|
||||
const nodeList = useMemo(
|
||||
() => JSON.parse(stringifyNodes) as FlowNodeItemType[],
|
||||
[stringifyNodes]
|
||||
);
|
||||
|
||||
const hasToolNode = useMemo(() => {
|
||||
return !!nodes.find((node) => node.data.flowNodeType === FlowNodeTypeEnum.tools);
|
||||
}, [nodes]);
|
||||
|
||||
const onFixView = useCallback(() => {
|
||||
const btn = document.querySelector('.custom-workflow-fix_view') as HTMLButtonElement;
|
||||
|
||||
setTimeout(() => {
|
||||
btn && btn.click();
|
||||
}, 100);
|
||||
}, []);
|
||||
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
||||
|
||||
/* edge */
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
const onDelEdge = useCallback(
|
||||
({
|
||||
nodeId,
|
||||
@@ -252,9 +240,34 @@ export const FlowProvider = ({
|
||||
[setEdges]
|
||||
);
|
||||
|
||||
/* connect */
|
||||
const [connectingEdge, setConnectingEdge] = useState<OnConnectStartParams>();
|
||||
|
||||
/* node */
|
||||
const [nodes = [], setNodes, onNodesChange] = useNodesState<FlowNodeItemType>([]);
|
||||
const [hoverNodeId, setHoverNodeId] = useState<string>();
|
||||
|
||||
const nodeList = useCreation(() => nodes.map((node) => node.data), [nodes]);
|
||||
|
||||
const hasToolNode = useMemo(() => {
|
||||
return !!nodes.find((node) => node.data.flowNodeType === FlowNodeTypeEnum.tools);
|
||||
}, [nodes]);
|
||||
|
||||
const onUpdateNodeError = useMemoizedFn((nodeId: string, isError: Boolean) => {
|
||||
setNodes((nodes) => {
|
||||
return nodes.map((item) => {
|
||||
if (item.data?.nodeId === nodeId) {
|
||||
item.selected = true;
|
||||
//@ts-ignore
|
||||
item.data.isError = isError;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// reset a node data. delete edge and replace it
|
||||
const onResetNode = useCallback(
|
||||
const onResetNode = useMemoizedFn(
|
||||
({ id, module }: { id: string; module: FlowNodeTemplateType }) => {
|
||||
setNodes((state) =>
|
||||
state.map((node) => {
|
||||
@@ -277,131 +290,142 @@ export const FlowProvider = ({
|
||||
return node;
|
||||
})
|
||||
);
|
||||
},
|
||||
[onDelEdge, setNodes]
|
||||
}
|
||||
);
|
||||
const onChangeNode = useCallback(
|
||||
(props: FlowNodeChangeProps) => {
|
||||
const { nodeId, type } = props;
|
||||
setNodes((nodes) =>
|
||||
nodes.map((node) => {
|
||||
if (node.id !== nodeId) return node;
|
||||
|
||||
const updateObj: Record<string, any> = {};
|
||||
const onChangeNode = useMemoizedFn((props: FlowNodeChangeProps) => {
|
||||
const { nodeId, type } = props;
|
||||
setNodes((nodes) =>
|
||||
nodes.map((node) => {
|
||||
if (node.id !== nodeId) return node;
|
||||
|
||||
if (type === 'attr') {
|
||||
if (props.key) {
|
||||
updateObj[props.key] = props.value;
|
||||
}
|
||||
} else if (type === 'updateInput') {
|
||||
updateObj.inputs = node.data.inputs.map((item) =>
|
||||
item.key === props.key ? props.value : item
|
||||
);
|
||||
} else if (type === 'replaceInput') {
|
||||
onDelEdge({ nodeId, targetHandle: props.key });
|
||||
const oldInputIndex = node.data.inputs.findIndex((item) => item.key === props.key);
|
||||
updateObj.inputs = node.data.inputs.filter((item) => item.key !== props.key);
|
||||
setTimeout(() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'addInput',
|
||||
index: oldInputIndex,
|
||||
value: props.value
|
||||
});
|
||||
});
|
||||
} else if (type === 'addInput') {
|
||||
const input = node.data.inputs.find((input) => input.key === props.value.key);
|
||||
if (input) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: 'key 重复'
|
||||
});
|
||||
updateObj.inputs = node.data.inputs;
|
||||
} else {
|
||||
if (props.index !== undefined) {
|
||||
const inputs = [...node.data.inputs];
|
||||
inputs.splice(props.index, 0, props.value);
|
||||
updateObj.inputs = inputs;
|
||||
} else {
|
||||
updateObj.inputs = node.data.inputs.concat(props.value);
|
||||
}
|
||||
}
|
||||
} else if (type === 'delInput') {
|
||||
onDelEdge({ nodeId, targetHandle: props.key });
|
||||
updateObj.inputs = node.data.inputs.filter((item) => item.key !== props.key);
|
||||
} else if (type === 'updateOutput') {
|
||||
updateObj.outputs = node.data.outputs.map((item) =>
|
||||
item.key === props.key ? props.value : item
|
||||
);
|
||||
} else if (type === 'replaceOutput') {
|
||||
onDelEdge({ nodeId, sourceHandle: props.key });
|
||||
const oldOutputIndex = node.data.outputs.findIndex((item) => item.key === props.key);
|
||||
updateObj.outputs = node.data.outputs.filter((item) => item.key !== props.key);
|
||||
console.log(props.value);
|
||||
setTimeout(() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'addOutput',
|
||||
index: oldOutputIndex,
|
||||
value: props.value
|
||||
});
|
||||
});
|
||||
} else if (type === 'addOutput') {
|
||||
const output = node.data.outputs.find((output) => output.key === props.value.key);
|
||||
if (output) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: 'key 重复'
|
||||
});
|
||||
updateObj.outputs = node.data.outputs;
|
||||
} else {
|
||||
if (props.index !== undefined) {
|
||||
const outputs = [...node.data.outputs];
|
||||
outputs.splice(props.index, 0, props.value);
|
||||
updateObj.outputs = outputs;
|
||||
} else {
|
||||
updateObj.outputs = node.data.outputs.concat(props.value);
|
||||
}
|
||||
}
|
||||
} else if (type === 'delOutput') {
|
||||
onDelEdge({ nodeId, sourceHandle: props.key });
|
||||
updateObj.outputs = node.data.outputs.filter((item) => item.key !== props.key);
|
||||
const updateObj: Record<string, any> = {};
|
||||
|
||||
if (type === 'attr') {
|
||||
if (props.key) {
|
||||
updateObj[props.key] = props.value;
|
||||
}
|
||||
|
||||
return {
|
||||
...node,
|
||||
data: {
|
||||
...node.data,
|
||||
...updateObj
|
||||
} else if (type === 'updateInput') {
|
||||
updateObj.inputs = node.data.inputs.map((item) =>
|
||||
item.key === props.key ? props.value : item
|
||||
);
|
||||
} else if (type === 'replaceInput') {
|
||||
onDelEdge({ nodeId, targetHandle: props.key });
|
||||
const oldInputIndex = node.data.inputs.findIndex((item) => item.key === props.key);
|
||||
updateObj.inputs = node.data.inputs.filter((item) => item.key !== props.key);
|
||||
setTimeout(() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'addInput',
|
||||
index: oldInputIndex,
|
||||
value: props.value
|
||||
});
|
||||
});
|
||||
} else if (type === 'addInput') {
|
||||
const input = node.data.inputs.find((input) => input.key === props.value.key);
|
||||
if (input) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: 'key 重复'
|
||||
});
|
||||
updateObj.inputs = node.data.inputs;
|
||||
} else {
|
||||
if (props.index !== undefined) {
|
||||
const inputs = [...node.data.inputs];
|
||||
inputs.splice(props.index, 0, props.value);
|
||||
updateObj.inputs = inputs;
|
||||
} else {
|
||||
updateObj.inputs = node.data.inputs.concat(props.value);
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
[onDelEdge, setNodes, toast]
|
||||
);
|
||||
const onUpdateNodeError = useCallback(
|
||||
(nodeId: string, isError: Boolean) => {
|
||||
setNodes((nodes) => {
|
||||
return nodes.map((item) => {
|
||||
if (item.data?.nodeId === nodeId) {
|
||||
item.selected = true;
|
||||
//@ts-ignore
|
||||
item.data.isError = isError;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
});
|
||||
},
|
||||
[setNodes]
|
||||
} else if (type === 'delInput') {
|
||||
onDelEdge({ nodeId, targetHandle: props.key });
|
||||
updateObj.inputs = node.data.inputs.filter((item) => item.key !== props.key);
|
||||
} else if (type === 'updateOutput') {
|
||||
updateObj.outputs = node.data.outputs.map((item) =>
|
||||
item.key === props.key ? props.value : item
|
||||
);
|
||||
} else if (type === 'replaceOutput') {
|
||||
onDelEdge({ nodeId, sourceHandle: props.key });
|
||||
const oldOutputIndex = node.data.outputs.findIndex((item) => item.key === props.key);
|
||||
updateObj.outputs = node.data.outputs.filter((item) => item.key !== props.key);
|
||||
console.log(props.value);
|
||||
setTimeout(() => {
|
||||
onChangeNode({
|
||||
nodeId,
|
||||
type: 'addOutput',
|
||||
index: oldOutputIndex,
|
||||
value: props.value
|
||||
});
|
||||
});
|
||||
} else if (type === 'addOutput') {
|
||||
const output = node.data.outputs.find((output) => output.key === props.value.key);
|
||||
if (output) {
|
||||
toast({
|
||||
status: 'warning',
|
||||
title: 'key 重复'
|
||||
});
|
||||
updateObj.outputs = node.data.outputs;
|
||||
} else {
|
||||
if (props.index !== undefined) {
|
||||
const outputs = [...node.data.outputs];
|
||||
outputs.splice(props.index, 0, props.value);
|
||||
updateObj.outputs = outputs;
|
||||
} else {
|
||||
updateObj.outputs = node.data.outputs.concat(props.value);
|
||||
}
|
||||
}
|
||||
} else if (type === 'delOutput') {
|
||||
onDelEdge({ nodeId, sourceHandle: props.key });
|
||||
updateObj.outputs = node.data.outputs.filter((item) => item.key !== props.key);
|
||||
}
|
||||
|
||||
return {
|
||||
...node,
|
||||
data: {
|
||||
...node.data,
|
||||
...updateObj
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
/* function */
|
||||
const onFixView = useMemoizedFn(() => {
|
||||
const btn = document.querySelector('.custom-workflow-fix_view') as HTMLButtonElement;
|
||||
|
||||
setTimeout(() => {
|
||||
btn && btn.click();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
/* If the module is connected by a tool, the tool input and the normal input are separated */
|
||||
const splitToolInputs = useMemoizedFn((inputs: FlowNodeInputItemType[], nodeId: string) => {
|
||||
const isTool = !!edges.find(
|
||||
(edge) => edge.targetHandle === NodeOutputKeyEnum.selectedTools && edge.target === nodeId
|
||||
);
|
||||
|
||||
return {
|
||||
isTool,
|
||||
toolInputs: inputs.filter((item) => isTool && item.toolDescription),
|
||||
commonInputs: inputs.filter((item) => {
|
||||
if (!isTool) return true;
|
||||
return !item.toolDescription;
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
const initData = useMemoizedFn(
|
||||
async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {
|
||||
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })));
|
||||
|
||||
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })));
|
||||
}
|
||||
);
|
||||
|
||||
/* Run workflow debug and get next runtime data */
|
||||
const [workflowDebugData, setWorkflowDebugData] = useState<{
|
||||
runtimeNodes: RuntimeNodeItemType[];
|
||||
runtimeEdges: RuntimeEdgeItemType[];
|
||||
nextRunNodes: RuntimeNodeItemType[];
|
||||
}>();
|
||||
/* debug */
|
||||
const [workflowDebugData, setWorkflowDebugData] = useState<DebugDataType>();
|
||||
const onNextNodeDebug = useCallback(
|
||||
async (debugData = workflowDebugData) => {
|
||||
if (!debugData) return;
|
||||
@@ -592,36 +616,6 @@ export const FlowProvider = ({
|
||||
[onNextNodeDebug, onStopNodeDebug]
|
||||
);
|
||||
|
||||
/* If the module is connected by a tool, the tool input and the normal input are separated */
|
||||
const splitToolInputs = useCallback(
|
||||
(inputs: FlowNodeInputItemType[], nodeId: string) => {
|
||||
const isTool = !!edges.find(
|
||||
(edge) => edge.targetHandle === NodeOutputKeyEnum.selectedTools && edge.target === nodeId
|
||||
);
|
||||
|
||||
return {
|
||||
isTool,
|
||||
toolInputs: inputs.filter((item) => isTool && item.toolDescription),
|
||||
commonInputs: inputs.filter((item) => {
|
||||
if (!isTool) return true;
|
||||
return !item.toolDescription;
|
||||
})
|
||||
};
|
||||
},
|
||||
[edges]
|
||||
);
|
||||
|
||||
const initData = useCallback(
|
||||
async (e: { nodes: StoreNodeItemType[]; edges: StoreEdgeItemType[] }) => {
|
||||
setNodes(e.nodes?.map((item) => storeNode2FlowNode({ item })));
|
||||
|
||||
setEdges(e.edges?.map((item) => storeEdgesRenderEdge({ edge: item })));
|
||||
|
||||
await delay(200);
|
||||
},
|
||||
[setEdges, setNodes]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eventBus.on(EventNameEnum.requestWorkflowStore, () => {
|
||||
eventBus.emit(EventNameEnum.receiveWorkflowStore, {
|
||||
@@ -633,43 +627,49 @@ export const FlowProvider = ({
|
||||
};
|
||||
}, [nodes]);
|
||||
|
||||
const value = {
|
||||
reactFlowWrapper,
|
||||
mode,
|
||||
filterAppIds,
|
||||
edges,
|
||||
setEdges,
|
||||
onEdgesChange,
|
||||
// nodes
|
||||
nodes,
|
||||
nodeList,
|
||||
setNodes,
|
||||
onNodesChange,
|
||||
hoverNodeId,
|
||||
setHoverNodeId,
|
||||
onUpdateNodeError,
|
||||
workflowDebugData,
|
||||
onNextNodeDebug,
|
||||
onStartNodeDebug,
|
||||
onStopNodeDebug,
|
||||
return (
|
||||
<WorkflowContext.Provider
|
||||
value={{
|
||||
reactFlowWrapper,
|
||||
...value,
|
||||
// node
|
||||
nodes,
|
||||
setNodes,
|
||||
onNodesChange,
|
||||
nodeList,
|
||||
hasToolNode,
|
||||
hoverNodeId,
|
||||
setHoverNodeId,
|
||||
onUpdateNodeError,
|
||||
onResetNode,
|
||||
onChangeNode,
|
||||
|
||||
basicNodeTemplates,
|
||||
// connect
|
||||
connectingEdge,
|
||||
setConnectingEdge,
|
||||
onFixView,
|
||||
onChangeNode,
|
||||
onResetNode,
|
||||
onDelEdge,
|
||||
initData,
|
||||
splitToolInputs,
|
||||
hasToolNode
|
||||
};
|
||||
// edge
|
||||
edges,
|
||||
setEdges,
|
||||
onEdgesChange,
|
||||
connectingEdge,
|
||||
setConnectingEdge,
|
||||
onDelEdge,
|
||||
|
||||
return <StateContext.Provider value={value}>{children}</StateContext.Provider>;
|
||||
// function
|
||||
onFixView,
|
||||
splitToolInputs,
|
||||
initData,
|
||||
|
||||
// debug
|
||||
workflowDebugData,
|
||||
onNextNodeDebug,
|
||||
onStartNodeDebug,
|
||||
onStopNodeDebug
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</WorkflowContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(FlowProvider);
|
||||
export default WorkflowContextProvider;
|
||||
|
||||
type GetWorkflowStoreResponse = {
|
||||
nodes: Node<FlowNodeItemType>[];
|
||||
Reference in New Issue
Block a user