Spaces:
Configuration error
Configuration error
| import PropTypes from 'prop-types' | |
| import { useNavigate } from 'react-router-dom' | |
| import { useSelector } from 'react-redux' | |
| import { useEffect, useRef, useState } from 'react' | |
| // material-ui | |
| import { useTheme } from '@mui/material/styles' | |
| import { Avatar, Box, ButtonBase, Typography, Stack, TextField } from '@mui/material' | |
| // icons | |
| import { IconSettings, IconChevronLeft, IconDeviceFloppy, IconPencil, IconCheck, IconX, IconCode } from '@tabler/icons' | |
| // project imports | |
| import Settings from 'views/settings' | |
| import SaveChatflowDialog from 'ui-component/dialog/SaveChatflowDialog' | |
| import APICodeDialog from 'ui-component/dialog/APICodeDialog' | |
| // API | |
| import chatflowsApi from 'api/chatflows' | |
| // Hooks | |
| import useApi from 'hooks/useApi' | |
| // utils | |
| import { generateExportFlowData } from 'utils/genericHelper' | |
| import { uiBaseURL } from 'store/constant' | |
| // ==============================|| CANVAS HEADER ||============================== // | |
| const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFlow }) => { | |
| const theme = useTheme() | |
| const navigate = useNavigate() | |
| const flowNameRef = useRef() | |
| const settingsRef = useRef() | |
| const [isEditingFlowName, setEditingFlowName] = useState(null) | |
| const [flowName, setFlowName] = useState('') | |
| const [isSettingsOpen, setSettingsOpen] = useState(false) | |
| const [flowDialogOpen, setFlowDialogOpen] = useState(false) | |
| const [apiDialogOpen, setAPIDialogOpen] = useState(false) | |
| const [apiDialogProps, setAPIDialogProps] = useState({}) | |
| const updateChatflowApi = useApi(chatflowsApi.updateChatflow) | |
| const canvas = useSelector((state) => state.canvas) | |
| const onSettingsItemClick = (setting) => { | |
| setSettingsOpen(false) | |
| if (setting === 'deleteChatflow') { | |
| handleDeleteFlow() | |
| } else if (setting === 'duplicateChatflow') { | |
| try { | |
| localStorage.setItem('duplicatedFlowData', chatflow.flowData) | |
| window.open(`${uiBaseURL}/canvas`, '_blank') | |
| } catch (e) { | |
| console.error(e) | |
| } | |
| } else if (setting === 'exportChatflow') { | |
| try { | |
| const flowData = JSON.parse(chatflow.flowData) | |
| let dataStr = JSON.stringify(generateExportFlowData(flowData)) | |
| let dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr) | |
| let exportFileDefaultName = `${chatflow.name} Chatflow.json` | |
| let linkElement = document.createElement('a') | |
| linkElement.setAttribute('href', dataUri) | |
| linkElement.setAttribute('download', exportFileDefaultName) | |
| linkElement.click() | |
| } catch (e) { | |
| console.error(e) | |
| } | |
| } | |
| } | |
| const onUploadFile = (file) => { | |
| setSettingsOpen(false) | |
| handleLoadFlow(file) | |
| } | |
| const submitFlowName = () => { | |
| if (chatflow.id) { | |
| const updateBody = { | |
| name: flowNameRef.current.value | |
| } | |
| updateChatflowApi.request(chatflow.id, updateBody) | |
| } | |
| } | |
| const onAPIDialogClick = () => { | |
| let isFormDataRequired = false | |
| try { | |
| const flowData = JSON.parse(chatflow.flowData) | |
| const nodes = flowData.nodes | |
| for (const node of nodes) { | |
| if (node.data.inputParams.find((param) => param.type === 'file')) { | |
| isFormDataRequired = true | |
| break | |
| } | |
| } | |
| } catch (e) { | |
| console.error(e) | |
| } | |
| setAPIDialogProps({ | |
| title: 'Embed in website or use as API', | |
| chatflowid: chatflow.id, | |
| chatflowApiKeyId: chatflow.apikeyid, | |
| isFormDataRequired | |
| }) | |
| setAPIDialogOpen(true) | |
| } | |
| const onSaveChatflowClick = () => { | |
| if (chatflow.id) handleSaveFlow(flowName) | |
| else setFlowDialogOpen(true) | |
| } | |
| const onConfirmSaveName = (flowName) => { | |
| setFlowDialogOpen(false) | |
| handleSaveFlow(flowName) | |
| } | |
| useEffect(() => { | |
| if (updateChatflowApi.data) { | |
| setFlowName(updateChatflowApi.data.name) | |
| } | |
| setEditingFlowName(false) | |
| // eslint-disable-next-line react-hooks/exhaustive-deps | |
| }, [updateChatflowApi.data]) | |
| useEffect(() => { | |
| if (chatflow) { | |
| setFlowName(chatflow.name) | |
| } | |
| }, [chatflow]) | |
| return ( | |
| <> | |
| <Box> | |
| <ButtonBase title='Back' sx={{ borderRadius: '50%' }}> | |
| <Avatar | |
| variant='rounded' | |
| sx={{ | |
| ...theme.typography.commonAvatar, | |
| ...theme.typography.mediumAvatar, | |
| transition: 'all .2s ease-in-out', | |
| background: theme.palette.secondary.light, | |
| color: theme.palette.secondary.dark, | |
| '&:hover': { | |
| background: theme.palette.secondary.dark, | |
| color: theme.palette.secondary.light | |
| } | |
| }} | |
| color='inherit' | |
| onClick={() => | |
| window.history.state && window.history.state.idx > 0 ? navigate(-1) : navigate('/', { replace: true }) | |
| } | |
| > | |
| <IconChevronLeft stroke={1.5} size='1.3rem' /> | |
| </Avatar> | |
| </ButtonBase> | |
| </Box> | |
| <Box sx={{ flexGrow: 1 }}> | |
| {!isEditingFlowName && ( | |
| <Stack flexDirection='row'> | |
| <Typography | |
| sx={{ | |
| fontSize: '1.5rem', | |
| fontWeight: 600, | |
| ml: 2 | |
| }} | |
| > | |
| {canvas.isDirty && <strong style={{ color: theme.palette.orange.main }}>*</strong>} {flowName} | |
| </Typography> | |
| {chatflow?.id && ( | |
| <ButtonBase title='Edit Name' sx={{ borderRadius: '50%' }}> | |
| <Avatar | |
| variant='rounded' | |
| sx={{ | |
| ...theme.typography.commonAvatar, | |
| ...theme.typography.mediumAvatar, | |
| transition: 'all .2s ease-in-out', | |
| ml: 1, | |
| background: theme.palette.secondary.light, | |
| color: theme.palette.secondary.dark, | |
| '&:hover': { | |
| background: theme.palette.secondary.dark, | |
| color: theme.palette.secondary.light | |
| } | |
| }} | |
| color='inherit' | |
| onClick={() => setEditingFlowName(true)} | |
| > | |
| <IconPencil stroke={1.5} size='1.3rem' /> | |
| </Avatar> | |
| </ButtonBase> | |
| )} | |
| </Stack> | |
| )} | |
| {isEditingFlowName && ( | |
| <Stack flexDirection='row'> | |
| <TextField | |
| size='small' | |
| inputRef={flowNameRef} | |
| sx={{ | |
| width: '50%', | |
| ml: 2 | |
| }} | |
| defaultValue={flowName} | |
| /> | |
| <ButtonBase title='Save Name' sx={{ borderRadius: '50%' }}> | |
| <Avatar | |
| variant='rounded' | |
| sx={{ | |
| ...theme.typography.commonAvatar, | |
| ...theme.typography.mediumAvatar, | |
| transition: 'all .2s ease-in-out', | |
| background: theme.palette.success.light, | |
| color: theme.palette.success.dark, | |
| ml: 1, | |
| '&:hover': { | |
| background: theme.palette.success.dark, | |
| color: theme.palette.success.light | |
| } | |
| }} | |
| color='inherit' | |
| onClick={submitFlowName} | |
| > | |
| <IconCheck stroke={1.5} size='1.3rem' /> | |
| </Avatar> | |
| </ButtonBase> | |
| <ButtonBase title='Cancel' sx={{ borderRadius: '50%' }}> | |
| <Avatar | |
| variant='rounded' | |
| sx={{ | |
| ...theme.typography.commonAvatar, | |
| ...theme.typography.mediumAvatar, | |
| transition: 'all .2s ease-in-out', | |
| background: theme.palette.error.light, | |
| color: theme.palette.error.dark, | |
| ml: 1, | |
| '&:hover': { | |
| background: theme.palette.error.dark, | |
| color: theme.palette.error.light | |
| } | |
| }} | |
| color='inherit' | |
| onClick={() => setEditingFlowName(false)} | |
| > | |
| <IconX stroke={1.5} size='1.3rem' /> | |
| </Avatar> | |
| </ButtonBase> | |
| </Stack> | |
| )} | |
| </Box> | |
| <Box> | |
| {chatflow?.id && ( | |
| <ButtonBase title='API Endpoint' sx={{ borderRadius: '50%', mr: 2 }}> | |
| <Avatar | |
| variant='rounded' | |
| sx={{ | |
| ...theme.typography.commonAvatar, | |
| ...theme.typography.mediumAvatar, | |
| transition: 'all .2s ease-in-out', | |
| background: theme.palette.canvasHeader.deployLight, | |
| color: theme.palette.canvasHeader.deployDark, | |
| '&:hover': { | |
| background: theme.palette.canvasHeader.deployDark, | |
| color: theme.palette.canvasHeader.deployLight | |
| } | |
| }} | |
| color='inherit' | |
| onClick={onAPIDialogClick} | |
| > | |
| <IconCode stroke={1.5} size='1.3rem' /> | |
| </Avatar> | |
| </ButtonBase> | |
| )} | |
| <ButtonBase title='Save Chatflow' sx={{ borderRadius: '50%', mr: 2 }}> | |
| <Avatar | |
| variant='rounded' | |
| sx={{ | |
| ...theme.typography.commonAvatar, | |
| ...theme.typography.mediumAvatar, | |
| transition: 'all .2s ease-in-out', | |
| background: theme.palette.canvasHeader.saveLight, | |
| color: theme.palette.canvasHeader.saveDark, | |
| '&:hover': { | |
| background: theme.palette.canvasHeader.saveDark, | |
| color: theme.palette.canvasHeader.saveLight | |
| } | |
| }} | |
| color='inherit' | |
| onClick={onSaveChatflowClick} | |
| > | |
| <IconDeviceFloppy stroke={1.5} size='1.3rem' /> | |
| </Avatar> | |
| </ButtonBase> | |
| <ButtonBase ref={settingsRef} title='Settings' sx={{ borderRadius: '50%' }}> | |
| <Avatar | |
| variant='rounded' | |
| sx={{ | |
| ...theme.typography.commonAvatar, | |
| ...theme.typography.mediumAvatar, | |
| transition: 'all .2s ease-in-out', | |
| background: theme.palette.canvasHeader.settingsLight, | |
| color: theme.palette.canvasHeader.settingsDark, | |
| '&:hover': { | |
| background: theme.palette.canvasHeader.settingsDark, | |
| color: theme.palette.canvasHeader.settingsLight | |
| } | |
| }} | |
| onClick={() => setSettingsOpen(!isSettingsOpen)} | |
| > | |
| <IconSettings stroke={1.5} size='1.3rem' /> | |
| </Avatar> | |
| </ButtonBase> | |
| </Box> | |
| <Settings | |
| chatflow={chatflow} | |
| isSettingsOpen={isSettingsOpen} | |
| anchorEl={settingsRef.current} | |
| onClose={() => setSettingsOpen(false)} | |
| onSettingsItemClick={onSettingsItemClick} | |
| onUploadFile={onUploadFile} | |
| /> | |
| <SaveChatflowDialog | |
| show={flowDialogOpen} | |
| dialogProps={{ | |
| title: `Save New Chatflow`, | |
| confirmButtonName: 'Save', | |
| cancelButtonName: 'Cancel' | |
| }} | |
| onCancel={() => setFlowDialogOpen(false)} | |
| onConfirm={onConfirmSaveName} | |
| /> | |
| <APICodeDialog show={apiDialogOpen} dialogProps={apiDialogProps} onCancel={() => setAPIDialogOpen(false)} /> | |
| </> | |
| ) | |
| } | |
| CanvasHeader.propTypes = { | |
| chatflow: PropTypes.object, | |
| handleSaveFlow: PropTypes.func, | |
| handleDeleteFlow: PropTypes.func, | |
| handleLoadFlow: PropTypes.func | |
| } | |
| export default CanvasHeader | |