mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 13:00:56 +03:00
f4647044bd
ability to hide/show agent messages for share chatbot
538 lines
22 KiB
React
538 lines
22 KiB
React
import { useState } from 'react'
|
|
import { useDispatch, useSelector } from 'react-redux'
|
|
import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from '@/store/actions'
|
|
import { SketchPicker } from 'react-color'
|
|
import PropTypes from 'prop-types'
|
|
|
|
import { Box, Typography, Button, Switch, OutlinedInput, Popover, Stack, IconButton } from '@mui/material'
|
|
import { useTheme } from '@mui/material/styles'
|
|
|
|
// Project import
|
|
import { StyledButton } from '@/ui-component/button/StyledButton'
|
|
import { TooltipWithParser } from '@/ui-component/tooltip/TooltipWithParser'
|
|
|
|
// Icons
|
|
import { IconX, IconCopy, IconArrowUpRightCircle } from '@tabler/icons-react'
|
|
|
|
// API
|
|
import chatflowsApi from '@/api/chatflows'
|
|
|
|
// utils
|
|
import useNotifier from '@/utils/useNotifier'
|
|
|
|
// Const
|
|
import { baseURL } from '@/store/constant'
|
|
|
|
const defaultConfig = {
|
|
backgroundColor: '#ffffff',
|
|
fontSize: 16,
|
|
poweredByTextColor: '#303235',
|
|
botMessage: {
|
|
backgroundColor: '#f7f8ff',
|
|
textColor: '#303235'
|
|
},
|
|
userMessage: {
|
|
backgroundColor: '#3B81F6',
|
|
textColor: '#ffffff'
|
|
},
|
|
textInput: {
|
|
backgroundColor: '#ffffff',
|
|
textColor: '#303235',
|
|
sendButtonColor: '#3B81F6'
|
|
}
|
|
}
|
|
|
|
const ShareChatbot = ({ isSessionMemory, isAgentCanvas }) => {
|
|
const dispatch = useDispatch()
|
|
const theme = useTheme()
|
|
const chatflow = useSelector((state) => state.canvas.chatflow)
|
|
const chatflowid = chatflow.id
|
|
const chatbotConfig = chatflow.chatbotConfig ? JSON.parse(chatflow.chatbotConfig) : {}
|
|
|
|
useNotifier()
|
|
|
|
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
|
|
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
|
|
|
|
const [isPublicChatflow, setChatflowIsPublic] = useState(chatflow.isPublic ?? false)
|
|
const [generateNewSession, setGenerateNewSession] = useState(chatbotConfig?.generateNewSession ?? false)
|
|
|
|
const [title, setTitle] = useState(chatbotConfig?.title ?? '')
|
|
const [titleAvatarSrc, setTitleAvatarSrc] = useState(chatbotConfig?.titleAvatarSrc ?? '')
|
|
|
|
const [welcomeMessage, setWelcomeMessage] = useState(chatbotConfig?.welcomeMessage ?? '')
|
|
const [errorMessage, setErrorMessage] = useState(chatbotConfig?.errorMessage ?? '')
|
|
const [backgroundColor, setBackgroundColor] = useState(chatbotConfig?.backgroundColor ?? defaultConfig.backgroundColor)
|
|
const [fontSize, setFontSize] = useState(chatbotConfig?.fontSize ?? defaultConfig.fontSize)
|
|
const [poweredByTextColor, setPoweredByTextColor] = useState(chatbotConfig?.poweredByTextColor ?? defaultConfig.poweredByTextColor)
|
|
const [showAgentMessages, setShowAgentMessages] = useState(chatbotConfig?.showAgentMessages || (isAgentCanvas ? true : undefined))
|
|
|
|
const [botMessageBackgroundColor, setBotMessageBackgroundColor] = useState(
|
|
chatbotConfig?.botMessage?.backgroundColor ?? defaultConfig.botMessage.backgroundColor
|
|
)
|
|
const [botMessageTextColor, setBotMessageTextColor] = useState(
|
|
chatbotConfig?.botMessage?.textColor ?? defaultConfig.botMessage.textColor
|
|
)
|
|
const [botMessageAvatarSrc, setBotMessageAvatarSrc] = useState(chatbotConfig?.botMessage?.avatarSrc ?? '')
|
|
const [botMessageShowAvatar, setBotMessageShowAvatar] = useState(chatbotConfig?.botMessage?.showAvatar ?? false)
|
|
|
|
const [userMessageBackgroundColor, setUserMessageBackgroundColor] = useState(
|
|
chatbotConfig?.userMessage?.backgroundColor ?? defaultConfig.userMessage.backgroundColor
|
|
)
|
|
const [userMessageTextColor, setUserMessageTextColor] = useState(
|
|
chatbotConfig?.userMessage?.textColor ?? defaultConfig.userMessage.textColor
|
|
)
|
|
const [userMessageAvatarSrc, setUserMessageAvatarSrc] = useState(chatbotConfig?.userMessage?.avatarSrc ?? '')
|
|
const [userMessageShowAvatar, setUserMessageShowAvatar] = useState(chatbotConfig?.userMessage?.showAvatar ?? false)
|
|
|
|
const [textInputBackgroundColor, setTextInputBackgroundColor] = useState(
|
|
chatbotConfig?.textInput?.backgroundColor ?? defaultConfig.textInput.backgroundColor
|
|
)
|
|
const [textInputTextColor, setTextInputTextColor] = useState(chatbotConfig?.textInput?.textColor ?? defaultConfig.textInput.textColor)
|
|
const [textInputPlaceholder, setTextInputPlaceholder] = useState(chatbotConfig?.textInput?.placeholder ?? '')
|
|
const [textInputSendButtonColor, setTextInputSendButtonColor] = useState(
|
|
chatbotConfig?.textInput?.sendButtonColor ?? defaultConfig.textInput.sendButtonColor
|
|
)
|
|
|
|
const [colorAnchorEl, setColorAnchorEl] = useState(null)
|
|
const [selectedColorConfig, setSelectedColorConfig] = useState('')
|
|
const [sketchPickerColor, setSketchPickerColor] = useState('')
|
|
const openColorPopOver = Boolean(colorAnchorEl)
|
|
|
|
const [copyAnchorEl, setCopyAnchorEl] = useState(null)
|
|
const openCopyPopOver = Boolean(copyAnchorEl)
|
|
|
|
const formatObj = () => {
|
|
const obj = {
|
|
botMessage: {
|
|
showAvatar: false
|
|
},
|
|
userMessage: {
|
|
showAvatar: false
|
|
},
|
|
textInput: {},
|
|
overrideConfig: {}
|
|
}
|
|
if (title) obj.title = title
|
|
if (titleAvatarSrc) obj.titleAvatarSrc = titleAvatarSrc
|
|
if (welcomeMessage) obj.welcomeMessage = welcomeMessage
|
|
if (errorMessage) obj.errorMessage = errorMessage
|
|
if (backgroundColor) obj.backgroundColor = backgroundColor
|
|
if (fontSize) obj.fontSize = fontSize
|
|
if (poweredByTextColor) obj.poweredByTextColor = poweredByTextColor
|
|
|
|
if (botMessageBackgroundColor) obj.botMessage.backgroundColor = botMessageBackgroundColor
|
|
if (botMessageTextColor) obj.botMessage.textColor = botMessageTextColor
|
|
if (botMessageAvatarSrc) obj.botMessage.avatarSrc = botMessageAvatarSrc
|
|
if (botMessageShowAvatar) obj.botMessage.showAvatar = botMessageShowAvatar
|
|
|
|
if (userMessageBackgroundColor) obj.userMessage.backgroundColor = userMessageBackgroundColor
|
|
if (userMessageTextColor) obj.userMessage.textColor = userMessageTextColor
|
|
if (userMessageAvatarSrc) obj.userMessage.avatarSrc = userMessageAvatarSrc
|
|
if (userMessageShowAvatar) obj.userMessage.showAvatar = userMessageShowAvatar
|
|
|
|
if (textInputBackgroundColor) obj.textInput.backgroundColor = textInputBackgroundColor
|
|
if (textInputTextColor) obj.textInput.textColor = textInputTextColor
|
|
if (textInputPlaceholder) obj.textInput.placeholder = textInputPlaceholder
|
|
if (textInputSendButtonColor) obj.textInput.sendButtonColor = textInputSendButtonColor
|
|
|
|
if (isSessionMemory) obj.overrideConfig.generateNewSession = generateNewSession
|
|
|
|
if (chatbotConfig?.starterPrompts) obj.starterPrompts = chatbotConfig.starterPrompts
|
|
|
|
if (isAgentCanvas) {
|
|
// if showAgentMessages is undefined, default to true
|
|
if (showAgentMessages === undefined || showAgentMessages === null) {
|
|
obj.showAgentMessages = true
|
|
} else {
|
|
obj.showAgentMessages = showAgentMessages
|
|
}
|
|
}
|
|
|
|
return obj
|
|
}
|
|
|
|
const onSave = async () => {
|
|
try {
|
|
const saveResp = await chatflowsApi.updateChatflow(chatflowid, {
|
|
chatbotConfig: JSON.stringify(formatObj())
|
|
})
|
|
if (saveResp.data) {
|
|
enqueueSnackbar({
|
|
message: 'Chatbot 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 })
|
|
}
|
|
} catch (error) {
|
|
enqueueSnackbar({
|
|
message: `Failed to save Chatbot Configuration: ${
|
|
typeof error.response.data === 'object' ? error.response.data.message : error.response.data
|
|
}`,
|
|
options: {
|
|
key: new Date().getTime() + Math.random(),
|
|
variant: 'error',
|
|
persist: true,
|
|
action: (key) => (
|
|
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
|
<IconX />
|
|
</Button>
|
|
)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const onSwitchChange = async (checked) => {
|
|
try {
|
|
const saveResp = await chatflowsApi.updateChatflow(chatflowid, { isPublic: checked })
|
|
if (saveResp.data) {
|
|
enqueueSnackbar({
|
|
message: 'Chatbot 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 })
|
|
}
|
|
} catch (error) {
|
|
enqueueSnackbar({
|
|
message: `Failed to save Chatbot Configuration: ${
|
|
typeof error.response.data === 'object' ? error.response.data.message : error.response.data
|
|
}`,
|
|
options: {
|
|
key: new Date().getTime() + Math.random(),
|
|
variant: 'error',
|
|
persist: true,
|
|
action: (key) => (
|
|
<Button style={{ color: 'white' }} onClick={() => closeSnackbar(key)}>
|
|
<IconX />
|
|
</Button>
|
|
)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
const handleClosePopOver = () => {
|
|
setColorAnchorEl(null)
|
|
}
|
|
|
|
const handleCloseCopyPopOver = () => {
|
|
setCopyAnchorEl(null)
|
|
}
|
|
|
|
const onColorSelected = (hexColor) => {
|
|
switch (selectedColorConfig) {
|
|
case 'backgroundColor':
|
|
setBackgroundColor(hexColor)
|
|
break
|
|
case 'poweredByTextColor':
|
|
setPoweredByTextColor(hexColor)
|
|
break
|
|
case 'botMessageBackgroundColor':
|
|
setBotMessageBackgroundColor(hexColor)
|
|
break
|
|
case 'botMessageTextColor':
|
|
setBotMessageTextColor(hexColor)
|
|
break
|
|
case 'userMessageBackgroundColor':
|
|
setUserMessageBackgroundColor(hexColor)
|
|
break
|
|
case 'userMessageTextColor':
|
|
setUserMessageTextColor(hexColor)
|
|
break
|
|
case 'textInputBackgroundColor':
|
|
setTextInputBackgroundColor(hexColor)
|
|
break
|
|
case 'textInputTextColor':
|
|
setTextInputTextColor(hexColor)
|
|
break
|
|
case 'textInputSendButtonColor':
|
|
setTextInputSendButtonColor(hexColor)
|
|
break
|
|
}
|
|
setSketchPickerColor(hexColor)
|
|
}
|
|
|
|
const onTextChanged = (value, fieldName) => {
|
|
switch (fieldName) {
|
|
case 'title':
|
|
setTitle(value)
|
|
break
|
|
case 'titleAvatarSrc':
|
|
setTitleAvatarSrc(value)
|
|
break
|
|
case 'welcomeMessage':
|
|
setWelcomeMessage(value)
|
|
break
|
|
case 'errorMessage':
|
|
setErrorMessage(value)
|
|
break
|
|
case 'fontSize':
|
|
setFontSize(value)
|
|
break
|
|
case 'botMessageAvatarSrc':
|
|
setBotMessageAvatarSrc(value)
|
|
break
|
|
case 'userMessageAvatarSrc':
|
|
setUserMessageAvatarSrc(value)
|
|
break
|
|
case 'textInputPlaceholder':
|
|
setTextInputPlaceholder(value)
|
|
break
|
|
}
|
|
}
|
|
|
|
const onBooleanChanged = (value, fieldName) => {
|
|
switch (fieldName) {
|
|
case 'botMessageShowAvatar':
|
|
setBotMessageShowAvatar(value)
|
|
break
|
|
case 'userMessageShowAvatar':
|
|
setUserMessageShowAvatar(value)
|
|
break
|
|
case 'generateNewSession':
|
|
setGenerateNewSession(value)
|
|
break
|
|
case 'showAgentMessages':
|
|
setShowAgentMessages(value)
|
|
break
|
|
}
|
|
}
|
|
|
|
const colorField = (color, fieldName, fieldLabel) => {
|
|
return (
|
|
<Box sx={{ pt: 2, pb: 2 }}>
|
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
|
|
<Typography sx={{ mb: 1 }}>{fieldLabel}</Typography>
|
|
<Box
|
|
sx={{
|
|
cursor: 'pointer',
|
|
width: '30px',
|
|
height: '30px',
|
|
border: '1px solid #616161',
|
|
marginRight: '10px',
|
|
backgroundColor: color ?? '#ffffff',
|
|
borderRadius: '5px'
|
|
}}
|
|
onClick={(event) => {
|
|
setSelectedColorConfig(fieldName)
|
|
setSketchPickerColor(color ?? '#ffffff')
|
|
setColorAnchorEl(event.currentTarget)
|
|
}}
|
|
></Box>
|
|
</div>
|
|
</Box>
|
|
)
|
|
}
|
|
|
|
const booleanField = (value, fieldName, fieldLabel) => {
|
|
return (
|
|
<Box sx={{ pt: 2, pb: 2 }}>
|
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
|
|
<Typography sx={{ mb: 1 }}>{fieldLabel}</Typography>
|
|
<Switch
|
|
id={fieldName}
|
|
checked={value}
|
|
onChange={(event) => {
|
|
onBooleanChanged(event.target.checked, fieldName)
|
|
}}
|
|
/>
|
|
</div>
|
|
</Box>
|
|
)
|
|
}
|
|
|
|
const textField = (message, fieldName, fieldLabel, fieldType = 'string', placeholder = '') => {
|
|
return (
|
|
<Box sx={{ pt: 2, pb: 2 }}>
|
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
|
|
<Typography sx={{ mb: 1 }}>{fieldLabel}</Typography>
|
|
<OutlinedInput
|
|
id={fieldName}
|
|
type={fieldType}
|
|
fullWidth
|
|
value={message}
|
|
placeholder={placeholder}
|
|
name={fieldName}
|
|
onChange={(e) => {
|
|
onTextChanged(e.target.value, fieldName)
|
|
}}
|
|
/>
|
|
</div>
|
|
</Box>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Stack direction='row'>
|
|
<Typography
|
|
sx={{
|
|
p: 1,
|
|
borderRadius: 10,
|
|
backgroundColor: theme.palette.primary.light,
|
|
width: 'max-content',
|
|
height: 'max-content'
|
|
}}
|
|
variant='h5'
|
|
>
|
|
{`${baseURL}/chatbot/${chatflowid}`}
|
|
</Typography>
|
|
<IconButton
|
|
title='Copy Link'
|
|
color='success'
|
|
onClick={(event) => {
|
|
navigator.clipboard.writeText(`${baseURL}/chatbot/${chatflowid}`)
|
|
setCopyAnchorEl(event.currentTarget)
|
|
setTimeout(() => {
|
|
handleCloseCopyPopOver()
|
|
}, 1500)
|
|
}}
|
|
>
|
|
<IconCopy />
|
|
</IconButton>
|
|
<IconButton title='Open New Tab' color='primary' onClick={() => window.open(`${baseURL}/chatbot/${chatflowid}`, '_blank')}>
|
|
<IconArrowUpRightCircle />
|
|
</IconButton>
|
|
<div style={{ flex: 1 }} />
|
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
|
<Switch
|
|
checked={isPublicChatflow}
|
|
onChange={(event) => {
|
|
setChatflowIsPublic(event.target.checked)
|
|
onSwitchChange(event.target.checked)
|
|
}}
|
|
/>
|
|
<Typography>Make Public</Typography>
|
|
<TooltipWithParser
|
|
style={{ marginLeft: 10 }}
|
|
title={'Making public will allow anyone to access the chatbot without username & password'}
|
|
/>
|
|
</div>
|
|
</Stack>
|
|
{textField(title, 'title', 'Title', 'string', 'Flowise Assistant')}
|
|
{textField(
|
|
titleAvatarSrc,
|
|
'titleAvatarSrc',
|
|
'Title Avatar Link',
|
|
'string',
|
|
`https://raw.githubusercontent.com/FlowiseAI/Flowise/main/assets/FloWiseAI_dark.png`
|
|
)}
|
|
{textField(welcomeMessage, 'welcomeMessage', 'Welcome Message', 'string', 'Hello! This is custom welcome message')}
|
|
{textField(errorMessage, 'errorMessage', 'Error Message', 'string', 'This is custom error message')}
|
|
{colorField(backgroundColor, 'backgroundColor', 'Background Color')}
|
|
{textField(fontSize, 'fontSize', 'Font Size', 'number')}
|
|
{colorField(poweredByTextColor, 'poweredByTextColor', 'PoweredBy TextColor')}
|
|
{booleanField(showAgentMessages, 'showAgentMessages', 'Show Agent Reasoning')}
|
|
|
|
{/*BOT Message*/}
|
|
<Typography variant='h4' sx={{ mb: 1, mt: 2 }}>
|
|
Bot Message
|
|
</Typography>
|
|
{colorField(botMessageBackgroundColor, 'botMessageBackgroundColor', 'Background Color')}
|
|
{colorField(botMessageTextColor, 'botMessageTextColor', 'Text Color')}
|
|
{textField(
|
|
botMessageAvatarSrc,
|
|
'botMessageAvatarSrc',
|
|
'Avatar Link',
|
|
'string',
|
|
`https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png`
|
|
)}
|
|
{booleanField(botMessageShowAvatar, 'botMessageShowAvatar', 'Show Avatar')}
|
|
|
|
{/*USER Message*/}
|
|
<Typography variant='h4' sx={{ mb: 1, mt: 2 }}>
|
|
User Message
|
|
</Typography>
|
|
{colorField(userMessageBackgroundColor, 'userMessageBackgroundColor', 'Background Color')}
|
|
{colorField(userMessageTextColor, 'userMessageTextColor', 'Text Color')}
|
|
{textField(
|
|
userMessageAvatarSrc,
|
|
'userMessageAvatarSrc',
|
|
'Avatar Link',
|
|
'string',
|
|
`https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png`
|
|
)}
|
|
{booleanField(userMessageShowAvatar, 'userMessageShowAvatar', 'Show Avatar')}
|
|
|
|
{/*TEXT Input*/}
|
|
<Typography variant='h4' sx={{ mb: 1, mt: 2 }}>
|
|
Text Input
|
|
</Typography>
|
|
{colorField(textInputBackgroundColor, 'textInputBackgroundColor', 'Background Color')}
|
|
{colorField(textInputTextColor, 'textInputTextColor', 'Text Color')}
|
|
{textField(textInputPlaceholder, 'textInputPlaceholder', 'TextInput Placeholder', 'string', `Type question..`)}
|
|
{colorField(textInputSendButtonColor, 'textInputSendButtonColor', 'TextIntput Send Button Color')}
|
|
|
|
{/*Session Memory Input*/}
|
|
{isSessionMemory && (
|
|
<>
|
|
<Typography variant='h4' sx={{ mb: 1, mt: 2 }}>
|
|
Session Memory
|
|
</Typography>
|
|
{booleanField(generateNewSession, 'generateNewSession', 'Start new session when chatbot link is opened or refreshed')}
|
|
</>
|
|
)}
|
|
|
|
<StyledButton style={{ marginBottom: 10, marginTop: 10 }} variant='contained' onClick={() => onSave()}>
|
|
Save Changes
|
|
</StyledButton>
|
|
<Popover
|
|
open={openColorPopOver}
|
|
anchorEl={colorAnchorEl}
|
|
onClose={handleClosePopOver}
|
|
anchorOrigin={{
|
|
vertical: 'top',
|
|
horizontal: 'right'
|
|
}}
|
|
transformOrigin={{
|
|
vertical: 'top',
|
|
horizontal: 'left'
|
|
}}
|
|
>
|
|
<SketchPicker color={sketchPickerColor} onChange={(color) => onColorSelected(color.hex)} />
|
|
</Popover>
|
|
<Popover
|
|
open={openCopyPopOver}
|
|
anchorEl={copyAnchorEl}
|
|
onClose={handleCloseCopyPopOver}
|
|
anchorOrigin={{
|
|
vertical: 'top',
|
|
horizontal: 'right'
|
|
}}
|
|
transformOrigin={{
|
|
vertical: 'top',
|
|
horizontal: 'left'
|
|
}}
|
|
>
|
|
<Typography variant='h6' sx={{ pl: 1, pr: 1, color: 'white', background: theme.palette.success.dark }}>
|
|
Copied!
|
|
</Typography>
|
|
</Popover>
|
|
</>
|
|
)
|
|
}
|
|
|
|
ShareChatbot.propTypes = {
|
|
isSessionMemory: PropTypes.bool,
|
|
isAgentCanvas: PropTypes.bool
|
|
}
|
|
|
|
export default ShareChatbot
|