diff --git a/docSite/content/zh-cn/docs/development/upgrading/4912.md b/docSite/content/zh-cn/docs/development/upgrading/4912.md index 1b96ecd1b..1144d3b10 100644 --- a/docSite/content/zh-cn/docs/development/upgrading/4912.md +++ b/docSite/content/zh-cn/docs/development/upgrading/4912.md @@ -12,7 +12,8 @@ weight: 788 1. AI proxy 监控完善,支持以图表/表格形式查看模型调用和性能情况。 2. HTTP 节点和 MCP 支持单独“鉴权配置”,鉴权配置明文不会二次返回客户端,以保障数据安全。 3. 问题分类和内容提取,提示词中自动加入上一轮结果进行额外引导。 -4. 商业版支持知识库分块时,LLM 进行自动分段识别。 +4. 判断器支持变量引用。 +5. 商业版支持知识库分块时,LLM 进行自动分段识别。 ## ⚙️ 优化 diff --git a/packages/global/core/workflow/template/system/ifElse/constant.ts b/packages/global/core/workflow/template/system/ifElse/constant.ts index ac49ac3e4..0e3151592 100644 --- a/packages/global/core/workflow/template/system/ifElse/constant.ts +++ b/packages/global/core/workflow/template/system/ifElse/constant.ts @@ -113,3 +113,15 @@ export const allConditionList = [ value: VariableConditionEnum.lengthLessThanOrEqualTo } ]; +export const renderNumberConditionList = new Set([ + VariableConditionEnum.greaterThan, + VariableConditionEnum.greaterThanOrEqualTo, + VariableConditionEnum.lessThan, + VariableConditionEnum.lessThanOrEqualTo, + VariableConditionEnum.lengthEqualTo, + VariableConditionEnum.lengthNotEqualTo, + VariableConditionEnum.lengthGreaterThan, + VariableConditionEnum.lengthGreaterThanOrEqualTo, + VariableConditionEnum.lengthLessThan, + VariableConditionEnum.lengthLessThanOrEqualTo +]); diff --git a/packages/global/core/workflow/template/system/ifElse/index.ts b/packages/global/core/workflow/template/system/ifElse/index.ts index 237823552..ffbe49536 100644 --- a/packages/global/core/workflow/template/system/ifElse/index.ts +++ b/packages/global/core/workflow/template/system/ifElse/index.ts @@ -37,7 +37,8 @@ export const IfElseNode: FlowNodeTemplateType = { { variable: undefined, condition: undefined, - value: undefined + value: undefined, + valueType: 'input' } ] } diff --git a/packages/global/core/workflow/template/system/ifElse/type.d.ts b/packages/global/core/workflow/template/system/ifElse/type.d.ts index 185ab5cae..a47c33a5f 100644 --- a/packages/global/core/workflow/template/system/ifElse/type.d.ts +++ b/packages/global/core/workflow/template/system/ifElse/type.d.ts @@ -5,7 +5,8 @@ export type IfElseConditionType = 'AND' | 'OR'; export type ConditionListItemType = { variable?: ReferenceItemValueType; condition?: VariableConditionEnum; - value?: string; + value?: string | ReferenceItemValueType; + valueType?: 'input' | 'reference'; }; export type IfElseListItemType = { condition: IfElseConditionType; diff --git a/packages/service/core/workflow/dispatch/tools/runIfElse.ts b/packages/service/core/workflow/dispatch/tools/runIfElse.ts index 26c175c0e..28b381a4f 100644 --- a/packages/service/core/workflow/dispatch/tools/runIfElse.ts +++ b/packages/service/core/workflow/dispatch/tools/runIfElse.ts @@ -1,7 +1,10 @@ import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants'; import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants'; import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants'; -import { type DispatchNodeResultType } from '@fastgpt/global/core/workflow/runtime/type'; +import { + type RuntimeNodeItemType, + type DispatchNodeResultType +} from '@fastgpt/global/core/workflow/runtime/type'; import { IfElseResultEnum, VariableConditionEnum @@ -14,6 +17,7 @@ import { import { type ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type'; import { getElseIFLabel, getHandleId } from '@fastgpt/global/core/workflow/utils'; import { getReferenceVariableValue } from '@fastgpt/global/core/workflow/runtime/utils'; +import { type ReferenceItemValueType } from '@fastgpt/global/core/workflow/type/io'; type Props = ModuleDispatchProps<{ [NodeInputKeyEnum.condition]: IfElseConditionType; @@ -49,7 +53,7 @@ function isInclude(value: any, target: any) { } } -function checkCondition(condition: VariableConditionEnum, inputValue: any, value: string) { +function checkCondition(condition: VariableConditionEnum, inputValue: any, value: any) { const operations: Record boolean> = { [VariableConditionEnum.isEmpty]: () => isEmpty(inputValue), [VariableConditionEnum.isNotEmpty]: () => !isEmpty(inputValue), @@ -100,19 +104,29 @@ function checkCondition(condition: VariableConditionEnum, inputValue: any, value function getResult( condition: IfElseConditionType, list: ConditionListItemType[], - variables: any, - runtimeNodes: any[] + variables: Record, + runtimeNodes: RuntimeNodeItemType[] ) { const listResult = list.map((item) => { - const { variable, condition: variableCondition, value } = item; + const { variable, condition: variableCondition, value, valueType } = item; + if (!variableCondition) return; - const inputValue = getReferenceVariableValue({ + const conditionLeftValue = getReferenceVariableValue({ value: variable, variables, nodes: runtimeNodes }); - return checkCondition(variableCondition as VariableConditionEnum, inputValue, value || ''); + const conditionRightValue = + valueType === 'reference' + ? getReferenceVariableValue({ + value: value as ReferenceItemValueType, + variables, + nodes: runtimeNodes + }) + : value; + + return checkCondition(variableCondition, conditionLeftValue, conditionRightValue); }); return condition === 'AND' ? listResult.every(Boolean) : listResult.some(Boolean); diff --git a/packages/web/components/common/Icon/constants.ts b/packages/web/components/common/Icon/constants.ts index d0c53defa..0f8cd8ef1 100644 --- a/packages/web/components/common/Icon/constants.ts +++ b/packages/web/components/common/Icon/constants.ts @@ -8,6 +8,7 @@ export const iconPaths = { chatSend: () => import('./icons/chatSend.svg'), check: () => import('./icons/check.svg'), checkCircle: () => import('./icons/checkCircle.svg'), + circleMinus: () => import('./icons/circleMinus.svg'), close: () => import('./icons/close.svg'), closeSolid: () => import('./icons/closeSolid.svg'), code: () => import('./icons/code.svg'), diff --git a/packages/web/components/common/Icon/icons/circleMinus.svg b/packages/web/components/common/Icon/icons/circleMinus.svg new file mode 100644 index 000000000..bd5487497 --- /dev/null +++ b/packages/web/components/common/Icon/icons/circleMinus.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/packages/web/components/common/Icon/icons/minus.svg b/packages/web/components/common/Icon/icons/minus.svg index bd5487497..1763637ff 100644 --- a/packages/web/components/common/Icon/icons/minus.svg +++ b/packages/web/components/common/Icon/icons/minus.svg @@ -1,4 +1,3 @@ - - - + + \ No newline at end of file diff --git a/packages/web/components/common/Input/NumberInput/index.tsx b/packages/web/components/common/Input/NumberInput/index.tsx index 377e166c2..74810c779 100644 --- a/packages/web/components/common/Input/NumberInput/index.tsx +++ b/packages/web/components/common/Input/NumberInput/index.tsx @@ -4,7 +4,8 @@ import { NumberInputField, NumberInputStepper, NumberDecrementStepper, - type NumberInputProps + type NumberInputProps, + type NumberInputFieldProps } from '@chakra-ui/react'; import React from 'react'; import MyIcon from '../../Icon'; @@ -16,11 +17,11 @@ type Props = Omit & { placeholder?: string; register?: UseFormRegister; name?: string; - bg?: string; + inputFieldProps?: NumberInputFieldProps; }; const MyNumberInput = (props: Props) => { - const { register, name, onChange, onBlur, placeholder, bg, ...restProps } = props; + const { register, name, onChange, onBlur, placeholder, inputFieldProps, ...restProps } = props; return ( { }} > { valueAsNumber: true }) : {})} + {...inputFieldProps} /> diff --git a/packages/web/components/common/MySelect/MultipleRowSelect.tsx b/packages/web/components/common/MySelect/MultipleRowSelect.tsx index 37276bb39..a495040e3 100644 --- a/packages/web/components/common/MySelect/MultipleRowSelect.tsx +++ b/packages/web/components/common/MySelect/MultipleRowSelect.tsx @@ -26,7 +26,7 @@ export const MultipleRowSelect = ({ onSelect, ButtonProps, changeOnEverySelect = false, - rowMinWidth = 'autp' + rowMinWidth = 'auto' }: MultipleSelectProps & { rowMinWidth?: string; }) => { @@ -66,7 +66,7 @@ export const MultipleRowSelect = ({ if (currentScrollTop !== undefined && MenuRef.current[index]) { MenuRef.current[index]!.scrollTop = currentScrollTop; } - }, [cloneValue, currentScrollTop]); + }, [currentScrollTop, index]); return ( <> @@ -143,7 +143,7 @@ export const MultipleRowSelect = ({ ); }, - [cloneValue] + [changeOnEverySelect, cloneValue, emptyTip, maxH, minWidth, onClose, onSelect, rowMinWidth, t] ); const onOpenSelect = useCallback(() => { @@ -172,7 +172,6 @@ export const MultipleRowSelect = ({ ref={ButtonRef} width={'100%'} px={3} - rightIcon={} variant={'whitePrimaryOutline'} size={'lg'} fontSize={'sm'} @@ -189,7 +188,12 @@ export const MultipleRowSelect = ({ : {})} {...ButtonProps} > - {label ?? placeholder} + + + {label ?? placeholder} + + + ); }, - [navigationPath, formatValue, onSelect] + [navigationPath, maxH, emptyTip, t, formatValue, onChange] ); const onOpenSelect = useCallback(() => { setNavigationPath([]); onOpen(); - }, []); + }, [onOpen]); return ( diff --git a/packages/web/components/common/Textarea/PromptEditor/index.module.scss b/packages/web/components/common/Textarea/PromptEditor/index.module.scss index a161224d6..6e60721ea 100644 --- a/packages/web/components/common/Textarea/PromptEditor/index.module.scss +++ b/packages/web/components/common/Textarea/PromptEditor/index.module.scss @@ -25,31 +25,6 @@ } } -.contentEditable_isFlow { - position: relative; - height: 100%; - width: 100%; - border: 1px solid var(--chakra-colors-myGray-200); - border-radius: var(--chakra-radii-sm); - padding: 6px 8px; - font-size: var(--chakra-fontSizes-sm); - overflow-y: auto; - - &:hover { - border-color: var(--chakra-colors-primary-300); - } - &::-webkit-scrollbar { - color: var(--chakra-colors-myGray-100); - } - &::-webkit-scrollbar-thumb { - background-color: var(--chakra-colors-myGray-200) !important; - cursor: pointer; - } - &::-webkit-scrollbar-thumb:hover { - background-color: var(--chakra-colors-myGray-250) !important; - } -} - .contentEditable:focus { outline: none; border: 1px solid; diff --git a/packages/web/i18n/en/workflow.json b/packages/web/i18n/en/workflow.json index d40b0ff36..c49449457 100644 --- a/packages/web/i18n/en/workflow.json +++ b/packages/web/i18n/en/workflow.json @@ -21,6 +21,8 @@ "can_not_loop": "This node can't loop.", "choose_another_application_to_call": "Select another application to call", "classification_result": "Classification Result", + "click_to_change_reference": "Click to switch input mode", + "click_to_change_value": "Click to switch reference mode", "code.Reset template": "Reset Template", "code.Reset template confirm": "Confirm reset code template? This will reset all inputs and outputs to template values. Please save your current code.", "code.Switch language confirm": "Switching the language will reset the code, will it continue?", diff --git a/packages/web/i18n/zh-CN/workflow.json b/packages/web/i18n/zh-CN/workflow.json index 6eb075039..6296b79e0 100644 --- a/packages/web/i18n/zh-CN/workflow.json +++ b/packages/web/i18n/zh-CN/workflow.json @@ -21,6 +21,8 @@ "can_not_loop": "该节点不支持循环嵌套", "choose_another_application_to_call": "选择一个其他应用进行调用", "classification_result": "分类结果", + "click_to_change_reference": "点击切换输入模式", + "click_to_change_value": "点击切换变量引用模式", "code.Reset template": "还原模板", "code.Reset template confirm": "确认还原代码模板?将会重置所有输入和输出至模板值,请注意保存当前代码。", "code.Switch language confirm": "切换语言将重置代码,是否继续?", diff --git a/packages/web/i18n/zh-Hant/workflow.json b/packages/web/i18n/zh-Hant/workflow.json index 7607ebd5b..2dd7c3a31 100644 --- a/packages/web/i18n/zh-Hant/workflow.json +++ b/packages/web/i18n/zh-Hant/workflow.json @@ -21,6 +21,8 @@ "can_not_loop": "這個節點不能迴圈。", "choose_another_application_to_call": "選擇另一個應用程式來呼叫", "classification_result": "分類結果", + "click_to_change_reference": "點擊切換輸入模式", + "click_to_change_value": "點擊切換變量引用模式", "code.Reset template": "重設範本", "code.Reset template confirm": "確定要重設程式碼範本嗎?這將會把所有輸入和輸出重設為範本值。請儲存您目前的程式碼。", "code.Switch language confirm": "切換語言將重設代碼,是否繼續?", diff --git a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/VariableInput.tsx b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/VariableInput.tsx index d0c83a2c8..1c15c0056 100644 --- a/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/VariableInput.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/ChatBox/components/VariableInput.tsx @@ -94,7 +94,7 @@ export const VariableInputItem = ({ step={1} min={item.min} max={item.max} - bg={'white'} + inputFieldProps={{ bg: 'white' }} value={value} onChange={onChange} isInvalid={errors?.variables && Object.keys(errors.variables).includes(item.key)} @@ -250,18 +250,16 @@ const VariableInput = ({ ))} {variableList.length === 0 && !chatStarted && ( - - } - size={'sm'} - maxW={'100px'} - onClick={handleSubmitChat(() => { - chatForm.setValue('chatStarted', true); - })} - > - {t('common:core.chat.Start Chat')} - - + } + size={'sm'} + maxW={'100px'} + onClick={handleSubmitChat(() => { + chatForm.setValue('chatStarted', true); + })} + > + {t('common:core.chat.Start Chat')} + )} @@ -287,7 +285,6 @@ const VariableInput = ({ size={'sm'} maxW={'100px'} onClick={handleSubmitChat(() => { - console.log('start chat'); chatForm.setValue('chatStarted', true); })} > diff --git a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/renderPluginInput.tsx b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/renderPluginInput.tsx index 9ccedbf64..ae398fe1d 100644 --- a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/renderPluginInput.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/renderPluginInput.tsx @@ -198,7 +198,6 @@ const RenderPluginInput = ({ step={1} min={input.min} max={input.max} - bg={'myGray.50'} isDisabled={isDisabled} isInvalid={isInvalid} value={value} diff --git a/projects/app/src/components/core/chat/components/Interactive/InteractiveComponents.tsx b/projects/app/src/components/core/chat/components/Interactive/InteractiveComponents.tsx index 9ed221280..01b1f1afb 100644 --- a/projects/app/src/components/core/chat/components/Interactive/InteractiveComponents.tsx +++ b/projects/app/src/components/core/chat/components/Interactive/InteractiveComponents.tsx @@ -146,10 +146,10 @@ export const FormInputComponent = React.memo(function FormInputComponent({ max={max} defaultValue={defaultValue} isDisabled={submitted} - bg={'white'} register={register} name={label} isRequired={required} + inputFieldProps={{ bg: 'white' }} /> ); case FlowNodeInputTypeEnum.select: diff --git a/projects/app/src/pageComponents/account/bill/InvoiceTable.tsx b/projects/app/src/pageComponents/account/bill/InvoiceTable.tsx index 5ac60bce0..27f1aa509 100644 --- a/projects/app/src/pageComponents/account/bill/InvoiceTable.tsx +++ b/projects/app/src/pageComponents/account/bill/InvoiceTable.tsx @@ -1,4 +1,4 @@ -import { getInvoiceRecords, readInvoiceFile } from '@/web/support/wallet/bill/invoice/api'; +import { getInvoiceRecords } from '@/web/support/wallet/bill/invoice/api'; import MyBox from '@fastgpt/web/components/common/MyBox'; import { useTranslation } from 'next-i18next'; import { useState } from 'react'; @@ -23,6 +23,7 @@ import dayjs from 'dayjs'; import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools'; import MyModal from '@fastgpt/web/components/common/MyModal'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; +import { downloadFetch } from '@/web/common/system/utils'; const InvoiceTable = () => { const { t } = useTranslation(); @@ -138,25 +139,10 @@ function InvoiceDetailModal({ const { t } = useTranslation(); const { runAsync: handleDownloadInvoice } = useRequest2(async (id: string) => { - const fileInfo = await readInvoiceFile(id); - - // Blob - const byteCharacters = atob(fileInfo.data); - const byteNumbers = new Array(byteCharacters.length); - for (let i = 0; i < byteCharacters.length; i++) { - byteNumbers[i] = byteCharacters.charCodeAt(i); - } - const byteArray = new Uint8Array(byteNumbers); - const blob = new Blob([byteArray], { type: fileInfo.mimeType }); - const fileUrl = URL.createObjectURL(blob); - - // preview - window.open(fileUrl, '_blank'); - - // clean - setTimeout(() => { - URL.revokeObjectURL(fileUrl); - }, 1000); + await downloadFetch({ + url: `/api/proApi/support/wallet/bill/invoice/downloadFile?id=${id}`, + filename: `${invoice.teamName}.pdf` + }); }); return ( diff --git a/projects/app/src/pageComponents/app/detail/MCPTools/ChatTest.tsx b/projects/app/src/pageComponents/app/detail/MCPTools/ChatTest.tsx index eabace35b..6e9974ba1 100644 --- a/projects/app/src/pageComponents/app/detail/MCPTools/ChatTest.tsx +++ b/projects/app/src/pageComponents/app/detail/MCPTools/ChatTest.tsx @@ -214,15 +214,7 @@ const RenderToolInput = ({ ); } if (paramInfo.type === 'number') { - return ( - - ); + return ; } if (paramInfo.type === 'boolean') { return ; diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeCQNode.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeCQNode.tsx index d05abeab7..4aff440bc 100644 --- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeCQNode.tsx +++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeCQNode.tsx @@ -39,7 +39,7 @@ const NodeCQNode = ({ data, selected }: NodeProps) => { ) => { step={100} value={item.value} name={NodeInputKeyEnum.datasetMaxTokens} - bg={'white'} + inputFieldProps={{ bg: 'white' }} onChange={(e) => { onChangeNode({ nodeId, diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeIfElse/ListItem.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeIfElse/ListItem.tsx index dce48a9a5..5a1e5b72b 100644 --- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeIfElse/ListItem.tsx +++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeIfElse/ListItem.tsx @@ -1,16 +1,16 @@ -import { Box, Button, Flex } from '@chakra-ui/react'; +import { Box, Button, Flex, HStack } from '@chakra-ui/react'; import { type DraggableProvided, type DraggableStateSnapshot } from '@fastgpt/web/components/common/DndDrag/index'; import Container from '../../components/Container'; -import { MinusIcon, SmallAddIcon } from '@chakra-ui/icons'; +import { MinusIcon } from '@chakra-ui/icons'; import { type IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { type ReferenceItemValueType } from '@fastgpt/global/core/workflow/type/io'; import { useTranslation } from 'next-i18next'; import { ReferSelector, useReference } from '../render/RenderInput/templates/Reference'; -import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants'; +import { VARIABLE_NODE_ID, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants'; import { VariableConditionEnum, allConditionList, @@ -18,6 +18,7 @@ import { booleanConditionList, numberConditionList, objectConditionList, + renderNumberConditionList, stringConditionList } from '@fastgpt/global/core/workflow/template/system/ifElse/constant'; import { useContextSelector } from 'use-context-selector'; @@ -28,9 +29,12 @@ import MyInput from '@/components/MyInput'; import { getElseIFLabel, getHandleId } from '@fastgpt/global/core/workflow/utils'; import { MySourceHandle } from '../render/Handle'; import { Position, useReactFlow } from 'reactflow'; -import { getRefData } from '@/web/core/workflow/utils'; +import { getRefData, getWorkflowGlobalVariables } from '@/web/core/workflow/utils'; import DragIcon from '@fastgpt/web/components/common/DndDrag/DragIcon'; import { AppContext } from '@/pageComponents/app/detail/context'; +import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput'; +import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; +import MyIconButton from '@fastgpt/web/components/common/Icon/button'; const ListItem = ({ provided, @@ -57,7 +61,6 @@ const ListItem = ({ const Render = useMemo(() => { return ( {ifElseList.length > 1 && } - + {getElseIFLabel(conditionIndex)} {conditionItem.list?.length > 1 && ( { onUpdateIfElseList( @@ -95,7 +102,7 @@ const ListItem = ({ )} - + {ifElseList.length > 1 && ( { onUpdateIfElseList(ifElseList.filter((_, index) => index !== conditionIndex)); onDelEdge({ @@ -119,102 +126,96 @@ const ListItem = ({ return ( {/* condition list */} - + {/* variable reference */} - - { - onUpdateIfElseList( - ifElseList.map((ifElse, index) => { - if (index === conditionIndex) { - return { - ...ifElse, - list: ifElse.list.map((item, index) => { - if (index === i) { - return { - ...item, - variable: e, - condition: undefined - }; - } - return item; - }) - }; - } - return ifElse; - }) - ); - }} - /> - - {/* condition select */} - - { - onUpdateIfElseList( - ifElseList.map((ifElse, index) => { - if (index === conditionIndex) { - return { - ...ifElse, - list: ifElse.list.map((item, index) => { - if (index === i) { - return { - ...item, - condition: e - }; - } - return item; - }) - }; - } - return ifElse; - }) - ); - }} - /> - - {/* value */} - - { - onUpdateIfElseList( - ifElseList.map((ifElse, index) => { + { + onUpdateIfElseList( + ifElseList.map((ifElse, index) => { + if (index === conditionIndex) { return { ...ifElse, - list: - index === conditionIndex - ? ifElse.list.map((item, index) => { - if (index === i) { - return { - ...item, - value: e - }; - } - return item; - }) - : ifElse.list + list: ifElse.list.map((item, index) => { + if (index === i) { + return { + ...item, + variable: e, + condition: undefined + }; + } + return item; + }) }; - }) - ); - }} - /> - + } + return ifElse; + }) + ); + }} + /> + {/* condition select */} + { + onUpdateIfElseList( + ifElseList.map((ifElse, index) => { + if (index === conditionIndex) { + return { + ...ifElse, + list: ifElse.list.map((item, index) => { + if (index === i) { + return { + ...item, + condition: e + }; + } + return item; + }) + }; + } + return ifElse; + }) + ); + }} + /> + {/* value */} + { + onUpdateIfElseList( + ifElseList.map((ifElse, index) => { + return { + ...ifElse, + list: + index === conditionIndex + ? ifElse.list.map((item, index) => { + if (index === i) { + return { + ...item, + value, + valueType + }; + } + return item; + }) + : ifElse.list + }; + }) + ); + }} + /> {/* delete */} {conditionItem.list.length > 1 && ( - { onUpdateIfElseList( ifElseList.map((ifElse, index) => { @@ -235,30 +236,32 @@ const ListItem = ({ ); })} - + + + {!snapshot.isDragging && ( ); }; @@ -392,7 +400,9 @@ const ConditionSelect = ({ return ( void; + updateValue: (value: string | ReferenceItemValueType, valueType: 'input' | 'reference') => void; + nodeId: string; }) => { const { t } = useTranslation(); const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList); + const appDetail = useContextSelector(AppContext, (v) => v.appDetail); + + const isReference = useMemo(() => type === 'reference', [type]); + + const globalVariables = getWorkflowGlobalVariables({ + nodes: nodeList, + chatConfig: appDetail.chatConfig + }); // get value type const valueType = useMemo(() => { - if (!variable) return; - const node = nodeList.find((node) => node.nodeId === variable[0]); + if (variable?.[0] === VARIABLE_NODE_ID) { + return globalVariables.find((item) => item.key === variable[1])?.valueType; + } else { + const node = nodeList.find((node) => node.nodeId === variable?.[0]); + const output = node?.outputs.find((item) => item.id === variable?.[1]); + return output?.valueType; + } + }, [globalVariables, nodeList, variable]); + const { referenceList } = useReference({ + nodeId, + valueType + }); - if (!node) return WorkflowIOValueTypeEnum.any; - const output = node.outputs.find((item) => item.id === variable[1]); + const showBooleanSelect = useMemo(() => { + return ( + valueType === WorkflowIOValueTypeEnum.boolean || + (valueType === WorkflowIOValueTypeEnum.arrayBoolean && + condition && + !renderNumberConditionList.has(condition)) + ); + }, [condition, valueType]); + const showNumberInput = useMemo(() => { + return ( + valueType === WorkflowIOValueTypeEnum.number || + valueType === WorkflowIOValueTypeEnum.arrayNumber || + (valueType?.includes('array') && condition && renderNumberConditionList.has(condition)) + ); + }, [condition, valueType]); - if (!output) return WorkflowIOValueTypeEnum.any; - return output.valueType; - }, [nodeList, variable]); - - const Render = useMemo(() => { - if (valueType === WorkflowIOValueTypeEnum.boolean) { + const RenderInput = useMemo(() => { + if (showBooleanSelect) { return ( updateValue(e, 'input')} + value={value as string} placeholder={t('workflow:ifelse.Select value')} - isDisabled={ - condition === VariableConditionEnum.isEmpty || - condition === VariableConditionEnum.isNotEmpty - } + borderLeftRadius={0} + h={10} + borderColor={'myGray.200'} + /> + ); + } else if (showNumberInput) { + return ( + updateValue(String(e), 'input')} /> ); } else { return ( onChange(e.target.value)} + borderLeftRadius={0} + onChange={(e) => updateValue(e.target.value, 'input')} /> ); } - }, [condition, onChange, value, valueType, t]); + }, [showBooleanSelect, showNumberInput, value, t, condition, updateValue]); - return Render; + const RenderReference = useMemo(() => { + return ( + { + updateValue(e as ReferenceItemValueType, 'reference'); + }} + isArray={false} + ButtonProps={{ + borderRadius: 'sm', + borderLeftRadius: 'none', + borderColor: 'myGray.200', + w: '100%' + }} + /> + ); + }, [t, referenceList, isReference, value, updateValue]); + + const isDisabled = + condition === VariableConditionEnum.isEmpty || condition === VariableConditionEnum.isNotEmpty; + + return ( + + + + { + if (isDisabled) return; + + if (isReference) { + updateValue('', 'input'); + } else { + updateValue(['', undefined], 'reference'); + } + }} + > + {isReference ? ( + + ) : ( + + )} + + + + {isReference ? RenderReference : RenderInput} + + + {isDisabled && ( + + )} + + ); }; diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeIfElse/index.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeIfElse/index.tsx index 091bc3917..ecfa5949d 100644 --- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeIfElse/index.tsx +++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeIfElse/index.tsx @@ -3,7 +3,7 @@ import NodeCard from '../render/NodeCard'; import { useTranslation } from 'next-i18next'; import { Box, Button, Flex } from '@chakra-ui/react'; import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants'; -import { type NodeProps, Position, useViewport } from 'reactflow'; +import { type NodeProps, Position } from 'reactflow'; import { type FlowNodeItemType } from '@fastgpt/global/core/workflow/type/node'; import { type IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type'; import { useContextSelector } from 'use-context-selector'; @@ -14,11 +14,11 @@ import { MySourceHandle } from '../render/Handle'; import { getHandleId } from '@fastgpt/global/core/workflow/utils'; import ListItem from './ListItem'; import { IfElseResultEnum } from '@fastgpt/global/core/workflow/template/system/ifElse/constant'; +import MyIcon from '@fastgpt/web/components/common/Icon'; const NodeIfElse = ({ data, selected }: NodeProps) => { const { t } = useTranslation(); const { nodeId, inputs = [] } = data; - const { zoom } = useViewport(); const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode); const elseHandleId = getHandleId(nodeId, 'source', IfElseResultEnum.ELSE); @@ -108,6 +108,7 @@ const NodeIfElse = ({ data, selected }: NodeProps) => { } onClick={() => { const ifElseListInput = inputs.find( (input) => input.key === NodeInputKeyEnum.ifElseList diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeUserSelect.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeUserSelect.tsx index bc00661ca..e3fca1c1a 100644 --- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeUserSelect.tsx +++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeUserSelect.tsx @@ -157,7 +157,7 @@ const OptionItem = ({ ) => if (valueType === WorkflowIOValueTypeEnum.number) { return ( onUpdateNewValue(String(e || 0))} /> diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/NumberInput.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/NumberInput.tsx index 35db09e7b..3f3ee3192 100644 --- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/NumberInput.tsx +++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/NumberInput.tsx @@ -13,7 +13,7 @@ const NumberInputRender = ({ item, nodeId }: RenderInputProps) => { value={item.value} min={item.min} max={item.max} - bg={'white'} + inputFieldProps={{ bg: 'white' }} rounded={'md'} onChange={(e) => { onChangeNode({ diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Reference.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Reference.tsx index 5fe795cf2..b3a2835bd 100644 --- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Reference.tsx +++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/Reference.tsx @@ -47,7 +47,7 @@ type CommonSelectProps = { }[]; }[]; popDirection?: 'top' | 'bottom'; - styles?: ButtonProps; + ButtonProps?: ButtonProps; }; type SelectProps = CommonSelectProps & { isArray?: T; @@ -87,7 +87,7 @@ export const useReference = ({ return { label: ( - + {t(node.name as any)} ), @@ -168,7 +168,8 @@ const SingleReferenceSelector = ({ value, list = [], onSelect, - popDirection + popDirection, + ButtonProps }: SelectProps) => { const getSelectValue = useCallback( (value: ReferenceValueType) => { @@ -196,12 +197,10 @@ const SingleReferenceSelector = ({ - - {nodeName} - - {outputName} - + + {nodeName} + + {outputName} ) : ( @@ -213,9 +212,10 @@ const SingleReferenceSelector = ({ list={list} onSelect={onSelect as any} popDirection={popDirection} + ButtonProps={ButtonProps} /> ); - }, [getSelectValue, list, onSelect, placeholder, popDirection, value]); + }, [ButtonProps, getSelectValue, list, onSelect, placeholder, popDirection, value]); return ItemSelector; }; @@ -226,8 +226,6 @@ const MultipleReferenceSelector = ({ onSelect, popDirection }: SelectProps) => { - const { t } = useTranslation(); - const getSelectValue = useCallback( (value: ReferenceValueType) => { if (!value) return []; diff --git a/projects/app/src/pageComponents/dataset/detail/Form/CollectionChunkForm.tsx b/projects/app/src/pageComponents/dataset/detail/Form/CollectionChunkForm.tsx index 3ac7164cb..610868d77 100644 --- a/projects/app/src/pageComponents/dataset/detail/Form/CollectionChunkForm.tsx +++ b/projects/app/src/pageComponents/dataset/detail/Form/CollectionChunkForm.tsx @@ -269,7 +269,7 @@ const CollectionChunkForm = ({ form }: { form: UseFormReturn export const getInvoiceRecords = (data: PaginationProps) => POST>(`/proApi/support/wallet/bill/invoice/records`, data); - -export const readInvoiceFile = (id: string) => - GET(`/proApi/support/wallet/bill/invoice/file/read`, { id });