diff --git a/packages/ui/src/assets/images/langchain.png b/packages/ui/src/assets/images/langchain.png
index 587dd3140..d8ee337ff 100644
Binary files a/packages/ui/src/assets/images/langchain.png and b/packages/ui/src/assets/images/langchain.png differ
diff --git a/packages/ui/src/themes/compStyleOverride.js b/packages/ui/src/themes/compStyleOverride.js
index c04cc3f17..18014c705 100644
--- a/packages/ui/src/themes/compStyleOverride.js
+++ b/packages/ui/src/themes/compStyleOverride.js
@@ -45,8 +45,7 @@ export default function componentStyleOverrides(theme) {
MuiSvgIcon: {
styleOverrides: {
root: {
- color: theme?.customization?.isDarkMode ? theme.colors?.paper : 'inherit',
- background: theme?.customization?.isDarkMode ? theme.colors?.darkPrimaryLight : 'inherit'
+ color: theme?.customization?.isDarkMode ? theme.colors?.paper : 'inherit'
}
}
},
diff --git a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx
index f657b96ad..c5b117c11 100644
--- a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx
+++ b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.jsx
@@ -1,11 +1,33 @@
import PropTypes from 'prop-types'
-import { useState } from 'react'
+import { useState, useMemo } from 'react'
import { createPortal } from 'react-dom'
-import { Box, Dialog, DialogContent, DialogTitle, Tabs, Tab } from '@mui/material'
-import { tabsClasses } from '@mui/material/Tabs'
+import { useSelector } from 'react-redux'
+import { Box, Dialog, DialogContent, DialogTitle, Typography, IconButton } from '@mui/material'
+import { useTheme } from '@mui/material/styles'
+import {
+ IconX,
+ IconShieldLock,
+ IconWorldWww,
+ IconUserPlus,
+ IconMessageChatbot,
+ IconArrowForwardUp,
+ IconThumbUp,
+ IconMicrophone,
+ IconVolume,
+ IconUpload,
+ IconChartBar,
+ IconCode,
+ IconServer,
+ IconAdjustments
+} from '@tabler/icons-react'
+import PerfectScrollbar from 'react-perfect-scrollbar'
+
+// Section components
import SpeechToText from '@/ui-component/extended/SpeechToText'
import TextToSpeech from '@/ui-component/extended/TextToSpeech'
-import Security from '@/ui-component/extended/Security'
+import RateLimit from '@/ui-component/extended/RateLimit'
+import AllowedDomains from '@/ui-component/extended/AllowedDomains'
+import OverrideConfig from '@/ui-component/extended/OverrideConfig'
import ChatFeedback from '@/ui-component/extended/ChatFeedback'
import AnalyseFlow from '@/ui-component/extended/AnalyseFlow'
import StarterPrompts from '@/ui-component/extended/StarterPrompts'
@@ -15,146 +37,448 @@ import FileUpload from '@/ui-component/extended/FileUpload'
import PostProcessing from '@/ui-component/extended/PostProcessing'
import McpServer from '@/ui-component/extended/McpServer'
-const CHATFLOW_CONFIGURATION_TABS = [
+const CONFIGURATION_GROUPS = [
{
- label: 'Security',
- id: 'security'
+ label: 'General',
+ sections: [
+ {
+ label: 'Rate Limit',
+ id: 'rateLimit',
+ icon: IconShieldLock,
+ description: 'Limit API requests per time window'
+ },
+ {
+ label: 'Allowed Domains',
+ id: 'allowedDomains',
+ icon: IconWorldWww,
+ description: 'Restrict chatbot to specific domains'
+ },
+ {
+ label: 'Leads',
+ id: 'leads',
+ icon: IconUserPlus,
+ description: 'Capture visitor contact information'
+ }
+ ]
},
{
- label: 'Starter Prompts',
- id: 'conversationStarters'
+ label: 'Chat',
+ sections: [
+ {
+ label: 'Starter Prompts',
+ id: 'conversationStarters',
+ icon: IconMessageChatbot,
+ description: 'Suggested prompts for new conversations'
+ },
+ {
+ label: 'Follow-up Prompts',
+ id: 'followUpPrompts',
+ icon: IconArrowForwardUp,
+ description: 'Auto-generate follow-up questions'
+ },
+ {
+ label: 'Chat Feedback',
+ id: 'chatFeedback',
+ icon: IconThumbUp,
+ description: 'Allow users to rate responses'
+ }
+ ]
},
{
- label: 'Follow-up Prompts',
- id: 'followUpPrompts'
+ label: 'Media & Files',
+ sections: [
+ {
+ label: 'Speech to Text',
+ id: 'speechToText',
+ icon: IconMicrophone,
+ description: 'Voice input transcription'
+ },
+ {
+ label: 'Text to Speech',
+ id: 'textToSpeech',
+ icon: IconVolume,
+ description: 'Audio response playback'
+ },
+ {
+ label: 'File Upload',
+ id: 'fileUpload',
+ icon: IconUpload,
+ description: 'Allow file uploads in chat'
+ }
+ ]
},
{
- label: 'Speech to Text',
- id: 'speechToText'
- },
- {
- label: 'Text to Speech',
- id: 'textToSpeech'
- },
- {
- label: 'Chat Feedback',
- id: 'chatFeedback'
- },
- {
- label: 'Analyse Chatflow',
- id: 'analyseChatflow'
- },
- {
- label: 'Leads',
- id: 'leads'
- },
- {
- label: 'File Upload',
- id: 'fileUpload'
- },
- {
- label: 'Post Processing',
- id: 'postProcessing'
- },
- {
- label: 'MCP Server',
- id: 'mcpServer'
+ label: 'Advanced',
+ sections: [
+ {
+ label: 'Analytics',
+ id: 'analyseChatflow',
+ icon: IconChartBar,
+ description: 'Connect analytics providers'
+ },
+ {
+ label: 'Post Processing',
+ id: 'postProcessing',
+ icon: IconCode,
+ description: 'Custom JavaScript post-processing'
+ },
+ {
+ label: 'MCP Server',
+ id: 'mcpServer',
+ icon: IconServer,
+ description: 'Model Context Protocol server'
+ },
+ {
+ label: 'Override Config',
+ id: 'overrideConfig',
+ icon: IconAdjustments,
+ description: 'Override flow configuration via API'
+ }
+ ]
}
]
-function TabPanel(props) {
- const { children, value, index, ...other } = props
- return (
-
- {value === index && {children}}
-
- )
-}
+function getSectionStatus(sectionId, chatflow) {
+ if (!chatflow) return false
-TabPanel.propTypes = {
- children: PropTypes.node,
- index: PropTypes.number.isRequired,
- value: PropTypes.number.isRequired
-}
+ let chatbotConfig = {}
+ let apiConfig = {}
+ try {
+ chatbotConfig = chatflow.chatbotConfig ? JSON.parse(chatflow.chatbotConfig) : {}
+ apiConfig = chatflow.apiConfig ? JSON.parse(chatflow.apiConfig) : {}
+ } catch {
+ return false
+ }
-function a11yProps(index) {
- return {
- id: `chatflow-config-tab-${index}`,
- 'aria-controls': `chatflow-config-tabpanel-${index}`
+ switch (sectionId) {
+ case 'rateLimit':
+ return apiConfig?.rateLimit?.status === true
+ case 'allowedDomains':
+ return Array.isArray(chatbotConfig?.allowedOrigins) && chatbotConfig.allowedOrigins.some((o) => o && o.trim() !== '')
+ case 'leads':
+ return chatbotConfig?.leads?.status === true
+ case 'conversationStarters': {
+ const sp = chatbotConfig?.starterPrompts
+ if (!sp) return false
+ return Object.values(sp).some((entry) => entry?.prompt && entry.prompt.trim() !== '')
+ }
+ case 'followUpPrompts':
+ return chatbotConfig?.followUpPrompts?.status === true
+ case 'chatFeedback':
+ return chatbotConfig?.chatFeedback?.status === true
+ case 'speechToText': {
+ const stt = chatbotConfig?.speechToText
+ if (!stt) return false
+ return Object.values(stt).some((provider) => provider?.status === true)
+ }
+ case 'textToSpeech': {
+ const tts = chatbotConfig?.textToSpeech
+ if (!tts) return false
+ return Object.values(tts).some((provider) => provider?.status === true)
+ }
+ case 'fileUpload':
+ return chatbotConfig?.fullFileUpload?.status === true
+ case 'analyseChatflow': {
+ const ap = chatbotConfig?.analyticsProviders
+ if (!ap) return false
+ return Object.values(ap).some((provider) => provider?.status === true)
+ }
+ case 'postProcessing':
+ return chatbotConfig?.postProcessing?.status === true
+ case 'mcpServer':
+ return chatbotConfig?.mcpServer?.status === true
+ case 'overrideConfig':
+ return apiConfig?.overrideConfig?.status === true
+ default:
+ return false
}
}
+// Flatten all sections for quick lookup
+const ALL_SECTIONS = CONFIGURATION_GROUPS.flatMap((g) => g.sections)
+
+const SIDEBAR_WIDTH = 220
+
const ChatflowConfigurationDialog = ({ show, isAgentCanvas, dialogProps, onCancel }) => {
const portalElement = document.getElementById('portal')
- const [tabValue, setTabValue] = useState(0)
+ const theme = useTheme()
+ const chatflow = useSelector((state) => state.canvas.chatflow)
+ const customization = useSelector((state) => state.customization)
- const filteredTabs = CHATFLOW_CONFIGURATION_TABS.filter((tab) => !isAgentCanvas || !tab.hideInAgentFlow)
+ const [activeSection, setActiveSection] = useState('rateLimit')
+ const [mcpServerEnabled, setMcpServerEnabled] = useState(false)
+
+ const isDark = theme.palette.mode === 'dark' || customization?.isDarkMode
+
+ // Filter groups/sections based on agent canvas
+ const filteredGroups = useMemo(() => {
+ return CONFIGURATION_GROUPS.map((group) => ({
+ ...group,
+ sections: group.sections.filter((section) => !isAgentCanvas || !section.hideInAgentFlow)
+ })).filter((group) => group.sections.length > 0)
+ }, [isAgentCanvas])
+
+ // Get all section IDs for validation
+ const allSectionIds = useMemo(() => {
+ return filteredGroups.flatMap((g) => g.sections.map((s) => s.id))
+ }, [filteredGroups])
+
+ // Reset activeSection if current one is filtered out
+ const currentSection = allSectionIds.includes(activeSection) ? activeSection : allSectionIds[0] || 'rateLimit'
+ const currentSectionData = ALL_SECTIONS.find((s) => s.id === currentSection)
+
+ const renderContent = () => {
+ const props = { dialogProps }
+ switch (currentSection) {
+ case 'rateLimit':
+ return
+ case 'allowedDomains':
+ return
+ case 'leads':
+ return
+ case 'conversationStarters':
+ return
+ case 'followUpPrompts':
+ return
+ case 'chatFeedback':
+ return
+ case 'speechToText':
+ return
+ case 'textToSpeech':
+ return
+ case 'fileUpload':
+ return
+ case 'analyseChatflow':
+ return
+ case 'postProcessing':
+ return
+ case 'mcpServer':
+ return setMcpServerEnabled(enabled)} />
+ case 'overrideConfig':
+ return
+ default:
+ return null
+ }
+ }
const component = show ? (
) : null
diff --git a/packages/ui/src/ui-component/extended/AllowedDomains.jsx b/packages/ui/src/ui-component/extended/AllowedDomains.jsx
index 75ae32a63..29a44a579 100644
--- a/packages/ui/src/ui-component/extended/AllowedDomains.jsx
+++ b/packages/ui/src/ui-component/extended/AllowedDomains.jsx
@@ -17,7 +17,7 @@ import useNotifier from '@/utils/useNotifier'
// API
import chatflowsApi from '@/api/chatflows'
-const AllowedDomains = ({ dialogProps, onConfirm }) => {
+const AllowedDomains = ({ dialogProps, onConfirm, hideTitle = false }) => {
const dispatch = useDispatch()
useNotifier()
@@ -119,14 +119,16 @@ const AllowedDomains = ({ dialogProps, onConfirm }) => {
}, [dialogProps])
return (
-
-
- Allowed Domains
-
-
+
+ {!hideTitle && (
+
+ Allowed Domains
+
+
+ )}
Domains
@@ -193,16 +195,19 @@ const AllowedDomains = ({ dialogProps, onConfirm }) => {
/>
-
- Save
-
+
+
+ Save
+
+
)
}
AllowedDomains.propTypes = {
dialogProps: PropTypes.object,
- onConfirm: PropTypes.func
+ onConfirm: PropTypes.func,
+ hideTitle: PropTypes.bool
}
export default AllowedDomains
diff --git a/packages/ui/src/ui-component/extended/AnalyseFlow.jsx b/packages/ui/src/ui-component/extended/AnalyseFlow.jsx
index de162e51a..84038f4c6 100644
--- a/packages/ui/src/ui-component/extended/AnalyseFlow.jsx
+++ b/packages/ui/src/ui-component/extended/AnalyseFlow.jsx
@@ -15,6 +15,7 @@ import {
ListItemAvatar,
ListItemText
} from '@mui/material'
+import { useTheme } from '@mui/material/styles'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import { IconX } from '@tabler/icons-react'
@@ -221,6 +222,7 @@ const analyticProviders = [
const AnalyseFlow = ({ dialogProps }) => {
const dispatch = useDispatch()
+ const theme = useTheme()
useNotifier()
@@ -339,7 +341,12 @@ const AnalyseFlow = ({ dialogProps }) => {
sx={{ ml: 1 }}
primary={provider.label}
secondary={
-
+
{provider.url}
}
@@ -416,9 +423,11 @@ const AnalyseFlow = ({ dialogProps }) => {
))}
-
- Save
-
+
+
+ Save
+
+
>
)
}
diff --git a/packages/ui/src/ui-component/extended/ChatFeedback.jsx b/packages/ui/src/ui-component/extended/ChatFeedback.jsx
index 132d073e2..ca55dc5b7 100644
--- a/packages/ui/src/ui-component/extended/ChatFeedback.jsx
+++ b/packages/ui/src/ui-component/extended/ChatFeedback.jsx
@@ -3,7 +3,7 @@ import { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
// material-ui
-import { Button, Box } from '@mui/material'
+import { Button, Box, Stack } from '@mui/material'
import { IconX } from '@tabler/icons-react'
// Project import
@@ -91,14 +91,14 @@ const ChatFeedback = ({ dialogProps, onConfirm }) => {
}, [dialogProps])
return (
- <>
-
-
+
+
+
+
+ Save
+
-
- Save
-
- >
+
)
}
diff --git a/packages/ui/src/ui-component/extended/FileUpload.jsx b/packages/ui/src/ui-component/extended/FileUpload.jsx
index d688cb754..fc5613590 100644
--- a/packages/ui/src/ui-component/extended/FileUpload.jsx
+++ b/packages/ui/src/ui-component/extended/FileUpload.jsx
@@ -5,7 +5,19 @@ import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackba
import parser from 'html-react-parser'
// material-ui
-import { Button, Box, Typography, FormControl, RadioGroup, FormControlLabel, Radio } from '@mui/material'
+import {
+ Button,
+ Box,
+ Typography,
+ FormControl,
+ RadioGroup,
+ FormControlLabel,
+ Radio,
+ Accordion,
+ AccordionSummary,
+ AccordionDetails
+} from '@mui/material'
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import { IconX, IconBulb } from '@tabler/icons-react'
// Project import
@@ -20,7 +32,7 @@ import chatflowsApi from '@/api/chatflows'
const message = `The full contents of uploaded files will be converted to text and sent to the Agent.
-Refer docs for more details.`
+Refer docs for more details.`
const availableFileTypes = [
{ name: 'CSS', ext: 'text/css', extension: '.css' },
@@ -52,8 +64,6 @@ const FileUpload = ({ dialogProps }) => {
const [allowedFileTypes, setAllowedFileTypes] = useState([])
const [chatbotConfig, setChatbotConfig] = useState({})
const [pdfUsage, setPdfUsage] = useState('perPage')
- const [pdfLegacyBuild, setPdfLegacyBuild] = useState(false)
-
const handleChange = (value) => {
setFullFileUpload(value)
}
@@ -71,18 +81,13 @@ const FileUpload = ({ dialogProps }) => {
setPdfUsage(event.target.value)
}
- const handleLegacyBuildChange = (value) => {
- setPdfLegacyBuild(value)
- }
-
const onSave = async () => {
try {
const value = {
status: fullFileUpload,
allowedUploadFileTypes: allowedFileTypes.join(','),
pdfFile: {
- usage: pdfUsage,
- legacyBuild: pdfLegacyBuild
+ usage: pdfUsage
}
}
chatbotConfig.fullFileUpload = value
@@ -140,13 +145,8 @@ const FileUpload = ({ dialogProps }) => {
const allowedFileTypes = chatbotConfig.fullFileUpload.allowedUploadFileTypes.split(',')
setAllowedFileTypes(allowedFileTypes)
}
- if (chatbotConfig.fullFileUpload?.pdfFile) {
- if (chatbotConfig.fullFileUpload.pdfFile.usage) {
- setPdfUsage(chatbotConfig.fullFileUpload.pdfFile.usage)
- }
- if (chatbotConfig.fullFileUpload.pdfFile.legacyBuild !== undefined) {
- setPdfLegacyBuild(chatbotConfig.fullFileUpload.pdfFile.legacyBuild)
- }
+ if (chatbotConfig.fullFileUpload?.pdfFile?.usage) {
+ setPdfUsage(chatbotConfig.fullFileUpload.pdfFile.usage)
}
} catch (e) {
setChatbotConfig({})
@@ -170,31 +170,27 @@ const FileUpload = ({ dialogProps }) => {
mb: 2
}}
>
-
-
-
- {parser(message)}
-
-
+
+ {parser(message)}
+
- Allow Uploads of Type
+ Allow Uploads of Type
{
disabled={!fullFileUpload}
onChange={handleAllowedFileTypesChange}
/>
-
))}
- {allowedFileTypes.includes('application/pdf') && fullFileUpload && (
-
- }
+ sx={{ minHeight: 40, px: 2, '& .MuiAccordionSummary-content': { my: 0.75 } }}
>
- PDF Configuration
-
-
-
- PDF Usage
-
-
- } label='One document per page' />
- } label='One document per file' />
-
-
-
-
-
-
-
-
+ Advanced Settings
+
+
+ {/* PDF Processing */}
+ {allowedFileTypes.includes('application/pdf') && (
+
+
+ PDF Processing
+
+
+
+ }
+ label={One document per page}
+ />
+ }
+ label={One document per file}
+ />
+
+
+
+ )}
+
+
)}
-
- Save
-
+
+
+ Save
+
+
>
)
}
diff --git a/packages/ui/src/ui-component/extended/FollowUpPrompts.jsx b/packages/ui/src/ui-component/extended/FollowUpPrompts.jsx
index bc0d95bc1..8a7a711b8 100644
--- a/packages/ui/src/ui-component/extended/FollowUpPrompts.jsx
+++ b/packages/ui/src/ui-component/extended/FollowUpPrompts.jsx
@@ -601,9 +601,11 @@ const FollowUpPrompts = ({ dialogProps }) => {
>
)}
-
- Save
-
+
+
+ Save
+
+
>
)
}
diff --git a/packages/ui/src/ui-component/extended/Leads.jsx b/packages/ui/src/ui-component/extended/Leads.jsx
index 395902986..58fa8169b 100644
--- a/packages/ui/src/ui-component/extended/Leads.jsx
+++ b/packages/ui/src/ui-component/extended/Leads.jsx
@@ -160,14 +160,16 @@ const Leads = ({ dialogProps }) => {
>
)}
-
- Save
-
+
+
+ Save
+
+
>
)
}
diff --git a/packages/ui/src/ui-component/extended/McpServer.jsx b/packages/ui/src/ui-component/extended/McpServer.jsx
index 892c0dba8..b712130a9 100644
--- a/packages/ui/src/ui-component/extended/McpServer.jsx
+++ b/packages/ui/src/ui-component/extended/McpServer.jsx
@@ -23,7 +23,7 @@ import useNotifier from '@/utils/useNotifier'
import mcpServerApi from '@/api/mcpserver'
import chatflowsApi from '@/api/chatflows'
-const McpServer = ({ dialogProps }) => {
+const McpServer = ({ dialogProps, onStatusChange }) => {
const dispatch = useDispatch()
const theme = useTheme()
const customization = useSelector((state) => state.customization)
@@ -123,6 +123,7 @@ const McpServer = ({ dialogProps }) => {
setToken(resp.data.token || '')
setToolName(resp.data.toolName || '')
setDescription(resp.data.description || '')
+ onStatusChange?.(resp.data.enabled)
showSuccess('MCP Server settings saved')
}
} else {
@@ -136,12 +137,14 @@ const McpServer = ({ dialogProps }) => {
setToolName(resp.data.toolName || '')
setDescription(resp.data.description || '')
setHasExistingConfig(true)
+ onStatusChange?.(resp.data.enabled)
showSuccess('MCP Server settings saved')
}
}
} else {
await mcpServerApi.deleteMcpServerConfig(dialogProps.chatflow.id)
setMcpEnabled(false)
+ onStatusChange?.(false)
showSuccess('MCP Server disabled')
}
await refreshChatflowStore()
@@ -215,13 +218,15 @@ const McpServer = ({ dialogProps }) => {
useEffect(() => {
if (getMcpServerConfigApi.data) {
- setMcpEnabled(getMcpServerConfigApi.data.enabled || false)
+ const enabled = getMcpServerConfigApi.data.enabled || false
+ setMcpEnabled(enabled)
setToolName(getMcpServerConfigApi.data.toolName || '')
setDescription(getMcpServerConfigApi.data.description || '')
setToken(getMcpServerConfigApi.data.token || '')
setHasExistingConfig(!!getMcpServerConfigApi.data.token)
+ onStatusChange?.(enabled)
}
- }, [getMcpServerConfigApi.data])
+ }, [getMcpServerConfigApi.data]) // eslint-disable-line react-hooks/exhaustive-deps
if (getMcpServerConfigApi.loading) {
return (
@@ -391,20 +396,23 @@ const McpServer = ({ dialogProps }) => {
)}
-
- {loading ? 'Saving...' : 'Save'}
-
+
+
+ {loading ? 'Saving...' : 'Save'}
+
+
>
)
}
McpServer.propTypes = {
- dialogProps: PropTypes.object
+ dialogProps: PropTypes.object,
+ onStatusChange: PropTypes.func
}
export default McpServer
diff --git a/packages/ui/src/ui-component/extended/OverrideConfig.jsx b/packages/ui/src/ui-component/extended/OverrideConfig.jsx
index 32397b4b9..0ca1b4c85 100644
--- a/packages/ui/src/ui-component/extended/OverrideConfig.jsx
+++ b/packages/ui/src/ui-component/extended/OverrideConfig.jsx
@@ -5,6 +5,7 @@ import {
Accordion,
AccordionDetails,
AccordionSummary,
+ Box,
Button,
Paper,
Stack,
@@ -17,7 +18,6 @@ import {
Typography,
Card
} from '@mui/material'
-import { useTheme } from '@mui/material/styles'
// Project import
import { StyledButton } from '@/ui-component/button/StyledButton'
@@ -39,6 +39,9 @@ import variablesApi from '@/api/variables'
// utils
const OverrideConfigTable = ({ columns, onToggle, rows, sx }) => {
+ const customization = useSelector((state) => state.customization)
+ const isDark = customization?.isDarkMode
+
const handleChange = (enabled, row) => {
onToggle(row, enabled)
}
@@ -47,10 +50,8 @@ const OverrideConfigTable = ({ columns, onToggle, rows, sx }) => {
if (key === 'enabled') {
return handleChange(enabled, row)} value={row.enabled} />
} else if (key === 'type' && row.schema) {
- // If there's schema information, add a tooltip
let schemaContent
if (Array.isArray(row.schema)) {
- // Handle array format: [{ name: "field", type: "string" }, ...]
schemaContent =
'[
' +
row.schema
@@ -67,30 +68,53 @@ const OverrideConfigTable = ({ columns, onToggle, rows, sx }) => {
.join(',
') +
'
]'
} else if (typeof row.schema === 'object' && row.schema !== null) {
- // Handle object format: { "field": "string", "field2": "number", ... }
schemaContent = JSON.stringify(row.schema, null, 2).replace(/\n/g, '
').replace(/ /g, ' ')
} else {
schemaContent = 'No schema available'
}
return (
-
- {row[key]}
+
+ {row[key]}
Schema:
${schemaContent}`} />
)
} else {
- return row[key]
+ return {row[key]}
}
}
+ const columnLabels = { label: 'Label', name: 'Name', type: 'Type', enabled: 'On' }
+
return (
-
-
+
+
{columns.map((col, index) => (
- {col.charAt(0).toUpperCase() + col.slice(1)}
+
+ {columnLabels[col] || col.charAt(0).toUpperCase() + col.slice(1)}
+
))}
@@ -99,7 +123,19 @@ const OverrideConfigTable = ({ columns, onToggle, rows, sx }) => {
{Object.keys(row).map((key, index) => {
if (key !== 'id' && key !== 'schema') {
- return {renderCellContent(key, row)}
+ return (
+
+ {renderCellContent(key, row)}
+
+ )
}
})}
@@ -117,14 +153,14 @@ OverrideConfigTable.propTypes = {
onToggle: PropTypes.func
}
-const OverrideConfig = ({ dialogProps }) => {
+const OverrideConfig = ({ dialogProps, hideTitle = false }) => {
const dispatch = useDispatch()
+ const customization = useSelector((state) => state.customization)
const chatflow = useSelector((state) => state.canvas.chatflow)
const chatflowid = chatflow.id
const apiConfig = chatflow.apiConfig ? JSON.parse(chatflow.apiConfig) : {}
useNotifier()
- const theme = useTheme()
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
@@ -359,22 +395,32 @@ const OverrideConfig = ({ dialogProps }) => {
}, [getAllVariablesApi.data])
return (
-
-
- Override Configuration
- documentation for more information.'
- }
- />
-
+
+ {!hideTitle && (
+
+ Override Configuration
+ documentation for more information.'
+ }
+ />
+
+ )}
{overrideConfigStatus && (
<>
{nodeOverrides && nodeConfig && (
-
+
Nodes
@@ -388,6 +434,11 @@ const OverrideConfig = ({ dialogProps }) => {
onChange={handleAccordionChange(nodeLabel)}
key={nodeLabel}
disableGutters
+ sx={{
+ '&:before': {
+ bgcolor: customization.isDarkMode ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.06)'
+ }
+ }}
>
}
@@ -444,7 +495,15 @@ const OverrideConfig = ({ dialogProps }) => {
)}
{variableOverrides && variableOverrides.length > 0 && (
-
+
Variables
@@ -459,15 +518,18 @@ const OverrideConfig = ({ dialogProps }) => {
>
)}
-
- Save
-
+
+
+ Save
+
+
)
}
OverrideConfig.propTypes = {
- dialogProps: PropTypes.object
+ dialogProps: PropTypes.object,
+ hideTitle: PropTypes.bool
}
export default OverrideConfig
diff --git a/packages/ui/src/ui-component/extended/PostProcessing.jsx b/packages/ui/src/ui-component/extended/PostProcessing.jsx
index fb9543a55..e6cab9400 100644
--- a/packages/ui/src/ui-component/extended/PostProcessing.jsx
+++ b/packages/ui/src/ui-component/extended/PostProcessing.jsx
@@ -179,7 +179,7 @@ const PostProcessing = ({ dialogProps }) => {
style={{
marginTop: '10px',
border: '1px solid',
- borderColor: theme.palette.grey['300'],
+ borderColor: customization.isDarkMode ? 'rgba(255,255,255,0.12)' : theme.palette.grey['300'],
borderRadius: '6px',
height: '200px',
width: '100%'
@@ -196,7 +196,16 @@ const PostProcessing = ({ dialogProps }) => {
/>
-
+
{
}}
>
}>
- Available Variables
+ Available Variables
-
-
+
+
- Variable
- Type
- Description
+
+ Variable
+
+
+ Type
+
+
+ Description
+
-
+
$flow.rawOutput
@@ -283,11 +334,11 @@ const PostProcessing = ({ dialogProps }) => {
List of artifacts generated during execution
-
+
$flow.fileAnnotations
- array
- File annotations associated with the response
+ array
+ File annotations associated with the response
@@ -295,14 +346,16 @@ const PostProcessing = ({ dialogProps }) => {
-
- Save
-
+
+
+ Save
+
+
{
+const RateLimit = ({ dialogProps, hideTitle = false }) => {
const dispatch = useDispatch()
const chatflow = useSelector((state) => state.canvas.chatflow)
const chatflowid = chatflow.id
@@ -147,36 +147,39 @@ const RateLimit = ({ dialogProps }) => {
}
return (
-
-
- Rate Limit{' '}
- Rate Limit Setup Guide to set up Rate Limit correctly in your hosting environment.'
- }
- />
-
-
-
- {rateLimitStatus && (
-
- {textField(limitMax, 'limitMax', 'Message Limit per Duration', 'number', '5')}
- {textField(limitDuration, 'limitDuration', 'Duration in Second', 'number', '60')}
- {textField(limitMsg, 'limitMsg', 'Limit Message', 'string', 'You have reached the quota')}
-
- )}
-
- onSave()} sx={{ width: 'auto' }}>
- Save
-
+
+ {!hideTitle && (
+
+ Rate Limit{' '}
+ Rate Limit Setup Guide to set up Rate Limit correctly in your hosting environment.'
+ }
+ />
+
+ )}
+
+ {rateLimitStatus && (
+
+ {textField(limitMax, 'limitMax', 'Message Limit per Duration', 'number', '5')}
+ {textField(limitDuration, 'limitDuration', 'Duration in Second', 'number', '60')}
+ {textField(limitMsg, 'limitMsg', 'Limit Message', 'string', 'You have reached the quota')}
+
+ )}
+
+ onSave()} sx={{ minWidth: 100 }}>
+ Save
+
+
)
}
RateLimit.propTypes = {
isSessionMemory: PropTypes.bool,
- dialogProps: PropTypes.object
+ dialogProps: PropTypes.object,
+ hideTitle: PropTypes.bool
}
export default RateLimit
diff --git a/packages/ui/src/ui-component/extended/SpeechToText.jsx b/packages/ui/src/ui-component/extended/SpeechToText.jsx
index 2c732b2d0..2ca7fd95c 100644
--- a/packages/ui/src/ui-component/extended/SpeechToText.jsx
+++ b/packages/ui/src/ui-component/extended/SpeechToText.jsx
@@ -478,14 +478,16 @@ const SpeechToText = ({ dialogProps, onConfirm }) => {
))}
>
)}
-
- Save
-
+
+
+ Save
+
+
>
)
}
diff --git a/packages/ui/src/ui-component/extended/StarterPrompts.jsx b/packages/ui/src/ui-component/extended/StarterPrompts.jsx
index 31504fc59..861bea1e1 100644
--- a/packages/ui/src/ui-component/extended/StarterPrompts.jsx
+++ b/packages/ui/src/ui-component/extended/StarterPrompts.jsx
@@ -4,7 +4,7 @@ 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 { Button, IconButton, OutlinedInput, Box, List, InputAdornment, Typography } from '@mui/material'
import { IconX, IconTrash, IconPlus, IconBulb } from '@tabler/icons-react'
// Project import
@@ -133,28 +133,24 @@ const StarterPrompts = ({ dialogProps, onConfirm }) => {
return (
<>
-
-
-
-
- Starter prompts will only be shown when there is no messages on the chat
-
-
-
+
+
+ Starter prompts will only be shown when there are no messages on the chat
+
+
:not(style)': { m: 1 }, pt: 2 }}>
{inputFields.map((data, index) => {
@@ -199,9 +195,11 @@ const StarterPrompts = ({ dialogProps, onConfirm }) => {
})}
-
- Save
-
+
+
+ Save
+
+
>
)
}
diff --git a/packages/ui/src/ui-component/extended/TextToSpeech.jsx b/packages/ui/src/ui-component/extended/TextToSpeech.jsx
index 226d45a1e..8ce171615 100644
--- a/packages/ui/src/ui-component/extended/TextToSpeech.jsx
+++ b/packages/ui/src/ui-component/extended/TextToSpeech.jsx
@@ -641,14 +641,16 @@ const TextToSpeech = ({ dialogProps }) => {
>
)}
-
- Save
-
+
+
+ Save
+
+
>
)
}