mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 09:00:52 +03:00
Marketplace: Adding filters and a collapsible panel show/hide
This commit is contained in:
@@ -10,6 +10,8 @@ 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 langchainPNG from 'assets/images/langchain.png'
|
||||
import llamaIndexPNG from 'assets/images/llamaindex.png'
|
||||
|
||||
const StyledTableCell = styled(TableCell)(({ theme }) => ({
|
||||
[`&.${tableCellClasses.head}`]: {
|
||||
@@ -31,7 +33,7 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({
|
||||
}
|
||||
}))
|
||||
|
||||
export const MarketplaceTable = ({ data, images, filterFunction, filterByBadge, filterByType }) => {
|
||||
export const MarketplaceTable = ({ data, filterFunction, filterByBadge, filterByType, filterByFramework }) => {
|
||||
const navigate = useNavigate()
|
||||
const openTemplate = (selectedTemplate) => {
|
||||
if (selectedTemplate.flowData) {
|
||||
@@ -61,10 +63,13 @@ export const MarketplaceTable = ({ data, images, filterFunction, filterByBadge,
|
||||
<Table sx={{ minWidth: 650 }} size='small' aria-label='a dense table'>
|
||||
<TableHead>
|
||||
<TableRow sx={{ marginTop: '10', backgroundColor: 'primary' }}>
|
||||
<StyledTableCell component='th' scope='row' style={{ width: '5%' }} key='0'>
|
||||
{''}
|
||||
</StyledTableCell>
|
||||
<StyledTableCell component='th' scope='row' style={{ width: '15%' }} key='0'>
|
||||
Name
|
||||
</StyledTableCell>
|
||||
<StyledTableCell component='th' scope='row' style={{ width: '10%' }} key='1'>
|
||||
<StyledTableCell component='th' scope='row' style={{ width: '5%' }} key='1'>
|
||||
Type
|
||||
</StyledTableCell>
|
||||
<StyledTableCell style={{ width: '35%' }} key='2'>
|
||||
@@ -83,9 +88,20 @@ export const MarketplaceTable = ({ data, images, filterFunction, filterByBadge,
|
||||
.filter(filterByBadge)
|
||||
.filter(filterByType)
|
||||
.filter(filterFunction)
|
||||
.filter(filterByFramework)
|
||||
.map((row, index) => (
|
||||
<StyledTableRow key={index}>
|
||||
<TableCell key='0'>
|
||||
<Typography>
|
||||
{row.framework === 'Langchain' && (
|
||||
<img src={langchainPNG} alt='langchain' style={{ width: 30, height: 30 }} />
|
||||
)}
|
||||
{row.framework === 'LlamaIndex' && (
|
||||
<img src={llamaIndexPNG} alt='llamaIndex' style={{ width: 30, height: 30 }} />
|
||||
)}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell key='1'>
|
||||
<Typography
|
||||
sx={{ fontSize: '1.2rem', fontWeight: 500, overflowWrap: 'break-word', whiteSpace: 'pre-line' }}
|
||||
>
|
||||
@@ -94,15 +110,15 @@ export const MarketplaceTable = ({ data, images, filterFunction, filterByBadge,
|
||||
</Button>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell key='1'>
|
||||
<TableCell key='2'>
|
||||
<Typography>{row.type}</Typography>
|
||||
</TableCell>
|
||||
<TableCell key='1'>
|
||||
<TableCell key='3'>
|
||||
<Typography sx={{ overflowWrap: 'break-word', whiteSpace: 'pre-line' }}>
|
||||
{row.description || ''}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell key='2'>
|
||||
<TableCell key='4'>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
@@ -125,7 +141,7 @@ export const MarketplaceTable = ({ data, images, filterFunction, filterByBadge,
|
||||
))}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell key='3'>
|
||||
<TableCell key='5'>
|
||||
<Typography>
|
||||
{row.badge &&
|
||||
row.badge
|
||||
@@ -152,8 +168,8 @@ export const MarketplaceTable = ({ data, images, filterFunction, filterByBadge,
|
||||
|
||||
MarketplaceTable.propTypes = {
|
||||
data: PropTypes.array,
|
||||
images: PropTypes.object,
|
||||
filterFunction: PropTypes.func,
|
||||
filterByBadge: PropTypes.func,
|
||||
filterByType: PropTypes.func
|
||||
filterByType: PropTypes.func,
|
||||
filterByFramework: PropTypes.func
|
||||
}
|
||||
|
||||
@@ -19,10 +19,11 @@ import {
|
||||
Select,
|
||||
OutlinedInput,
|
||||
Checkbox,
|
||||
ListItemText
|
||||
ListItemText,
|
||||
Button
|
||||
} from '@mui/material'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
import { IconLayoutGrid, IconList, IconSearch } from '@tabler/icons'
|
||||
import { IconChevronsDown, IconChevronsUp, IconLayoutGrid, IconList, IconSearch } from '@tabler/icons'
|
||||
|
||||
// project imports
|
||||
import MainCard from 'ui-component/cards/MainCard'
|
||||
@@ -69,6 +70,7 @@ const ITEM_HEIGHT = 48
|
||||
const ITEM_PADDING_TOP = 8
|
||||
const badges = ['POPULAR', 'NEW']
|
||||
const types = ['Chatflow', 'Tool']
|
||||
const framework = ['Langchain', 'LlamaIndex']
|
||||
const MenuProps = {
|
||||
PaperProps: {
|
||||
style: {
|
||||
@@ -98,7 +100,8 @@ const Marketplace = () => {
|
||||
|
||||
const [badgeFilter, setBadgeFilter] = useState([])
|
||||
const [typeFilter, setTypeFilter] = useState([])
|
||||
|
||||
const [frameworkFilter, setFrameworkFilter] = useState([])
|
||||
const [open, setOpen] = useState(false)
|
||||
const handleBadgeFilterChange = (event) => {
|
||||
const {
|
||||
target: { value }
|
||||
@@ -117,6 +120,15 @@ const Marketplace = () => {
|
||||
typeof value === 'string' ? value.split(',') : value
|
||||
)
|
||||
}
|
||||
const handleFrameworkFilterChange = (event) => {
|
||||
const {
|
||||
target: { value }
|
||||
} = event
|
||||
setFrameworkFilter(
|
||||
// On autofill we get a stringified value.
|
||||
typeof value === 'string' ? value.split(',') : value
|
||||
)
|
||||
}
|
||||
|
||||
const handleViewChange = (event, nextView) => {
|
||||
localStorage.setItem('mpDisplayStyle', nextView)
|
||||
@@ -143,6 +155,10 @@ const Marketplace = () => {
|
||||
return typeFilter.length > 0 ? typeFilter.includes(data.type) : true
|
||||
}
|
||||
|
||||
function filterByFramework(data) {
|
||||
return frameworkFilter.length > 0 ? frameworkFilter.includes(data.framework) : true
|
||||
}
|
||||
|
||||
const onUseTemplate = (selectedTool) => {
|
||||
const dialogProp = {
|
||||
title: 'Add New Tool',
|
||||
@@ -224,9 +240,11 @@ const Marketplace = () => {
|
||||
<h1>Marketplace</h1>
|
||||
<TextField
|
||||
size='small'
|
||||
id='search-filter-textbox'
|
||||
sx={{ display: { xs: 'none', sm: 'block' }, ml: 3 }}
|
||||
variant='outlined'
|
||||
placeholder='Search name or description'
|
||||
fullWidth='true'
|
||||
placeholder='Search name or description or node name'
|
||||
onChange={onSearchChange}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
@@ -236,52 +254,14 @@ const Marketplace = () => {
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<FormControl sx={{ m: 1, width: 300 }}>
|
||||
<InputLabel size='small' id='type-badge'>
|
||||
Type
|
||||
</InputLabel>
|
||||
<Select
|
||||
size='small'
|
||||
labelId='type-badge-checkbox-label'
|
||||
id='type-badge-checkbox'
|
||||
multiple
|
||||
value={typeFilter}
|
||||
onChange={handleTypeFilterChange}
|
||||
input={<OutlinedInput label='Badge' />}
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
MenuProps={MenuProps}
|
||||
>
|
||||
{types.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
<Checkbox checked={typeFilter.indexOf(name) > -1} />
|
||||
<ListItemText primary={name} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl sx={{ m: 1, width: 300 }}>
|
||||
<InputLabel size='small' id='filter-badge'>
|
||||
Tag
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId='filter-badge-label'
|
||||
id='filter-badge-checkbox'
|
||||
size='small'
|
||||
multiple
|
||||
value={badgeFilter}
|
||||
onChange={handleBadgeFilterChange}
|
||||
input={<OutlinedInput label='Badge' />}
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
MenuProps={MenuProps}
|
||||
>
|
||||
{badges.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
<Checkbox checked={badgeFilter.indexOf(name) > -1} />
|
||||
<ListItemText primary={name} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
sx={{ width: '220px', ml: 3, mr: 5 }}
|
||||
variant='outlined'
|
||||
onClick={() => setOpen(!open)}
|
||||
startIcon={open ? <IconChevronsUp /> : <IconChevronsDown />}
|
||||
>
|
||||
{open ? 'Hide Filters' : 'Show Filters'}
|
||||
</Button>
|
||||
<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'>
|
||||
@@ -313,6 +293,93 @@ const Marketplace = () => {
|
||||
</ButtonGroup>
|
||||
</Toolbar>
|
||||
</Box>
|
||||
{open && (
|
||||
<Box sx={{ flexGrow: 1, mb: 2 }}>
|
||||
<Toolbar
|
||||
disableGutters={true}
|
||||
style={{
|
||||
margin: 1,
|
||||
padding: 1,
|
||||
paddingBottom: 10,
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-start',
|
||||
width: '100%',
|
||||
borderBottom: '1px solid'
|
||||
}}
|
||||
>
|
||||
<FormControl sx={{ m: 1, width: 250 }}>
|
||||
<InputLabel size='small' id='filter-badge-label'>
|
||||
Tag
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId='filter-badge-label'
|
||||
id='filter-badge-checkbox'
|
||||
size='small'
|
||||
multiple
|
||||
value={badgeFilter}
|
||||
onChange={handleBadgeFilterChange}
|
||||
input={<OutlinedInput label='Badge' />}
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
MenuProps={MenuProps}
|
||||
>
|
||||
{badges.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
<Checkbox checked={badgeFilter.indexOf(name) > -1} />
|
||||
<ListItemText primary={name} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl sx={{ m: 1, width: 250 }}>
|
||||
<InputLabel size='small' id='type-badge-label'>
|
||||
Type
|
||||
</InputLabel>
|
||||
<Select
|
||||
size='small'
|
||||
labelId='type-badge-label'
|
||||
id='type-badge-checkbox'
|
||||
multiple
|
||||
value={typeFilter}
|
||||
onChange={handleTypeFilterChange}
|
||||
input={<OutlinedInput label='Badge' />}
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
MenuProps={MenuProps}
|
||||
>
|
||||
{types.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
<Checkbox checked={typeFilter.indexOf(name) > -1} />
|
||||
<ListItemText primary={name} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl sx={{ m: 1, width: 250 }}>
|
||||
<InputLabel size='small' id='type-fw-label'>
|
||||
Framework
|
||||
</InputLabel>
|
||||
<Select
|
||||
size='small'
|
||||
labelId='type-fw-label'
|
||||
id='type-fw-checkbox'
|
||||
multiple
|
||||
value={frameworkFilter}
|
||||
onChange={handleFrameworkFilterChange}
|
||||
input={<OutlinedInput label='Badge' />}
|
||||
renderValue={(selected) => selected.join(', ')}
|
||||
MenuProps={MenuProps}
|
||||
>
|
||||
{framework.map((name) => (
|
||||
<MenuItem key={name} value={name}>
|
||||
<Checkbox checked={frameworkFilter.indexOf(name) > -1} />
|
||||
<ListItemText primary={name} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Toolbar>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!isLoading && (!view || view === 'card') && getAllTemplatesMarketplacesApi.data && (
|
||||
<>
|
||||
<Grid container spacing={gridSpacing}>
|
||||
@@ -320,6 +387,7 @@ const Marketplace = () => {
|
||||
.filter(filterByBadge)
|
||||
.filter(filterByType)
|
||||
.filter(filterFlows)
|
||||
.filter(filterByFramework)
|
||||
.map((data, index) => (
|
||||
<Grid key={index} item lg={3} md={4} sm={6} xs={12}>
|
||||
{data.badge && (
|
||||
@@ -351,10 +419,10 @@ const Marketplace = () => {
|
||||
<MarketplaceTable
|
||||
sx={{ mt: 20 }}
|
||||
data={getAllTemplatesMarketplacesApi.data}
|
||||
images={images}
|
||||
filterFunction={filterFlows}
|
||||
filterByType={filterByType}
|
||||
filterByBadge={filterByBadge}
|
||||
filterByFramework={filterByFramework}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user