Files
Flowise/packages/ui/src/ui-component/table/FlowListTable.jsx
T
Zubair Khalid a7b4ae733f [FEATURE] Show time with date for last modified date for chatflow/agentflow/credentials/variables (#4300)
feat(ui): show time with date for last modified date for chatflow/agentflow/credentials/variables

Co-authored-by: coolpengwing <coolpengwing@gmail.com>
2025-04-16 00:14:22 +08:00

289 lines
15 KiB
React

import { useState } from 'react'
import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'
import moment from 'moment'
import { styled } from '@mui/material/styles'
import {
Box,
Chip,
Paper,
Skeleton,
Stack,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
TableSortLabel,
Tooltip,
Typography,
useTheme
} from '@mui/material'
import { tableCellClasses } from '@mui/material/TableCell'
import FlowListMenu from '../button/FlowListMenu'
import { Link } from 'react-router-dom'
const StyledTableCell = styled(TableCell)(({ theme }) => ({
borderColor: theme.palette.grey[900] + 25,
[`&.${tableCellClasses.head}`]: {
color: theme.palette.grey[900]
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14,
height: 64
}
}))
const StyledTableRow = styled(TableRow)(() => ({
// hide last border
'&:last-child td, &:last-child th': {
border: 0
}
}))
const getLocalStorageKeyName = (name, isAgentCanvas) => {
return (isAgentCanvas ? 'agentcanvas' : 'chatflowcanvas') + '_' + name
}
export const FlowListTable = ({ data, images, isLoading, filterFunction, updateFlowsApi, setError, isAgentCanvas }) => {
const theme = useTheme()
const customization = useSelector((state) => state.customization)
const localStorageKeyOrder = getLocalStorageKeyName('order', isAgentCanvas)
const localStorageKeyOrderBy = getLocalStorageKeyName('orderBy', isAgentCanvas)
const [order, setOrder] = useState(localStorage.getItem(localStorageKeyOrder) || 'desc')
const [orderBy, setOrderBy] = useState(localStorage.getItem(localStorageKeyOrderBy) || 'updatedDate')
const handleRequestSort = (property) => {
const isAsc = orderBy === property && order === 'asc'
const newOrder = isAsc ? 'desc' : 'asc'
setOrder(newOrder)
setOrderBy(property)
localStorage.setItem(localStorageKeyOrder, newOrder)
localStorage.setItem(localStorageKeyOrderBy, property)
}
const sortedData = data
? [...data].sort((a, b) => {
if (orderBy === 'name') {
return order === 'asc' ? (a.name || '').localeCompare(b.name || '') : (b.name || '').localeCompare(a.name || '')
} else if (orderBy === 'updatedDate') {
return order === 'asc'
? new Date(a.updatedDate) - new Date(b.updatedDate)
: new Date(b.updatedDate) - new Date(a.updatedDate)
}
return 0
})
: []
return (
<>
<TableContainer sx={{ border: 1, borderColor: theme.palette.grey[900] + 25, borderRadius: 2 }} component={Paper}>
<Table sx={{ minWidth: 650 }} size='small' aria-label='a dense table'>
<TableHead
sx={{
backgroundColor: customization.isDarkMode ? theme.palette.common.black : theme.palette.grey[100],
height: 56
}}
>
<TableRow>
<StyledTableCell component='th' scope='row' style={{ width: '20%' }} key='0'>
<TableSortLabel active={orderBy === 'name'} direction={order} onClick={() => handleRequestSort('name')}>
Name
</TableSortLabel>
</StyledTableCell>
<StyledTableCell style={{ width: '25%' }} key='1'>
Category
</StyledTableCell>
<StyledTableCell style={{ width: '30%' }} key='2'>
Nodes
</StyledTableCell>
<StyledTableCell style={{ width: '15%' }} key='3'>
<TableSortLabel
active={orderBy === 'updatedDate'}
direction={order}
onClick={() => handleRequestSort('updatedDate')}
>
Last Modified Date
</TableSortLabel>
</StyledTableCell>
<StyledTableCell style={{ width: '10%' }} key='4'>
Actions
</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{isLoading ? (
<>
<StyledTableRow>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
</StyledTableRow>
<StyledTableRow>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
<StyledTableCell>
<Skeleton variant='text' />
</StyledTableCell>
</StyledTableRow>
</>
) : (
<>
{sortedData.filter(filterFunction).map((row, index) => (
<StyledTableRow key={index}>
<StyledTableCell key='0'>
<Tooltip title={row.templateName || row.name}>
<Typography
sx={{
display: '-webkit-box',
fontSize: 14,
fontWeight: 500,
WebkitLineClamp: 2,
WebkitBoxOrient: 'vertical',
textOverflow: 'ellipsis',
overflow: 'hidden'
}}
>
<Link
to={`/${isAgentCanvas ? 'agentcanvas' : 'canvas'}/${row.id}`}
style={{ color: '#2196f3', textDecoration: 'none' }}
>
{row.templateName || row.name}
</Link>
</Typography>
</Tooltip>
</StyledTableCell>
<StyledTableCell key='1'>
<div
style={{
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
marginTop: 5
}}
>
&nbsp;
{row.category &&
row.category
.split(';')
.map((tag, index) => (
<Chip key={index} label={tag} style={{ marginRight: 5, marginBottom: 5 }} />
))}
</div>
</StyledTableCell>
<StyledTableCell key='2'>
{images[row.id] && (
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'start',
gap: 1
}}
>
{images[row.id]
.slice(0, images[row.id].length > 5 ? 5 : images[row.id].length)
.map((img) => (
<Box
key={img}
sx={{
width: 30,
height: 30,
borderRadius: '50%',
backgroundColor: customization.isDarkMode
? theme.palette.common.white
: theme.palette.grey[300] + 75
}}
>
<img
style={{
width: '100%',
height: '100%',
padding: 5,
objectFit: 'contain'
}}
alt=''
src={img}
/>
</Box>
))}
{images[row.id].length > 5 && (
<Typography
sx={{
alignItems: 'center',
display: 'flex',
fontSize: '.9rem',
fontWeight: 200
}}
>
+ {images[row.id].length - 5} More
</Typography>
)}
</Box>
)}
</StyledTableCell>
<StyledTableCell key='3'>
{moment(row.updatedDate).format('MMMM Do, YYYY HH:mm:ss')}
</StyledTableCell>
<StyledTableCell key='4'>
<Stack
direction={{ xs: 'column', sm: 'row' }}
spacing={1}
justifyContent='center'
alignItems='center'
>
<FlowListMenu
isAgentCanvas={isAgentCanvas}
chatflow={row}
setError={setError}
updateFlowsApi={updateFlowsApi}
/>
</Stack>
</StyledTableCell>
</StyledTableRow>
))}
</>
)}
</TableBody>
</Table>
</TableContainer>
</>
)
}
FlowListTable.propTypes = {
data: PropTypes.array,
images: PropTypes.object,
isLoading: PropTypes.bool,
filterFunction: PropTypes.func,
updateFlowsApi: PropTypes.object,
setError: PropTypes.func,
isAgentCanvas: PropTypes.bool
}