Update chatflow configuration dialog - add starter prompts, analyse chatflow. Rename files.
This commit is contained in:
parent
b7bb043d3a
commit
7020974b55
|
|
@ -1,14 +1,5 @@
|
|||
// assets
|
||||
import {
|
||||
IconTrash,
|
||||
IconFileUpload,
|
||||
IconFileExport,
|
||||
IconCopy,
|
||||
IconSearch,
|
||||
IconMessage,
|
||||
IconPictureInPictureOff,
|
||||
IconAdjustmentsHorizontal
|
||||
} from '@tabler/icons'
|
||||
import { IconTrash, IconFileUpload, IconFileExport, IconCopy, IconMessage, IconAdjustmentsHorizontal } from '@tabler/icons'
|
||||
|
||||
// constant
|
||||
const icons = {
|
||||
|
|
@ -16,9 +7,7 @@ const icons = {
|
|||
IconFileUpload,
|
||||
IconFileExport,
|
||||
IconCopy,
|
||||
IconSearch,
|
||||
IconMessage,
|
||||
IconPictureInPictureOff,
|
||||
IconAdjustmentsHorizontal
|
||||
}
|
||||
|
||||
|
|
@ -29,13 +18,6 @@ const settings = {
|
|||
title: '',
|
||||
type: 'group',
|
||||
children: [
|
||||
{
|
||||
id: 'conversationStarters',
|
||||
title: 'Starter Prompts',
|
||||
type: 'item',
|
||||
url: '',
|
||||
icon: icons.IconPictureInPictureOff
|
||||
},
|
||||
{
|
||||
id: 'viewMessages',
|
||||
title: 'View Messages',
|
||||
|
|
@ -71,13 +53,6 @@ const settings = {
|
|||
url: '',
|
||||
icon: icons.IconFileExport
|
||||
},
|
||||
{
|
||||
id: 'analyseChatflow',
|
||||
title: 'Analyse Chatflow',
|
||||
type: 'item',
|
||||
url: '',
|
||||
icon: icons.IconSearch
|
||||
},
|
||||
{
|
||||
id: 'deleteChatflow',
|
||||
title: 'Delete Chatflow',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,325 @@
|
|||
import { useDispatch } from 'react-redux'
|
||||
import { useState, useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions'
|
||||
|
||||
// material-ui
|
||||
import {
|
||||
Typography,
|
||||
Box,
|
||||
Button,
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
AccordionDetails,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText
|
||||
} from '@mui/material'
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
|
||||
import { IconX } from '@tabler/icons'
|
||||
|
||||
// Project import
|
||||
import CredentialInputHandler from 'views/canvas/CredentialInputHandler'
|
||||
import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser'
|
||||
import { SwitchInput } from 'ui-component/switch/Switch'
|
||||
import { Input } from 'ui-component/input/Input'
|
||||
import { StyledButton } from 'ui-component/button/StyledButton'
|
||||
import langsmithPNG from 'assets/images/langchain.png'
|
||||
import langfuseSVG from 'assets/images/langfuse.svg'
|
||||
import lunarySVG from 'assets/images/lunary.svg'
|
||||
|
||||
// store
|
||||
import useNotifier from 'utils/useNotifier'
|
||||
|
||||
// API
|
||||
import chatflowsApi from 'api/chatflows'
|
||||
|
||||
const analyticProviders = [
|
||||
{
|
||||
label: 'LangSmith',
|
||||
name: 'langSmith',
|
||||
icon: langsmithPNG,
|
||||
url: 'https://smith.langchain.com',
|
||||
inputs: [
|
||||
{
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['langsmithApi']
|
||||
},
|
||||
{
|
||||
label: 'Project Name',
|
||||
name: 'projectName',
|
||||
type: 'string',
|
||||
optional: true,
|
||||
description: 'If not provided, default will be used',
|
||||
placeholder: 'default'
|
||||
},
|
||||
{
|
||||
label: 'On/Off',
|
||||
name: 'status',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'LangFuse',
|
||||
name: 'langFuse',
|
||||
icon: langfuseSVG,
|
||||
url: 'https://langfuse.com',
|
||||
inputs: [
|
||||
{
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['langfuseApi']
|
||||
},
|
||||
{
|
||||
label: 'Release',
|
||||
name: 'release',
|
||||
type: 'string',
|
||||
optional: true,
|
||||
description: 'The release number/hash of the application to provide analytics grouped by release'
|
||||
},
|
||||
{
|
||||
label: 'On/Off',
|
||||
name: 'status',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Lunary',
|
||||
name: 'lunary',
|
||||
icon: lunarySVG,
|
||||
url: 'https://lunary.ai',
|
||||
inputs: [
|
||||
{
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['lunaryApi']
|
||||
},
|
||||
{
|
||||
label: 'On/Off',
|
||||
name: 'status',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const AnalyseFlow = ({ dialogProps, onCancel }) => {
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useNotifier()
|
||||
|
||||
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
|
||||
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
|
||||
|
||||
const [analytic, setAnalytic] = useState({})
|
||||
const [providerExpanded, setProviderExpanded] = useState({})
|
||||
|
||||
const onSave = async () => {
|
||||
try {
|
||||
const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, {
|
||||
analytic: JSON.stringify(analytic)
|
||||
})
|
||||
if (saveResp.data) {
|
||||
enqueueSnackbar({
|
||||
message: 'Analytic Configuration Saved',
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'success',
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data })
|
||||
}
|
||||
onCancel()
|
||||
} catch (error) {
|
||||
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
|
||||
enqueueSnackbar({
|
||||
message: `Failed to save Analytic Configuration: ${errorData}`,
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'error',
|
||||
persist: true,
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const setValue = (value, providerName, inputParamName) => {
|
||||
let newVal = {}
|
||||
if (!Object.prototype.hasOwnProperty.call(analytic, providerName)) {
|
||||
newVal = { ...analytic, [providerName]: {} }
|
||||
} else {
|
||||
newVal = { ...analytic }
|
||||
}
|
||||
|
||||
newVal[providerName][inputParamName] = value
|
||||
setAnalytic(newVal)
|
||||
}
|
||||
|
||||
const handleAccordionChange = (providerName) => (event, isExpanded) => {
|
||||
const accordianProviders = { ...providerExpanded }
|
||||
accordianProviders[providerName] = isExpanded
|
||||
setProviderExpanded(accordianProviders)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (dialogProps.chatflow && dialogProps.chatflow.analytic) {
|
||||
try {
|
||||
setAnalytic(JSON.parse(dialogProps.chatflow.analytic))
|
||||
} catch (e) {
|
||||
setAnalytic({})
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
setAnalytic({})
|
||||
setProviderExpanded({})
|
||||
}
|
||||
}, [dialogProps])
|
||||
|
||||
return (
|
||||
<>
|
||||
{analyticProviders.map((provider, index) => (
|
||||
<Accordion
|
||||
expanded={providerExpanded[provider.name] || false}
|
||||
onChange={handleAccordionChange(provider.name)}
|
||||
disableGutters
|
||||
key={index}
|
||||
>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls={provider.name} id={provider.name}>
|
||||
<ListItem style={{ padding: 0, margin: 0 }} alignItems='center'>
|
||||
<ListItemAvatar>
|
||||
<div
|
||||
style={{
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'white'
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
padding: 10,
|
||||
objectFit: 'contain'
|
||||
}}
|
||||
alt='AI'
|
||||
src={provider.icon}
|
||||
/>
|
||||
</div>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
sx={{ ml: 1 }}
|
||||
primary={provider.label}
|
||||
secondary={
|
||||
<a target='_blank' rel='noreferrer' href={provider.url}>
|
||||
{provider.url}
|
||||
</a>
|
||||
}
|
||||
/>
|
||||
{analytic[provider.name] && analytic[provider.name].status && (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignContent: 'center',
|
||||
alignItems: 'center',
|
||||
background: '#d8f3dc',
|
||||
borderRadius: 15,
|
||||
padding: 5,
|
||||
paddingLeft: 7,
|
||||
paddingRight: 7,
|
||||
marginRight: 10
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: 15,
|
||||
height: 15,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#70e000'
|
||||
}}
|
||||
/>
|
||||
<span style={{ color: '#006400', marginLeft: 10 }}>ON</span>
|
||||
</div>
|
||||
)}
|
||||
</ListItem>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
{provider.inputs.map((inputParam, index) => (
|
||||
<Box key={index} sx={{ p: 2 }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Typography>
|
||||
{inputParam.label}
|
||||
{!inputParam.optional && <span style={{ color: 'red' }}> *</span>}
|
||||
{inputParam.description && (
|
||||
<TooltipWithParser style={{ marginLeft: 10 }} title={inputParam.description} />
|
||||
)}
|
||||
</Typography>
|
||||
</div>
|
||||
{providerExpanded[provider.name] && inputParam.type === 'credential' && (
|
||||
<CredentialInputHandler
|
||||
data={analytic[provider.name] ? { credential: analytic[provider.name].credentialId } : {}}
|
||||
inputParam={inputParam}
|
||||
onSelect={(newValue) => setValue(newValue, provider.name, 'credentialId')}
|
||||
/>
|
||||
)}
|
||||
{providerExpanded[provider.name] && inputParam.type === 'boolean' && (
|
||||
<SwitchInput
|
||||
onChange={(newValue) => setValue(newValue, provider.name, inputParam.name)}
|
||||
value={
|
||||
analytic[provider.name] ? analytic[provider.name][inputParam.name] : inputParam.default ?? false
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{providerExpanded[provider.name] &&
|
||||
(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && (
|
||||
<Input
|
||||
inputParam={inputParam}
|
||||
onChange={(newValue) => setValue(newValue, provider.name, inputParam.name)}
|
||||
value={
|
||||
analytic[provider.name]
|
||||
? analytic[provider.name][inputParam.name]
|
||||
: inputParam.default ?? ''
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
))}
|
||||
<StyledButton style={{ marginBottom: 10, marginTop: 10 }} variant='contained' onClick={onSave}>
|
||||
Save
|
||||
</StyledButton>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
AnalyseFlow.propTypes = {
|
||||
show: PropTypes.bool,
|
||||
dialogProps: PropTypes.object,
|
||||
onCancel: PropTypes.func
|
||||
}
|
||||
|
||||
export default AnalyseFlow
|
||||
|
|
@ -1,358 +0,0 @@
|
|||
import { createPortal } from 'react-dom'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { useState, useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions'
|
||||
|
||||
// material-ui
|
||||
import {
|
||||
Typography,
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
DialogActions,
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
AccordionDetails,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText
|
||||
} from '@mui/material'
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
|
||||
import { IconX } from '@tabler/icons'
|
||||
|
||||
// Project import
|
||||
import CredentialInputHandler from 'views/canvas/CredentialInputHandler'
|
||||
import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser'
|
||||
import { SwitchInput } from 'ui-component/switch/Switch'
|
||||
import { Input } from 'ui-component/input/Input'
|
||||
import { StyledButton } from 'ui-component/button/StyledButton'
|
||||
import langsmithPNG from 'assets/images/langchain.png'
|
||||
import langfuseSVG from 'assets/images/langfuse.svg'
|
||||
import lunarySVG from 'assets/images/lunary.svg'
|
||||
|
||||
// store
|
||||
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
||||
import useNotifier from 'utils/useNotifier'
|
||||
|
||||
// API
|
||||
import chatflowsApi from 'api/chatflows'
|
||||
|
||||
const analyticProviders = [
|
||||
{
|
||||
label: 'LangSmith',
|
||||
name: 'langSmith',
|
||||
icon: langsmithPNG,
|
||||
url: 'https://smith.langchain.com',
|
||||
inputs: [
|
||||
{
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['langsmithApi']
|
||||
},
|
||||
{
|
||||
label: 'Project Name',
|
||||
name: 'projectName',
|
||||
type: 'string',
|
||||
optional: true,
|
||||
description: 'If not provided, default will be used',
|
||||
placeholder: 'default'
|
||||
},
|
||||
{
|
||||
label: 'On/Off',
|
||||
name: 'status',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'LangFuse',
|
||||
name: 'langFuse',
|
||||
icon: langfuseSVG,
|
||||
url: 'https://langfuse.com',
|
||||
inputs: [
|
||||
{
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['langfuseApi']
|
||||
},
|
||||
{
|
||||
label: 'Release',
|
||||
name: 'release',
|
||||
type: 'string',
|
||||
optional: true,
|
||||
description: 'The release number/hash of the application to provide analytics grouped by release'
|
||||
},
|
||||
{
|
||||
label: 'On/Off',
|
||||
name: 'status',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Lunary',
|
||||
name: 'lunary',
|
||||
icon: lunarySVG,
|
||||
url: 'https://lunary.ai',
|
||||
inputs: [
|
||||
{
|
||||
label: 'Connect Credential',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['lunaryApi']
|
||||
},
|
||||
{
|
||||
label: 'On/Off',
|
||||
name: 'status',
|
||||
type: 'boolean',
|
||||
optional: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const AnalyseFlowDialog = ({ show, dialogProps, onCancel }) => {
|
||||
const portalElement = document.getElementById('portal')
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useNotifier()
|
||||
|
||||
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
|
||||
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
|
||||
|
||||
const [analytic, setAnalytic] = useState({})
|
||||
const [providerExpanded, setProviderExpanded] = useState({})
|
||||
|
||||
const onSave = async () => {
|
||||
try {
|
||||
const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, {
|
||||
analytic: JSON.stringify(analytic)
|
||||
})
|
||||
if (saveResp.data) {
|
||||
enqueueSnackbar({
|
||||
message: 'Analytic Configuration Saved',
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'success',
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data })
|
||||
}
|
||||
onCancel()
|
||||
} catch (error) {
|
||||
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
|
||||
enqueueSnackbar({
|
||||
message: `Failed to save Analytic Configuration: ${errorData}`,
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'error',
|
||||
persist: true,
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const setValue = (value, providerName, inputParamName) => {
|
||||
let newVal = {}
|
||||
if (!Object.prototype.hasOwnProperty.call(analytic, providerName)) {
|
||||
newVal = { ...analytic, [providerName]: {} }
|
||||
} else {
|
||||
newVal = { ...analytic }
|
||||
}
|
||||
|
||||
newVal[providerName][inputParamName] = value
|
||||
setAnalytic(newVal)
|
||||
}
|
||||
|
||||
const handleAccordionChange = (providerName) => (event, isExpanded) => {
|
||||
const accordianProviders = { ...providerExpanded }
|
||||
accordianProviders[providerName] = isExpanded
|
||||
setProviderExpanded(accordianProviders)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (dialogProps.chatflow && dialogProps.chatflow.analytic) {
|
||||
try {
|
||||
setAnalytic(JSON.parse(dialogProps.chatflow.analytic))
|
||||
} catch (e) {
|
||||
setAnalytic({})
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
setAnalytic({})
|
||||
setProviderExpanded({})
|
||||
}
|
||||
}, [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='sm'
|
||||
aria-labelledby='alert-dialog-title'
|
||||
aria-describedby='alert-dialog-description'
|
||||
>
|
||||
<DialogTitle sx={{ fontSize: '1rem' }} id='alert-dialog-title'>
|
||||
Analyse Chatflow
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
{analyticProviders.map((provider, index) => (
|
||||
<Accordion
|
||||
expanded={providerExpanded[provider.name] || false}
|
||||
onChange={handleAccordionChange(provider.name)}
|
||||
disableGutters
|
||||
key={index}
|
||||
>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls={provider.name} id={provider.name}>
|
||||
<ListItem style={{ padding: 0, margin: 0 }} alignItems='center'>
|
||||
<ListItemAvatar>
|
||||
<div
|
||||
style={{
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'white'
|
||||
}}
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
padding: 10,
|
||||
objectFit: 'contain'
|
||||
}}
|
||||
alt='AI'
|
||||
src={provider.icon}
|
||||
/>
|
||||
</div>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
sx={{ ml: 1 }}
|
||||
primary={provider.label}
|
||||
secondary={
|
||||
<a target='_blank' rel='noreferrer' href={provider.url}>
|
||||
{provider.url}
|
||||
</a>
|
||||
}
|
||||
/>
|
||||
{analytic[provider.name] && analytic[provider.name].status && (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignContent: 'center',
|
||||
alignItems: 'center',
|
||||
background: '#d8f3dc',
|
||||
borderRadius: 15,
|
||||
padding: 5,
|
||||
paddingLeft: 7,
|
||||
paddingRight: 7,
|
||||
marginRight: 10
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: 15,
|
||||
height: 15,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#70e000'
|
||||
}}
|
||||
/>
|
||||
<span style={{ color: '#006400', marginLeft: 10 }}>ON</span>
|
||||
</div>
|
||||
)}
|
||||
</ListItem>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
{provider.inputs.map((inputParam, index) => (
|
||||
<Box key={index} sx={{ p: 2 }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<Typography>
|
||||
{inputParam.label}
|
||||
{!inputParam.optional && <span style={{ color: 'red' }}> *</span>}
|
||||
{inputParam.description && (
|
||||
<TooltipWithParser style={{ marginLeft: 10 }} title={inputParam.description} />
|
||||
)}
|
||||
</Typography>
|
||||
</div>
|
||||
{providerExpanded[provider.name] && inputParam.type === 'credential' && (
|
||||
<CredentialInputHandler
|
||||
data={analytic[provider.name] ? { credential: analytic[provider.name].credentialId } : {}}
|
||||
inputParam={inputParam}
|
||||
onSelect={(newValue) => setValue(newValue, provider.name, 'credentialId')}
|
||||
/>
|
||||
)}
|
||||
{providerExpanded[provider.name] && inputParam.type === 'boolean' && (
|
||||
<SwitchInput
|
||||
onChange={(newValue) => setValue(newValue, provider.name, inputParam.name)}
|
||||
value={
|
||||
analytic[provider.name]
|
||||
? analytic[provider.name][inputParam.name]
|
||||
: inputParam.default ?? false
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{providerExpanded[provider.name] &&
|
||||
(inputParam.type === 'string' ||
|
||||
inputParam.type === 'password' ||
|
||||
inputParam.type === 'number') && (
|
||||
<Input
|
||||
inputParam={inputParam}
|
||||
onChange={(newValue) => setValue(newValue, provider.name, inputParam.name)}
|
||||
value={
|
||||
analytic[provider.name]
|
||||
? analytic[provider.name][inputParam.name]
|
||||
: inputParam.default ?? ''
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
))}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<StyledButton variant='contained' onClick={onSave}>
|
||||
Save
|
||||
</StyledButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
) : null
|
||||
|
||||
return createPortal(component, portalElement)
|
||||
}
|
||||
|
||||
AnalyseFlowDialog.propTypes = {
|
||||
show: PropTypes.bool,
|
||||
dialogProps: PropTypes.object,
|
||||
onCancel: PropTypes.func
|
||||
}
|
||||
|
||||
export default AnalyseFlowDialog
|
||||
|
|
@ -93,7 +93,7 @@ const ChatFeedback = ({ dialogProps }) => {
|
|||
<Box sx={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
||||
<SwitchInput label='Enable chat feedback' onChange={handleChange} value={chatFeedbackStatus} />
|
||||
</Box>
|
||||
<StyledButton variant='contained' onClick={onSave}>
|
||||
<StyledButton style={{ marginBottom: 10, marginTop: 10 }} variant='contained' onClick={onSave}>
|
||||
Save
|
||||
</StyledButton>
|
||||
</>
|
||||
|
|
@ -2,16 +2,22 @@ import PropTypes from 'prop-types'
|
|||
import { useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import { Box, Dialog, DialogContent, DialogTitle, Tabs, Tab } from '@mui/material'
|
||||
import SpeechToText from './SpeechToTextDialog'
|
||||
import SpeechToText from './SpeechToText'
|
||||
import Configuration from 'views/chatflows/Configuration'
|
||||
import AllowedDomains from './AllowedDomainsDialog'
|
||||
import ChatFeedback from './ChatFeedbackDialog'
|
||||
import AllowedDomains from './AllowedDomains'
|
||||
import ChatFeedback from './ChatFeedback'
|
||||
import AnalyseFlow from './AnalyseFlow'
|
||||
import StarterPrompts from './StarterPrompts'
|
||||
|
||||
const CHATFLOW_CONFIGURATION_TABS = [
|
||||
{
|
||||
label: 'Rate Limiting',
|
||||
id: 'rateLimiting'
|
||||
},
|
||||
{
|
||||
label: 'Starter Prompts',
|
||||
id: 'conversationStarters'
|
||||
},
|
||||
{
|
||||
label: 'Speech to Text',
|
||||
id: 'speechToText'
|
||||
|
|
@ -23,6 +29,10 @@ const CHATFLOW_CONFIGURATION_TABS = [
|
|||
{
|
||||
label: 'Allowed Domains',
|
||||
id: 'allowedDomains'
|
||||
},
|
||||
{
|
||||
label: 'Analyse Chatflow',
|
||||
id: 'analyseChatflow'
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -34,7 +44,7 @@ function TabPanel(props) {
|
|||
hidden={value !== index}
|
||||
id={`chatflow-config-tabpanel-${index}`}
|
||||
aria-labelledby={`chatflow-config-tab-${index}`}
|
||||
style={{ paddingTop: '1rem' }}
|
||||
style={{ width: '100%', paddingTop: '1rem' }}
|
||||
{...other}
|
||||
>
|
||||
{value === index && <Box sx={{ p: 1 }}>{children}</Box>}
|
||||
|
|
@ -73,22 +83,28 @@ const ChatflowConfigurationDialog = ({ show, dialogProps, onCancel }) => {
|
|||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Tabs
|
||||
sx={{ position: 'relative', minHeight: '50px', height: '50px' }}
|
||||
variant='fullWidth'
|
||||
sx={{ position: 'relative', minHeight: '40px', height: '40px' }}
|
||||
value={tabValue}
|
||||
onChange={(event, value) => setTabValue(value)}
|
||||
aria-label='tabs'
|
||||
>
|
||||
{CHATFLOW_CONFIGURATION_TABS.map((item, index) => (
|
||||
<Tab sx={{ minHeight: '50px', height: '50px' }} key={index} label={item.label} {...a11yProps(index)}></Tab>
|
||||
<Tab
|
||||
sx={{ minHeight: '40px', height: '40px', textAlign: 'left', display: 'flex', alignItems: 'start', mb: 1 }}
|
||||
key={index}
|
||||
label={item.label}
|
||||
{...a11yProps(index)}
|
||||
></Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
{CHATFLOW_CONFIGURATION_TABS.map((item, index) => (
|
||||
<TabPanel key={index} value={tabValue} index={index}>
|
||||
{item.id === 'rateLimiting' && <Configuration />}
|
||||
{item.id === 'conversationStarters' ? <StarterPrompts dialogProps={dialogProps} /> : null}
|
||||
{item.id === 'speechToText' ? <SpeechToText dialogProps={dialogProps} /> : null}
|
||||
{item.id === 'chatFeedback' ? <ChatFeedback dialogProps={dialogProps} /> : null}
|
||||
{item.id === 'allowedDomains' ? <AllowedDomains dialogProps={dialogProps} /> : null}
|
||||
{item.id === 'analyseChatflow' ? <AnalyseFlow dialogProps={dialogProps} /> : null}
|
||||
</TabPanel>
|
||||
))}
|
||||
</DialogContent>
|
||||
|
|
|
|||
|
|
@ -183,8 +183,10 @@ const SpeechToText = ({ dialogProps }) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Box fullWidth sx={{ my: 2, display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
<Typography>Speech To Text Providers</Typography>
|
||||
<Box fullWidth sx={{ mb: 1, display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
<Typography variant='h4' sx={{ mb: 1 }}>
|
||||
Providers
|
||||
</Typography>
|
||||
<FormControl fullWidth>
|
||||
<Select value={selectedProvider} onChange={handleProviderChange}>
|
||||
<MenuItem value='none'>None</MenuItem>
|
||||
|
|
@ -289,6 +291,7 @@ const SpeechToText = ({ dialogProps }) => {
|
|||
</>
|
||||
)}
|
||||
<StyledButton
|
||||
style={{ marginBottom: 10, marginTop: 10 }}
|
||||
disabled={selectedProvider !== 'none' && !speechToText[selectedProvider]?.credentialId}
|
||||
variant='contained'
|
||||
onClick={onSave}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
import { useDispatch } from 'react-redux'
|
||||
import { useState, useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions'
|
||||
|
||||
// material-ui
|
||||
import { Button, IconButton, OutlinedInput, Box, List, InputAdornment } from '@mui/material'
|
||||
import { IconX, IconTrash, IconPlus, IconBulb } from '@tabler/icons'
|
||||
|
||||
// Project import
|
||||
import { StyledButton } from 'ui-component/button/StyledButton'
|
||||
|
||||
// store
|
||||
import useNotifier from 'utils/useNotifier'
|
||||
|
||||
// API
|
||||
import chatflowsApi from 'api/chatflows'
|
||||
|
||||
const StarterPrompts = ({ dialogProps, onConfirm }) => {
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useNotifier()
|
||||
|
||||
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
|
||||
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
|
||||
|
||||
const [inputFields, setInputFields] = useState([
|
||||
{
|
||||
prompt: ''
|
||||
}
|
||||
])
|
||||
|
||||
const [chatbotConfig, setChatbotConfig] = useState({})
|
||||
|
||||
const addInputField = () => {
|
||||
setInputFields([
|
||||
...inputFields,
|
||||
{
|
||||
prompt: ''
|
||||
}
|
||||
])
|
||||
}
|
||||
const removeInputFields = (index) => {
|
||||
const rows = [...inputFields]
|
||||
rows.splice(index, 1)
|
||||
setInputFields(rows)
|
||||
}
|
||||
|
||||
const handleChange = (index, evnt) => {
|
||||
const { name, value } = evnt.target
|
||||
const list = [...inputFields]
|
||||
list[index][name] = value
|
||||
setInputFields(list)
|
||||
}
|
||||
|
||||
const onSave = async () => {
|
||||
try {
|
||||
let value = {
|
||||
starterPrompts: {
|
||||
...inputFields
|
||||
}
|
||||
}
|
||||
chatbotConfig.starterPrompts = value.starterPrompts
|
||||
const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, {
|
||||
chatbotConfig: JSON.stringify(chatbotConfig)
|
||||
})
|
||||
if (saveResp.data) {
|
||||
enqueueSnackbar({
|
||||
message: 'Conversation Starter Prompts Saved',
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'success',
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data })
|
||||
}
|
||||
onConfirm()
|
||||
} catch (error) {
|
||||
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
|
||||
enqueueSnackbar({
|
||||
message: `Failed to save Conversation Starter Prompts: ${errorData}`,
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'error',
|
||||
persist: true,
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (dialogProps.chatflow && dialogProps.chatflow.chatbotConfig) {
|
||||
try {
|
||||
let chatbotConfig = JSON.parse(dialogProps.chatflow.chatbotConfig)
|
||||
setChatbotConfig(chatbotConfig || {})
|
||||
if (chatbotConfig.starterPrompts) {
|
||||
let inputFields = []
|
||||
Object.getOwnPropertyNames(chatbotConfig.starterPrompts).forEach((key) => {
|
||||
if (chatbotConfig.starterPrompts[key]) {
|
||||
inputFields.push(chatbotConfig.starterPrompts[key])
|
||||
}
|
||||
})
|
||||
setInputFields(inputFields)
|
||||
} else {
|
||||
setInputFields([
|
||||
{
|
||||
prompt: ''
|
||||
}
|
||||
])
|
||||
}
|
||||
} catch (e) {
|
||||
setInputFields([
|
||||
{
|
||||
prompt: ''
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
return () => {}
|
||||
}, [dialogProps])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
borderRadius: 10,
|
||||
background: '#d8f3dc',
|
||||
padding: 10
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<IconBulb size={30} color='#2d6a4f' />
|
||||
<span style={{ color: '#2d6a4f', marginLeft: 10, fontWeight: 500 }}>
|
||||
Starter prompts will only be shown when there is no messages on the chat
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Box sx={{ '& > :not(style)': { m: 1 }, pt: 2 }}>
|
||||
<List>
|
||||
{inputFields.map((data, index) => {
|
||||
return (
|
||||
<div key={index} style={{ display: 'flex', width: '100%' }}>
|
||||
<Box sx={{ width: '95%', mb: 1 }}>
|
||||
<OutlinedInput
|
||||
sx={{ width: '100%' }}
|
||||
key={index}
|
||||
type='text'
|
||||
onChange={(e) => handleChange(index, e)}
|
||||
size='small'
|
||||
value={data.prompt}
|
||||
name='prompt'
|
||||
endAdornment={
|
||||
<InputAdornment position='end' sx={{ padding: '2px' }}>
|
||||
{inputFields.length > 1 && (
|
||||
<IconButton
|
||||
sx={{ height: 30, width: 30 }}
|
||||
size='small'
|
||||
color='error'
|
||||
disabled={inputFields.length === 1}
|
||||
onClick={() => removeInputFields(index)}
|
||||
edge='end'
|
||||
>
|
||||
<IconTrash />
|
||||
</IconButton>
|
||||
)}
|
||||
</InputAdornment>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ width: '5%', mb: 1 }}>
|
||||
{index === inputFields.length - 1 && (
|
||||
<IconButton color='primary' onClick={addInputField}>
|
||||
<IconPlus />
|
||||
</IconButton>
|
||||
)}
|
||||
</Box>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Box>
|
||||
<StyledButton variant='contained' onClick={onSave}>
|
||||
Save
|
||||
</StyledButton>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
StarterPrompts.propTypes = {
|
||||
show: PropTypes.bool,
|
||||
dialogProps: PropTypes.object,
|
||||
onCancel: PropTypes.func,
|
||||
onConfirm: PropTypes.func
|
||||
}
|
||||
|
||||
export default StarterPrompts
|
||||
|
|
@ -1,149 +1,24 @@
|
|||
import { createPortal } from 'react-dom'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions'
|
||||
|
||||
// material-ui
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
OutlinedInput,
|
||||
DialogTitle,
|
||||
DialogActions,
|
||||
Box,
|
||||
List,
|
||||
InputAdornment
|
||||
} from '@mui/material'
|
||||
import { IconX, IconTrash, IconPlus, IconBulb } from '@tabler/icons'
|
||||
|
||||
// Project import
|
||||
import { StyledButton } from 'ui-component/button/StyledButton'
|
||||
import { Dialog, DialogContent, DialogTitle } from '@mui/material'
|
||||
|
||||
// store
|
||||
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
||||
import useNotifier from 'utils/useNotifier'
|
||||
|
||||
// API
|
||||
import chatflowsApi from 'api/chatflows'
|
||||
// Project imports
|
||||
import StarterPrompts from './StarterPrompts'
|
||||
|
||||
const StarterPromptsDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
||||
const StarterPromptsDialog = ({ show, dialogProps, onCancel }) => {
|
||||
const portalElement = document.getElementById('portal')
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useNotifier()
|
||||
|
||||
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
|
||||
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
|
||||
|
||||
const [inputFields, setInputFields] = useState([
|
||||
{
|
||||
prompt: ''
|
||||
}
|
||||
])
|
||||
|
||||
const [chatbotConfig, setChatbotConfig] = useState({})
|
||||
|
||||
const addInputField = () => {
|
||||
setInputFields([
|
||||
...inputFields,
|
||||
{
|
||||
prompt: ''
|
||||
}
|
||||
])
|
||||
}
|
||||
const removeInputFields = (index) => {
|
||||
const rows = [...inputFields]
|
||||
rows.splice(index, 1)
|
||||
setInputFields(rows)
|
||||
}
|
||||
|
||||
const handleChange = (index, evnt) => {
|
||||
const { name, value } = evnt.target
|
||||
const list = [...inputFields]
|
||||
list[index][name] = value
|
||||
setInputFields(list)
|
||||
}
|
||||
|
||||
const onSave = async () => {
|
||||
try {
|
||||
let value = {
|
||||
starterPrompts: {
|
||||
...inputFields
|
||||
}
|
||||
}
|
||||
chatbotConfig.starterPrompts = value.starterPrompts
|
||||
const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, {
|
||||
chatbotConfig: JSON.stringify(chatbotConfig)
|
||||
})
|
||||
if (saveResp.data) {
|
||||
enqueueSnackbar({
|
||||
message: 'Conversation Starter Prompts Saved',
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'success',
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data })
|
||||
}
|
||||
onConfirm()
|
||||
} catch (error) {
|
||||
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
|
||||
enqueueSnackbar({
|
||||
message: `Failed to save Conversation Starter Prompts: ${errorData}`,
|
||||
options: {
|
||||
key: new Date().getTime() + Math.random(),
|
||||
variant: 'error',
|
||||
persist: true,
|
||||
action: (key) => (
|
||||
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
||||
<IconX />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (dialogProps.chatflow && dialogProps.chatflow.chatbotConfig) {
|
||||
try {
|
||||
let chatbotConfig = JSON.parse(dialogProps.chatflow.chatbotConfig)
|
||||
setChatbotConfig(chatbotConfig || {})
|
||||
if (chatbotConfig.starterPrompts) {
|
||||
let inputFields = []
|
||||
Object.getOwnPropertyNames(chatbotConfig.starterPrompts).forEach((key) => {
|
||||
if (chatbotConfig.starterPrompts[key]) {
|
||||
inputFields.push(chatbotConfig.starterPrompts[key])
|
||||
}
|
||||
})
|
||||
setInputFields(inputFields)
|
||||
} else {
|
||||
setInputFields([
|
||||
{
|
||||
prompt: ''
|
||||
}
|
||||
])
|
||||
}
|
||||
} catch (e) {
|
||||
setInputFields([
|
||||
{
|
||||
prompt: ''
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
return () => {}
|
||||
}, [dialogProps])
|
||||
|
||||
useEffect(() => {
|
||||
if (show) dispatch({ type: SHOW_CANVAS_DIALOG })
|
||||
else dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||
|
|
@ -163,79 +38,8 @@ const StarterPromptsDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
|||
{dialogProps.title || 'Conversation Starter Prompts'}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
borderRadius: 10,
|
||||
background: '#d8f3dc',
|
||||
padding: 10
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<IconBulb size={30} color='#2d6a4f' />
|
||||
<span style={{ color: '#2d6a4f', marginLeft: 10, fontWeight: 500 }}>
|
||||
Starter prompts will only be shown when there is no messages on the chat
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Box sx={{ '& > :not(style)': { m: 1 }, pt: 2 }}>
|
||||
<List>
|
||||
{inputFields.map((data, index) => {
|
||||
return (
|
||||
<div key={index} style={{ display: 'flex', width: '100%' }}>
|
||||
<Box sx={{ width: '95%', mb: 1 }}>
|
||||
<OutlinedInput
|
||||
sx={{ width: '100%' }}
|
||||
key={index}
|
||||
type='text'
|
||||
onChange={(e) => handleChange(index, e)}
|
||||
size='small'
|
||||
value={data.prompt}
|
||||
name='prompt'
|
||||
endAdornment={
|
||||
<InputAdornment position='end' sx={{ padding: '2px' }}>
|
||||
{inputFields.length > 1 && (
|
||||
<IconButton
|
||||
sx={{ height: 30, width: 30 }}
|
||||
size='small'
|
||||
color='error'
|
||||
disabled={inputFields.length === 1}
|
||||
onClick={() => removeInputFields(index)}
|
||||
edge='end'
|
||||
>
|
||||
<IconTrash />
|
||||
</IconButton>
|
||||
)}
|
||||
</InputAdornment>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ width: '5%', mb: 1 }}>
|
||||
{index === inputFields.length - 1 && (
|
||||
<IconButton color='primary' onClick={addInputField}>
|
||||
<IconPlus />
|
||||
</IconButton>
|
||||
)}
|
||||
</Box>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</Box>
|
||||
<StarterPrompts dialogProps={dialogProps} />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onCancel}>Cancel</Button>
|
||||
<StyledButton variant='contained' onClick={onSave}>
|
||||
Save
|
||||
</StyledButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
) : null
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ import { IconSettings, IconChevronLeft, IconDeviceFloppy, IconPencil, IconCheck,
|
|||
import Settings from 'views/settings'
|
||||
import SaveChatflowDialog from 'ui-component/dialog/SaveChatflowDialog'
|
||||
import APICodeDialog from 'views/chatflows/APICodeDialog'
|
||||
import AnalyseFlowDialog from 'ui-component/dialog/AnalyseFlowDialog'
|
||||
import ViewMessagesDialog from 'ui-component/dialog/ViewMessagesDialog'
|
||||
import StarterPromptsDialog from 'ui-component/dialog/StarterPromptsDialog'
|
||||
|
||||
// API
|
||||
import chatflowsApi from 'api/chatflows'
|
||||
|
|
@ -45,10 +43,6 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
|
|||
const [flowDialogOpen, setFlowDialogOpen] = useState(false)
|
||||
const [apiDialogOpen, setAPIDialogOpen] = useState(false)
|
||||
const [apiDialogProps, setAPIDialogProps] = useState({})
|
||||
const [analyseDialogOpen, setAnalyseDialogOpen] = useState(false)
|
||||
const [analyseDialogProps, setAnalyseDialogProps] = useState({})
|
||||
const [conversationStartersDialogOpen, setConversationStartersDialogOpen] = useState(false)
|
||||
const [conversationStartersDialogProps, setConversationStartersDialogProps] = useState({})
|
||||
const [viewMessagesDialogOpen, setViewMessagesDialogOpen] = useState(false)
|
||||
const [viewMessagesDialogProps, setViewMessagesDialogProps] = useState({})
|
||||
const [chatflowConfigurationDialogOpen, setChatflowConfigurationDialogOpen] = useState(false)
|
||||
|
|
@ -62,18 +56,6 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
|
|||
|
||||
if (setting === 'deleteChatflow') {
|
||||
handleDeleteFlow()
|
||||
} else if (setting === 'conversationStarters') {
|
||||
setConversationStartersDialogProps({
|
||||
title: 'Starter Prompts - ' + chatflow.name,
|
||||
chatflow: chatflow
|
||||
})
|
||||
setConversationStartersDialogOpen(true)
|
||||
} else if (setting === 'analyseChatflow') {
|
||||
setAnalyseDialogProps({
|
||||
title: 'Analyse Chatflow',
|
||||
chatflow: chatflow
|
||||
})
|
||||
setAnalyseDialogOpen(true)
|
||||
} else if (setting === 'viewMessages') {
|
||||
setViewMessagesDialogProps({
|
||||
title: 'View Messages',
|
||||
|
|
@ -393,13 +375,6 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
|
|||
onConfirm={onConfirmSaveName}
|
||||
/>
|
||||
<APICodeDialog show={apiDialogOpen} dialogProps={apiDialogProps} onCancel={() => setAPIDialogOpen(false)} />
|
||||
<AnalyseFlowDialog show={analyseDialogOpen} dialogProps={analyseDialogProps} onCancel={() => setAnalyseDialogOpen(false)} />
|
||||
<StarterPromptsDialog
|
||||
show={conversationStartersDialogOpen}
|
||||
dialogProps={conversationStartersDialogProps}
|
||||
onConfirm={() => setConversationStartersDialogOpen(false)}
|
||||
onCancel={() => setConversationStartersDialogOpen(false)}
|
||||
/>
|
||||
<ViewMessagesDialog
|
||||
show={viewMessagesDialogOpen}
|
||||
dialogProps={viewMessagesDialogProps}
|
||||
|
|
|
|||
Loading…
Reference in New Issue