mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 15:00:57 +03:00
Merge branch 'main' into FEATURE/Vision
# Conflicts: # packages/components/nodes/chains/ConversationChain/ConversationChain.ts # packages/server/src/index.ts # packages/server/src/utils/index.ts
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "flowise-ui",
|
||||
"version": "1.4.6",
|
||||
"version": "1.4.9",
|
||||
"license": "SEE LICENSE IN LICENSE.md",
|
||||
"homepage": "https://flowiseai.com",
|
||||
"author": {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import client from './client'
|
||||
|
||||
const fetchAllLinks = (url, relativeLinksMethod) =>
|
||||
client.get(`/fetch-links?url=${encodeURIComponent(url)}&relativeLinksMethod=${relativeLinksMethod}`)
|
||||
|
||||
export default {
|
||||
fetchAllLinks
|
||||
}
|
||||
@@ -36,7 +36,7 @@ const settings = {
|
||||
},
|
||||
{
|
||||
id: 'enableSpeechToText',
|
||||
title: 'Enable Speech to Text',
|
||||
title: 'Speech to Text',
|
||||
type: 'item',
|
||||
url: '',
|
||||
icon: icons.IconMicrophone
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// material-ui
|
||||
import { styled } from '@mui/material/styles'
|
||||
|
||||
// project imports
|
||||
import MainCard from './MainCard'
|
||||
|
||||
const NodeCardWrapper = styled(MainCard)(({ theme }) => ({
|
||||
background: theme.palette.card.main,
|
||||
color: theme.darkTextPrimary,
|
||||
border: 'solid 1px',
|
||||
borderColor: theme.palette.primary[200] + 75,
|
||||
width: '300px',
|
||||
height: 'auto',
|
||||
padding: '10px',
|
||||
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 8%)',
|
||||
'&:hover': {
|
||||
borderColor: theme.palette.primary.main
|
||||
}
|
||||
}))
|
||||
|
||||
export default NodeCardWrapper
|
||||
@@ -0,0 +1,184 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { createPortal } from 'react-dom'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
FormControl,
|
||||
IconButton,
|
||||
OutlinedInput,
|
||||
Stack,
|
||||
Typography
|
||||
} from '@mui/material'
|
||||
import { IconTrash } from '@tabler/icons'
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar'
|
||||
|
||||
import { BackdropLoader } from 'ui-component/loading/BackdropLoader'
|
||||
import { StyledButton } from 'ui-component/button/StyledButton'
|
||||
|
||||
import scraperApi from 'api/scraper'
|
||||
|
||||
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
||||
|
||||
const ManageScrapedLinksDialog = ({ show, dialogProps, onCancel, onSave }) => {
|
||||
const portalElement = document.getElementById('portal')
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [selectedLinks, setSelectedLinks] = useState([])
|
||||
const [url, setUrl] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (dialogProps.url) setUrl(dialogProps.url)
|
||||
if (dialogProps.selectedLinks) setSelectedLinks(dialogProps.selectedLinks)
|
||||
|
||||
return () => {
|
||||
setLoading(false)
|
||||
setSelectedLinks([])
|
||||
setUrl('')
|
||||
}
|
||||
}, [dialogProps])
|
||||
|
||||
useEffect(() => {
|
||||
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
|
||||
else dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
}, [show, dispatch])
|
||||
|
||||
const handleFetchLinks = async () => {
|
||||
setLoading(true)
|
||||
const fetchLinksResp = await scraperApi.fetchAllLinks(url, 'webCrawl')
|
||||
if (fetchLinksResp.data) {
|
||||
setSelectedLinks(fetchLinksResp.data.links)
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const handleChangeLink = (index, event) => {
|
||||
const { value } = event.target
|
||||
const links = [...selectedLinks]
|
||||
links[index] = value
|
||||
setSelectedLinks(links)
|
||||
}
|
||||
|
||||
const handleRemoveLink = (index) => {
|
||||
const links = [...selectedLinks]
|
||||
links.splice(index, 1)
|
||||
setSelectedLinks(links)
|
||||
}
|
||||
|
||||
const handleSaveLinks = () => {
|
||||
onSave(url, selectedLinks)
|
||||
}
|
||||
|
||||
const component = show ? (
|
||||
<Dialog
|
||||
onClose={onCancel}
|
||||
open={show}
|
||||
fullWidth
|
||||
maxWidth='sm'
|
||||
aria-labelledby='manage-scraped-links-dialog-title'
|
||||
aria-describedby='manage-scraped-links-dialog-description'
|
||||
>
|
||||
<DialogTitle sx={{ fontSize: '1rem' }} id='manage-scraped-links-dialog-title'>
|
||||
{dialogProps.title || `Manage Scraped Links - ${url}`}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Box sx={{ mb: 4 }}>
|
||||
<Stack flexDirection='row' gap={1} sx={{ width: '100%' }}>
|
||||
<FormControl sx={{ mt: 1, width: '100%', display: 'flex', flexShrink: 1 }} size='small'>
|
||||
<OutlinedInput
|
||||
id='url'
|
||||
size='small'
|
||||
type='text'
|
||||
value={url}
|
||||
name='url'
|
||||
onChange={(e) => {
|
||||
setUrl(e.target.value)
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
sx={{ borderRadius: '12px', mt: 1, display: 'flex', flexShrink: 0 }}
|
||||
size='small'
|
||||
variant='contained'
|
||||
onClick={handleFetchLinks}
|
||||
>
|
||||
Fetch Links
|
||||
</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Typography sx={{ mb: 2, fontWeight: 500 }}>Scraped Links</Typography>
|
||||
<>
|
||||
{loading && <BackdropLoader open={loading} />}
|
||||
{selectedLinks.length > 0 ? (
|
||||
<PerfectScrollbar
|
||||
style={{
|
||||
height: '100%',
|
||||
maxHeight: '320px',
|
||||
overflowX: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 4
|
||||
}}
|
||||
>
|
||||
{selectedLinks.map((link, index) => (
|
||||
<div key={index} style={{ display: 'flex', width: '100%' }}>
|
||||
<Box sx={{ display: 'flex', width: '100%' }}>
|
||||
<OutlinedInput
|
||||
sx={{ width: '100%' }}
|
||||
key={index}
|
||||
type='text'
|
||||
onChange={(e) => handleChangeLink(index, e)}
|
||||
size='small'
|
||||
value={link}
|
||||
name={`link_${index}`}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ width: 'auto', flexGrow: 1 }}>
|
||||
<IconButton
|
||||
sx={{ height: 30, width: 30 }}
|
||||
size='small'
|
||||
color='error'
|
||||
onClick={() => handleRemoveLink(index)}
|
||||
edge='end'
|
||||
>
|
||||
<IconTrash />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</div>
|
||||
))}
|
||||
</PerfectScrollbar>
|
||||
) : (
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Typography sx={{ my: 2 }}>Links scraped from the URL will appear here</Typography>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onCancel}>Cancel</Button>
|
||||
<StyledButton variant='contained' onClick={handleSaveLinks}>
|
||||
Save
|
||||
</StyledButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
) : null
|
||||
|
||||
return createPortal(component, portalElement)
|
||||
}
|
||||
|
||||
ManageScrapedLinksDialog.propTypes = {
|
||||
show: PropTypes.bool,
|
||||
dialogProps: PropTypes.object,
|
||||
onCancel: PropTypes.func,
|
||||
onSave: PropTypes.func
|
||||
}
|
||||
|
||||
export default ManageScrapedLinksDialog
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { FormControl, OutlinedInput, Popover } from '@mui/material'
|
||||
import { FormControl, OutlinedInput, InputBase, Popover } from '@mui/material'
|
||||
import SelectVariable from 'ui-component/json/SelectVariable'
|
||||
import { getAvailableNodesForVariable } from 'utils/genericHelper'
|
||||
|
||||
@@ -50,29 +50,67 @@ export const Input = ({ inputParam, value, nodes, edges, nodeId, onChange, disab
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormControl sx={{ mt: 1, width: '100%' }} size='small'>
|
||||
<OutlinedInput
|
||||
id={inputParam.name}
|
||||
size='small'
|
||||
disabled={disabled}
|
||||
type={getInputType(inputParam.type)}
|
||||
placeholder={inputParam.placeholder}
|
||||
multiline={!!inputParam.rows}
|
||||
rows={inputParam.rows ?? 1}
|
||||
value={myValue}
|
||||
name={inputParam.name}
|
||||
onChange={(e) => {
|
||||
setMyValue(e.target.value)
|
||||
onChange(e.target.value)
|
||||
}}
|
||||
inputProps={{
|
||||
step: inputParam.step ?? 1,
|
||||
style: {
|
||||
height: inputParam.rows ? '90px' : 'inherit'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
{inputParam.name === 'note' ? (
|
||||
<FormControl sx={{ width: '100%', height: 'auto' }} size='small'>
|
||||
<InputBase
|
||||
id={nodeId}
|
||||
size='small'
|
||||
disabled={disabled}
|
||||
type={getInputType(inputParam.type)}
|
||||
placeholder={inputParam.placeholder}
|
||||
multiline={!!inputParam.rows}
|
||||
minRows={inputParam.rows ?? 1}
|
||||
value={myValue}
|
||||
name={inputParam.name}
|
||||
onChange={(e) => {
|
||||
setMyValue(e.target.value)
|
||||
onChange(e.target.value)
|
||||
}}
|
||||
inputProps={{
|
||||
step: inputParam.step ?? 1,
|
||||
style: {
|
||||
border: 'none',
|
||||
background: 'none',
|
||||
color: '#212121'
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
border: 'none',
|
||||
background: 'none',
|
||||
padding: '10px 14px',
|
||||
textarea: {
|
||||
'&::placeholder': {
|
||||
color: '#616161'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
) : (
|
||||
<FormControl sx={{ mt: 1, width: '100%' }} size='small'>
|
||||
<OutlinedInput
|
||||
id={inputParam.name}
|
||||
size='small'
|
||||
disabled={disabled}
|
||||
type={getInputType(inputParam.type)}
|
||||
placeholder={inputParam.placeholder}
|
||||
multiline={!!inputParam.rows}
|
||||
rows={inputParam.rows ?? 1}
|
||||
value={myValue}
|
||||
name={inputParam.name}
|
||||
onChange={(e) => {
|
||||
setMyValue(e.target.value)
|
||||
onChange(e.target.value)
|
||||
}}
|
||||
inputProps={{
|
||||
step: inputParam.step ?? 1,
|
||||
style: {
|
||||
height: inputParam.rows ? '90px' : 'inherit'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
<div ref={ref}></div>
|
||||
{inputParam?.acceptVariable && (
|
||||
<Popover
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { styled } from '@mui/material/styles'
|
||||
import Tooltip, { tooltipClasses } from '@mui/material/Tooltip'
|
||||
|
||||
const NodeTooltip = 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]
|
||||
}
|
||||
}))
|
||||
|
||||
export default NodeTooltip
|
||||
@@ -3,12 +3,13 @@ import { useContext, useState, useEffect } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
// material-ui
|
||||
import { styled, useTheme } from '@mui/material/styles'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import { IconButton, Box, Typography, Divider, Button } from '@mui/material'
|
||||
import Tooltip, { tooltipClasses } from '@mui/material/Tooltip'
|
||||
import Tooltip from '@mui/material/Tooltip'
|
||||
|
||||
// project imports
|
||||
import MainCard from 'ui-component/cards/MainCard'
|
||||
import NodeCardWrapper from '../../ui-component/cards/NodeCardWrapper'
|
||||
import NodeTooltip from '../../ui-component/tooltip/NodeTooltip'
|
||||
import NodeInputHandler from './NodeInputHandler'
|
||||
import NodeOutputHandler from './NodeOutputHandler'
|
||||
import AdditionalParamsDialog from 'ui-component/dialog/AdditionalParamsDialog'
|
||||
@@ -19,28 +20,6 @@ import { baseURL } from 'store/constant'
|
||||
import { IconTrash, IconCopy, IconInfoCircle, IconAlertTriangle } from '@tabler/icons'
|
||||
import { flowContext } from 'store/context/ReactFlowContext'
|
||||
|
||||
const CardWrapper = styled(MainCard)(({ theme }) => ({
|
||||
background: theme.palette.card.main,
|
||||
color: theme.darkTextPrimary,
|
||||
border: 'solid 1px',
|
||||
borderColor: theme.palette.primary[200] + 75,
|
||||
width: '300px',
|
||||
height: 'auto',
|
||||
padding: '10px',
|
||||
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 8%)',
|
||||
'&:hover': {
|
||||
borderColor: theme.palette.primary.main
|
||||
}
|
||||
}))
|
||||
|
||||
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 }) => {
|
||||
@@ -93,7 +72,7 @@ const CanvasNode = ({ data }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<CardWrapper
|
||||
<NodeCardWrapper
|
||||
content={false}
|
||||
sx={{
|
||||
padding: 0,
|
||||
@@ -101,7 +80,7 @@ const CanvasNode = ({ data }) => {
|
||||
}}
|
||||
border={false}
|
||||
>
|
||||
<LightTooltip
|
||||
<NodeTooltip
|
||||
open={!canvas.canvasDialogShow && open}
|
||||
onClose={handleClose}
|
||||
onOpen={handleOpen}
|
||||
@@ -242,13 +221,12 @@ const CanvasNode = ({ data }) => {
|
||||
</Typography>
|
||||
</Box>
|
||||
<Divider />
|
||||
|
||||
{data.outputAnchors.map((outputAnchor, index) => (
|
||||
<NodeOutputHandler key={index} outputAnchor={outputAnchor} data={data} />
|
||||
))}
|
||||
</Box>
|
||||
</LightTooltip>
|
||||
</CardWrapper>
|
||||
</NodeTooltip>
|
||||
</NodeCardWrapper>
|
||||
<AdditionalParamsDialog
|
||||
show={showDialog}
|
||||
dialogProps={dialogProps}
|
||||
|
||||
@@ -28,6 +28,8 @@ import ToolDialog from 'views/tools/ToolDialog'
|
||||
import AssistantDialog from 'views/assistants/AssistantDialog'
|
||||
import ExpandTextDialog from 'ui-component/dialog/ExpandTextDialog'
|
||||
import FormatPromptValuesDialog from 'ui-component/dialog/FormatPromptValuesDialog'
|
||||
import PromptLangsmithHubDialog from 'ui-component/dialog/PromptLangsmithHubDialog'
|
||||
import ManageScrapedLinksDialog from 'ui-component/dialog/ManageScrapedLinksDialog'
|
||||
import CredentialInputHandler from './CredentialInputHandler'
|
||||
|
||||
// utils
|
||||
@@ -35,7 +37,6 @@ import { getInputVariables } from 'utils/genericHelper'
|
||||
|
||||
// const
|
||||
import { FLOWISE_CREDENTIAL_ID } from 'store/constant'
|
||||
import PromptLangsmithHubDialog from '../../ui-component/dialog/PromptLangsmithHubDialog'
|
||||
|
||||
const EDITABLE_OPTIONS = ['selectedTool', 'selectedAssistant']
|
||||
|
||||
@@ -62,22 +63,25 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||
const [showFormatPromptValuesDialog, setShowFormatPromptValuesDialog] = useState(false)
|
||||
const [formatPromptValuesDialogProps, setFormatPromptValuesDialogProps] = useState({})
|
||||
const [showPromptHubDialog, setShowPromptHubDialog] = useState(false)
|
||||
const [showManageScrapedLinksDialog, setShowManageScrapedLinksDialog] = useState(false)
|
||||
const [manageScrapedLinksDialogProps, setManageScrapedLinksDialogProps] = useState({})
|
||||
|
||||
const onExpandDialogClicked = (value, inputParam) => {
|
||||
const dialogProp = {
|
||||
const dialogProps = {
|
||||
value,
|
||||
inputParam,
|
||||
disabled,
|
||||
confirmButtonName: 'Save',
|
||||
cancelButtonName: 'Cancel'
|
||||
}
|
||||
setExpandDialogProps(dialogProp)
|
||||
setExpandDialogProps(dialogProps)
|
||||
setShowExpandDialog(true)
|
||||
}
|
||||
|
||||
const onShowPromptHubButtonClicked = () => {
|
||||
setShowPromptHubDialog(true)
|
||||
}
|
||||
|
||||
const onShowPromptHubButtonSubmit = (templates) => {
|
||||
setShowPromptHubDialog(false)
|
||||
for (const t of templates) {
|
||||
@@ -86,6 +90,24 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onManageLinksDialogClicked = (url, selectedLinks) => {
|
||||
const dialogProps = {
|
||||
url,
|
||||
selectedLinks,
|
||||
confirmButtonName: 'Save',
|
||||
cancelButtonName: 'Cancel'
|
||||
}
|
||||
setManageScrapedLinksDialogProps(dialogProps)
|
||||
setShowManageScrapedLinksDialog(true)
|
||||
}
|
||||
|
||||
const onManageLinksDialogSave = (url, links) => {
|
||||
setShowManageScrapedLinksDialog(false)
|
||||
data.inputs.url = url
|
||||
data.inputs.selectedLinks = links
|
||||
}
|
||||
|
||||
const onEditJSONClicked = (value, inputParam) => {
|
||||
// Preset values if the field is format prompt values
|
||||
let inputValue = value
|
||||
@@ -436,6 +458,37 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{(data.name === 'cheerioWebScraper' ||
|
||||
data.name === 'puppeteerWebScraper' ||
|
||||
data.name === 'playwrightWebScraper') &&
|
||||
inputParam.name === 'url' && (
|
||||
<>
|
||||
<Button
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
width: '100%'
|
||||
}}
|
||||
disabled={disabled}
|
||||
sx={{ borderRadius: '12px', width: '100%', mt: 1 }}
|
||||
variant='outlined'
|
||||
onClick={() =>
|
||||
onManageLinksDialogClicked(
|
||||
data.inputs[inputParam.name] ?? inputParam.default ?? '',
|
||||
data.inputs.selectedLinks
|
||||
)
|
||||
}
|
||||
>
|
||||
Manage Links
|
||||
</Button>
|
||||
<ManageScrapedLinksDialog
|
||||
show={showManageScrapedLinksDialog}
|
||||
dialogProps={manageScrapedLinksDialogProps}
|
||||
onCancel={() => setShowManageScrapedLinksDialog(false)}
|
||||
onSave={onManageLinksDialogSave}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { useContext, useState } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
|
||||
// project imports
|
||||
import NodeCardWrapper from '../../ui-component/cards/NodeCardWrapper'
|
||||
import NodeTooltip from '../../ui-component/tooltip/NodeTooltip'
|
||||
import { IconButton, Box } from '@mui/material'
|
||||
import { IconCopy, IconTrash } from '@tabler/icons'
|
||||
import { Input } from 'ui-component/input/Input'
|
||||
|
||||
// const
|
||||
import { flowContext } from '../../store/context/ReactFlowContext'
|
||||
|
||||
const StickyNote = ({ data }) => {
|
||||
const theme = useTheme()
|
||||
const canvas = useSelector((state) => state.canvas)
|
||||
const { deleteNode, duplicateNode } = useContext(flowContext)
|
||||
const [inputParam] = data.inputParams
|
||||
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const handleOpen = () => {
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<NodeCardWrapper
|
||||
content={false}
|
||||
sx={{
|
||||
padding: 0,
|
||||
borderColor: data.selected ? theme.palette.primary.main : theme.palette.text.secondary,
|
||||
backgroundColor: data.selected ? '#FFDC00' : '#FFE770'
|
||||
}}
|
||||
border={false}
|
||||
>
|
||||
<NodeTooltip
|
||||
open={!canvas.canvasDialogShow && open}
|
||||
onClose={handleClose}
|
||||
onOpen={handleOpen}
|
||||
disableFocusListener={true}
|
||||
title={
|
||||
<div
|
||||
style={{
|
||||
background: 'transparent',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
</div>
|
||||
}
|
||||
placement='right-start'
|
||||
>
|
||||
<Box>
|
||||
<Input
|
||||
key={data.id}
|
||||
inputParam={inputParam}
|
||||
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)}
|
||||
value={data.inputs[inputParam.name] ?? inputParam.default ?? ''}
|
||||
nodes={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getNodes() : []}
|
||||
edges={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getEdges() : []}
|
||||
nodeId={data.id}
|
||||
/>
|
||||
</Box>
|
||||
</NodeTooltip>
|
||||
</NodeCardWrapper>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
StickyNote.propTypes = {
|
||||
data: PropTypes.object
|
||||
}
|
||||
|
||||
export default StickyNote
|
||||
@@ -21,6 +21,7 @@ import { useTheme } from '@mui/material/styles'
|
||||
// project imports
|
||||
import CanvasNode from './CanvasNode'
|
||||
import ButtonEdge from './ButtonEdge'
|
||||
import StickyNote from './StickyNote'
|
||||
import CanvasHeader from './CanvasHeader'
|
||||
import AddNodes from './AddNodes'
|
||||
import ConfirmDialog from 'ui-component/dialog/ConfirmDialog'
|
||||
@@ -46,7 +47,7 @@ import useNotifier from 'utils/useNotifier'
|
||||
// const
|
||||
import { FLOWISE_CREDENTIAL_ID } from 'store/constant'
|
||||
|
||||
const nodeTypes = { customNode: CanvasNode }
|
||||
const nodeTypes = { customNode: CanvasNode, stickyNote: StickyNote }
|
||||
const edgeTypes = { buttonedge: ButtonEdge }
|
||||
|
||||
// ==============================|| CANVAS ||============================== //
|
||||
@@ -276,7 +277,7 @@ const Canvas = () => {
|
||||
const newNode = {
|
||||
id: newNodeId,
|
||||
position,
|
||||
type: 'customNode',
|
||||
type: nodeData.type !== 'StickyNote' ? 'customNode' : 'stickyNote',
|
||||
data: initNode(nodeData, newNodeId)
|
||||
}
|
||||
|
||||
|
||||
@@ -130,8 +130,8 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: start;
|
||||
justify-content: start;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
@@ -155,7 +155,7 @@
|
||||
overflow-y: scroll;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: start;
|
||||
align-items: flex-start;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,13 +101,13 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
|
||||
const isFileAllowedForUpload = (file) => {
|
||||
const constraints = getAllowChatFlowUploads.data
|
||||
/**
|
||||
* {isUploadAllowed: boolean, uploadFileSizeAndTypes: Array<{ fileTypes: string[], maxUploadSize: number }>}
|
||||
* {isImageUploadAllowed: boolean, imgUploadSizeAndTypes: Array<{ fileTypes: string[], maxUploadSize: number }>}
|
||||
*/
|
||||
let acceptFile = false
|
||||
if (constraints.isUploadAllowed) {
|
||||
if (constraints.isImageUploadAllowed) {
|
||||
const fileType = file.type
|
||||
const sizeInMB = file.size / 1024 / 1024
|
||||
constraints.uploadFileSizeAndTypes.map((allowed) => {
|
||||
constraints.imgUploadSizeAndTypes.map((allowed) => {
|
||||
if (allowed.fileTypes.includes(fileType) && sizeInMB <= allowed.maxUploadSize) {
|
||||
acceptFile = true
|
||||
}
|
||||
@@ -473,7 +473,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
|
||||
obj.fileUploads = JSON.parse(message.fileUploads)
|
||||
obj.fileUploads.forEach((file) => {
|
||||
if (file.type === 'stored-file') {
|
||||
file.data = `${baseURL}/api/v1/get-upload-file/${file.name}?chatId=${chatId}`
|
||||
file.data = `${baseURL}/api/v1/get-upload-file?chatflowId=${chatflowid}&chatId=${chatId}&fileName=${file.name}`
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -497,8 +497,8 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
|
||||
// Get chatflow uploads capability
|
||||
useEffect(() => {
|
||||
if (getAllowChatFlowUploads.data) {
|
||||
setIsChatFlowAvailableForUploads(getAllowChatFlowUploads.data?.isUploadAllowed ?? false)
|
||||
setIsChatFlowAvailableForSpeech(getAllowChatFlowUploads.data?.allowSpeechToText ?? false)
|
||||
setIsChatFlowAvailableForUploads(getAllowChatFlowUploads.data?.isImageUploadAllowed ?? false)
|
||||
setIsChatFlowAvailableForSpeech(getAllowChatFlowUploads.data?.isSpeechToTextEnabled ?? false)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [getAllowChatFlowUploads.data])
|
||||
@@ -603,10 +603,10 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
|
||||
onDrop={handleDrop}
|
||||
/>
|
||||
)}
|
||||
{isDragActive && getAllowChatFlowUploads.data?.isUploadAllowed && (
|
||||
{isDragActive && getAllowChatFlowUploads.data?.isImageUploadAllowed && (
|
||||
<Box className='drop-overlay'>
|
||||
<Typography variant='h2'>Drop here to upload</Typography>
|
||||
{getAllowChatFlowUploads.data.uploadFileSizeAndTypes.map((allowed) => {
|
||||
{getAllowChatFlowUploads.data.imgUploadSizeAndTypes.map((allowed) => {
|
||||
return (
|
||||
<>
|
||||
<Typography variant='subtitle1'>{allowed.fileTypes?.join(', ')}</Typography>
|
||||
|
||||
@@ -11,10 +11,10 @@ import { useTheme } from '@mui/material/styles'
|
||||
|
||||
// project imports
|
||||
import MarketplaceCanvasNode from './MarketplaceCanvasNode'
|
||||
|
||||
import MarketplaceCanvasHeader from './MarketplaceCanvasHeader'
|
||||
import StickyNote from '../canvas/StickyNote'
|
||||
|
||||
const nodeTypes = { customNode: MarketplaceCanvasNode }
|
||||
const nodeTypes = { customNode: MarketplaceCanvasNode, stickyNote: StickyNote }
|
||||
const edgeTypes = { buttonedge: '' }
|
||||
|
||||
// ==============================|| CANVAS ||============================== //
|
||||
|
||||
Reference in New Issue
Block a user