diff --git a/web/src/views/Workflow/components/Properties/VariableSelect.tsx b/web/src/views/Workflow/components/Properties/VariableSelect.tsx index f56180a0..7ae4eff5 100644 --- a/web/src/views/Workflow/components/Properties/VariableSelect.tsx +++ b/web/src/views/Workflow/components/Properties/VariableSelect.tsx @@ -1,18 +1,36 @@ +/* + * @Author: ZhaoYing + * @Date: 2026-02-03 15:40:13 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-03 15:40:13 + */ import { type FC } from 'react' import clsx from 'clsx'; import { Select, type SelectProps } from 'antd' import type { Suggestion } from '../Editor/plugin/AutocompletePlugin' type LabelRender = SelectProps['labelRender']; +/** + * Props for VariableSelect component + */ interface VariableSelectProps extends SelectProps { + /** Available variable options */ options: Suggestion[]; + /** Current selected value */ value?: string; - onChange?: (value: string) => void; + /** Whether to show clear button */ allowClear?: boolean; + /** Filter out boolean type variables */ filterBooleanType?: boolean; + /** Size of the select component */ size?: 'small' | 'middle' | 'large' } +/** + * VariableSelect component + * Custom select component for workflow variables with grouped options and custom rendering + * @param props - Component props + */ const VariableSelect: FC = ({ placeholder, options, @@ -24,9 +42,19 @@ const VariableSelect: FC = ({ ...resetPorps }) => { - const handleChange = (value: string) => { - onChange?.(value); + /** + * Handle value change and pass selected option to parent + * @param value - Selected value + */ + const handleChange: SelectProps['onChange'] = (value: string) => { + const filterItem = options.find(option => `{{${option.value}}}` === value) + onChange?.(value, filterItem); } + /** + * Custom label renderer for selected value + * Displays node icon, name and variable label + * @param props - Label render props + */ const labelRender: LabelRender = (props) => { const { value } = props const filterOption = filteredOptions.find(vo => `{{${vo.value}}}` === value) @@ -57,10 +85,14 @@ const VariableSelect: FC = ({ } return null } + // Filter options based on boolean type if needed const filteredOptions = filterBooleanType ? options.filter(option => option.dataType !== 'boolean') : options; + /** + * Group suggestions by node ID + */ const groupedSuggestions = filteredOptions.reduce((groups: Record, suggestion) => { const { nodeData } = suggestion const nodeId = nodeData.id as string; @@ -71,6 +103,9 @@ const VariableSelect: FC = ({ return groups; }, {}); + /** + * Format grouped options for Select component + */ const groupedOptions = Object.entries(groupedSuggestions).map(([_nodeId, suggestions]) => ({ label: suggestions[0].nodeData.name, options: suggestions.map(s => ({ diff --git a/web/src/views/Workflow/components/Properties/index.tsx b/web/src/views/Workflow/components/Properties/index.tsx index aa757275..59860005 100644 --- a/web/src/views/Workflow/components/Properties/index.tsx +++ b/web/src/views/Workflow/components/Properties/index.tsx @@ -1,3 +1,9 @@ +/* + * @Author: ZhaoYing + * @Date: 2026-02-03 15:39:59 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-03 15:39:59 + */ import { type FC, useEffect, useState, useMemo } from "react"; import clsx from 'clsx' import { useTranslation } from 'react-i18next' @@ -31,17 +37,35 @@ import RbSlider from './RbSlider' import JinjaRender from './JinjaRender' import CodeExecution from './CodeExecution' +/** + * Props for Properties component + */ interface PropertiesProps { + /** Currently selected node */ selectedNode?: Node | null; + /** Function to update selected node */ setSelectedNode: (node: Node | null) => void; + /** Reference to graph instance */ graphRef: React.MutableRefObject; + /** Handler for blank canvas click */ blankClick: () => void; + /** Handler for delete event */ deleteEvent: () => void; + /** Handler for copy event */ copyEvent: () => void; + /** Handler for paste event */ parseEvent: () => void; + /** Workflow configuration */ config?: any; + /** Chat variables */ chatVariables: ChatVariable[]; } + +/** + * Properties panel component + * Displays and manages configuration for selected workflow node + * @param props - Component props + */ const Properties: FC = ({ selectedNode, graphRef, @@ -83,6 +107,10 @@ const Properties: FC = ({ } }, [selectedNode, form]) + /** + * Update node label in graph + * @param newLabel - New label text + */ const updateNodeLabel = (newLabel: string) => { if (selectedNode && form) { const nodeData = selectedNode.data as NodeProperties; @@ -107,8 +135,6 @@ const Properties: FC = ({ })) } - - Object.keys(values).forEach(key => { if (selectedNode.data?.config?.[key]) { // Create a deep copy to avoid reference sharing between nodes @@ -131,7 +157,12 @@ const Properties: FC = ({ - // Filter out boolean type variables for loop and llm nodes + /** + * Get filtered variable list based on node type and config key + * @param nodeType - Type of the node + * @param key - Configuration key + * @returns Filtered variable list + */ const getFilteredVariableList = (nodeType?: string, key?: string) => { // Check if current node is a child of iteration node const parentIterationNode = selectedNode ? (() => { @@ -321,15 +352,33 @@ const Properties: FC = ({ console.log('values', values) + /** + * Get current node output variables + */ const currentNodeVariables = useMemo(() => { if (!selectedNode) return [] return getCurrentNodeVariables(selectedNode?.getData(), values) }, [selectedNode?.getData(), values]) const [outputCollapsed, setOutputCollapsed] = useState(true) + /** + * Toggle output section collapsed state + */ const handleToggle = () => { setOutputCollapsed((prev: boolean) => !prev) } + + /** + * Handle variable list change and update output type for iteration nodes + * @param _value - Selected value + * @param option - Selected option + * @param key - Configuration key + */ + const handleChangeVariableList = (_value: string, option: any, key: string) => { + if (selectedNode?.data?.type === 'iteration' && key === 'output') { + form.setFieldValue('output_type', option?.dataType) + } + } console.log('variableList', variableList, currentNodeVariables) return ( @@ -422,6 +471,9 @@ const Properties: FC = ({ ) } + if (selectedNode?.data?.type === 'iteration' && key === 'output_type') { + return (