mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 19:00:59 +03:00
- update marketplaces
- add version to nodes and credentials - hover over node actions
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import client from './client'
|
||||
|
||||
const getConfig = (id) => client.get(`/flow-config/${id}`)
|
||||
const getNodeConfig = (body) => client.post(`/node-config`, body)
|
||||
|
||||
export default {
|
||||
getConfig
|
||||
getConfig,
|
||||
getNodeConfig
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -13,6 +13,8 @@ export const REMOVE_DIRTY = '@canvas/REMOVE_DIRTY'
|
||||
export const SET_CHATFLOW = '@canvas/SET_CHATFLOW'
|
||||
export const SHOW_CANVAS_DIALOG = '@canvas/SHOW_CANVAS_DIALOG'
|
||||
export const HIDE_CANVAS_DIALOG = '@canvas/HIDE_CANVAS_DIALOG'
|
||||
export const SET_COMPONENT_NODES = '@canvas/SET_COMPONENT_NODES'
|
||||
export const SET_COMPONENT_CREDENTIALS = '@canvas/SET_COMPONENT_CREDENTIALS'
|
||||
|
||||
// action - notifier reducer
|
||||
export const ENQUEUE_SNACKBAR = 'ENQUEUE_SNACKBAR'
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { createContext, useState } from 'react'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import { getUniqueNodeId } from 'utils/genericHelper'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { SET_DIRTY } from 'store/actions'
|
||||
|
||||
const initialValue = {
|
||||
reactFlowInstance: null,
|
||||
@@ -14,17 +16,20 @@ const initialValue = {
|
||||
export const flowContext = createContext(initialValue)
|
||||
|
||||
export const ReactFlowContext = ({ children }) => {
|
||||
const dispatch = useDispatch()
|
||||
const [reactFlowInstance, setReactFlowInstance] = useState(null)
|
||||
|
||||
const deleteNode = (nodeid) => {
|
||||
deleteConnectedInput(nodeid, 'node')
|
||||
reactFlowInstance.setNodes(reactFlowInstance.getNodes().filter((n) => n.id !== nodeid))
|
||||
reactFlowInstance.setEdges(reactFlowInstance.getEdges().filter((ns) => ns.source !== nodeid && ns.target !== nodeid))
|
||||
dispatch({ type: SET_DIRTY })
|
||||
}
|
||||
|
||||
const deleteEdge = (edgeid) => {
|
||||
deleteConnectedInput(edgeid, 'edge')
|
||||
reactFlowInstance.setEdges(reactFlowInstance.getEdges().filter((edge) => edge.id !== edgeid))
|
||||
dispatch({ type: SET_DIRTY })
|
||||
}
|
||||
|
||||
const deleteConnectedInput = (id, type) => {
|
||||
@@ -103,6 +108,7 @@ export const ReactFlowContext = ({ children }) => {
|
||||
}
|
||||
|
||||
reactFlowInstance.setNodes([...nodes, duplicatedNode])
|
||||
dispatch({ type: SET_DIRTY })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ import * as actionTypes from '../actions'
|
||||
export const initialState = {
|
||||
isDirty: false,
|
||||
chatflow: null,
|
||||
canvasDialogShow: false
|
||||
canvasDialogShow: false,
|
||||
componentNodes: [],
|
||||
componentCredentials: []
|
||||
}
|
||||
|
||||
// ==============================|| CANVAS REDUCER ||============================== //
|
||||
@@ -36,6 +38,16 @@ const canvasReducer = (state = initialState, action) => {
|
||||
...state,
|
||||
canvasDialogShow: false
|
||||
}
|
||||
case actionTypes.SET_COMPONENT_NODES:
|
||||
return {
|
||||
...state,
|
||||
componentNodes: action.componentNodes
|
||||
}
|
||||
case actionTypes.SET_COMPONENT_CREDENTIALS:
|
||||
return {
|
||||
...state,
|
||||
componentCredentials: action.componentCredentials
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
|
||||
@@ -90,6 +90,10 @@ export default function themePalette(theme) {
|
||||
},
|
||||
codeEditor: {
|
||||
main: theme.customization.isDarkMode ? theme.colors?.darkPrimary800 : theme.colors?.primaryLight
|
||||
},
|
||||
nodeToolTip: {
|
||||
background: theme.customization.isDarkMode ? theme.colors?.darkPrimary800 : theme.colors?.paper,
|
||||
color: theme.customization.isDarkMode ? theme.colors?.paper : 'rgba(0, 0, 0, 0.87)'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ const AdditionalParamsDialog = ({ show, dialogProps, onCancel }) => {
|
||||
useEffect(() => {
|
||||
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
|
||||
else dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
}, [show, dispatch])
|
||||
|
||||
const component = show ? (
|
||||
|
||||
@@ -36,6 +36,7 @@ const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
||||
useEffect(() => {
|
||||
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
|
||||
else dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
}, [show, dispatch])
|
||||
|
||||
const component = show ? (
|
||||
|
||||
@@ -15,6 +15,7 @@ const FormatPromptValuesDialog = ({ show, dialogProps, onChange, onCancel }) =>
|
||||
useEffect(() => {
|
||||
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
|
||||
else dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
}, [show, dispatch])
|
||||
|
||||
const component = show ? (
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
import { createPortal } from 'react-dom'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
// Material
|
||||
import { Dialog, DialogContent, DialogTitle } from '@mui/material'
|
||||
import { TableViewOnly } from 'ui-component/table/Table'
|
||||
|
||||
// Store
|
||||
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
||||
import { baseURL } from 'store/constant'
|
||||
|
||||
// API
|
||||
import configApi from 'api/config'
|
||||
import useApi from 'hooks/useApi'
|
||||
|
||||
const NodeInfoDialog = ({ show, dialogProps, onCancel }) => {
|
||||
const portalElement = document.getElementById('portal')
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const getNodeConfigApi = useApi(configApi.getNodeConfig)
|
||||
|
||||
useEffect(() => {
|
||||
if (dialogProps.data) {
|
||||
getNodeConfigApi.request(dialogProps.data)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dialogProps])
|
||||
|
||||
useEffect(() => {
|
||||
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
|
||||
else dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
}, [show, dispatch])
|
||||
|
||||
const component = show ? (
|
||||
<Dialog
|
||||
onClose={onCancel}
|
||||
open={show}
|
||||
fullWidth
|
||||
maxWidth='md'
|
||||
aria-labelledby='alert-dialog-title'
|
||||
aria-describedby='alert-dialog-description'
|
||||
>
|
||||
<DialogTitle sx={{ fontSize: '1rem' }} id='alert-dialog-title'>
|
||||
{dialogProps.data && dialogProps.data.name && dialogProps.data.label && (
|
||||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
|
||||
<div
|
||||
style={{
|
||||
width: 50,
|
||||
height: 50,
|
||||
marginRight: 10,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'white'
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
padding: 7,
|
||||
borderRadius: '50%',
|
||||
objectFit: 'contain'
|
||||
}}
|
||||
alt={dialogProps.data.name}
|
||||
src={`${baseURL}/api/v1/node-icon/${dialogProps.data.name}`}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', marginLeft: 10 }}>
|
||||
{dialogProps.data.label}
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
width: 'max-content',
|
||||
borderRadius: 15,
|
||||
background: 'rgb(254,252,191)',
|
||||
padding: 5,
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
marginTop: 5,
|
||||
marginBottom: 5
|
||||
}}
|
||||
>
|
||||
<span style={{ color: 'rgb(116,66,16)', fontSize: '0.825rem' }}>{dialogProps.data.id}</span>
|
||||
</div>
|
||||
{dialogProps.data.version && (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
width: 'max-content',
|
||||
borderRadius: 15,
|
||||
background: '#e9edc9',
|
||||
padding: 5,
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
marginTop: 5,
|
||||
marginLeft: 10,
|
||||
marginBottom: 5
|
||||
}}
|
||||
>
|
||||
<span style={{ color: '#606c38', fontSize: '0.825rem' }}>version {dialogProps.data.version}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
{dialogProps.data?.description && (
|
||||
<div
|
||||
style={{
|
||||
padding: 10,
|
||||
marginBottom: 10
|
||||
}}
|
||||
>
|
||||
<span>{dialogProps.data.description}</span>
|
||||
</div>
|
||||
)}
|
||||
{getNodeConfigApi.data && getNodeConfigApi.data.length > 0 && (
|
||||
<TableViewOnly rows={getNodeConfigApi.data} columns={Object.keys(getNodeConfigApi.data[0])} />
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
) : null
|
||||
|
||||
return createPortal(component, portalElement)
|
||||
}
|
||||
|
||||
NodeInfoDialog.propTypes = {
|
||||
show: PropTypes.bool,
|
||||
dialogProps: PropTypes.object,
|
||||
onCancel: PropTypes.func
|
||||
}
|
||||
|
||||
export default NodeInfoDialog
|
||||
@@ -37,7 +37,7 @@ export const Input = ({ inputParam, value, onChange, disabled = false, showDialo
|
||||
onChange(e.target.value)
|
||||
}}
|
||||
inputProps={{
|
||||
step: inputParam.step ?? 0.1,
|
||||
step: inputParam.step ?? 1,
|
||||
style: {
|
||||
height: inputParam.rows ? '90px' : 'inherit'
|
||||
}
|
||||
|
||||
@@ -268,6 +268,7 @@ export const generateExportFlowData = (flowData) => {
|
||||
const newNodeData = {
|
||||
id: node.data.id,
|
||||
label: node.data.label,
|
||||
version: node.data.version,
|
||||
name: node.data.name,
|
||||
type: node.data.type,
|
||||
baseClasses: node.data.baseClasses,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState, useRef, useEffect } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
// material-ui
|
||||
@@ -38,12 +38,14 @@ import { IconPlus, IconSearch, IconMinus, IconX } from '@tabler/icons'
|
||||
|
||||
// const
|
||||
import { baseURL } from 'store/constant'
|
||||
import { SET_COMPONENT_NODES } from 'store/actions'
|
||||
|
||||
// ==============================|| ADD NODES||============================== //
|
||||
|
||||
const AddNodes = ({ nodesData, node }) => {
|
||||
const theme = useTheme()
|
||||
const customization = useSelector((state) => state.customization)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const [searchValue, setSearchValue] = useState('')
|
||||
const [nodes, setNodes] = useState({})
|
||||
@@ -131,8 +133,11 @@ const AddNodes = ({ nodesData, node }) => {
|
||||
}, [node])
|
||||
|
||||
useEffect(() => {
|
||||
if (nodesData) groupByCategory(nodesData)
|
||||
}, [nodesData])
|
||||
if (nodesData) {
|
||||
groupByCategory(nodesData)
|
||||
dispatch({ type: SET_COMPONENT_NODES, componentNodes: nodesData })
|
||||
}
|
||||
}, [nodesData, dispatch])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { useContext, useState } from 'react'
|
||||
import { useContext, useState, useEffect } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles'
|
||||
import { IconButton, Box, Typography, Divider, Button } from '@mui/material'
|
||||
import Tooltip, { tooltipClasses } from '@mui/material/Tooltip'
|
||||
|
||||
// project imports
|
||||
import MainCard from 'ui-component/cards/MainCard'
|
||||
import NodeInputHandler from './NodeInputHandler'
|
||||
import NodeOutputHandler from './NodeOutputHandler'
|
||||
import AdditionalParamsDialog from 'ui-component/dialog/AdditionalParamsDialog'
|
||||
import NodeInfoDialog from 'ui-component/dialog/NodeInfoDialog'
|
||||
|
||||
// const
|
||||
import { baseURL } from 'store/constant'
|
||||
import { IconTrash, IconCopy } from '@tabler/icons'
|
||||
import { IconTrash, IconCopy, IconInfoCircle, IconAlertTriangle } from '@tabler/icons'
|
||||
import { flowContext } from 'store/context/ReactFlowContext'
|
||||
|
||||
const CardWrapper = styled(MainCard)(({ theme }) => ({
|
||||
@@ -30,14 +33,39 @@ const CardWrapper = styled(MainCard)(({ theme }) => ({
|
||||
}
|
||||
}))
|
||||
|
||||
const LightTooltip = styled(({ className, ...props }) => <Tooltip {...props} classes={{ popper: className }} />)(({ theme }) => ({
|
||||
[`& .${tooltipClasses.tooltip}`]: {
|
||||
backgroundColor: theme.palette.nodeToolTip.background,
|
||||
color: theme.palette.nodeToolTip.color,
|
||||
boxShadow: theme.shadows[1]
|
||||
}
|
||||
}))
|
||||
|
||||
// ===========================|| CANVAS NODE ||=========================== //
|
||||
|
||||
const CanvasNode = ({ data }) => {
|
||||
const theme = useTheme()
|
||||
const canvas = useSelector((state) => state.canvas)
|
||||
const { deleteNode, duplicateNode } = useContext(flowContext)
|
||||
|
||||
const [showDialog, setShowDialog] = useState(false)
|
||||
const [dialogProps, setDialogProps] = useState({})
|
||||
const [showInfoDialog, setShowInfoDialog] = useState(false)
|
||||
const [infoDialogProps, setInfoDialogProps] = useState({})
|
||||
const [warningMessage, setWarningMessage] = useState('')
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const handleOpen = () => {
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
const nodeOutdatedMessage = (oldVersion, newVersion) => `Node version ${oldVersion} outdated\nUpdate to latest version ${newVersion}`
|
||||
|
||||
const nodeVersionEmptyMessage = (newVersion) => `Node outdated\nUpdate to latest version ${newVersion}`
|
||||
|
||||
const onDialogClicked = () => {
|
||||
const dialogProps = {
|
||||
@@ -50,6 +78,17 @@ const CanvasNode = ({ data }) => {
|
||||
setShowDialog(true)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const componentNode = canvas.componentNodes.find((nd) => nd.name === data.name)
|
||||
if (componentNode) {
|
||||
if (!data.version) {
|
||||
setWarningMessage(nodeVersionEmptyMessage(componentNode.version))
|
||||
} else {
|
||||
if (componentNode.version > data.version) setWarningMessage(nodeOutdatedMessage(data.version, componentNode.version))
|
||||
}
|
||||
}
|
||||
}, [canvas.componentNodes, data.name, data.version])
|
||||
|
||||
return (
|
||||
<>
|
||||
<CardWrapper
|
||||
@@ -60,118 +99,158 @@ const CanvasNode = ({ data }) => {
|
||||
}}
|
||||
border={false}
|
||||
>
|
||||
<Box>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Box style={{ width: 50, marginRight: 10, padding: 5 }}>
|
||||
<div
|
||||
style={{
|
||||
...theme.typography.commonAvatar,
|
||||
...theme.typography.largeAvatar,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'white',
|
||||
cursor: 'grab'
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{ width: '100%', height: '100%', padding: 5, objectFit: 'contain' }}
|
||||
src={`${baseURL}/api/v1/node-icon/${data.name}`}
|
||||
alt='Notification'
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: '1rem',
|
||||
fontWeight: 500
|
||||
}}
|
||||
>
|
||||
{data.label}
|
||||
</Typography>
|
||||
</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, '&:hover': { color: 'red' } }}
|
||||
color={theme?.customization?.isDarkMode ? theme.colors?.paper : 'inherit'}
|
||||
>
|
||||
<IconTrash />
|
||||
</IconButton>
|
||||
</div>
|
||||
{(data.inputAnchors.length > 0 || data.inputParams.length > 0) && (
|
||||
<>
|
||||
<Divider />
|
||||
<Box sx={{ background: theme.palette.asyncSelect.main, p: 1 }}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
Inputs
|
||||
</Typography>
|
||||
</Box>
|
||||
<Divider />
|
||||
</>
|
||||
)}
|
||||
{data.inputAnchors.map((inputAnchor, index) => (
|
||||
<NodeInputHandler key={index} inputAnchor={inputAnchor} data={data} />
|
||||
))}
|
||||
{data.inputParams.map((inputParam, index) => (
|
||||
<NodeInputHandler key={index} inputParam={inputParam} data={data} />
|
||||
))}
|
||||
{data.inputParams.find((param) => param.additionalParams) && (
|
||||
<LightTooltip
|
||||
open={!canvas.canvasDialogShow && open}
|
||||
onClose={handleClose}
|
||||
onOpen={handleOpen}
|
||||
disableFocusListener={true}
|
||||
title={
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
marginTop:
|
||||
data.inputParams.filter((param) => param.additionalParams).length ===
|
||||
data.inputParams.length + data.inputAnchors.length
|
||||
? 20
|
||||
: 0
|
||||
background: 'transparent',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}
|
||||
>
|
||||
<Button sx={{ borderRadius: 25, width: '90%', mb: 2 }} variant='outlined' onClick={onDialogClicked}>
|
||||
Additional Parameters
|
||||
</Button>
|
||||
<IconButton
|
||||
title='Duplicate'
|
||||
onClick={() => {
|
||||
duplicateNode(data.id)
|
||||
}}
|
||||
sx={{ height: '35px', width: '35px', '&: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: '35px', width: '35px', '&:hover': { color: 'red' } }}
|
||||
color={theme?.customization?.isDarkMode ? theme.colors?.paper : 'inherit'}
|
||||
>
|
||||
<IconTrash />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
title='Info'
|
||||
onClick={() => {
|
||||
setInfoDialogProps({ data })
|
||||
setShowInfoDialog(true)
|
||||
}}
|
||||
sx={{ height: '35px', width: '35px', '&:hover': { color: theme?.palette.secondary.main } }}
|
||||
color={theme?.customization?.isDarkMode ? theme.colors?.paper : 'inherit'}
|
||||
>
|
||||
<IconInfoCircle />
|
||||
</IconButton>
|
||||
</div>
|
||||
)}
|
||||
<Divider />
|
||||
<Box sx={{ background: theme.palette.asyncSelect.main, p: 1 }}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
Output
|
||||
</Typography>
|
||||
</Box>
|
||||
<Divider />
|
||||
}
|
||||
placement='right-start'
|
||||
>
|
||||
<Box>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Box style={{ width: 50, marginRight: 10, padding: 5 }}>
|
||||
<div
|
||||
style={{
|
||||
...theme.typography.commonAvatar,
|
||||
...theme.typography.largeAvatar,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'white',
|
||||
cursor: 'grab'
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{ width: '100%', height: '100%', padding: 5, objectFit: 'contain' }}
|
||||
src={`${baseURL}/api/v1/node-icon/${data.name}`}
|
||||
alt='Notification'
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: '1rem',
|
||||
fontWeight: 500,
|
||||
mr: 2
|
||||
}}
|
||||
>
|
||||
{data.label}
|
||||
</Typography>
|
||||
</Box>
|
||||
{warningMessage && (
|
||||
<>
|
||||
<div style={{ flexGrow: 1 }}></div>
|
||||
<Tooltip title={<span style={{ whiteSpace: 'pre-line' }}>{warningMessage}</span>} placement='top'>
|
||||
<IconButton sx={{ height: 35, width: 35 }}>
|
||||
<IconAlertTriangle size={35} color='orange' />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{(data.inputAnchors.length > 0 || data.inputParams.length > 0) && (
|
||||
<>
|
||||
<Divider />
|
||||
<Box sx={{ background: theme.palette.asyncSelect.main, p: 1 }}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
Inputs
|
||||
</Typography>
|
||||
</Box>
|
||||
<Divider />
|
||||
</>
|
||||
)}
|
||||
{data.inputAnchors.map((inputAnchor, index) => (
|
||||
<NodeInputHandler key={index} inputAnchor={inputAnchor} data={data} />
|
||||
))}
|
||||
{data.inputParams.map((inputParam, index) => (
|
||||
<NodeInputHandler key={index} inputParam={inputParam} data={data} />
|
||||
))}
|
||||
{data.inputParams.find((param) => param.additionalParams) && (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
marginTop:
|
||||
data.inputParams.filter((param) => param.additionalParams).length ===
|
||||
data.inputParams.length + data.inputAnchors.length
|
||||
? 20
|
||||
: 0
|
||||
}}
|
||||
>
|
||||
<Button sx={{ borderRadius: 25, width: '90%', mb: 2 }} variant='outlined' onClick={onDialogClicked}>
|
||||
Additional Parameters
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<Divider />
|
||||
<Box sx={{ background: theme.palette.asyncSelect.main, p: 1 }}>
|
||||
<Typography
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
Output
|
||||
</Typography>
|
||||
</Box>
|
||||
<Divider />
|
||||
|
||||
{data.outputAnchors.map((outputAnchor, index) => (
|
||||
<NodeOutputHandler key={index} outputAnchor={outputAnchor} data={data} />
|
||||
))}
|
||||
</Box>
|
||||
{data.outputAnchors.map((outputAnchor, index) => (
|
||||
<NodeOutputHandler key={index} outputAnchor={outputAnchor} data={data} />
|
||||
))}
|
||||
</Box>
|
||||
</LightTooltip>
|
||||
</CardWrapper>
|
||||
<AdditionalParamsDialog
|
||||
show={showDialog}
|
||||
dialogProps={dialogProps}
|
||||
onCancel={() => setShowDialog(false)}
|
||||
></AdditionalParamsDialog>
|
||||
<NodeInfoDialog show={showInfoDialog} dialogProps={infoDialogProps} onCancel={() => setShowInfoDialog(false)}></NodeInfoDialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ import useApi from 'hooks/useApi'
|
||||
// Const
|
||||
import { baseURL, maxScroll } from 'store/constant'
|
||||
|
||||
import robotPNG from 'assets/images/robot.png'
|
||||
import userPNG from 'assets/images/account.png'
|
||||
|
||||
export const ChatMessage = ({ open, chatflowid, isDialog }) => {
|
||||
const theme = useTheme()
|
||||
const customization = useSelector((state) => state.customization)
|
||||
@@ -281,21 +284,9 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
|
||||
>
|
||||
{/* Display the correct icon depending on the message type */}
|
||||
{message.type === 'apiMessage' ? (
|
||||
<img
|
||||
src='https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png'
|
||||
alt='AI'
|
||||
width='30'
|
||||
height='30'
|
||||
className='boticon'
|
||||
/>
|
||||
<img src={robotPNG} alt='AI' width='30' height='30' className='boticon' />
|
||||
) : (
|
||||
<img
|
||||
src='https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png'
|
||||
alt='Me'
|
||||
width='30'
|
||||
height='30'
|
||||
className='usericon'
|
||||
/>
|
||||
<img src={userPNG} alt='Me' width='30' height='30' className='usericon' />
|
||||
)}
|
||||
<div style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
|
||||
<div className='markdownanswer'>
|
||||
|
||||
@@ -27,6 +27,7 @@ import useNotifier from 'utils/useNotifier'
|
||||
|
||||
// const
|
||||
import { baseURL } from 'store/constant'
|
||||
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
||||
|
||||
const AddEditCredentialDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
||||
const portalElement = document.getElementById('portal')
|
||||
@@ -87,6 +88,12 @@ const AddEditCredentialDialog = ({ show, dialogProps, onCancel, onConfirm }) =>
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dialogProps])
|
||||
|
||||
useEffect(() => {
|
||||
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
|
||||
else dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
}, [show, dispatch])
|
||||
|
||||
const addNewCredential = async () => {
|
||||
try {
|
||||
const obj = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import {
|
||||
List,
|
||||
@@ -20,11 +20,12 @@ import { IconSearch, IconX } from '@tabler/icons'
|
||||
|
||||
// const
|
||||
import { baseURL } from 'store/constant'
|
||||
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
||||
|
||||
const CredentialListDialog = ({ show, dialogProps, onCancel, onCredentialSelected }) => {
|
||||
const portalElement = document.getElementById('portal')
|
||||
const customization = useSelector((state) => state.customization)
|
||||
|
||||
const dispatch = useDispatch()
|
||||
const theme = useTheme()
|
||||
const [searchValue, setSearchValue] = useState('')
|
||||
const [componentsCredentials, setComponentsCredentials] = useState([])
|
||||
@@ -43,10 +44,16 @@ const CredentialListDialog = ({ show, dialogProps, onCancel, onCredentialSelecte
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (show && dialogProps.componentsCredentials) {
|
||||
if (dialogProps.componentsCredentials) {
|
||||
setComponentsCredentials(dialogProps.componentsCredentials)
|
||||
}
|
||||
}, [show, dialogProps])
|
||||
}, [dialogProps])
|
||||
|
||||
useEffect(() => {
|
||||
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
|
||||
else dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
}, [show, dispatch])
|
||||
|
||||
const component = show ? (
|
||||
<Dialog
|
||||
|
||||
@@ -30,6 +30,7 @@ import CredentialEmptySVG from 'assets/images/credential_empty.svg'
|
||||
|
||||
// const
|
||||
import { baseURL } from 'store/constant'
|
||||
import { SET_COMPONENT_CREDENTIALS } from 'store/actions'
|
||||
|
||||
// ==============================|| Credentials ||============================== //
|
||||
|
||||
@@ -159,8 +160,9 @@ const Credentials = () => {
|
||||
useEffect(() => {
|
||||
if (getAllComponentsCredentialsApi.data) {
|
||||
setComponentsCredentials(getAllComponentsCredentialsApi.data)
|
||||
dispatch({ type: SET_COMPONENT_CREDENTIALS, componentsCredentials: getAllComponentsCredentialsApi.data })
|
||||
}
|
||||
}, [getAllComponentsCredentialsApi.data])
|
||||
}, [getAllComponentsCredentialsApi.data, dispatch])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -29,6 +29,7 @@ import useApi from 'hooks/useApi'
|
||||
// utils
|
||||
import useNotifier from 'utils/useNotifier'
|
||||
import { generateRandomGradient } from 'utils/genericHelper'
|
||||
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
||||
|
||||
const exampleAPIFunc = `/*
|
||||
* You can use any libraries imported in Flowise
|
||||
@@ -155,6 +156,12 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
|
||||
else dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
}, [show, dispatch])
|
||||
|
||||
useEffect(() => {
|
||||
if (getSpecificToolApi.data) {
|
||||
setToolId(getSpecificToolApi.data.id)
|
||||
|
||||
Reference in New Issue
Block a user