Add feature to be able to chain prompt values

This commit is contained in:
Henry
2023-04-16 23:17:08 +01:00
parent 0681a34408
commit 4b9c39cf54
25 changed files with 1496 additions and 246 deletions
+15 -3
View File
@@ -12,7 +12,7 @@ import NodeOutputHandler from './NodeOutputHandler'
// const
import { baseURL } from 'store/constant'
import { IconTrash } from '@tabler/icons'
import { IconTrash, IconCopy } from '@tabler/icons'
import { flowContext } from 'store/context/ReactFlowContext'
const CardWrapper = styled(MainCard)(({ theme }) => ({
@@ -33,7 +33,7 @@ const CardWrapper = styled(MainCard)(({ theme }) => ({
const CanvasNode = ({ data }) => {
const theme = useTheme()
const { deleteNode } = useContext(flowContext)
const { deleteNode, duplicateNode } = useContext(flowContext)
return (
<>
@@ -76,10 +76,22 @@ const CanvasNode = ({ data }) => {
</Box>
<div style={{ flexGrow: 1 }}></div>
<IconButton
title='Duplicate'
onClick={() => {
duplicateNode(data.id)
}}
sx={{ height: 35, width: 35, '&:hover': { color: theme?.palette.primary.main } }}
color={theme?.customization?.isDarkMode ? theme.colors?.paper : 'inherit'}
>
<IconCopy />
</IconButton>
<IconButton
title='Delete'
onClick={() => {
deleteNode(data.id)
}}
sx={{ height: 35, width: 35, mr: 1 }}
sx={{ height: 35, width: 35, mr: 1, '&:hover': { color: 'red' } }}
color={theme?.customization?.isDarkMode ? theme.colors?.paper : 'inherit'}
>
<IconTrash />
</IconButton>
@@ -4,13 +4,16 @@ import { useEffect, useRef, useState, useContext } from 'react'
// material-ui
import { useTheme, styled } from '@mui/material/styles'
import { Box, Typography, Tooltip } from '@mui/material'
import { Box, Typography, Tooltip, IconButton } from '@mui/material'
import { tooltipClasses } from '@mui/material/Tooltip'
import { IconArrowsMaximize } from '@tabler/icons'
// project import
import { Dropdown } from 'ui-component/dropdown/Dropdown'
import { Input } from 'ui-component/input/Input'
import { File } from 'ui-component/file/File'
import { flowContext } from 'store/context/ReactFlowContext'
import { isValidConnection } from 'utils/genericHelper'
import { isValidConnection, getAvailableNodesForVariable } from 'utils/genericHelper'
const CustomWidthTooltip = styled(({ className, ...props }) => <Tooltip {...props} classes={{ popper: className }} />)({
[`& .${tooltipClasses.tooltip}`]: {
@@ -23,9 +26,35 @@ const CustomWidthTooltip = styled(({ className, ...props }) => <Tooltip {...prop
const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false }) => {
const theme = useTheme()
const ref = useRef(null)
const { reactFlowInstance } = useContext(flowContext)
const updateNodeInternals = useUpdateNodeInternals()
const [position, setPosition] = useState(0)
const { reactFlowInstance } = useContext(flowContext)
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) {
@@ -68,11 +97,47 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false }) =
{inputParam && (
<>
{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 }}>
<Typography>
{inputParam.label}
{!inputParam.optional && <span style={{ color: 'red' }}>&nbsp;*</span>}
</Typography>
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Typography>
{inputParam.label}
{!inputParam.optional && <span style={{ color: 'red' }}>&nbsp;*</span>}
</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}
@@ -87,6 +152,10 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false }) =
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 === 'options' && (
@@ -8,6 +8,7 @@ import { Box, Typography, Tooltip } from '@mui/material'
import { tooltipClasses } from '@mui/material/Tooltip'
import { flowContext } from 'store/context/ReactFlowContext'
import { isValidConnection } from 'utils/genericHelper'
import { Dropdown } from 'ui-component/dropdown/Dropdown'
const CustomWidthTooltip = styled(({ className, ...props }) => <Tooltip {...props} classes={{ popper: className }} />)({
[`& .${tooltipClasses.tooltip}`]: {
@@ -17,11 +18,12 @@ const CustomWidthTooltip = styled(({ className, ...props }) => <Tooltip {...prop
// ===========================|| NodeOutputHandler ||=========================== //
const NodeOutputHandler = ({ outputAnchor, data }) => {
const NodeOutputHandler = ({ outputAnchor, data, disabled = false }) => {
const theme = useTheme()
const ref = useRef(null)
const updateNodeInternals = useUpdateNodeInternals()
const [position, setPosition] = useState(0)
const [dropdownValue, setDropdownValue] = useState(null)
const { reactFlowInstance } = useContext(flowContext)
useEffect(() => {
@@ -39,33 +41,82 @@ const NodeOutputHandler = ({ outputAnchor, data }) => {
}, 0)
}, [data.id, position, updateNodeInternals])
useEffect(() => {
if (dropdownValue) {
setTimeout(() => {
updateNodeInternals(data.id)
}, 0)
}
}, [data.id, dropdownValue, updateNodeInternals])
return (
<div ref={ref}>
<CustomWidthTooltip placement='right' title={outputAnchor.type}>
<Handle
type='source'
position={Position.Right}
key={outputAnchor.id}
id={outputAnchor.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, textAlign: 'end' }}>
<Typography>{outputAnchor.label}</Typography>
</Box>
{outputAnchor.type !== 'options' && !outputAnchor.options && (
<>
<CustomWidthTooltip placement='right' title={outputAnchor.type}>
<Handle
type='source'
position={Position.Right}
key={outputAnchor.id}
id={outputAnchor.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, textAlign: 'end' }}>
<Typography>{outputAnchor.label}</Typography>
</Box>
</>
)}
{outputAnchor.type === 'options' && outputAnchor.options && outputAnchor.options.length > 0 && (
<>
<CustomWidthTooltip
placement='right'
title={
outputAnchor.options.find((opt) => opt.name === data.outputs?.[outputAnchor.name])?.type ?? outputAnchor.type
}
>
<Handle
type='source'
position={Position.Right}
id={outputAnchor.options.find((opt) => opt.name === data.outputs?.[outputAnchor.name])?.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, textAlign: 'end' }}>
<Dropdown
disabled={disabled}
disableClearable={true}
name={outputAnchor.name}
options={outputAnchor.options}
onSelect={(newValue) => {
setDropdownValue(newValue)
data.outputs[outputAnchor.name] = newValue
}}
value={data.outputs[outputAnchor.name] ?? outputAnchor.default ?? 'choose an option'}
/>
</Box>
</>
)}
</div>
)
}
NodeOutputHandler.propTypes = {
outputAnchor: PropTypes.object,
data: PropTypes.object
data: PropTypes.object,
disabled: PropTypes.bool
}
export default NodeOutputHandler
+4
View File
@@ -108,10 +108,14 @@ const Canvas = () => {
setTimeout(() => setDirty(), 0)
let value
const inputAnchor = node.data.inputAnchors.find((ancr) => ancr.name === targetInput)
const inputParam = node.data.inputParams.find((param) => param.name === targetInput)
if (inputAnchor && inputAnchor.list) {
const newValues = node.data.inputs[targetInput] || []
newValues.push(`{{${sourceNodeId}.data.instance}}`)
value = newValues
} else if (inputParam && inputParam.acceptVariable) {
value = node.data.inputs[targetInput] || ''
} else {
value = `{{${sourceNodeId}.data.instance}}`
}
@@ -88,7 +88,7 @@ const MarketplaceCanvasNode = ({ data }) => {
</>
)}
{data.inputAnchors.map((inputAnchor, index) => (
<NodeInputHandler key={index} inputAnchor={inputAnchor} data={data} />
<NodeInputHandler disabled={true} key={index} inputAnchor={inputAnchor} data={data} />
))}
{data.inputParams.map((inputParam, index) => (
<NodeInputHandler disabled={true} key={index} inputParam={inputParam} data={data} />
@@ -108,7 +108,7 @@ const MarketplaceCanvasNode = ({ data }) => {
<Divider />
{data.outputAnchors.map((outputAnchor, index) => (
<NodeOutputHandler key={index} outputAnchor={outputAnchor} data={data} />
<NodeOutputHandler disabled={true} key={index} outputAnchor={outputAnchor} data={data} />
))}
</Box>
</CardWrapper>