feat(web): iteration add output_type ;
docs(web): add comments
This commit is contained in:
@@ -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 { type FC } from 'react'
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { Select, type SelectProps } from 'antd'
|
import { Select, type SelectProps } from 'antd'
|
||||||
import type { Suggestion } from '../Editor/plugin/AutocompletePlugin'
|
import type { Suggestion } from '../Editor/plugin/AutocompletePlugin'
|
||||||
type LabelRender = SelectProps['labelRender'];
|
type LabelRender = SelectProps['labelRender'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for VariableSelect component
|
||||||
|
*/
|
||||||
interface VariableSelectProps extends SelectProps {
|
interface VariableSelectProps extends SelectProps {
|
||||||
|
/** Available variable options */
|
||||||
options: Suggestion[];
|
options: Suggestion[];
|
||||||
|
/** Current selected value */
|
||||||
value?: string;
|
value?: string;
|
||||||
onChange?: (value: string) => void;
|
/** Whether to show clear button */
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
|
/** Filter out boolean type variables */
|
||||||
filterBooleanType?: boolean;
|
filterBooleanType?: boolean;
|
||||||
|
/** Size of the select component */
|
||||||
size?: 'small' | 'middle' | 'large'
|
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<VariableSelectProps> = ({
|
const VariableSelect: FC<VariableSelectProps> = ({
|
||||||
placeholder,
|
placeholder,
|
||||||
options,
|
options,
|
||||||
@@ -24,9 +42,19 @@ const VariableSelect: FC<VariableSelectProps> = ({
|
|||||||
...resetPorps
|
...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 labelRender: LabelRender = (props) => {
|
||||||
const { value } = props
|
const { value } = props
|
||||||
const filterOption = filteredOptions.find(vo => `{{${vo.value}}}` === value)
|
const filterOption = filteredOptions.find(vo => `{{${vo.value}}}` === value)
|
||||||
@@ -57,10 +85,14 @@ const VariableSelect: FC<VariableSelectProps> = ({
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
// Filter options based on boolean type if needed
|
||||||
const filteredOptions = filterBooleanType
|
const filteredOptions = filterBooleanType
|
||||||
? options.filter(option => option.dataType !== 'boolean')
|
? options.filter(option => option.dataType !== 'boolean')
|
||||||
: options;
|
: options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group suggestions by node ID
|
||||||
|
*/
|
||||||
const groupedSuggestions = filteredOptions.reduce((groups: Record<string, any[]>, suggestion) => {
|
const groupedSuggestions = filteredOptions.reduce((groups: Record<string, any[]>, suggestion) => {
|
||||||
const { nodeData } = suggestion
|
const { nodeData } = suggestion
|
||||||
const nodeId = nodeData.id as string;
|
const nodeId = nodeData.id as string;
|
||||||
@@ -71,6 +103,9 @@ const VariableSelect: FC<VariableSelectProps> = ({
|
|||||||
return groups;
|
return groups;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format grouped options for Select component
|
||||||
|
*/
|
||||||
const groupedOptions = Object.entries(groupedSuggestions).map(([_nodeId, suggestions]) => ({
|
const groupedOptions = Object.entries(groupedSuggestions).map(([_nodeId, suggestions]) => ({
|
||||||
label: suggestions[0].nodeData.name,
|
label: suggestions[0].nodeData.name,
|
||||||
options: suggestions.map(s => ({
|
options: suggestions.map(s => ({
|
||||||
|
|||||||
@@ -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 { type FC, useEffect, useState, useMemo } from "react";
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@@ -31,17 +37,35 @@ import RbSlider from './RbSlider'
|
|||||||
import JinjaRender from './JinjaRender'
|
import JinjaRender from './JinjaRender'
|
||||||
import CodeExecution from './CodeExecution'
|
import CodeExecution from './CodeExecution'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props for Properties component
|
||||||
|
*/
|
||||||
interface PropertiesProps {
|
interface PropertiesProps {
|
||||||
|
/** Currently selected node */
|
||||||
selectedNode?: Node | null;
|
selectedNode?: Node | null;
|
||||||
|
/** Function to update selected node */
|
||||||
setSelectedNode: (node: Node | null) => void;
|
setSelectedNode: (node: Node | null) => void;
|
||||||
|
/** Reference to graph instance */
|
||||||
graphRef: React.MutableRefObject<Graph | undefined>;
|
graphRef: React.MutableRefObject<Graph | undefined>;
|
||||||
|
/** Handler for blank canvas click */
|
||||||
blankClick: () => void;
|
blankClick: () => void;
|
||||||
|
/** Handler for delete event */
|
||||||
deleteEvent: () => void;
|
deleteEvent: () => void;
|
||||||
|
/** Handler for copy event */
|
||||||
copyEvent: () => void;
|
copyEvent: () => void;
|
||||||
|
/** Handler for paste event */
|
||||||
parseEvent: () => void;
|
parseEvent: () => void;
|
||||||
|
/** Workflow configuration */
|
||||||
config?: any;
|
config?: any;
|
||||||
|
/** Chat variables */
|
||||||
chatVariables: ChatVariable[];
|
chatVariables: ChatVariable[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties panel component
|
||||||
|
* Displays and manages configuration for selected workflow node
|
||||||
|
* @param props - Component props
|
||||||
|
*/
|
||||||
const Properties: FC<PropertiesProps> = ({
|
const Properties: FC<PropertiesProps> = ({
|
||||||
selectedNode,
|
selectedNode,
|
||||||
graphRef,
|
graphRef,
|
||||||
@@ -83,6 +107,10 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
}
|
}
|
||||||
}, [selectedNode, form])
|
}, [selectedNode, form])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update node label in graph
|
||||||
|
* @param newLabel - New label text
|
||||||
|
*/
|
||||||
const updateNodeLabel = (newLabel: string) => {
|
const updateNodeLabel = (newLabel: string) => {
|
||||||
if (selectedNode && form) {
|
if (selectedNode && form) {
|
||||||
const nodeData = selectedNode.data as NodeProperties;
|
const nodeData = selectedNode.data as NodeProperties;
|
||||||
@@ -107,8 +135,6 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Object.keys(values).forEach(key => {
|
Object.keys(values).forEach(key => {
|
||||||
if (selectedNode.data?.config?.[key]) {
|
if (selectedNode.data?.config?.[key]) {
|
||||||
// Create a deep copy to avoid reference sharing between nodes
|
// Create a deep copy to avoid reference sharing between nodes
|
||||||
@@ -131,7 +157,12 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 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) => {
|
const getFilteredVariableList = (nodeType?: string, key?: string) => {
|
||||||
// Check if current node is a child of iteration node
|
// Check if current node is a child of iteration node
|
||||||
const parentIterationNode = selectedNode ? (() => {
|
const parentIterationNode = selectedNode ? (() => {
|
||||||
@@ -321,15 +352,33 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
|
|
||||||
console.log('values', values)
|
console.log('values', values)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current node output variables
|
||||||
|
*/
|
||||||
const currentNodeVariables = useMemo(() => {
|
const currentNodeVariables = useMemo(() => {
|
||||||
if (!selectedNode) return []
|
if (!selectedNode) return []
|
||||||
return getCurrentNodeVariables(selectedNode?.getData(), values)
|
return getCurrentNodeVariables(selectedNode?.getData(), values)
|
||||||
}, [selectedNode?.getData(), values])
|
}, [selectedNode?.getData(), values])
|
||||||
|
|
||||||
const [outputCollapsed, setOutputCollapsed] = useState(true)
|
const [outputCollapsed, setOutputCollapsed] = useState(true)
|
||||||
|
/**
|
||||||
|
* Toggle output section collapsed state
|
||||||
|
*/
|
||||||
const handleToggle = () => {
|
const handleToggle = () => {
|
||||||
setOutputCollapsed((prev: boolean) => !prev)
|
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)
|
console.log('variableList', variableList, currentNodeVariables)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -422,6 +471,9 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (selectedNode?.data?.type === 'iteration' && key === 'output_type') {
|
||||||
|
return (<Form.Item key={key} name={key} hidden />)
|
||||||
|
}
|
||||||
if (config.type === 'define') {
|
if (config.type === 'define') {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -628,8 +680,8 @@ const Properties: FC<PropertiesProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return baseVariableList;
|
return baseVariableList;
|
||||||
})()
|
})()}
|
||||||
}
|
onChange={(value, option) => handleChangeVariableList(value, option, key)}
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
: config.type === 'switch'
|
: config.type === 'switch'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 15:06:18
|
* @Date: 2026-02-03 15:06:18
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-03 15:10:19
|
* @Last Modified time: 2026-02-03 15:25:25
|
||||||
*/
|
*/
|
||||||
import LoopNode from './components/Nodes/LoopNode';
|
import LoopNode from './components/Nodes/LoopNode';
|
||||||
import NormalNode from './components/Nodes/NormalNode';
|
import NormalNode from './components/Nodes/NormalNode';
|
||||||
@@ -317,6 +317,9 @@ export const nodeLibrary: NodeLibrary[] = [
|
|||||||
output: {
|
output: {
|
||||||
type: 'variableList',
|
type: 'variableList',
|
||||||
filterChildNodes: true
|
filterChildNodes: true
|
||||||
|
},
|
||||||
|
output_type: {
|
||||||
|
type: 'define',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user