update ui changes

This commit is contained in:
Henry 2023-12-21 17:28:25 +00:00
parent a2d4a3b8d0
commit f0cdf48d54
10 changed files with 223 additions and 42 deletions

View File

@ -85,26 +85,29 @@ class CustomTool_Tools implements INode {
// override variables defined in overrideConfig // override variables defined in overrideConfig
// nodeData.inputs.variables is an Object, check each property and override the variable // nodeData.inputs.variables is an Object, check each property and override the variable
if (nodeData?.inputs?.envVars) { if (nodeData?.inputs?.vars) {
for (const propertyName of Object.getOwnPropertyNames(nodeData.inputs.envVars)) { for (const propertyName of Object.getOwnPropertyNames(nodeData.inputs.vars)) {
const foundVar = variables.find((v) => v.name === propertyName) const foundVar = variables.find((v) => v.name === propertyName)
if (foundVar) { if (foundVar) {
// even if the variable was defined as runtime, we override it with static value // even if the variable was defined as runtime, we override it with static value
foundVar.type = 'static' foundVar.type = 'static'
foundVar.value = nodeData.inputs.envVars[propertyName] foundVar.value = nodeData.inputs.vars[propertyName]
} else { } else {
// add it the variables, if not found locally in the db // add it the variables, if not found locally in the db
variables.push({ name: propertyName, type: 'static', value: nodeData.inputs.envVars[propertyName] }) variables.push({ name: propertyName, type: 'static', value: nodeData.inputs.vars[propertyName] })
} }
} }
} }
const flow = { const flow = {
chatId: options.chatId, // id is uppercase (I) chatId: options.chatId, // id is uppercase (I)
chatflowId: options.chatflowid // id is lowercase (i) chatflowId: options.chatflowid // id is lowercase (i)
} }
let dynamicStructuredTool = new DynamicStructuredTool(obj) let dynamicStructuredTool = new DynamicStructuredTool(obj)
dynamicStructuredTool.setVariables(variables) dynamicStructuredTool.setVariables(variables)
dynamicStructuredTool.setFlowObject(flow) dynamicStructuredTool.setFlowObject(flow)
return dynamicStructuredTool return dynamicStructuredTool
} catch (e) { } catch (e) {
throw new Error(e) throw new Error(e)

View File

@ -102,15 +102,19 @@ export class DynamicStructuredTool<
sandbox[`$${item}`] = arg[item] sandbox[`$${item}`] = arg[item]
} }
} }
//inject variables
let env = {} // inject variables
let vars = {}
if (this.variables) { if (this.variables) {
for (const item of this.variables) { for (const item of this.variables) {
let value = item.value let value = item.value
// read from .env file
if (item.type === 'runtime') { if (item.type === 'runtime') {
value = process.env[item.name] value = process.env[item.name]
} }
Object.defineProperty(env, item.name, {
Object.defineProperty(vars, item.name, {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
writable: true, writable: true,
@ -118,10 +122,13 @@ export class DynamicStructuredTool<
}) })
} }
} }
sandbox['$env'] = env sandbox['$vars'] = vars
// inject flow properties
if (this.flowObj) { if (this.flowObj) {
sandbox['$flow'] = { ...this.flowObj, sessionId: overrideSessionId } sandbox['$flow'] = { ...this.flowObj, sessionId: overrideSessionId }
} }
const defaultAllowBuiltInDep = [ const defaultAllowBuiltInDep = [
'assert', 'assert',
'buffer', 'buffer',

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -53,7 +53,7 @@ const dashboard = {
}, },
{ {
id: 'variables', id: 'variables',
title: 'Environment Variables', title: 'Variables',
type: 'item', type: 'item',
url: '/variables', url: '/variables',
icon: icons.IconVariable, icon: icons.IconVariable,

View File

@ -369,7 +369,12 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
{inputParam?.acceptVariable && ( {inputParam?.acceptVariable && (
<> <>
<Button <Button
sx={{ borderRadius: 25, width: '100%', mb: 0, mt: 2 }} sx={{
borderRadius: 25,
width: '100%',
mb: 0,
mt: 2
}}
variant='outlined' variant='outlined'
disabled={disabled} disabled={disabled}
onClick={() => onEditJSONClicked(data.inputs[inputParam.name] ?? '', inputParam)} onClick={() => onEditJSONClicked(data.inputs[inputParam.name] ?? '', inputParam)}

View File

@ -0,0 +1,65 @@
import { createPortal } from 'react-dom'
import PropTypes from 'prop-types'
import { Dialog, DialogContent, DialogTitle } from '@mui/material'
const HowToUseFunctionDialog = ({ show, onCancel }) => {
const portalElement = document.getElementById('portal')
const component = show ? (
<Dialog
onClose={onCancel}
open={show}
fullWidth
maxWidth='sm'
aria-labelledby='alert-dialog-title'
aria-describedby='alert-dialog-description'
>
<DialogTitle sx={{ fontSize: '1rem' }} id='alert-dialog-title'>
How To Use Function
</DialogTitle>
<DialogContent>
<ul>
<li style={{ marginTop: 10 }}>You can use any libraries imported in Flowise</li>
<li style={{ marginTop: 10 }}>
You can use properties specified in Output Schema as variables with prefix $:
<ul style={{ marginTop: 10 }}>
<li>
Property = <code>userid</code>
</li>
<li>
Variable = <code>$userid</code>
</li>
</ul>
</li>
<li style={{ marginTop: 10 }}>
You can get default flow config:
<ul style={{ marginTop: 10 }}>
<li>
<code>$flow.sessionId</code>
</li>
<li>
<code>$flow.chatId</code>
</li>
<li>
<code>$flow.chatflowId</code>
</li>
</ul>
</li>
<li style={{ marginTop: 10 }}>
You can get custom variables:&nbsp;<code>{`$vars.<variable-name>`}</code>
</li>
<li style={{ marginTop: 10 }}>Must return a string value at the end of function</li>
</ul>
</DialogContent>
</Dialog>
) : null
return createPortal(component, portalElement)
}
HowToUseFunctionDialog.propTypes = {
show: PropTypes.bool,
onCancel: PropTypes.func
}
export default HowToUseFunctionDialog

View File

@ -13,6 +13,7 @@ import { GridActionsCellItem } from '@mui/x-data-grid'
import DeleteIcon from '@mui/icons-material/Delete' import DeleteIcon from '@mui/icons-material/Delete'
import ConfirmDialog from 'ui-component/dialog/ConfirmDialog' import ConfirmDialog from 'ui-component/dialog/ConfirmDialog'
import { CodeEditor } from 'ui-component/editor/CodeEditor' import { CodeEditor } from 'ui-component/editor/CodeEditor'
import HowToUseFunctionDialog from './HowToUseFunctionDialog'
// Icons // Icons
import { IconX, IconFileExport } from '@tabler/icons' import { IconX, IconFileExport } from '@tabler/icons'
@ -32,6 +33,8 @@ import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
const exampleAPIFunc = `/* const exampleAPIFunc = `/*
* You can use any libraries imported in Flowise * You can use any libraries imported in Flowise
* You can use properties specified in Output Schema as variables. Ex: Property = userid, Variable = $userid * You can use properties specified in Output Schema as variables. Ex: Property = userid, Variable = $userid
* You can get default flow config: $flow.sessionId, $flow.chatId, $flow.chatflowId
* You can get custom variables: $vars.<variable-name>
* Must return a string value at the end of function * Must return a string value at the end of function
*/ */
@ -74,6 +77,7 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
const [toolIcon, setToolIcon] = useState('') const [toolIcon, setToolIcon] = useState('')
const [toolSchema, setToolSchema] = useState([]) const [toolSchema, setToolSchema] = useState([])
const [toolFunc, setToolFunc] = useState('') const [toolFunc, setToolFunc] = useState('')
const [showHowToDialog, setShowHowToDialog] = useState(false)
const deleteItem = useCallback( const deleteItem = useCallback(
(id) => () => { (id) => () => {
@ -482,6 +486,14 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
/> />
</Typography> </Typography>
</Stack> </Stack>
<Button
style={{ marginBottom: 10, marginRight: 10 }}
color='secondary'
variant='outlined'
onClick={() => setShowHowToDialog(true)}
>
How to use Function
</Button>
{dialogProps.type !== 'TEMPLATE' && ( {dialogProps.type !== 'TEMPLATE' && (
<Button style={{ marginBottom: 10 }} variant='outlined' onClick={() => setToolFunc(exampleAPIFunc)}> <Button style={{ marginBottom: 10 }} variant='outlined' onClick={() => setToolFunc(exampleAPIFunc)}>
See Example See Example
@ -519,6 +531,7 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
)} )}
</DialogActions> </DialogActions>
<ConfirmDialog /> <ConfirmDialog />
<HowToUseFunctionDialog show={showHowToDialog} onCancel={() => setShowHowToDialog(false)} />
</Dialog> </Dialog>
) : null ) : null

View File

@ -24,17 +24,18 @@ import useNotifier from 'utils/useNotifier'
// const // const
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
import { TooltipWithParser } from '../../ui-component/tooltip/TooltipWithParser'
import { Dropdown } from '../../ui-component/dropdown/Dropdown' import { Dropdown } from '../../ui-component/dropdown/Dropdown'
const variableTypes = [ const variableTypes = [
{ {
label: 'Static Variable', label: 'Static',
name: 'static' name: 'static',
description: 'Variable value will be read from the value entered below'
}, },
{ {
label: 'Runtime Variable', label: 'Runtime',
name: 'runtime' name: 'runtime',
description: 'Variable value will be read from .env file'
} }
] ]
@ -208,6 +209,8 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
<div style={{ flexGrow: 1 }}></div> <div style={{ flexGrow: 1 }}></div>
</div> </div>
<OutlinedInput <OutlinedInput
size='small'
sx={{ mt: 1 }}
type='string' type='string'
fullWidth fullWidth
key='variableName' key='variableName'
@ -215,23 +218,6 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
value={variableName ?? ''} value={variableName ?? ''}
/> />
</Box> </Box>
<Box sx={{ p: 2 }}>
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Typography>
Value
<TooltipWithParser style={{ marginLeft: 10 }} title='Value is mandatory for static variables.' />
</Typography>
<div style={{ flexGrow: 1 }}></div>
</div>
<OutlinedInput
type='string'
fullWidth
key='variableValue'
onChange={(e) => setVariableValue(e.target.value)}
value={variableValue ?? ''}
/>
<Typography variant='subtitle2'>Leave the value empty for runtime variables. Will be populated at runtime.</Typography>
</Box>
<Box sx={{ p: 2 }}> <Box sx={{ p: 2 }}>
<div style={{ display: 'flex', flexDirection: 'row' }}> <div style={{ display: 'flex', flexDirection: 'row' }}>
<Typography> <Typography>
@ -245,14 +231,30 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
onSelect={(newValue) => setVariableType(newValue)} onSelect={(newValue) => setVariableType(newValue)}
value={variableType} value={variableType}
/> />
<Typography variant='subtitle2'>
Runtime: Value would be populated from env. Static: Value would be used as is.
</Typography>
</Box> </Box>
{variableType === 'static' && (
<Box sx={{ p: 2 }}>
<div style={{ display: 'flex', flexDirection: 'row' }}>
<Typography>
Value<span style={{ color: 'red' }}>&nbsp;*</span>
</Typography>
<div style={{ flexGrow: 1 }}></div>
</div>
<OutlinedInput
size='small'
sx={{ mt: 1 }}
type='string'
fullWidth
key='variableValue'
onChange={(e) => setVariableValue(e.target.value)}
value={variableValue ?? ''}
/>
</Box>
)}
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<StyledButton <StyledButton
disabled={!variableName || (variableType === 'static' && !variableValue)} disabled={!variableName || !variableType || (variableType === 'static' && !variableValue)}
variant='contained' variant='contained'
onClick={() => (dialogType === 'ADD' ? addNewVariable() : saveVariable())} onClick={() => (dialogType === 'ADD' ? addNewVariable() : saveVariable())}
> >

View File

@ -0,0 +1,72 @@
import { createPortal } from 'react-dom'
import PropTypes from 'prop-types'
import { Dialog, DialogContent, DialogTitle } from '@mui/material'
import { CodeEditor } from 'ui-component/editor/CodeEditor'
const overrideConfig = `{
overrideConfig: {
vars: {
var1: 'abc'
}
}
}`
const HowToUseVariablesDialog = ({ show, onCancel }) => {
const portalElement = document.getElementById('portal')
const component = show ? (
<Dialog
onClose={onCancel}
open={show}
fullWidth
maxWidth='sm'
aria-labelledby='alert-dialog-title'
aria-describedby='alert-dialog-description'
>
<DialogTitle sx={{ fontSize: '1rem' }} id='alert-dialog-title'>
How To Use Variables
</DialogTitle>
<DialogContent>
<p style={{ marginBottom: '10px' }}>Variables can be used in Custom Tool Function with the $ prefix.</p>
<CodeEditor
disabled={true}
value={`$vars.<variable-name>`}
height={'50px'}
theme={'dark'}
lang={'js'}
basicSetup={{ highlightActiveLine: false, highlightActiveLineGutter: false }}
/>
<p style={{ marginBottom: '10px' }}>
If variable type is Static, the value will be retrieved as it is. If variable type is Runtime, the value will be
retrieved from .env file.
</p>
<p style={{ marginBottom: '10px' }}>
You can also override variable values in API overrideConfig using <b>vars</b>:
</p>
<CodeEditor
disabled={true}
value={overrideConfig}
height={'170px'}
theme={'dark'}
lang={'js'}
basicSetup={{ highlightActiveLine: false, highlightActiveLineGutter: false }}
/>
<p>
Read more from{' '}
<a target='_blank' rel='noreferrer' href='https://docs.flowiseai.com/using-flowise/variables'>
docs
</a>
</p>
</DialogContent>
</Dialog>
) : null
return createPortal(component, portalElement)
}
HowToUseVariablesDialog.propTypes = {
show: PropTypes.bool,
onCancel: PropTypes.func
}
export default HowToUseVariablesDialog

View File

@ -19,7 +19,8 @@ import {
Toolbar, Toolbar,
TextField, TextField,
InputAdornment, InputAdornment,
ButtonGroup ButtonGroup,
Chip
} from '@mui/material' } from '@mui/material'
import { useTheme } from '@mui/material/styles' import { useTheme } from '@mui/material/styles'
@ -40,10 +41,11 @@ import useNotifier from 'utils/useNotifier'
// Icons // Icons
import { IconTrash, IconEdit, IconX, IconPlus, IconSearch, IconVariable } from '@tabler/icons' import { IconTrash, IconEdit, IconX, IconPlus, IconSearch, IconVariable } from '@tabler/icons'
import CredentialEmptySVG from 'assets/images/credential_empty.svg' import VariablesEmptySVG from 'assets/images/variables_empty.svg'
// const // const
import AddEditVariableDialog from './AddEditVariableDialog' import AddEditVariableDialog from './AddEditVariableDialog'
import HowToUseVariablesDialog from './HowToUseVariablesDialog'
// ==============================|| Credentials ||============================== // // ==============================|| Credentials ||============================== //
@ -60,6 +62,7 @@ const Variables = () => {
const [showVariableDialog, setShowVariableDialog] = useState(false) const [showVariableDialog, setShowVariableDialog] = useState(false)
const [variableDialogProps, setVariableDialogProps] = useState({}) const [variableDialogProps, setVariableDialogProps] = useState({})
const [variables, setVariables] = useState([]) const [variables, setVariables] = useState([])
const [showHowToDialog, setShowHowToDialog] = useState(false)
const { confirm } = useConfirm() const { confirm } = useConfirm()
@ -173,7 +176,7 @@ const Variables = () => {
width: '100%' width: '100%'
}} }}
> >
<h1>Environment Variables&nbsp;</h1> <h1>Variables&nbsp;</h1>
<TextField <TextField
size='small' size='small'
sx={{ display: { xs: 'none', sm: 'block' }, ml: 3 }} sx={{ display: { xs: 'none', sm: 'block' }, ml: 3 }}
@ -189,6 +192,9 @@ const Variables = () => {
}} }}
/> />
<Box sx={{ flexGrow: 1 }} /> <Box sx={{ flexGrow: 1 }} />
<Button variant='outlined' sx={{ mr: 2 }} onClick={() => setShowHowToDialog(true)}>
How To Use
</Button>
<ButtonGroup <ButtonGroup
sx={{ maxHeight: 40 }} sx={{ maxHeight: 40 }}
disableElevation disableElevation
@ -214,8 +220,8 @@ const Variables = () => {
<Box sx={{ p: 2, height: 'auto' }}> <Box sx={{ p: 2, height: 'auto' }}>
<img <img
style={{ objectFit: 'cover', height: '30vh', width: 'auto' }} style={{ objectFit: 'cover', height: '30vh', width: 'auto' }}
src={CredentialEmptySVG} src={VariablesEmptySVG}
alt='CredentialEmptySVG' alt='VariablesEmptySVG'
/> />
</Box> </Box>
<div>No Variables Yet</div> <div>No Variables Yet</div>
@ -267,7 +273,13 @@ const Variables = () => {
</div> </div>
</TableCell> </TableCell>
<TableCell>{variable.value}</TableCell> <TableCell>{variable.value}</TableCell>
<TableCell>{variable.type === 'static' ? 'Static Variable' : 'Runtime Variable'}</TableCell> <TableCell>
<Chip
color={variable.type === 'static' ? 'info' : 'secondary'}
size='small'
label={variable.type}
/>
</TableCell>
<TableCell>{moment(variable.updatedDate).format('DD-MMM-YY')}</TableCell> <TableCell>{moment(variable.updatedDate).format('DD-MMM-YY')}</TableCell>
<TableCell>{moment(variable.createdDate).format('DD-MMM-YY')}</TableCell> <TableCell>{moment(variable.createdDate).format('DD-MMM-YY')}</TableCell>
<TableCell> <TableCell>
@ -293,6 +305,7 @@ const Variables = () => {
onCancel={() => setShowVariableDialog(false)} onCancel={() => setShowVariableDialog(false)}
onConfirm={onConfirm} onConfirm={onConfirm}
></AddEditVariableDialog> ></AddEditVariableDialog>
<HowToUseVariablesDialog show={showHowToDialog} onCancel={() => setShowHowToDialog(false)}></HowToUseVariablesDialog>
<ConfirmDialog /> <ConfirmDialog />
</> </>
) )