setDeleteDialogOpen(false)}
+ onDelete={() => deleteAssistant()}
+ onDeleteBoth={() => deleteAssistant(true)}
+ />
{loading && }
) : null
diff --git a/packages/ui/src/views/assistants/DeleteConfirmDialog.js b/packages/ui/src/views/assistants/DeleteConfirmDialog.js
new file mode 100644
index 000000000..f4453631b
--- /dev/null
+++ b/packages/ui/src/views/assistants/DeleteConfirmDialog.js
@@ -0,0 +1,47 @@
+import { createPortal } from 'react-dom'
+import PropTypes from 'prop-types'
+import { Button, Dialog, DialogContent, DialogTitle } from '@mui/material'
+import { StyledButton } from 'ui-component/button/StyledButton'
+
+const DeleteConfirmDialog = ({ show, dialogProps, onCancel, onDelete, onDeleteBoth }) => {
+ const portalElement = document.getElementById('portal')
+
+ const component = show ? (
+
+ ) : null
+
+ return createPortal(component, portalElement)
+}
+
+DeleteConfirmDialog.propTypes = {
+ show: PropTypes.bool,
+ dialogProps: PropTypes.object,
+ onDeleteBoth: PropTypes.func,
+ onDelete: PropTypes.func,
+ onCancel: PropTypes.func
+}
+
+export default DeleteConfirmDialog
diff --git a/packages/ui/src/views/canvas/CanvasNode.js b/packages/ui/src/views/canvas/CanvasNode.js
index cabe23291..cfc51fe47 100644
--- a/packages/ui/src/views/canvas/CanvasNode.js
+++ b/packages/ui/src/views/canvas/CanvasNode.js
@@ -207,9 +207,11 @@ const CanvasNode = ({ data }) => {
{data.inputAnchors.map((inputAnchor, index) => (
))}
- {data.inputParams.map((inputParam, index) => (
-
- ))}
+ {data.inputParams
+ .filter((inputParam) => !inputParam.hidden)
+ .map((inputParam, index) => (
+
+ ))}
{data.inputParams.find((param) => param.additionalParams) && (
{
const [isLoading, setLoading] = useState(true)
const [images, setImages] = useState({})
+ const [search, setSearch] = useState('')
const [loginDialogOpen, setLoginDialogOpen] = useState(false)
const [loginDialogProps, setLoginDialogProps] = useState({})
const getAllChatflowsApi = useApi(chatflowsApi.getAllChatflows)
+ const [view, setView] = React.useState(localStorage.getItem('flowDisplayStyle') || 'card')
+
+ const handleChange = (event, nextView) => {
+ localStorage.setItem('flowDisplayStyle', nextView)
+ setView(nextView)
+ }
+
+ const onSearchChange = (event) => {
+ setSearch(event.target.value)
+ }
+
+ function filterFlows(data) {
+ return (
+ data.name.toLowerCase().indexOf(search.toLowerCase()) > -1 ||
+ (data.category && data.category.toLowerCase().indexOf(search.toLowerCase()) > -1)
+ )
+ }
const onLoginClick = (username, password) => {
localStorage.setItem('username', username)
@@ -102,26 +123,86 @@ const Chatflows = () => {
return (
-
- Chatflows
-
-
-
- }>
- Add New
-
+
+
+
+ Chatflows
+
+
+
+ )
+ }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }>
+ Add New
+
+
+
+
+
+ {!isLoading && (!view || view === 'card') && getAllChatflowsApi.data && (
+
+ {getAllChatflowsApi.data.filter(filterFlows).map((data, index) => (
+
+ goToCanvas(data)} data={data} images={images[data.id]} />
+
+ ))}
-
+ )}
+ {!isLoading && view === 'list' && getAllChatflowsApi.data && (
+
+ )}
-
- {!isLoading &&
- getAllChatflowsApi.data &&
- getAllChatflowsApi.data.map((data, index) => (
-
- goToCanvas(data)} data={data} images={images[data.id]} />
-
- ))}
-
+
{!isLoading && (!getAllChatflowsApi.data || getAllChatflowsApi.data.length === 0) && (
diff --git a/packages/ui/src/views/chatmessage/ChatMessage.js b/packages/ui/src/views/chatmessage/ChatMessage.js
index e006ba497..81ba95127 100644
--- a/packages/ui/src/views/chatmessage/ChatMessage.js
+++ b/packages/ui/src/views/chatmessage/ChatMessage.js
@@ -7,10 +7,11 @@ import rehypeMathjax from 'rehype-mathjax'
import rehypeRaw from 'rehype-raw'
import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
+import axios from 'axios'
-import { CircularProgress, OutlinedInput, Divider, InputAdornment, IconButton, Box, Chip } from '@mui/material'
+import { CircularProgress, OutlinedInput, Divider, InputAdornment, IconButton, Box, Chip, Button } from '@mui/material'
import { useTheme } from '@mui/material/styles'
-import { IconSend } from '@tabler/icons'
+import { IconSend, IconDownload } from '@tabler/icons'
// project import
import { CodeBlock } from 'ui-component/markdown/CodeBlock'
@@ -148,7 +149,13 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
setMessages((prevMessages) => [
...prevMessages,
- { message: text, sourceDocuments: data?.sourceDocuments, usedTools: data?.usedTools, type: 'apiMessage' }
+ {
+ message: text,
+ sourceDocuments: data?.sourceDocuments,
+ usedTools: data?.usedTools,
+ fileAnnotations: data?.fileAnnotations,
+ type: 'apiMessage'
+ }
])
}
@@ -179,6 +186,26 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
}
}
+ const downloadFile = async (fileAnnotation) => {
+ try {
+ const response = await axios.post(
+ `${baseURL}/api/v1/openai-assistants-file`,
+ { fileName: fileAnnotation.fileName },
+ { responseType: 'blob' }
+ )
+ const blob = new Blob([response.data], { type: response.headers['content-type'] })
+ const downloadUrl = window.URL.createObjectURL(blob)
+ const link = document.createElement('a')
+ link.href = downloadUrl
+ link.download = fileAnnotation.fileName
+ document.body.appendChild(link)
+ link.click()
+ link.remove()
+ } catch (error) {
+ console.error('Download failed:', error)
+ }
+ }
+
// Get chatmessages successful
useEffect(() => {
if (getChatmessageApi.data?.length) {
@@ -192,6 +219,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
}
if (message.sourceDocuments) obj.sourceDocuments = JSON.parse(message.sourceDocuments)
if (message.usedTools) obj.usedTools = JSON.parse(message.usedTools)
+ if (message.fileAnnotations) obj.fileAnnotations = JSON.parse(message.fileAnnotations)
return obj
})
setMessages((prevMessages) => [...prevMessages, ...loadedMessages])
@@ -352,10 +380,30 @@ export const ChatMessage = ({ open, chatflowid, isDialog }) => {
{message.message}
+ {message.fileAnnotations && (
+
+ {message.fileAnnotations.map((fileAnnotation, index) => {
+ return (
+
+ )
+ })}
+
+ )}
{message.sourceDocuments && (
{removeDuplicateURL(message).map((source, index) => {
- const URL = isValidURL(source.metadata.source)
+ const URL =
+ source.metadata && source.metadata.source
+ ? isValidURL(source.metadata.source)
+ : undefined
return (
{
const getAllCredentialsApi = useApi(credentialsApi.getAllCredentials)
const getAllComponentsCredentialsApi = useApi(credentialsApi.getAllComponentsCredentials)
+ const [search, setSearch] = useState('')
+ const onSearchChange = (event) => {
+ setSearch(event.target.value)
+ }
+ function filterCredentials(data) {
+ return data.credentialName.toLowerCase().indexOf(search.toLowerCase()) > -1
+ }
+
const listCredential = () => {
const dialogProp = {
title: 'Add New Credential',
@@ -168,17 +192,53 @@ const Credentials = () => {
<>
- Credentials
-
-
- }
- >
- Add Credential
-
+
+
+ Credentials
+
+
+
+ )
+ }}
+ />
+
+
+
+ }
+ >
+ Add Credential
+
+
+
+
+
{credentials.length <= 0 && (
@@ -205,7 +265,7 @@ const Credentials = () => {
- {credentials.map((credential, index) => (
+ {credentials.filter(filterCredentials).map((credential, index) => (