diff --git a/packages/ui/src/views/agentflowsv2/Canvas.jsx b/packages/ui/src/views/agentflowsv2/Canvas.jsx index 3a724666f94..bb76275ae36 100644 --- a/packages/ui/src/views/agentflowsv2/Canvas.jsx +++ b/packages/ui/src/views/agentflowsv2/Canvas.jsx @@ -31,6 +31,7 @@ import ConfirmDialog from '@/ui-component/dialog/ConfirmDialog' import EditNodeDialog from '@/views/agentflowsv2/EditNodeDialog' import ChatPopUp from '@/views/chatmessage/ChatPopUp' import ValidationPopUp from '@/views/chatmessage/ValidationPopUp' +import SaveChatflowDialog from '@/ui-component/dialog/SaveChatflowDialog' import { flowContext } from '@/store/context/ReactFlowContext' // API @@ -100,6 +101,7 @@ const AgentflowCanvas = () => { const [isSyncNodesButtonEnabled, setIsSyncNodesButtonEnabled] = useState(false) const [editNodeDialogOpen, setEditNodeDialogOpen] = useState(false) const [editNodeDialogProps, setEditNodeDialogProps] = useState({}) + const [flowDialogOpen, setFlowDialogOpen] = useState(false) const [isSnappingEnabled, setIsSnappingEnabled] = useState(false) const reactFlowWrapper = useRef(null) @@ -240,6 +242,15 @@ const AgentflowCanvas = () => { } } + const onConfirmSaveName = (flowName) => { + setFlowDialogOpen(false) + handleSaveFlow(flowName) + } + + const openSaveDialog = () => { + setFlowDialogOpen(true) + } + // eslint-disable-next-line const onNodeClick = useCallback((event, clickedNode) => { setSelectedNode(clickedNode) @@ -785,13 +796,28 @@ const AgentflowCanvas = () => { )} - + {!chatPopupOpen && } + setFlowDialogOpen(false)} + onConfirm={onConfirmSaveName} + /> ) diff --git a/packages/ui/src/views/canvas/index.jsx b/packages/ui/src/views/canvas/index.jsx index ebfbd0506fa..4027af6149f 100644 --- a/packages/ui/src/views/canvas/index.jsx +++ b/packages/ui/src/views/canvas/index.jsx @@ -24,6 +24,7 @@ import StickyNote from './StickyNote' import CanvasHeader from './CanvasHeader' import AddNodes from './AddNodes' import ConfirmDialog from '@/ui-component/dialog/ConfirmDialog' +import SaveChatflowDialog from '@/ui-component/dialog/SaveChatflowDialog' import ChatPopUp from '@/views/chatmessage/ChatPopUp' import VectorStorePopUp from '@/views/vectorstore/VectorStorePopUp' import { flowContext } from '@/store/context/ReactFlowContext' @@ -104,6 +105,7 @@ const Canvas = () => { const [lastUpdatedDateTime, setLasUpdatedDateTime] = useState('') const [chatflowName, setChatflowName] = useState('') const [flowData, setFlowData] = useState('') + const [flowDialogOpen, setFlowDialogOpen] = useState(false) // ==============================|| Chatflow API ||============================== // @@ -243,6 +245,16 @@ const Canvas = () => { } } + const openSaveDialog = () => { + if (chatflow?.id) { + // If chatflow has an ID, save directly using the flow name + handleSaveFlow(chatflow.name) + } else { + // If no ID, open the save dialog + setFlowDialogOpen(true) + } + } + // eslint-disable-next-line const onNodeClick = useCallback((event, clickedNode) => { setSelectedNode(clickedNode) @@ -431,7 +443,8 @@ const Canvas = () => { const chatflow = createNewChatflowApi.data dispatch({ type: SET_CHATFLOW, chatflow }) saveChatflowSuccess() - window.history.replaceState(state, null, `/${isAgentCanvas ? 'agentcanvas' : 'canvas'}/${chatflow.id}`) + setFlowDialogOpen(false) // Close the save dialog + navigate(`/${isAgentCanvas ? 'agentcanvas' : 'canvas'}/${chatflow.id}`) } else if (createNewChatflowApi.error) { errorFailed(`Failed to retrieve ${canvasTitle}: ${createNewChatflowApi.error.response.data.message}`) } @@ -645,12 +658,22 @@ const Canvas = () => { )} {isUpsertButtonEnabled && } - + + setFlowDialogOpen(false)} + onConfirm={(name) => handleSaveFlow(name)} + /> ) diff --git a/packages/ui/src/views/chatmessage/ChatMessage.jsx b/packages/ui/src/views/chatmessage/ChatMessage.jsx index b3eb5ed2718..cd8e9ec4509 100644 --- a/packages/ui/src/views/chatmessage/ChatMessage.jsx +++ b/packages/ui/src/views/chatmessage/ChatMessage.jsx @@ -38,7 +38,8 @@ import { IconSquareFilled, IconCheck, IconPaperclip, - IconSparkles + IconSparkles, + IconDeviceFloppy } from '@tabler/icons-react' import robotPNG from '@/assets/images/robot.png' import userPNG from '@/assets/images/account.png' @@ -162,7 +163,7 @@ CardWithDeleteOverlay.propTypes = { onDelete: PropTypes.func } -const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setPreviews }) => { +const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setPreviews, onOpenSaveDialog }) => { const theme = useTheme() const customization = useSelector((state) => state.customization) @@ -1672,6 +1673,43 @@ const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, previews, setP } } + // If no chatflowid and this is an agent canvas, show save prompt + if (!chatflowid) { + const handleSaveFlow = () => { + // Use the proper Flowise save dialog + if (onOpenSaveDialog) { + onOpenSaveDialog() + } + } + + return ( + + + + Save Flow to Continue + + + You need to save this {isAgentCanvas ? 'agent flow' : 'chatflow'} before you can test it with messages. + + + + ) + } + if (isConfigLoading) { return ( { +const ChatPopUp = ({ chatflowid, isAgentCanvas, onOpenChange, onOpenSaveDialog }) => { const theme = useTheme() const { confirm } = useConfirm() const dispatch = useDispatch() @@ -215,6 +215,7 @@ const ChatPopUp = ({ chatflowid, isAgentCanvas, onOpenChange }) => { open={open} previews={previews} setPreviews={setPreviews} + onOpenSaveDialog={onOpenSaveDialog} /> @@ -238,7 +239,8 @@ const ChatPopUp = ({ chatflowid, isAgentCanvas, onOpenChange }) => { ChatPopUp.propTypes = { chatflowid: PropTypes.string, isAgentCanvas: PropTypes.bool, - onOpenChange: PropTypes.func + onOpenChange: PropTypes.func, + onOpenSaveDialog: PropTypes.func } export default memo(ChatPopUp)