UI Improvements (#1935)

* Update styles for dashboard page

* Fix grid in chatflows and marketplaces pages

* Update styles for main routes

* Create ViewHeader component and use it in chatflows and marketplace

* Use viewheader in all main routes views and make the styles consistent

* Update table styles for chatflow and marketplace views

* Update table and grid styles in all main routes views

* Make backgrounds, borders, and colors everywhere

* Apply text ellipsis for titles in cards and tables

* Update credentials list dialog styles

* Update tools dialog styles

* Update styles for inputs and dialogs

* Show skeleton loaders for main routes

* Apply text ellipsis to chatflow title in canvas page

* Update icons for load and export buttons in tools and assistants

* Fix issue where table header is shown when number of elements is zero

* Add error boundary component to main routes

* Capture errors from all requests in main routes

* Fix id for add api key and add variable buttons

* Fix missing th tag in variables table body
This commit is contained in:
Ilango
2024-04-08 11:15:42 +05:30
committed by GitHub
parent 19e14c4798
commit 19bb23440a
32 changed files with 2267 additions and 1662 deletions
@@ -72,7 +72,7 @@ const StyledMenu = styled((props) => (
}
}))
export default function FlowListMenu({ chatflow, updateFlowsApi }) {
export default function FlowListMenu({ chatflow, setError, updateFlowsApi }) {
const { confirm } = useConfirm()
const dispatch = useDispatch()
const updateChatflowApi = useApi(chatflowsApi.updateChatflow)
@@ -153,6 +153,7 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) {
await updateChatflowApi.request(chatflow.id, updateBody)
await updateFlowsApi.request()
} catch (error) {
setError(error)
enqueueSnackbar({
message: error.response.data.message,
options: {
@@ -191,6 +192,7 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) {
await updateChatflowApi.request(chatflow.id, updateBody)
await updateFlowsApi.request()
} catch (error) {
setError(error)
enqueueSnackbar({
message: error.response.data.message,
options: {
@@ -222,6 +224,7 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) {
await chatflowsApi.deleteChatflow(chatflow.id)
await updateFlowsApi.request()
} catch (error) {
setError(error)
enqueueSnackbar({
message: error.response.data.message,
options: {
@@ -370,5 +373,6 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) {
FlowListMenu.propTypes = {
chatflow: PropTypes.object,
setError: PropTypes.func,
updateFlowsApi: PropTypes.object
}
+97 -83
View File
@@ -1,12 +1,12 @@
import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'
// material-ui
import { styled } from '@mui/material/styles'
import { Box, Grid, Typography } from '@mui/material'
import { Box, Grid, Typography, useTheme } from '@mui/material'
// project imports
import MainCard from '@/ui-component/cards/MainCard'
import SkeletonChatflowCard from '@/ui-component/cards/Skeleton/ChatflowCard'
const CardWrapper = styled(MainCard)(({ theme }) => ({
background: theme.palette.card.main,
@@ -19,101 +19,115 @@ const CardWrapper = styled(MainCard)(({ theme }) => ({
background: theme.palette.card.hover,
boxShadow: '0 2px 14px 0 rgb(32 40 45 / 20%)'
},
height: '100%',
minHeight: '160px',
maxHeight: '300px',
maxWidth: '300px',
width: '100%',
overflowWrap: 'break-word',
whiteSpace: 'pre-line'
}))
// ===========================|| CONTRACT CARD ||=========================== //
const ItemCard = ({ isLoading, data, images, onClick }) => {
const ItemCard = ({ data, images, onClick }) => {
const theme = useTheme()
const customization = useSelector((state) => state.customization)
return (
<>
{isLoading ? (
<SkeletonChatflowCard />
) : (
<CardWrapper border={false} content={false} onClick={onClick}>
<Box sx={{ p: 2.25 }}>
<Grid container direction='column'>
<div
style={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center'
}}
>
{data.iconSrc && (
<div
style={{
width: 35,
height: 35,
marginRight: 10,
borderRadius: '50%',
background: `url(${data.iconSrc})`,
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center center'
}}
></div>
)}
{!data.iconSrc && data.color && (
<div
style={{
width: 35,
height: 35,
marginRight: 10,
borderRadius: '50%',
background: data.color
}}
></div>
)}
<Typography
sx={{ fontSize: '1.5rem', fontWeight: 500, overflowWrap: 'break-word', whiteSpace: 'pre-line' }}
>
{data.templateName || data.name}
</Typography>
</div>
{data.description && (
<span style={{ marginTop: 10, overflowWrap: 'break-word', whiteSpace: 'pre-line' }}>
{data.description}
</span>
)}
{images && (
<CardWrapper content={false} onClick={onClick} sx={{ border: 1, borderColor: theme.palette.grey[900] + 25, borderRadius: 2 }}>
<Box sx={{ height: '100%', p: 2.25 }}>
<Grid container justifyContent='space-between' direction='column' sx={{ height: '100%', gap: 3 }}>
<Box display='flex' flexDirection='column' sx={{ width: '100%' }}>
<div
style={{
width: '100%',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
overflow: 'hidden'
}}
>
{data.iconSrc && (
<div
style={{
width: 35,
height: 35,
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
marginTop: 5
flexShrink: 0,
marginRight: 10,
borderRadius: '50%',
background: `url(${data.iconSrc})`,
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center center'
}}
></div>
)}
{!data.iconSrc && data.color && (
<div
style={{
width: 35,
height: 35,
display: 'flex',
flexShrink: 0,
marginRight: 10,
borderRadius: '50%',
background: data.color
}}
></div>
)}
<Typography
sx={{
display: '-webkit-box',
fontSize: '1.25rem',
fontWeight: 500,
WebkitLineClamp: 2,
WebkitBoxOrient: 'vertical',
textOverflow: 'ellipsis',
overflow: 'hidden'
}}
>
{data.templateName || data.name}
</Typography>
</div>
{data.description && (
<span style={{ marginTop: 10, overflowWrap: 'break-word', whiteSpace: 'pre-line' }}>{data.description}</span>
)}
</Box>
{images && (
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'start',
gap: 1
}}
>
{images.slice(0, images.length > 3 ? 3 : images.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
}}
>
{images.map((img) => (
<div
key={img}
style={{
width: 35,
height: 35,
marginRight: 5,
borderRadius: '50%',
backgroundColor: 'white',
marginTop: 5
}}
>
<img
style={{ width: '100%', height: '100%', padding: 5, objectFit: 'contain' }}
alt=''
src={img}
/>
</div>
))}
</div>
<img style={{ width: '100%', height: '100%', padding: 5, objectFit: 'contain' }} alt='' src={img} />
</Box>
))}
{images.length > 3 && (
<Typography sx={{ alignItems: 'center', display: 'flex', fontSize: '.9rem', fontWeight: 200 }}>
+ {images.length - 3} More
</Typography>
)}
</Grid>
</Box>
</CardWrapper>
)}
</>
</Box>
)}
</Grid>
</Box>
</CardWrapper>
)
}
@@ -2,7 +2,6 @@ import PropTypes from 'prop-types'
import { forwardRef } from 'react'
// material-ui
import { useTheme } from '@mui/material/styles'
import { Card, CardContent, CardHeader, Divider, Typography } from '@mui/material'
// constant
@@ -14,12 +13,14 @@ const headerSX = {
const MainCard = forwardRef(function MainCard(
{
border = true,
boxShadow,
children,
content = true,
contentClass = '',
contentSX = {},
contentSX = {
px: 2,
py: 0
},
darkTitle,
secondary,
shadow,
@@ -29,18 +30,17 @@ const MainCard = forwardRef(function MainCard(
},
ref
) {
const theme = useTheme()
return (
<Card
ref={ref}
{...others}
sx={{
border: border ? '1px solid' : 'none',
borderColor: theme.palette.primary[200] + 75,
background: 'transparent',
':hover': {
boxShadow: boxShadow ? shadow || '0 2px 14px 0 rgb(32 40 45 / 8%)' : 'inherit'
},
maxWidth: '1280px',
mx: 'auto',
...sx
}}
>
@@ -114,7 +114,7 @@ export const AsyncDropdown = ({
disabled={disabled}
disableClearable={disableClearable}
size='small'
sx={{ width: '100%' }}
sx={{ width: '100%', height: '52px' }}
open={open}
onOpen={() => {
setOpen(true)
@@ -148,6 +148,7 @@ export const AsyncDropdown = ({
</Fragment>
)
}}
sx={{ height: '100%', '& .MuiInputBase-root': { height: '100%' } }}
/>
)}
renderOption={(props, option) => (
@@ -25,7 +25,7 @@ export const Dropdown = ({ name, value, options, onSelect, disabled = false, dis
let [internalValue, setInternalValue] = useState(value ?? 'choose an option')
return (
<FormControl sx={{ mt: 1, width: '100%' }} size='small'>
<FormControl sx={{ width: '100%', height: '52px' }} size='small'>
<Autocomplete
id={name}
disabled={disabled}
@@ -39,7 +39,9 @@ export const Dropdown = ({ name, value, options, onSelect, disabled = false, dis
onSelect(value)
}}
PopperComponent={StyledPopper}
renderInput={(params) => <TextField {...params} value={internalValue} />}
renderInput={(params) => (
<TextField {...params} value={internalValue} sx={{ height: '100%', '& .MuiInputBase-root': { height: '100%' } }} />
)}
renderOption={(props, option) => (
<Box component='li' {...props}>
<div style={{ display: 'flex', flexDirection: 'column' }}>
@@ -50,6 +52,7 @@ export const Dropdown = ({ name, value, options, onSelect, disabled = false, dis
</div>
</Box>
)}
sx={{ height: '100%' }}
/>
</FormControl>
)
@@ -30,7 +30,7 @@ export const MultiDropdown = ({ name, value, options, onSelect, formControlSx =
let [internalValue, setInternalValue] = useState(value ?? [])
return (
<FormControl sx={{ mt: 1, width: '100%', ...formControlSx }} size='small'>
<FormControl sx={{ width: '100%', height: '52px', ...formControlSx }} size='small'>
<Autocomplete
id={name}
disabled={disabled}
@@ -53,7 +53,9 @@ export const MultiDropdown = ({ name, value, options, onSelect, formControlSx =
onSelect(value)
}}
PopperComponent={StyledPopper}
renderInput={(params) => <TextField {...params} value={internalValue} />}
renderInput={(params) => (
<TextField {...params} value={internalValue} sx={{ height: '100%', '& .MuiInputBase-root': { height: '100%' } }} />
)}
renderOption={(props, option) => (
<Box component='li' {...props}>
<div style={{ display: 'flex', flexDirection: 'column' }}>
@@ -64,6 +66,7 @@ export const MultiDropdown = ({ name, value, options, onSelect, formControlSx =
</div>
</Box>
)}
sx={{ height: '100%' }}
/>
</FormControl>
)
+1 -9
View File
@@ -1,9 +1,7 @@
import PropTypes from 'prop-types'
import { DataGrid } from '@mui/x-data-grid'
import { IconPlus } from '@tabler/icons'
import { Button } from '@mui/material'
export const Grid = ({ columns, rows, style, disabled = false, onRowUpdate, addNewRow }) => {
export const Grid = ({ columns, rows, style, disabled = false, onRowUpdate }) => {
const handleProcessRowUpdate = (newRow) => {
onRowUpdate(newRow)
return newRow
@@ -11,11 +9,6 @@ export const Grid = ({ columns, rows, style, disabled = false, onRowUpdate, addN
return (
<>
{!disabled && (
<Button variant='outlined' onClick={addNewRow} startIcon={<IconPlus />}>
Add Item
</Button>
)}
{rows && columns && (
<div style={{ marginTop: 10, height: 300, width: '100%', ...style }}>
<DataGrid
@@ -38,6 +31,5 @@ Grid.propTypes = {
columns: PropTypes.array,
style: PropTypes.any,
disabled: PropTypes.bool,
addNewRow: PropTypes.func,
onRowUpdate: PropTypes.func
}
@@ -1,50 +1,61 @@
import PropTypes from 'prop-types'
import { useNavigate } from 'react-router-dom'
import { useSelector } from 'react-redux'
import moment from 'moment'
import { styled } from '@mui/material/styles'
import Table from '@mui/material/Table'
import TableBody from '@mui/material/TableBody'
import TableCell, { tableCellClasses } from '@mui/material/TableCell'
import TableContainer from '@mui/material/TableContainer'
import TableHead from '@mui/material/TableHead'
import TableRow from '@mui/material/TableRow'
import Paper from '@mui/material/Paper'
import Chip from '@mui/material/Chip'
import { Button, Stack, Typography } from '@mui/material'
import {
Box,
Chip,
Paper,
Skeleton,
Stack,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
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}`]: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white
color: theme.palette.grey[900]
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14
fontSize: 14,
height: 64
}
}))
const StyledTableRow = styled(TableRow)(({ theme }) => ({
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.action.hover
},
const StyledTableRow = styled(TableRow)(() => ({
// hide last border
'&:last-child td, &:last-child th': {
border: 0
}
}))
export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi }) => {
const navigate = useNavigate()
const goToCanvas = (selectedChatflow) => {
navigate(`/canvas/${selectedChatflow.id}`)
}
export const FlowListTable = ({ data, images, isLoading, filterFunction, updateFlowsApi, setError }) => {
const theme = useTheme()
const customization = useSelector((state) => state.customization)
return (
<>
<TableContainer style={{ marginTop: '30', border: 1 }} component={Paper}>
<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>
<TableRow sx={{ marginTop: '10', backgroundColor: 'primary' }}>
<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'>
Name
</StyledTableCell>
@@ -63,82 +74,150 @@ export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi })
</TableRow>
</TableHead>
<TableBody>
{data.filter(filterFunction).map((row, index) => (
<StyledTableRow key={index}>
<TableCell key='0'>
<Typography
sx={{ fontSize: '1.2rem', fontWeight: 500, overflowWrap: 'break-word', whiteSpace: 'pre-line' }}
>
<Button onClick={() => goToCanvas(row)} sx={{ textAlign: 'left' }}>
{row.templateName || row.name}
</Button>
</Typography>
</TableCell>
<TableCell 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>
</TableCell>
<TableCell key='2'>
{images[row.id] && (
<div
style={{
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
marginTop: 5
}}
>
{images[row.id].slice(0, images[row.id].length > 5 ? 5 : images[row.id].length).map((img) => (
<div
key={img}
style={{
width: 35,
height: 35,
marginRight: 5,
borderRadius: '50%',
backgroundColor: 'white',
marginTop: 5
{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>
</>
) : (
<>
{data?.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'
}}
>
<img
style={{ width: '100%', height: '100%', padding: 5, objectFit: 'contain' }}
alt=''
src={img}
/>
</div>
))}
{images[row.id].length > 5 && (
<Typography
sx={{ alignItems: 'center', display: 'flex', fontSize: '.8rem', fontWeight: 200 }}
>
+ {images[row.id].length - 5} More
<Link to={`/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>
)}
</div>
)}
</TableCell>
<TableCell key='3'>{moment(row.updatedDate).format('MMMM Do, YYYY')}</TableCell>
<TableCell key='4'>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={1} justifyContent='center' alignItems='center'>
<FlowListMenu chatflow={row} updateFlowsApi={updateFlowsApi} />
</Stack>
</TableCell>
</StyledTableRow>
))}
</StyledTableCell>
<StyledTableCell key='3'>{moment(row.updatedDate).format('MMMM Do, YYYY')}</StyledTableCell>
<StyledTableCell key='4'>
<Stack
direction={{ xs: 'column', sm: 'row' }}
spacing={1}
justifyContent='center'
alignItems='center'
>
<FlowListMenu chatflow={row} setError={setError} updateFlowsApi={updateFlowsApi} />
</Stack>
</StyledTableCell>
</StyledTableRow>
))}
</>
)}
</TableBody>
</Table>
</TableContainer>
@@ -149,6 +228,8 @@ export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi })
FlowListTable.propTypes = {
data: PropTypes.array,
images: PropTypes.object,
isLoading: PropTypes.bool,
filterFunction: PropTypes.func,
updateFlowsApi: PropTypes.object
updateFlowsApi: PropTypes.object,
setError: PropTypes.func
}
@@ -1,36 +1,54 @@
import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'
import { styled } from '@mui/material/styles'
import Table from '@mui/material/Table'
import TableBody from '@mui/material/TableBody'
import TableCell, { tableCellClasses } from '@mui/material/TableCell'
import TableContainer from '@mui/material/TableContainer'
import TableHead from '@mui/material/TableHead'
import TableRow from '@mui/material/TableRow'
import Paper from '@mui/material/Paper'
import Chip from '@mui/material/Chip'
import { Button, Typography } from '@mui/material'
import { tableCellClasses } from '@mui/material/TableCell'
import {
Button,
Chip,
Paper,
Skeleton,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
useTheme
} from '@mui/material'
const StyledTableCell = styled(TableCell)(({ theme }) => ({
borderColor: theme.palette.grey[900] + 25,
[`&.${tableCellClasses.head}`]: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white
color: theme.palette.grey[900]
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14
fontSize: 14,
height: 64
}
}))
const StyledTableRow = styled(TableRow)(({ theme }) => ({
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.action.hover
},
const StyledTableRow = styled(TableRow)(() => ({
// hide last border
'&:last-child td, &:last-child th': {
border: 0
}
}))
export const MarketplaceTable = ({ data, filterFunction, filterByBadge, filterByType, filterByFramework, goToCanvas, goToTool }) => {
export const MarketplaceTable = ({
data,
filterFunction,
filterByBadge,
filterByType,
filterByFramework,
goToCanvas,
goToTool,
isLoading
}) => {
const theme = useTheme()
const customization = useSelector((state) => state.customization)
const openTemplate = (selectedTemplate) => {
if (selectedTemplate.flowData) {
goToCanvas(selectedTemplate)
@@ -41,10 +59,15 @@ export const MarketplaceTable = ({ data, filterFunction, filterByBadge, filterBy
return (
<>
<TableContainer style={{ marginTop: '30', border: 1 }} component={Paper}>
<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>
<TableRow sx={{ marginTop: '10', backgroundColor: 'primary' }}>
<TableHead
sx={{
backgroundColor: customization.isDarkMode ? theme.palette.common.black : theme.palette.grey[100],
height: 56
}}
>
<TableRow>
<StyledTableCell component='th' scope='row' style={{ width: '15%' }} key='0'>
Name
</StyledTableCell>
@@ -63,71 +86,120 @@ export const MarketplaceTable = ({ data, filterFunction, filterByBadge, filterBy
</TableRow>
</TableHead>
<TableBody>
{data
.filter(filterByBadge)
.filter(filterByType)
.filter(filterFunction)
.filter(filterByFramework)
.map((row, index) => (
<StyledTableRow key={index}>
<TableCell key='0'>
<Typography
sx={{ fontSize: '1.2rem', fontWeight: 500, overflowWrap: 'break-word', whiteSpace: 'pre-line' }}
>
<Button onClick={() => openTemplate(row)} sx={{ textAlign: 'left' }}>
{row.templateName || row.name}
</Button>
</Typography>
</TableCell>
<TableCell key='1'>
<Typography>{row.type}</Typography>
</TableCell>
<TableCell key='2'>
<Typography sx={{ overflowWrap: 'break-word', whiteSpace: 'pre-line' }}>
{row.description || ''}
</Typography>
</TableCell>
<TableCell key='3'>
<div
style={{
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
marginTop: 5
}}
>
{row.categories &&
row.categories
.split(',')
.map((tag, index) => (
<Chip
variant='outlined'
key={index}
size='small'
label={tag.toUpperCase()}
style={{ marginRight: 3, marginBottom: 3 }}
/>
))}
</div>
</TableCell>
<TableCell key='4'>
<Typography>
{row.badge &&
row.badge
.split(';')
.map((tag, index) => (
<Chip
color={tag === 'POPULAR' ? 'primary' : 'error'}
key={index}
size='small'
label={tag.toUpperCase()}
style={{ marginRight: 5, marginBottom: 5 }}
/>
))}
</Typography>
</TableCell>
{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>
</>
) : (
<>
{data
?.filter(filterByBadge)
.filter(filterByType)
.filter(filterFunction)
.filter(filterByFramework)
.map((row, index) => (
<StyledTableRow key={index}>
<StyledTableCell key='0'>
<Typography
sx={{
display: '-webkit-box',
fontSize: 14,
fontWeight: 500,
WebkitLineClamp: 2,
WebkitBoxOrient: 'vertical',
textOverflow: 'ellipsis',
overflow: 'hidden'
}}
>
<Button onClick={() => openTemplate(row)} sx={{ textAlign: 'left' }}>
{row.templateName || row.name}
</Button>
</Typography>
</StyledTableCell>
<StyledTableCell key='1'>
<Typography>{row.type}</Typography>
</StyledTableCell>
<StyledTableCell key='2'>
<Typography sx={{ overflowWrap: 'break-word', whiteSpace: 'pre-line' }}>
{row.description || ''}
</Typography>
</StyledTableCell>
<StyledTableCell key='3'>
<div
style={{
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
marginTop: 5
}}
>
{row.categories &&
row.categories
.split(',')
.map((tag, index) => (
<Chip
variant='outlined'
key={index}
size='small'
label={tag.toUpperCase()}
style={{ marginRight: 3, marginBottom: 3 }}
/>
))}
</div>
</StyledTableCell>
<StyledTableCell key='4'>
<Typography>
{row.badge &&
row.badge
.split(';')
.map((tag, index) => (
<Chip
color={tag === 'POPULAR' ? 'primary' : 'error'}
key={index}
size='small'
label={tag.toUpperCase()}
style={{ marginRight: 5, marginBottom: 5 }}
/>
))}
</Typography>
</StyledTableCell>
</StyledTableRow>
))}
</>
)}
</TableBody>
</Table>
</TableContainer>
@@ -142,5 +214,6 @@ MarketplaceTable.propTypes = {
filterByType: PropTypes.func,
filterByFramework: PropTypes.func,
goToTool: PropTypes.func,
goToCanvas: PropTypes.func
goToCanvas: PropTypes.func,
isLoading: PropTypes.bool
}
@@ -4,15 +4,15 @@ import parser from 'html-react-parser'
import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'
export const TooltipWithParser = ({ title, style }) => {
export const TooltipWithParser = ({ title, sx }) => {
const customization = useSelector((state) => state.customization)
return (
<Tooltip title={parser(title)} placement='right'>
<IconButton sx={{ height: 15, width: 15 }}>
<IconButton sx={{ height: 15, width: 15, ml: 2, mt: -0.5 }}>
<Info
style={{
...style,
sx={{
...sx,
background: 'transparent',
color: customization.isDarkMode ? 'white' : 'inherit',
height: 15,
@@ -26,5 +26,5 @@ export const TooltipWithParser = ({ title, style }) => {
TooltipWithParser.propTypes = {
title: PropTypes.node,
style: PropTypes.any
sx: PropTypes.any
}