import PropTypes from 'prop-types' import { Handle, Position, useUpdateNodeInternals } from 'reactflow' import { useEffect, useRef, useState, useContext } from 'react' import { useSelector, useDispatch } from 'react-redux' import { cloneDeep } from 'lodash' import showdown from 'showdown' import parser from 'html-react-parser' // material-ui import { useTheme, styled } from '@mui/material/styles' import { Popper, Box, Typography, Tooltip, IconButton, Button, TextField, Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material' import { useGridApiContext } from '@mui/x-data-grid' import IconAutoFixHigh from '@mui/icons-material/AutoFixHigh' import { tooltipClasses } from '@mui/material/Tooltip' import { IconWand, IconVariable, IconArrowsMaximize, IconEdit, IconAlertTriangle, IconBulb, IconRefresh, IconX } from '@tabler/icons-react' import { Tabs } from '@mui/base/Tabs' import Autocomplete, { autocompleteClasses } from '@mui/material/Autocomplete' // project import import { Dropdown } from '@/ui-component/dropdown/Dropdown' import { MultiDropdown } from '@/ui-component/dropdown/MultiDropdown' import { AsyncDropdown } from '@/ui-component/dropdown/AsyncDropdown' import { Input } from '@/ui-component/input/Input' import { RichInput } from '@/ui-component/input/RichInput' import { DataGrid } from '@/ui-component/grid/DataGrid' import { File } from '@/ui-component/file/File' import { SwitchInput } from '@/ui-component/switch/Switch' import { flowContext } from '@/store/context/ReactFlowContext' import { JsonEditorInput } from '@/ui-component/json/JsonEditor' import { TooltipWithParser } from '@/ui-component/tooltip/TooltipWithParser' import { CodeEditor } from '@/ui-component/editor/CodeEditor' import { TabPanel } from '@/ui-component/tabs/TabPanel' import { TabsList } from '@/ui-component/tabs/TabsList' import { ArrayRenderer } from '@/ui-component/array/ArrayRenderer' import { Tab } from '@/ui-component/tabs/Tab' import { ConfigInput } from '@/views/agentflowsv2/ConfigInput' import { BackdropLoader } from '@/ui-component/loading/BackdropLoader' import DocStoreInputHandler from '@/views/docstore/DocStoreInputHandler' import ToolDialog from '@/views/tools/ToolDialog' import AssistantDialog from '@/views/assistants/openai/AssistantDialog' import FormatPromptValuesDialog from '@/ui-component/dialog/FormatPromptValuesDialog' import ExpandTextDialog from '@/ui-component/dialog/ExpandTextDialog' import ExpandRichInputDialog from '@/ui-component/dialog/ExpandRichInputDialog' import ConditionDialog from '@/ui-component/dialog/ConditionDialog' import PromptLangsmithHubDialog from '@/ui-component/dialog/PromptLangsmithHubDialog' import ManageScrapedLinksDialog from '@/ui-component/dialog/ManageScrapedLinksDialog' import CredentialInputHandler from './CredentialInputHandler' import InputHintDialog from '@/ui-component/dialog/InputHintDialog' import NvidiaNIMDialog from '@/ui-component/dialog/NvidiaNIMDialog' import PromptGeneratorDialog from '@/ui-component/dialog/PromptGeneratorDialog' // API import assistantsApi from '@/api/assistants' import documentstoreApi from '@/api/documentstore' // utils import { initNode, getInputVariables, getCustomConditionOutputs, isValidConnection, getAvailableNodesForVariable } from '@/utils/genericHelper' import useNotifier from '@/utils/useNotifier' // const import { baseURL, FLOWISE_CREDENTIAL_ID } from '@/store/constant' import { closeSnackbar as closeSnackbarAction, enqueueSnackbar as enqueueSnackbarAction } from '@/store/actions' const EDITABLE_OPTIONS = ['selectedTool', 'selectedAssistant'] const CustomWidthTooltip = styled(({ className, ...props }) => )({ [`& .${tooltipClasses.tooltip}`]: { maxWidth: 500 } }) const StyledPopper = styled(Popper)({ boxShadow: '0px 8px 10px -5px rgb(0 0 0 / 20%), 0px 16px 24px 2px rgb(0 0 0 / 14%), 0px 6px 30px 5px rgb(0 0 0 / 12%)', borderRadius: '10px', [`& .${autocompleteClasses.listbox}`]: { boxSizing: 'border-box', '& ul': { padding: 10, margin: 10 } } }) const markdownConverter = new showdown.Converter({ simplifiedAutoLink: true, strikethrough: true, tables: true, tasklists: true }) // ===========================|| NodeInputHandler ||=========================== // const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isAdditionalParams = false, disablePadding = false, parentParamForArray = null, arrayIndex = null, onHideNodeInfoDialog, onCustomDataChange }) => { const theme = useTheme() const customization = useSelector((state) => state.customization) const ref = useRef(null) const { reactFlowInstance, deleteEdge, onNodeDataChange } = useContext(flowContext) const updateNodeInternals = useUpdateNodeInternals() useNotifier() const dispatch = useDispatch() const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) const [position, setPosition] = useState(0) const [showExpandDialog, setShowExpandDialog] = useState(false) const [expandDialogProps, setExpandDialogProps] = useState({}) const [showExpandRichDialog, setShowExpandRichDialog] = useState(false) const [expandRichDialogProps, setExpandRichDialogProps] = useState({}) const [showAsyncOptionDialog, setAsyncOptionEditDialog] = useState('') const [asyncOptionEditDialogProps, setAsyncOptionEditDialogProps] = useState({}) const [reloadTimestamp, setReloadTimestamp] = useState(Date.now().toString()) const [showFormatPromptValuesDialog, setShowFormatPromptValuesDialog] = useState(false) const [formatPromptValuesDialogProps, setFormatPromptValuesDialogProps] = useState({}) const [showPromptHubDialog, setShowPromptHubDialog] = useState(false) const [showManageScrapedLinksDialog, setShowManageScrapedLinksDialog] = useState(false) const [manageScrapedLinksDialogProps, setManageScrapedLinksDialogProps] = useState({}) const [showInputHintDialog, setShowInputHintDialog] = useState(false) const [inputHintDialogProps, setInputHintDialogProps] = useState({}) const [showConditionDialog, setShowConditionDialog] = useState(false) const [conditionDialogProps, setConditionDialogProps] = useState({}) const [isNvidiaNIMDialogOpen, setIsNvidiaNIMDialogOpen] = useState(false) const [tabValue, setTabValue] = useState(0) const [modelSelectionDialogOpen, setModelSelectionDialogOpen] = useState(false) const [availableChatModels, setAvailableChatModels] = useState([]) const [availableChatModelsOptions, setAvailableChatModelsOptions] = useState([]) const [selectedTempChatModel, setSelectedTempChatModel] = useState({}) const [modelSelectionCallback, setModelSelectionCallback] = useState(null) const [loading, setLoading] = useState(false) const [promptGeneratorDialogOpen, setPromptGeneratorDialogOpen] = useState(false) const [promptGeneratorDialogProps, setPromptGeneratorDialogProps] = useState({}) const handleDataChange = ({ inputParam, newValue }) => { data.inputs[inputParam.name] = newValue const allowedShowHideInputTypes = ['boolean', 'asyncOptions', 'asyncMultiOptions', 'options', 'multiOptions'] if (allowedShowHideInputTypes.includes(inputParam.type)) { if (onCustomDataChange) { onCustomDataChange({ nodeId: data.id, inputParam, newValue }) } else { onNodeDataChange({ nodeId: data.id, inputParam, newValue }) } } } const onInputHintDialogClicked = (hint) => { const dialogProps = { ...hint } setInputHintDialogProps(dialogProps) setShowInputHintDialog(true) } const onExpandDialogClicked = (value, inputParam, languageType) => { const dialogProps = { value, inputParam, disabled, languageType, nodes: reactFlowInstance?.getNodes() || [], edges: reactFlowInstance?.getEdges() || [], nodeId: data.id, confirmButtonName: 'Save', cancelButtonName: 'Cancel' } if (inputParam.acceptVariable) { setExpandRichDialogProps(dialogProps) setShowExpandRichDialog(true) } else { setExpandDialogProps(dialogProps) setShowExpandDialog(true) } } const onConditionDialogClicked = (inputParam) => { const dialogProps = { data, inputParam, disabled, confirmButtonName: 'Save', cancelButtonName: 'Cancel' } setConditionDialogProps(dialogProps) setShowConditionDialog(true) onHideNodeInfoDialog(true) } const onShowPromptHubButtonClicked = () => { setShowPromptHubDialog(true) } const onShowPromptHubButtonSubmit = (templates) => { setShowPromptHubDialog(false) for (const t of templates) { if (Object.prototype.hasOwnProperty.call(data.inputs, t.type)) { data.inputs[t.type] = t.template } } } const onManageLinksDialogClicked = (url, selectedLinks, relativeLinksMethod, limit) => { const dialogProps = { url, relativeLinksMethod, limit, selectedLinks, confirmButtonName: 'Save', cancelButtonName: 'Cancel' } setManageScrapedLinksDialogProps(dialogProps) setShowManageScrapedLinksDialog(true) } const onManageLinksDialogSave = (url, links) => { setShowManageScrapedLinksDialog(false) data.inputs.url = url data.inputs.selectedLinks = links } const getJSONValue = (templateValue) => { if (!templateValue) return '' const obj = {} const inputVariables = getInputVariables(templateValue) for (const inputVariable of inputVariables) { obj[inputVariable] = '' } if (Object.keys(obj).length) return JSON.stringify(obj) return '' } const getDataGridColDef = (columns, inputParam) => { const colDef = [] for (const column of columns) { const stateNode = reactFlowInstance ? reactFlowInstance.getNodes().find((node) => node.data.name === 'seqState') : null if (column.type === 'asyncSingleSelect' && column.loadMethod && column.loadMethod.includes('loadStateKeys')) { if (stateNode) { const tabParam = stateNode.data.inputParams.find((param) => param.tabIdentifier) if (tabParam && tabParam.tabs.length > 0) { const selectedTabIdentifier = tabParam.tabIdentifier const selectedTab = stateNode.data.inputs[`${selectedTabIdentifier}_${stateNode.data.id}`] || tabParam.default || tabParam.tabs[0].name const datagridValues = stateNode.data.inputs[selectedTab] if (datagridValues) { try { const parsedDatagridValues = JSON.parse(datagridValues) const keys = Array.isArray(parsedDatagridValues) ? parsedDatagridValues.map((item) => item.key) : Object.keys(parsedDatagridValues) colDef.push({ ...column, field: column.field, headerName: column.headerName, type: 'singleSelect', editable: true, valueOptions: keys }) } catch (error) { console.error('Error parsing stateMemory', error) } } } } else { colDef.push({ ...column, field: column.field, headerName: column.headerName, type: 'singleSelect', editable: true, valueOptions: [] }) } } else if (column.type === 'freeSolo') { const preLoadOptions = [] if (column.loadMethod && column.loadMethod.includes('getPreviousMessages')) { const nodes = getAvailableNodesForVariable( reactFlowInstance?.getNodes() || [], reactFlowInstance?.getEdges() || [], data.id, inputParam.id ) for (const node of nodes) { preLoadOptions.push({ value: `$${node.id}`, label: `Output from ${node.data.id}` }) } } if (column.loadMethod && column.loadMethod.includes('loadStateKeys')) { if (stateNode) { const tabParam = stateNode.data.inputParams.find((param) => param.tabIdentifier) if (tabParam && tabParam.tabs.length > 0) { const selectedTabIdentifier = tabParam.tabIdentifier const selectedTab = stateNode.data.inputs[`${selectedTabIdentifier}_${stateNode.data.id}`] || tabParam.default || tabParam.tabs[0].name const datagridValues = stateNode.data.inputs[selectedTab] if (datagridValues) { try { const parsedDatagridValues = JSON.parse(datagridValues) const keys = Array.isArray(parsedDatagridValues) ? parsedDatagridValues.map((item) => item.key) : Object.keys(parsedDatagridValues) for (const key of keys) { preLoadOptions.push({ value: `$flow.state.${key}`, label: `Value from ${key}` }) } } catch (error) { console.error('Error parsing stateMemory', error) } } } } } colDef.push({ ...column, field: column.field, headerName: column.headerName, renderEditCell: ({ id, field, value }) => { // eslint-disable-next-line react-hooks/rules-of-hooks const apiRef = useGridApiContext() return ( } renderOption={(props, option) => (
  • {option.value}
    {option.label}
  • )} getOptionLabel={(option) => { return typeof option === 'string' ? option : option.value }} onInputChange={(event, newValue) => { apiRef.current.setEditCellValue({ id, field, value: newValue }) }} sx={{ '& .MuiInputBase-root': { height: '50px' // Adjust this value as needed }, '& .MuiOutlinedInput-root': { border: 'none' }, '& .MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline': { border: 'none' } }} /> ) } }) } else { colDef.push(column) } } return colDef } const getDropdownOptions = (inputParam) => { const preLoadOptions = [] if (inputParam.loadPreviousNodes) { const nodes = getAvailableNodesForVariable( reactFlowInstance?.getNodes() || [], reactFlowInstance?.getEdges() || [], data.id, inputParam.id ) for (const node of nodes) { preLoadOptions.push({ name: `{{ ${node.data.id} }}`, label: `{{ ${node.data.id} }}`, description: `Output from ${node.data.id}` }) } } return [...preLoadOptions, ...inputParam.options] } const getTabValue = (inputParam) => { return inputParam.tabs.findIndex((item) => item.name === data.inputs[`${inputParam.tabIdentifier}_${data.id}`]) >= 0 ? inputParam.tabs.findIndex((item) => item.name === data.inputs[`${inputParam.tabIdentifier}_${data.id}`]) : tabValue } const onEditJSONClicked = (value, inputParam) => { // Preset values if the field is format prompt values let inputValue = value if (inputParam.name === 'promptValues' && !value) { const templateValue = (data.inputs['template'] ?? '') + (data.inputs['systemMessagePrompt'] ?? '') + (data.inputs['humanMessagePrompt'] ?? '') + (data.inputs['workerPrompt'] ?? '') inputValue = getJSONValue(templateValue) } const dialogProp = { value: inputValue, inputParam, nodes: reactFlowInstance?.getNodes() || [], edges: reactFlowInstance?.getEdges() || [], nodeId: data.id, data } setFormatPromptValuesDialogProps(dialogProp) setShowFormatPromptValuesDialog(true) } const onExpandDialogSave = (newValue, inputParamName) => { data.inputs[inputParamName] = newValue setShowExpandDialog(false) } const onExpandRichDialogSave = (newValue, inputParamName) => { data.inputs[inputParamName] = newValue setShowExpandRichDialog(false) } const onConditionDialogSave = (newData, inputParam, tabValue) => { data.inputs[`${inputParam.tabIdentifier}_${data.id}`] = inputParam.tabs[tabValue].name const existingEdges = reactFlowInstance?.getEdges().filter((edge) => edge.source === data.id) || [] const { outputAnchors, toBeRemovedEdgeIds } = getCustomConditionOutputs( newData.inputs[inputParam.tabs[tabValue].name], data.id, existingEdges, inputParam.tabs[tabValue].type === 'datagrid' ) if (!outputAnchors) return data.outputAnchors = outputAnchors for (const edgeId of toBeRemovedEdgeIds) { deleteEdge(edgeId) } setShowConditionDialog(false) onHideNodeInfoDialog(false) } const editAsyncOption = (inputParamName, inputValue) => { if (inputParamName === 'selectedTool') { setAsyncOptionEditDialogProps({ title: 'Edit Tool', type: 'EDIT', cancelButtonName: 'Cancel', confirmButtonName: 'Save', toolId: inputValue }) } else if (inputParamName === 'selectedAssistant') { setAsyncOptionEditDialogProps({ title: 'Edit Assistant', type: 'EDIT', cancelButtonName: 'Cancel', confirmButtonName: 'Save', assistantId: inputValue }) } setAsyncOptionEditDialog(inputParamName) } const addAsyncOption = (inputParamName) => { if (inputParamName === 'selectedTool') { setAsyncOptionEditDialogProps({ title: 'Add New Tool', type: 'ADD', cancelButtonName: 'Cancel', confirmButtonName: 'Add' }) } else if (inputParamName === 'selectedAssistant') { setAsyncOptionEditDialogProps({ title: 'Add New Assistant', type: 'ADD', cancelButtonName: 'Cancel', confirmButtonName: 'Add' }) } setAsyncOptionEditDialog(inputParamName) } const onConfirmAsyncOption = (selectedOptionId = '') => { if (!selectedOptionId) { data.inputs[showAsyncOptionDialog] = '' handleDataChange({ inputParam: { name: showAsyncOptionDialog }, newValue: '' }) } else { data.inputs[showAsyncOptionDialog] = selectedOptionId handleDataChange({ inputParam: { name: showAsyncOptionDialog }, newValue: selectedOptionId }) setReloadTimestamp(Date.now().toString()) } setAsyncOptionEditDialogProps({}) setAsyncOptionEditDialog('') } const handleNvidiaNIMDialogComplete = (containerData) => { if (containerData) { data.inputs['basePath'] = containerData.baseUrl data.inputs['modelName'] = containerData.image } } const loadChatModels = async () => { try { const resp = await assistantsApi.getChatModels() if (resp.data) { const chatModels = resp.data ?? [] const chatModelsOptions = chatModels.map((model) => ({ name: model.name, label: model.label, description: model.description, imageSrc: `${baseURL}/api/v1/node-icon/${model.name}` })) setAvailableChatModels(chatModels) setAvailableChatModelsOptions(chatModelsOptions) } } catch (error) { console.error('Error loading chat models:', error) } } const checkInputParamsMandatory = () => { let canSubmit = true if (selectedTempChatModel && Object.keys(selectedTempChatModel).length > 0) { const inputParams = (selectedTempChatModel.inputParams ?? []).filter((inputParam) => !inputParam.hidden) for (const inputParam of inputParams) { if (!inputParam.optional && (!selectedTempChatModel.inputs[inputParam.name] || !selectedTempChatModel.credential)) { if (inputParam.type === 'credential' && !selectedTempChatModel.credential) { canSubmit = false break } else if (inputParam.type !== 'credential' && !selectedTempChatModel.inputs[inputParam.name]) { canSubmit = false break } } } } return canSubmit } const displayWarning = () => { enqueueSnackbar({ message: 'Please fill in all mandatory fields.', options: { key: new Date().getTime() + Math.random(), variant: 'warning', action: (key) => ( ) } }) } const generateDocStoreToolDesc = async (storeId) => { if (!storeId) { enqueueSnackbar({ message: 'Please select a knowledge base', options: { key: new Date().getTime() + Math.random(), variant: 'error', action: (key) => ( ) } }) return } storeId = storeId.split(':')[0] const isValid = checkInputParamsMandatory() if (!isValid) { displayWarning() return } // Check if model is already selected in the node const currentNode = reactFlowInstance?.getNodes().find((node) => node.id === data.id) const currentNodeInputs = currentNode?.data?.inputs const existingModel = currentNodeInputs?.llmModel || currentNodeInputs?.agentModel || currentNodeInputs?.humanInputModel if (existingModel) { try { setLoading(true) const selectedChatModelObj = { name: existingModel, inputs: currentNodeInputs?.llmModelConfig || currentNodeInputs?.agentModelConfig || currentNodeInputs?.humanInputModelConfig } const resp = await documentstoreApi.generateDocStoreToolDesc(storeId, { selectedChatModel: selectedChatModelObj }) if (resp.data) { setLoading(false) const content = resp.data?.content || resp.data.kwargs?.content // Update the input value directly data.inputs[inputParam.name] = content enqueueSnackbar({ message: 'Document Store Tool Description generated successfully', options: { key: new Date().getTime() + Math.random(), variant: 'success', action: (key) => ( ) } }) } } catch (error) { console.error('Error generating doc store tool desc', error) setLoading(false) enqueueSnackbar({ message: typeof error.response.data === 'object' ? error.response.data.message : error.response.data, options: { key: new Date().getTime() + Math.random(), variant: 'error', persist: true, action: (key) => ( ) } }) } return } // If no model selected, load chat models and open model selection dialog await loadChatModels() setModelSelectionCallback(() => async (selectedModel) => { try { setLoading(true) const selectedChatModelObj = { name: selectedModel.name, inputs: selectedModel.inputs } const resp = await documentstoreApi.generateDocStoreToolDesc(storeId, { selectedChatModel: selectedChatModelObj }) if (resp.data) { setLoading(false) const content = resp.data?.content || resp.data.kwargs?.content // Update the input value directly data.inputs[inputParam.name] = content enqueueSnackbar({ message: 'Document Store Tool Description generated successfully', options: { key: new Date().getTime() + Math.random(), variant: 'success', action: (key) => ( ) } }) } } catch (error) { console.error('Error generating doc store tool desc', error) setLoading(false) enqueueSnackbar({ message: typeof error.response.data === 'object' ? error.response.data.message : error.response.data, options: { key: new Date().getTime() + Math.random(), variant: 'error', persist: true, action: (key) => ( ) } }) } }) setModelSelectionDialogOpen(true) } const generateInstruction = async () => { const isValid = checkInputParamsMandatory() if (!isValid) { displayWarning() return } const currentNode = reactFlowInstance?.getNodes().find((node) => node.id === data.id) const currentNodeInputs = currentNode?.data?.inputs // Check if model is already selected in the node const existingModel = currentNodeInputs?.llmModel || currentNodeInputs?.agentModel || currentNodeInputs?.humanInputModel if (existingModel) { // Open prompt generator dialog directly with existing model setPromptGeneratorDialogProps({ title: 'Generate Instructions', description: 'You can generate a prompt template by sharing basic details about your task.', data: { selectedChatModel: { name: existingModel, inputs: currentNodeInputs?.llmModelConfig || currentNodeInputs?.agentModelConfig || currentNodeInputs?.humanInputModelConfig } } }) setPromptGeneratorDialogOpen(true) return } // If no model selected, load chat models and open model selection dialog await loadChatModels() setModelSelectionCallback(() => async (selectedModel) => { // After model selection, open prompt generator dialog setPromptGeneratorDialogProps({ title: 'Generate Instructions', description: 'You can generate a prompt template by sharing basic details about your task.', data: { selectedChatModel: selectedModel } }) setPromptGeneratorDialogOpen(true) }) setModelSelectionDialogOpen(true) } useEffect(() => { if (ref.current && ref.current.offsetTop && ref.current.clientHeight) { setPosition(ref.current.offsetTop + ref.current.clientHeight / 2) updateNodeInternals(data.id) } }, [data.id, ref, updateNodeInternals]) useEffect(() => { updateNodeInternals(data.id) }, [data.id, position, updateNodeInternals]) return (
    {inputAnchor && ( <> isValidConnection(connection, reactFlowInstance)} style={{ height: 10, width: 10, backgroundColor: data.selected ? theme.palette.primary.main : theme.palette.text.secondary, top: position }} /> {inputAnchor.label} {!inputAnchor.optional &&  *} {inputAnchor.description && } )} {((inputParam && !inputParam.additionalParams) || isAdditionalParams) && ( <> {inputParam.acceptVariable && !isAdditionalParams && ( isValidConnection(connection, reactFlowInstance)} style={{ height: 10, width: 10, backgroundColor: data.selected ? theme.palette.primary.main : theme.palette.text.secondary, top: position }} /> )} {(data.name === 'promptTemplate' || data.name === 'chatPromptTemplate') && (inputParam.name === 'template' || inputParam.name === 'systemMessagePrompt') && ( <> setShowPromptHubDialog(false)} onSubmit={onShowPromptHubButtonSubmit} > )} {data.name === 'chatNvidiaNIM' && inputParam.name === 'modelName' && ( <> )}
    {inputParam.label} {!inputParam.optional &&  *} {inputParam.description && }
    {inputParam.hint && !isAdditionalParams && ( onInputHintDialogClicked(inputParam.hint)} > )} {inputParam.hint && isAdditionalParams && ( )} {inputParam.acceptVariable && inputParam.type === 'string' && ( )} {inputParam.generateDocStoreDescription && ( generateDocStoreToolDesc(data.inputs['documentStore'])} > )} {inputParam.generateInstruction && ( generateInstruction()} > )} {((inputParam.type === 'string' && inputParam.rows) || inputParam.type === 'code') && ( onExpandDialogClicked(data.inputs[inputParam.name] ?? inputParam.default ?? '', inputParam) } > )}
    {inputParam.warning && (
    {parser(inputParam.warning)}
    )} {inputParam.type === 'credential' && ( { data.credential = newValue data.inputs[FLOWISE_CREDENTIAL_ID] = newValue // in case data.credential is not updated }} /> )} {inputParam.type === 'tabs' && ( <> { setTabValue(val) data.inputs[`${inputParam.tabIdentifier}_${data.id}`] = inputParam.tabs[val].name }} aria-label='tabs' variant='fullWidth' defaultValue={getTabValue(inputParam)} > {inputParam.tabs.map((inputChildParam, index) => ( {inputChildParam.label} ))} {inputParam.tabs .filter((inputParam) => inputParam.display !== false) .map((inputChildParam, index) => ( ))} )} {inputParam.type === 'file' && ( (data.inputs[inputParam.name] = newValue)} value={data.inputs[inputParam.name] ?? inputParam.default ?? 'Choose a file to upload'} /> )} {inputParam.type === 'boolean' && ( handleDataChange({ inputParam, newValue })} value={data.inputs[inputParam.name] ?? inputParam.default ?? false} /> )} {inputParam.type === 'datagrid' && ( (data.inputs[inputParam.name] = newValue)} /> )} {inputParam.type === 'code' && ( <>
    {inputParam.codeExample && ( )}
    (data.inputs[inputParam.name] = code)} basicSetup={{ highlightActiveLine: false, highlightActiveLineGutter: false }} />
    )} {(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && (inputParam?.acceptVariable && (window.location.href.includes('v2/agentcanvas') || window.location.href.includes('v2/marketplace')) ? ( (data.inputs[inputParam.name] = newValue)} value={data.inputs[inputParam.name] ?? inputParam.default ?? ''} nodes={reactFlowInstance ? reactFlowInstance.getNodes() : []} edges={reactFlowInstance ? reactFlowInstance.getEdges() : []} nodeId={data.id} /> ) : ( (data.inputs[inputParam.name] = newValue)} value={data.inputs[inputParam.name] ?? inputParam.default ?? ''} nodes={[]} edges={[]} nodeId={data.id} /> ))} {inputParam.type === 'json' && ( <> {!inputParam?.acceptVariable && ( (data.inputs[inputParam.name] = newValue)} value={ data.inputs[inputParam.name] || inputParam.default || getJSONValue(data.inputs['workerPrompt']) || '' } isSequentialAgent={data.category === 'Sequential Agents'} isDarkMode={customization.isDarkMode} /> )} {inputParam?.acceptVariable && ( <> setShowFormatPromptValuesDialog(false)} onChange={(newValue) => (data.inputs[inputParam.name] = newValue)} > )} )} {inputParam.type === 'options' && (
    handleDataChange({ inputParam, newValue })} value={data.inputs[inputParam.name] ?? inputParam.default ?? 'choose an option'} />
    )} {inputParam.type === 'multiOptions' && (
    handleDataChange({ inputParam, newValue })} value={data.inputs[inputParam.name] ?? inputParam.default ?? 'choose an option'} />
    )} {(inputParam.type === 'asyncOptions' || inputParam.type === 'asyncMultiOptions') && ( <> {data.inputParams.length === 1 &&
    }
    { if (inputParam.loadConfig) setReloadTimestamp(Date.now().toString()) handleDataChange({ inputParam, newValue }) }} onCreateNew={() => addAsyncOption(inputParam.name)} /> {EDITABLE_OPTIONS.includes(inputParam.name) && data.inputs[inputParam.name] && ( editAsyncOption(inputParam.name, data.inputs[inputParam.name])} > )} {inputParam.refresh && ( setReloadTimestamp(Date.now().toString())} > )}
    )} {inputParam.type === 'array' && } {/* CUSTOM INPUT LOGIC */} {inputParam.type.includes('conditionFunction') && ( <> )} {(data.name === 'cheerioWebScraper' || data.name === 'puppeteerWebScraper' || data.name === 'playwrightWebScraper') && inputParam.name === 'url' && ( <> setShowManageScrapedLinksDialog(false)} onSave={onManageLinksDialogSave} /> )} {inputParam.loadConfig && data && data.inputs && data.inputs[inputParam.name] && ( <> )} )} setAsyncOptionEditDialog('')} onConfirm={onConfirmAsyncOption} > setAsyncOptionEditDialog('')} onConfirm={onConfirmAsyncOption} > setShowExpandDialog(false)} onConfirm={(newValue, inputParamName) => onExpandDialogSave(newValue, inputParamName)} onInputHintDialogClicked={onInputHintDialogClicked} > setShowExpandRichDialog(false)} onConfirm={(newValue, inputParamName) => onExpandRichDialogSave(newValue, inputParamName)} onInputHintDialogClicked={onInputHintDialogClicked} > { setShowConditionDialog(false) onHideNodeInfoDialog(false) }} onConfirm={(newData, inputParam, tabValue) => onConditionDialogSave(newData, inputParam, tabValue)} > setShowInputHintDialog(false)} > setIsNvidiaNIMDialogOpen(false)} onComplete={handleNvidiaNIMDialogComplete} > { setModelSelectionDialogOpen(false) setSelectedTempChatModel({}) }} aria-labelledby='model-selection-dialog-title' maxWidth='sm' fullWidth > Select Model { if (!newValue) { setSelectedTempChatModel({}) } else { const foundChatComponent = availableChatModels.find((chatModel) => chatModel.name === newValue) if (foundChatComponent) { const chatModelId = `${foundChatComponent.name}_0` const clonedComponent = cloneDeep(foundChatComponent) const initChatModelData = initNode(clonedComponent, chatModelId) setSelectedTempChatModel(initChatModelData) } } }} value={selectedTempChatModel?.name ?? 'choose an option'} /> {selectedTempChatModel && Object.keys(selectedTempChatModel).length > 0 && ( {(selectedTempChatModel.inputParams ?? []) .filter((inputParam) => !inputParam.hidden) .map((inputParam, index) => ( ))} )} setPromptGeneratorDialogOpen(false)} onConfirm={(generatedInstruction) => { try { if (inputParam?.acceptVariable && window.location.href.includes('v2/agentcanvas')) { const htmlContent = markdownConverter.makeHtml(generatedInstruction) data.inputs[inputParam.name] = htmlContent } else { data.inputs[inputParam.name] = generatedInstruction } setPromptGeneratorDialogOpen(false) } catch (error) { enqueueSnackbar({ message: 'Error setting generated instruction', options: { key: new Date().getTime() + Math.random(), variant: 'error', persist: true, action: (key) => ( ) } }) } }} /> {loading && }
    ) } NodeInputHandler.propTypes = { inputAnchor: PropTypes.object, inputParam: PropTypes.object, data: PropTypes.object, disabled: PropTypes.bool, isAdditionalParams: PropTypes.bool, disablePadding: PropTypes.bool, parentParamForArray: PropTypes.object, arrayIndex: PropTypes.number, onCustomDataChange: PropTypes.func, onHideNodeInfoDialog: PropTypes.func } export default NodeInputHandler