mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-29 09:01:06 +03:00
Feature: add tooltip display on icon hover in chatflows and marketplace page (#4428)
* feat: add tooltip display on icon hover in chatflows and marketplace page * update list view, remove sticky note images --------- Co-authored-by: Henry <hzj94@hotmail.com>
This commit is contained in:
@@ -3,10 +3,11 @@ import { useSelector } from 'react-redux'
|
|||||||
|
|
||||||
// material-ui
|
// material-ui
|
||||||
import { styled } from '@mui/material/styles'
|
import { styled } from '@mui/material/styles'
|
||||||
import { Box, Grid, Typography, useTheme } from '@mui/material'
|
import { Box, Grid, Tooltip, Typography, useTheme } from '@mui/material'
|
||||||
|
|
||||||
// project imports
|
// project imports
|
||||||
import MainCard from '@/ui-component/cards/MainCard'
|
import MainCard from '@/ui-component/cards/MainCard'
|
||||||
|
import MoreItemsTooltip from '../tooltip/MoreItemsTooltip'
|
||||||
|
|
||||||
const CardWrapper = styled(MainCard)(({ theme }) => ({
|
const CardWrapper = styled(MainCard)(({ theme }) => ({
|
||||||
background: theme.palette.card.main,
|
background: theme.palette.card.main,
|
||||||
@@ -116,14 +117,14 @@ const ItemCard = ({ data, images, icons, onClick }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{[
|
{[
|
||||||
...(images || []).map((img) => ({ type: 'image', src: img })),
|
...(images || []).map((img) => ({ type: 'image', src: img.imageSrc, label: img.label })),
|
||||||
...(icons || []).map((ic) => ({ type: 'icon', icon: ic.icon, color: ic.color }))
|
...(icons || []).map((ic) => ({ type: 'icon', icon: ic.icon, color: ic.color, label: ic.name }))
|
||||||
]
|
]
|
||||||
.slice(0, 3)
|
.slice(0, 3)
|
||||||
.map((item, index) =>
|
.map((item, index) => (
|
||||||
item.type === 'image' ? (
|
<Tooltip key={item.src || index} title={item.label} placement='top'>
|
||||||
|
{item.type === 'image' ? (
|
||||||
<Box
|
<Box
|
||||||
key={item.src}
|
|
||||||
sx={{
|
sx={{
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
@@ -141,7 +142,6 @@ const ItemCard = ({ data, images, icons, onClick }) => {
|
|||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
key={index}
|
|
||||||
style={{
|
style={{
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
@@ -152,12 +152,28 @@ const ItemCard = ({ data, images, icons, onClick }) => {
|
|||||||
>
|
>
|
||||||
<item.icon size={25} color={item.color} />
|
<item.icon size={25} color={item.color} />
|
||||||
</div>
|
</div>
|
||||||
)
|
|
||||||
)}
|
)}
|
||||||
{images?.length + (icons?.length || 0) > 3 && (
|
</Tooltip>
|
||||||
<Typography sx={{ alignItems: 'center', display: 'flex', fontSize: '.9rem', fontWeight: 200 }}>
|
))}
|
||||||
+ {images?.length + (icons?.length || 0) - 3} More
|
|
||||||
|
{(images?.length || 0) + (icons?.length || 0) > 3 && (
|
||||||
|
<MoreItemsTooltip
|
||||||
|
images={[
|
||||||
|
...(images?.slice(3) || []),
|
||||||
|
...(icons?.slice(Math.max(0, 3 - (images?.length || 0))) || []).map((ic) => ({ label: ic.name }))
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
fontSize: '.9rem',
|
||||||
|
fontWeight: 200
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
+ {(images?.length || 0) + (icons?.length || 0) - 3} More
|
||||||
</Typography>
|
</Typography>
|
||||||
|
</MoreItemsTooltip>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import FlowListMenu from '../button/FlowListMenu'
|
|||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { useAuth } from '@/hooks/useAuth'
|
import { useAuth } from '@/hooks/useAuth'
|
||||||
|
|
||||||
|
import MoreItemsTooltip from '../tooltip/MoreItemsTooltip'
|
||||||
|
|
||||||
const StyledTableCell = styled(TableCell)(({ theme }) => ({
|
const StyledTableCell = styled(TableCell)(({ theme }) => ({
|
||||||
borderColor: theme.palette.grey[900] + 25,
|
borderColor: theme.palette.grey[900] + 25,
|
||||||
|
|
||||||
@@ -234,18 +236,23 @@ export const FlowListTable = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{[
|
{[
|
||||||
...(images[row.id] || []).map((img) => ({ type: 'image', src: img })),
|
...(images[row.id] || []).map((img) => ({
|
||||||
|
type: 'image',
|
||||||
|
src: img.imageSrc,
|
||||||
|
label: img.label
|
||||||
|
})),
|
||||||
...(icons[row.id] || []).map((ic) => ({
|
...(icons[row.id] || []).map((ic) => ({
|
||||||
type: 'icon',
|
type: 'icon',
|
||||||
icon: ic.icon,
|
icon: ic.icon,
|
||||||
color: ic.color
|
color: ic.color,
|
||||||
|
title: ic.name
|
||||||
}))
|
}))
|
||||||
]
|
]
|
||||||
.slice(0, 5)
|
.slice(0, 5)
|
||||||
.map((item, index) =>
|
.map((item, index) => (
|
||||||
item.type === 'image' ? (
|
<Tooltip key={item.imageSrc || index} title={item.label} placement='top'>
|
||||||
|
{item.type === 'image' ? (
|
||||||
<Box
|
<Box
|
||||||
key={item.src}
|
|
||||||
sx={{
|
sx={{
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
@@ -268,7 +275,6 @@ export const FlowListTable = ({
|
|||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
key={index}
|
|
||||||
style={{
|
style={{
|
||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
@@ -279,9 +285,20 @@ export const FlowListTable = ({
|
|||||||
>
|
>
|
||||||
<item.icon size={25} color={item.color} />
|
<item.icon size={25} color={item.color} />
|
||||||
</div>
|
</div>
|
||||||
)
|
|
||||||
)}
|
)}
|
||||||
|
</Tooltip>
|
||||||
|
))}
|
||||||
|
|
||||||
{(images[row.id]?.length || 0) + (icons[row.id]?.length || 0) > 5 && (
|
{(images[row.id]?.length || 0) + (icons[row.id]?.length || 0) > 5 && (
|
||||||
|
<MoreItemsTooltip
|
||||||
|
images={[
|
||||||
|
...(images[row.id]?.slice(5) || []),
|
||||||
|
...(
|
||||||
|
icons[row.id]?.slice(Math.max(0, 5 - (images[row.id]?.length || 0))) ||
|
||||||
|
[]
|
||||||
|
).map((ic) => ({ label: ic.name }))
|
||||||
|
]}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -292,6 +309,7 @@ export const FlowListTable = ({
|
|||||||
>
|
>
|
||||||
+ {(images[row.id]?.length || 0) + (icons[row.id]?.length || 0) - 5} More
|
+ {(images[row.id]?.length || 0) + (icons[row.id]?.length || 0) - 5} More
|
||||||
</Typography>
|
</Typography>
|
||||||
|
</MoreItemsTooltip>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { Tooltip, Typography } from '@mui/material'
|
||||||
|
import { styled } from '@mui/material/styles'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
const StyledOl = styled('ol')(() => ({
|
||||||
|
paddingLeft: 20,
|
||||||
|
margin: 0
|
||||||
|
}))
|
||||||
|
|
||||||
|
const StyledLi = styled('li')(() => ({
|
||||||
|
paddingBottom: 4
|
||||||
|
}))
|
||||||
|
|
||||||
|
const MoreItemsTooltip = ({ images, children }) => {
|
||||||
|
if (!images || images.length === 0) return children
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<StyledOl>
|
||||||
|
{images.map((img) => (
|
||||||
|
<StyledLi key={img.imageSrc || img.label}>
|
||||||
|
<Typography>{img.label}</Typography>
|
||||||
|
</StyledLi>
|
||||||
|
))}
|
||||||
|
</StyledOl>
|
||||||
|
}
|
||||||
|
placement='top'
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MoreItemsTooltip
|
||||||
|
|
||||||
|
MoreItemsTooltip.propTypes = {
|
||||||
|
images: PropTypes.array,
|
||||||
|
children: PropTypes.node
|
||||||
|
}
|
||||||
@@ -117,13 +117,17 @@ const Agentflows = () => {
|
|||||||
images[agentflows[i].id] = []
|
images[agentflows[i].id] = []
|
||||||
icons[agentflows[i].id] = []
|
icons[agentflows[i].id] = []
|
||||||
for (let j = 0; j < nodes.length; j += 1) {
|
for (let j = 0; j < nodes.length; j += 1) {
|
||||||
|
if (nodes[j].data.name === 'stickyNote' || nodes[j].data.name === 'stickyNoteAgentflow') continue
|
||||||
const foundIcon = AGENTFLOW_ICONS.find((icon) => icon.name === nodes[j].data.name)
|
const foundIcon = AGENTFLOW_ICONS.find((icon) => icon.name === nodes[j].data.name)
|
||||||
if (foundIcon) {
|
if (foundIcon) {
|
||||||
icons[agentflows[i].id].push(foundIcon)
|
icons[agentflows[i].id].push(foundIcon)
|
||||||
} else {
|
} else {
|
||||||
const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}`
|
const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}`
|
||||||
if (!images[agentflows[i].id].includes(imageSrc)) {
|
if (!images[agentflows[i].id].some((img) => img.imageSrc === imageSrc)) {
|
||||||
images[agentflows[i].id].push(imageSrc)
|
images[agentflows[i].id].push({
|
||||||
|
imageSrc,
|
||||||
|
label: nodes[j].data.label
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,9 +89,13 @@ const Chatflows = () => {
|
|||||||
const nodes = flowData.nodes || []
|
const nodes = flowData.nodes || []
|
||||||
images[chatflows[i].id] = []
|
images[chatflows[i].id] = []
|
||||||
for (let j = 0; j < nodes.length; j += 1) {
|
for (let j = 0; j < nodes.length; j += 1) {
|
||||||
|
if (nodes[j].data.name === 'stickyNote' || nodes[j].data.name === 'stickyNoteAgentflow') continue
|
||||||
const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}`
|
const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}`
|
||||||
if (!images[chatflows[i].id].includes(imageSrc)) {
|
if (!images[chatflows[i].id].some((img) => img.imageSrc === imageSrc)) {
|
||||||
images[chatflows[i].id].push(imageSrc)
|
images[chatflows[i].id].push({
|
||||||
|
imageSrc,
|
||||||
|
label: nodes[j].data.label
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -375,13 +375,17 @@ const Marketplace = () => {
|
|||||||
images[flows[i].id] = []
|
images[flows[i].id] = []
|
||||||
icons[flows[i].id] = []
|
icons[flows[i].id] = []
|
||||||
for (let j = 0; j < nodes.length; j += 1) {
|
for (let j = 0; j < nodes.length; j += 1) {
|
||||||
|
if (nodes[j].data.name === 'stickyNote' || nodes[j].data.name === 'stickyNoteAgentflow') continue
|
||||||
const foundIcon = AGENTFLOW_ICONS.find((icon) => icon.name === nodes[j].data.name)
|
const foundIcon = AGENTFLOW_ICONS.find((icon) => icon.name === nodes[j].data.name)
|
||||||
if (foundIcon) {
|
if (foundIcon) {
|
||||||
icons[flows[i].id].push(foundIcon)
|
icons[flows[i].id].push(foundIcon)
|
||||||
} else {
|
} else {
|
||||||
const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}`
|
const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}`
|
||||||
if (!images[flows[i].id].includes(imageSrc)) {
|
if (!images[flows[i].id].some((img) => img.imageSrc === imageSrc)) {
|
||||||
images[flows[i].id].push(imageSrc)
|
images[flows[i].id].push({
|
||||||
|
imageSrc,
|
||||||
|
label: nodes[j].data.name
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user