220 lines
9.0 KiB
JavaScript
220 lines
9.0 KiB
JavaScript
import { useEffect, useState } from 'react'
|
|
import { useNavigate } from 'react-router-dom'
|
|
import { useSelector } from 'react-redux'
|
|
|
|
// material-ui
|
|
import { Grid, Box, Stack, Toolbar, ToggleButton, ButtonGroup, InputAdornment, TextField } from '@mui/material'
|
|
import { useTheme } from '@mui/material/styles'
|
|
|
|
// project imports
|
|
import MainCard from '@/ui-component/cards/MainCard'
|
|
import ItemCard from '@/ui-component/cards/ItemCard'
|
|
import { gridSpacing } from '@/store/constant'
|
|
import WorkflowEmptySVG from '@/assets/images/workflow_empty.svg'
|
|
import LoginDialog from '@/ui-component/dialog/LoginDialog'
|
|
|
|
// API
|
|
import chatflowsApi from '@/api/chatflows'
|
|
|
|
// Hooks
|
|
import useApi from '@/hooks/useApi'
|
|
|
|
// const
|
|
import { baseURL } from '@/store/constant'
|
|
|
|
// icons
|
|
import { IconPlus, IconSearch, IconLayoutGrid, IconList } from '@tabler/icons'
|
|
import * as React from 'react'
|
|
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'
|
|
import { FlowListTable } from '../../ui-component/table/FlowListTable'
|
|
import { StyledButton } from '../../ui-component/button/StyledButton'
|
|
|
|
// ==============================|| CHATFLOWS ||============================== //
|
|
|
|
const Chatflows = () => {
|
|
const navigate = useNavigate()
|
|
const theme = useTheme()
|
|
const customization = useSelector((state) => state.customization)
|
|
|
|
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)
|
|
localStorage.setItem('password', password)
|
|
navigate(0)
|
|
}
|
|
|
|
const addNew = () => {
|
|
navigate('/canvas')
|
|
}
|
|
|
|
const goToCanvas = (selectedChatflow) => {
|
|
navigate(`/canvas/${selectedChatflow.id}`)
|
|
}
|
|
|
|
useEffect(() => {
|
|
getAllChatflowsApi.request()
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
if (getAllChatflowsApi.error) {
|
|
if (getAllChatflowsApi.error?.response?.status === 401) {
|
|
setLoginDialogProps({
|
|
title: 'Login',
|
|
confirmButtonName: 'Login'
|
|
})
|
|
setLoginDialogOpen(true)
|
|
}
|
|
}
|
|
}, [getAllChatflowsApi.error])
|
|
|
|
useEffect(() => {
|
|
setLoading(getAllChatflowsApi.loading)
|
|
}, [getAllChatflowsApi.loading])
|
|
|
|
useEffect(() => {
|
|
if (getAllChatflowsApi.data) {
|
|
try {
|
|
const chatflows = getAllChatflowsApi.data
|
|
const images = {}
|
|
for (let i = 0; i < chatflows.length; i += 1) {
|
|
const flowDataStr = chatflows[i].flowData
|
|
const flowData = JSON.parse(flowDataStr)
|
|
const nodes = flowData.nodes || []
|
|
images[chatflows[i].id] = []
|
|
for (let j = 0; j < nodes.length; j += 1) {
|
|
const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}`
|
|
if (!images[chatflows[i].id].includes(imageSrc)) {
|
|
images[chatflows[i].id].push(imageSrc)
|
|
}
|
|
}
|
|
}
|
|
setImages(images)
|
|
} catch (e) {
|
|
console.error(e)
|
|
}
|
|
}
|
|
}, [getAllChatflowsApi.data])
|
|
|
|
return (
|
|
<MainCard sx={{ background: customization.isDarkMode ? theme.palette.common.black : '' }}>
|
|
<Stack flexDirection='column'>
|
|
<Box sx={{ flexGrow: 1 }}>
|
|
<Toolbar
|
|
disableGutters={true}
|
|
style={{
|
|
margin: 1,
|
|
padding: 1,
|
|
paddingBottom: 10,
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
width: '100%'
|
|
}}
|
|
>
|
|
<h1>Chatflows</h1>
|
|
<TextField
|
|
size='small'
|
|
sx={{ display: { xs: 'none', sm: 'block' }, ml: 3 }}
|
|
variant='outlined'
|
|
placeholder='Search name or category'
|
|
onChange={onSearchChange}
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position='start'>
|
|
<IconSearch />
|
|
</InputAdornment>
|
|
)
|
|
}}
|
|
/>
|
|
<Box sx={{ flexGrow: 1 }} />
|
|
<ButtonGroup sx={{ maxHeight: 40 }} disableElevation variant='contained' aria-label='outlined primary button group'>
|
|
<ButtonGroup disableElevation variant='contained' aria-label='outlined primary button group'>
|
|
<ToggleButtonGroup sx={{ maxHeight: 40 }} value={view} color='primary' exclusive onChange={handleChange}>
|
|
<ToggleButton
|
|
sx={{ color: theme?.customization?.isDarkMode ? 'white' : 'inherit' }}
|
|
variant='contained'
|
|
value='card'
|
|
title='Card View'
|
|
selectedColor='#00abc0'
|
|
>
|
|
<IconLayoutGrid />
|
|
</ToggleButton>
|
|
<ToggleButton
|
|
sx={{ color: theme?.customization?.isDarkMode ? 'white' : 'inherit' }}
|
|
variant='contained'
|
|
value='list'
|
|
title='List View'
|
|
>
|
|
<IconList />
|
|
</ToggleButton>
|
|
</ToggleButtonGroup>
|
|
</ButtonGroup>
|
|
<Box sx={{ width: 5 }} />
|
|
<ButtonGroup disableElevation aria-label='outlined primary button group'>
|
|
<StyledButton variant='contained' onClick={addNew} startIcon={<IconPlus />}>
|
|
Add New
|
|
</StyledButton>
|
|
</ButtonGroup>
|
|
</ButtonGroup>
|
|
</Toolbar>
|
|
</Box>
|
|
{!isLoading && (!view || view === 'card') && getAllChatflowsApi.data && (
|
|
<Grid container spacing={gridSpacing}>
|
|
{getAllChatflowsApi.data.filter(filterFlows).map((data, index) => (
|
|
<Grid key={index} item lg={3} md={4} sm={6} xs={12}>
|
|
<ItemCard onClick={() => goToCanvas(data)} data={data} images={images[data.id]} />
|
|
</Grid>
|
|
))}
|
|
</Grid>
|
|
)}
|
|
{!isLoading && view === 'list' && getAllChatflowsApi.data && (
|
|
<FlowListTable
|
|
sx={{ mt: 20 }}
|
|
data={getAllChatflowsApi.data}
|
|
images={images}
|
|
filterFunction={filterFlows}
|
|
updateFlowsApi={getAllChatflowsApi}
|
|
/>
|
|
)}
|
|
</Stack>
|
|
|
|
{!isLoading && (!getAllChatflowsApi.data || getAllChatflowsApi.data.length === 0) && (
|
|
<Stack sx={{ alignItems: 'center', justifyContent: 'center' }} flexDirection='column'>
|
|
<Box sx={{ p: 2, height: 'auto' }}>
|
|
<img style={{ objectFit: 'cover', height: '30vh', width: 'auto' }} src={WorkflowEmptySVG} alt='WorkflowEmptySVG' />
|
|
</Box>
|
|
<div>No Chatflows Yet</div>
|
|
</Stack>
|
|
)}
|
|
<LoginDialog show={loginDialogOpen} dialogProps={loginDialogProps} onConfirm={onLoginClick} />
|
|
</MainCard>
|
|
)
|
|
}
|
|
|
|
export default Chatflows
|