mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 15:00:57 +03:00
Merge branch 'main' into feature/ChatHistory2
This commit is contained in:
@@ -81,27 +81,6 @@ const analyticProviders = [
|
||||
type: 'credential',
|
||||
credentialNames: ['langfuseApi']
|
||||
},
|
||||
{
|
||||
label: 'Flush At',
|
||||
name: 'flushAt',
|
||||
type: 'number',
|
||||
optional: true,
|
||||
description: 'Number of queued requests'
|
||||
},
|
||||
{
|
||||
label: 'Flush Interval',
|
||||
name: 'flushInterval',
|
||||
type: 'number',
|
||||
optional: true,
|
||||
description: 'Interval in ms to flush requests'
|
||||
},
|
||||
{
|
||||
label: 'Request Timeout',
|
||||
name: 'requestTimeout',
|
||||
type: 'number',
|
||||
optional: true,
|
||||
description: 'Timeout in ms for requests'
|
||||
},
|
||||
{
|
||||
label: 'Release',
|
||||
name: 'release',
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { useState } from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
import { Popper, FormControl, TextField, Box, Typography } from '@mui/material'
|
||||
import Autocomplete, { autocompleteClasses } from '@mui/material/Autocomplete'
|
||||
import { styled } from '@mui/material/styles'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const MultiDropdown = ({ name, value, options, onSelect, disabled = false, disableClearable = false }) => {
|
||||
const customization = useSelector((state) => state.customization)
|
||||
const findMatchingOptions = (options = [], internalValue) => {
|
||||
let values = []
|
||||
if (internalValue && typeof internalValue === 'string') values = JSON.parse(internalValue)
|
||||
else values = internalValue
|
||||
return options.filter((option) => values.includes(option.name))
|
||||
}
|
||||
const getDefaultOptionValue = () => []
|
||||
let [internalValue, setInternalValue] = useState(value ?? [])
|
||||
|
||||
return (
|
||||
<FormControl sx={{ mt: 1, width: '100%' }} size='small'>
|
||||
<Autocomplete
|
||||
id={name}
|
||||
disabled={disabled}
|
||||
disableClearable={disableClearable}
|
||||
size='small'
|
||||
multiple
|
||||
filterSelectedOptions
|
||||
options={options || []}
|
||||
value={findMatchingOptions(options, internalValue) || getDefaultOptionValue()}
|
||||
onChange={(e, selections) => {
|
||||
let value = ''
|
||||
if (selections.length) {
|
||||
const selectionNames = []
|
||||
for (let i = 0; i < selections.length; i += 1) {
|
||||
selectionNames.push(selections[i].name)
|
||||
}
|
||||
value = JSON.stringify(selectionNames)
|
||||
}
|
||||
setInternalValue(value)
|
||||
onSelect(value)
|
||||
}}
|
||||
PopperComponent={StyledPopper}
|
||||
renderInput={(params) => <TextField {...params} value={internalValue} />}
|
||||
renderOption={(props, option) => (
|
||||
<Box component='li' {...props}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<Typography variant='h5'>{option.label}</Typography>
|
||||
{option.description && (
|
||||
<Typography sx={{ color: customization.isDarkMode ? '#9e9e9e' : '' }}>{option.description}</Typography>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
/>
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
|
||||
MultiDropdown.propTypes = {
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
options: PropTypes.array,
|
||||
onSelect: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
disableClearable: PropTypes.bool
|
||||
}
|
||||
@@ -39,7 +39,20 @@ export const initNode = (nodeData, newNodeId) => {
|
||||
const incoming = nodeData.inputs ? nodeData.inputs.length : 0
|
||||
const outgoing = 1
|
||||
|
||||
const whitelistTypes = ['asyncOptions', 'options', 'string', 'number', 'boolean', 'password', 'json', 'code', 'date', 'file', 'folder']
|
||||
const whitelistTypes = [
|
||||
'asyncOptions',
|
||||
'options',
|
||||
'multiOptions',
|
||||
'string',
|
||||
'number',
|
||||
'boolean',
|
||||
'password',
|
||||
'json',
|
||||
'code',
|
||||
'date',
|
||||
'file',
|
||||
'folder'
|
||||
]
|
||||
|
||||
// Inputs
|
||||
for (let i = 0; i < incoming; i += 1) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { IconArrowsMaximize, IconEdit, IconAlertTriangle } from '@tabler/icons'
|
||||
|
||||
// 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 { File } from 'ui-component/file/File'
|
||||
@@ -308,6 +309,15 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||
value={data.inputs[inputParam.name] ?? inputParam.default ?? 'choose an option'}
|
||||
/>
|
||||
)}
|
||||
{inputParam.type === 'multiOptions' && (
|
||||
<MultiDropdown
|
||||
disabled={disabled}
|
||||
name={inputParam.name}
|
||||
options={inputParam.options}
|
||||
onSelect={(newValue) => (data.inputs[inputParam.name] = newValue)}
|
||||
value={data.inputs[inputParam.name] ?? inputParam.default ?? 'choose an option'}
|
||||
/>
|
||||
)}
|
||||
{inputParam.type === 'asyncOptions' && (
|
||||
<>
|
||||
{data.inputParams.length === 1 && <div style={{ marginTop: 10 }} />}
|
||||
|
||||
Reference in New Issue
Block a user