diff --git a/web/src/views/Workflow/components/Editor/index.tsx b/web/src/views/Workflow/components/Editor/index.tsx index c517dfce..e8bbe9b0 100644 --- a/web/src/views/Workflow/components/Editor/index.tsx +++ b/web/src/views/Workflow/components/Editor/index.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2025-12-23 16:22:51 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-25 10:58:47 + * @Last Modified time: 2026-04-03 20:44:16 */ import { type FC, useState, useMemo } from 'react'; import { LexicalComposer } from '@lexical/react/LexicalComposer'; @@ -147,7 +147,7 @@ const Editor: FC =({ - { setCount(count) }} onChange={onChange} /> + diff --git a/web/src/views/Workflow/components/Editor/nodes/VariableNode.tsx b/web/src/views/Workflow/components/Editor/nodes/VariableNode.tsx index 2763bec7..24560395 100644 --- a/web/src/views/Workflow/components/Editor/nodes/VariableNode.tsx +++ b/web/src/views/Workflow/components/Editor/nodes/VariableNode.tsx @@ -32,8 +32,7 @@ const VariableComponent: React.FC<{ nodeKey: NodeKey; data: Suggestion }> = ({ e.stopPropagation(); setSelected(!isSelected); }; - - console.log('data', data) + return ( void; onChange?: (value: string) => void }) => { const [editor] = useLexicalComposerContext(); - const isReadyRef = useRef(false); + const onChangeRef = useRef(onChange); + onChangeRef.current = onChange; useEffect(() => { return editor.registerUpdateListener(({ editorState, tags }) => { - if (tags.has('programmatic')) { - isReadyRef.current = true; - return; - } - if (!isReadyRef.current) return; + if (tags.has('programmatic')) return; editorState.read(() => { const root = $getRoot(); let serializedContent = ''; @@ -38,10 +35,10 @@ const CharacterCountPlugin = ({ setCount, onChange }: { setCount: (count: number serializedContent = paragraphs.join('\n'); setCount(serializedContent.length); - onChange?.(serializedContent); + onChangeRef.current?.(serializedContent); }); }); - }, [editor, setCount, onChange]); + }, [editor, setCount]); return null; } diff --git a/web/src/views/Workflow/components/Properties/ListOperator/FilterConditions/index.tsx b/web/src/views/Workflow/components/Properties/ListOperator/FilterConditions/index.tsx index 11a1d479..685f51ff 100644 --- a/web/src/views/Workflow/components/Properties/ListOperator/FilterConditions/index.tsx +++ b/web/src/views/Workflow/components/Properties/ListOperator/FilterConditions/index.tsx @@ -67,11 +67,10 @@ const FilterConditions: FC = ({ const form = Form.useFormInstance(); const handleKeyFieldChange = (index: number, newValue: string) => { - form.setFieldValue(['filter_by', index], { + form.setFieldValue([parentName, 'conditions', index], { key: newValue, comparison_operator: undefined, value: undefined, - value_type: undefined, }); }; @@ -85,8 +84,8 @@ const FilterConditions: FC = ({ className="rb:relative" > {fields.map((field, index) => { - const filter_by = form.getFieldValue(['filter_by']) || []; - const currentCondition = filter_by[index] || {}; + const conditions = form.getFieldValue([parentName, 'conditions']) || []; + const currentCondition = conditions[index] || {}; const currentOperator = currentCondition.comparison_operator; const hideValueField = currentOperator === 'empty' || currentOperator === 'not_empty'; const keyFieldValue = currentCondition.key; @@ -103,9 +102,7 @@ const FilterConditions: FC = ({ >
{variableType === 'array[file]' && - + ({ diff --git a/web/src/views/Workflow/components/Properties/ListOperator/index.tsx b/web/src/views/Workflow/components/Properties/ListOperator/index.tsx index 8ebdc891..79d77afd 100644 --- a/web/src/views/Workflow/components/Properties/ListOperator/index.tsx +++ b/web/src/views/Workflow/components/Properties/ListOperator/index.tsx @@ -20,12 +20,12 @@ const ListOperator: FC = ({ options }) => { const { t } = useTranslation() const form = Form.useFormInstance() const values = Form.useWatch([], form) || {} - const variableOption = options.find(option => `{{${option.value}}}` === values?.variable) + const variableOption = options.find(option => `{{${option.value}}}` === values?.input_list) const variableType = variableOption?.dataType return ( <> - + vo.dataType.includes('array') && vo.dataType !== 'array[object]')} diff --git a/web/src/views/Workflow/components/Properties/VariableSelect.tsx b/web/src/views/Workflow/components/Properties/VariableSelect.tsx index 01215dc3..a5428a60 100644 --- a/web/src/views/Workflow/components/Properties/VariableSelect.tsx +++ b/web/src/views/Workflow/components/Properties/VariableSelect.tsx @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 15:40:13 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-04-03 18:51:17 + * @Last Modified time: 2026-04-03 20:19:34 */ import { useState, useRef, useEffect, useLayoutEffect, type FC } from 'react' import { createPortal } from 'react-dom' @@ -49,36 +49,26 @@ const VariableSelect: FC = ({ const CHILD_PANEL_HEIGHT = 280; // max-h-60 (240) + header (~40) - // Calculate dropdown position when opening - useEffect(() => { - if (!open || !containerRef.current) return; - const rect = containerRef.current.getBoundingClientRect(); - setDropdownPos({ top: rect.bottom + 8, left: rect.left, width: rect.width }); - }, [open]); - - // Adjust dropdown vertical position after render + // Calculate dropdown position (runs synchronously after DOM paint to avoid flicker) useLayoutEffect(() => { - if (!open || !dropdownRef.current || !containerRef.current) return; + if (!open || !containerRef.current) return; const triggerRect = containerRef.current.getBoundingClientRect(); + const MARGIN = 8; + const width = triggerRect.width; + // Set initial width/left immediately; top will be refined once dropdownRef is available + if (!dropdownRef.current) { + setDropdownPos({ top: triggerRect.bottom + MARGIN, left: triggerRect.left, width }); + return; + } const dropdownHeight = dropdownRef.current.offsetHeight; const dropdownWidth = dropdownRef.current.offsetWidth; - const viewportHeight = window.innerHeight; - const MARGIN = 8; - - // Horizontal: left-align to trigger, clamp to viewport const left = Math.min(triggerRect.left, window.innerWidth - dropdownWidth - 10); - - const spaceBelow = viewportHeight - triggerRect.bottom - MARGIN; + const spaceBelow = window.innerHeight - triggerRect.bottom - MARGIN; const spaceAbove = triggerRect.top - MARGIN; - - let finalTop: number; - if (spaceBelow >= dropdownHeight || spaceBelow >= spaceAbove) { - finalTop = triggerRect.bottom + MARGIN; - } else { - finalTop = triggerRect.top - dropdownHeight - MARGIN; - if (finalTop < MARGIN) finalTop = MARGIN; - } - setDropdownPos(prev => ({ ...prev, top: finalTop, left })); + const top = (spaceBelow >= dropdownHeight || spaceBelow >= spaceAbove) + ? triggerRect.bottom + MARGIN + : Math.max(MARGIN, triggerRect.top - dropdownHeight - MARGIN); + setDropdownPos({ top, left, width }); }, [open, search, Array.isArray(value) ? value.length : 0]); const filteredOptions = filterBooleanType @@ -182,9 +172,10 @@ const VariableSelect: FC = ({ const el = itemRefs.current.get(key); if (el) { const rect = el.getBoundingClientRect(); - const absoluteBottom = rect.top + CHILD_PANEL_HEIGHT; - const overflow = absoluteBottom - (window.innerHeight - 10); - const top = overflow > 0 ? rect.top - overflow : rect.top; + const spaceBelow = window.innerHeight - rect.top - 10; + const top = spaceBelow >= CHILD_PANEL_HEIGHT + ? rect.top + : Math.max(10, window.innerHeight - CHILD_PANEL_HEIGHT - 10); setChildPanelPos({ top, right: window.innerWidth - rect.left + 8 }); } }; @@ -203,7 +194,7 @@ const VariableSelect: FC = ({ variant === 'outlined' && 'rb:border rb:border-[#d9d9d9] hover:rb:border-[#4096ff]', variant === 'outlined' && open && 'rb:border-[#4096ff] rb:shadow-[0_0_0_2px_rgba(5,145,255,0.1)]', variant === 'borderless' && 'rb:border-none rb:shadow-none rb:bg-transparent', - multiple ? 'rb:min-h-8 rb:py-1' : size === 'small' ? 'rb:h-6 rb:text-[10px]' : size === 'large' ? 'rb:h-10' : 'rb:h-8 rb:text-[12px]', + multiple && size === 'small' ? 'rb:min-h-6 rb:py-0.75' : multiple ? 'rb:min-h-8 rb:py-1' : size === 'small' ? 'rb:h-6 rb:text-[10px]' : size === 'large' ? 'rb:h-10' : 'rb:h-8 rb:text-[12px]', !multiple && (size === 'small' ? 'rb:text-[10px]' : 'rb:text-[12px]'), className )} diff --git a/web/src/views/Workflow/constant.ts b/web/src/views/Workflow/constant.ts index 517648b5..7909d183 100644 --- a/web/src/views/Workflow/constant.ts +++ b/web/src/views/Workflow/constant.ts @@ -2,7 +2,7 @@ * @Author: ZhaoYing * @Date: 2026-02-03 15:06:18 * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-03-31 10:08:26 + * @Last Modified time: 2026-04-03 20:28:08 */ import LoopNode from './components/Nodes/LoopNode'; import NormalNode from './components/Nodes/NormalNode'; @@ -463,7 +463,7 @@ export const nodeLibrary: NodeLibrary[] = [ }, { type: "list-operator", icon: 'rb:bg-[url("@/assets/images/workflow/list-operator.svg")]', config: { - variable: { + input_list: { type: 'variableList', }, filter_by: {