|
import PropTypes from 'prop-types' |
|
import { Handle, Position, useUpdateNodeInternals } from 'reactflow' |
|
import { useEffect, useRef, useState, useContext } from 'react' |
|
import { useSelector } from 'react-redux' |
|
|
|
|
|
import { useTheme, styled } from '@mui/material/styles' |
|
import { Box, Typography, Tooltip, IconButton } from '@mui/material' |
|
import { tooltipClasses } from '@mui/material/Tooltip' |
|
import { IconArrowsMaximize } from '@tabler/icons' |
|
|
|
|
|
import { Dropdown } from 'ui-component/dropdown/Dropdown' |
|
import { Input } from 'ui-component/input/Input' |
|
import { File } from 'ui-component/file/File' |
|
import { SwitchInput } from 'ui-component/switch/Switch' |
|
import { flowContext } from 'store/context/ReactFlowContext' |
|
import { isValidConnection, getAvailableNodesForVariable } from 'utils/genericHelper' |
|
import { JsonEditorInput } from 'ui-component/json/JsonEditor' |
|
import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser' |
|
|
|
const CustomWidthTooltip = styled(({ className, ...props }) => <Tooltip {...props} classes={{ popper: className }} />)({ |
|
[`& .${tooltipClasses.tooltip}`]: { |
|
maxWidth: 500 |
|
} |
|
}) |
|
|
|
|
|
|
|
const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isAdditionalParams = false }) => { |
|
const theme = useTheme() |
|
const customization = useSelector((state) => state.customization) |
|
const ref = useRef(null) |
|
const { reactFlowInstance } = useContext(flowContext) |
|
const updateNodeInternals = useUpdateNodeInternals() |
|
const [position, setPosition] = useState(0) |
|
const [showExpandDialog, setShowExpandDialog] = useState(false) |
|
const [expandDialogProps, setExpandDialogProps] = useState({}) |
|
|
|
const onExpandDialogClicked = (value, inputParam) => { |
|
const dialogProp = { |
|
value, |
|
inputParam, |
|
disabled, |
|
confirmButtonName: 'Save', |
|
cancelButtonName: 'Cancel' |
|
} |
|
|
|
if (!disabled) { |
|
const nodes = reactFlowInstance.getNodes() |
|
const edges = reactFlowInstance.getEdges() |
|
const nodesForVariable = inputParam.acceptVariable ? getAvailableNodesForVariable(nodes, edges, data.id, inputParam.id) : [] |
|
dialogProp.availableNodesForVariable = nodesForVariable |
|
} |
|
setExpandDialogProps(dialogProp) |
|
setShowExpandDialog(true) |
|
} |
|
|
|
const onExpandDialogSave = (newValue, inputParamName) => { |
|
setShowExpandDialog(false) |
|
data.inputs[inputParamName] = newValue |
|
} |
|
|
|
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 ( |
|
<div ref={ref}> |
|
{inputAnchor && ( |
|
<> |
|
<CustomWidthTooltip placement='left' title={inputAnchor.type}> |
|
<Handle |
|
type='target' |
|
position={Position.Left} |
|
key={inputAnchor.id} |
|
id={inputAnchor.id} |
|
isValidConnection={(connection) => isValidConnection(connection, reactFlowInstance)} |
|
style={{ |
|
height: 10, |
|
width: 10, |
|
backgroundColor: data.selected ? theme.palette.primary.main : theme.palette.text.secondary, |
|
top: position |
|
}} |
|
/> |
|
</CustomWidthTooltip> |
|
<Box sx={{ p: 2 }}> |
|
<Typography> |
|
{inputAnchor.label} |
|
{!inputAnchor.optional && <span style={{ color: 'red' }}> *</span>} |
|
</Typography> |
|
</Box> |
|
</> |
|
)} |
|
|
|
{((inputParam && !inputParam.additionalParams) || isAdditionalParams) && ( |
|
<> |
|
{inputParam.acceptVariable && ( |
|
<CustomWidthTooltip placement='left' title={inputParam.type}> |
|
<Handle |
|
type='target' |
|
position={Position.Left} |
|
key={inputParam.id} |
|
id={inputParam.id} |
|
isValidConnection={(connection) => isValidConnection(connection, reactFlowInstance)} |
|
style={{ |
|
height: 10, |
|
width: 10, |
|
backgroundColor: data.selected ? theme.palette.primary.main : theme.palette.text.secondary, |
|
top: position |
|
}} |
|
/> |
|
</CustomWidthTooltip> |
|
)} |
|
<Box sx={{ p: 2 }}> |
|
<div style={{ display: 'flex', flexDirection: 'row' }}> |
|
<Typography> |
|
{inputParam.label} |
|
{!inputParam.optional && <span style={{ color: 'red' }}> *</span>} |
|
{inputParam.description && <TooltipWithParser style={{ marginLeft: 10 }} title={inputParam.description} />} |
|
</Typography> |
|
<div style={{ flexGrow: 1 }}></div> |
|
{inputParam.type === 'string' && inputParam.rows && ( |
|
<IconButton |
|
size='small' |
|
sx={{ |
|
height: 25, |
|
width: 25 |
|
}} |
|
title='Expand' |
|
color='primary' |
|
onClick={() => |
|
onExpandDialogClicked(data.inputs[inputParam.name] ?? inputParam.default ?? '', inputParam) |
|
} |
|
> |
|
<IconArrowsMaximize /> |
|
</IconButton> |
|
)} |
|
</div> |
|
{inputParam.type === 'file' && ( |
|
<File |
|
disabled={disabled} |
|
fileType={inputParam.fileType || '*'} |
|
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)} |
|
value={data.inputs[inputParam.name] ?? inputParam.default ?? 'Choose a file to upload'} |
|
/> |
|
)} |
|
{inputParam.type === 'boolean' && ( |
|
<SwitchInput |
|
disabled={disabled} |
|
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)} |
|
value={data.inputs[inputParam.name] ?? inputParam.default ?? false} |
|
/> |
|
)} |
|
{(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && ( |
|
<Input |
|
disabled={disabled} |
|
inputParam={inputParam} |
|
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)} |
|
value={data.inputs[inputParam.name] ?? inputParam.default ?? ''} |
|
showDialog={showExpandDialog} |
|
dialogProps={expandDialogProps} |
|
onDialogCancel={() => setShowExpandDialog(false)} |
|
onDialogConfirm={(newValue, inputParamName) => onExpandDialogSave(newValue, inputParamName)} |
|
/> |
|
)} |
|
{inputParam.type === 'json' && ( |
|
<JsonEditorInput |
|
disabled={disabled} |
|
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)} |
|
value={data.inputs[inputParam.name] ?? inputParam.default ?? ''} |
|
isDarkMode={customization.isDarkMode} |
|
/> |
|
)} |
|
{inputParam.type === 'options' && ( |
|
<Dropdown |
|
disabled={disabled} |
|
name={inputParam.name} |
|
options={inputParam.options} |
|
onSelect={(newValue) => (data.inputs[inputParam.name] = newValue)} |
|
value={data.inputs[inputParam.name] ?? inputParam.default ?? 'chose an option'} |
|
/> |
|
)} |
|
</Box> |
|
</> |
|
)} |
|
</div> |
|
) |
|
} |
|
|
|
NodeInputHandler.propTypes = { |
|
inputAnchor: PropTypes.object, |
|
inputParam: PropTypes.object, |
|
data: PropTypes.object, |
|
disabled: PropTypes.bool, |
|
isAdditionalParams: PropTypes.bool |
|
} |
|
|
|
export default NodeInputHandler |
|
|