From 7ef0e99eb25a63ebe0a693c52782271ca9abdd41 Mon Sep 17 00:00:00 2001 From: Anoop P <44577841+anoopw3bdev@users.noreply.github.com> Date: Wed, 28 May 2025 02:04:10 +0530 Subject: [PATCH] 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 --- .../ui/src/ui-component/cards/ItemCard.jsx | 98 ++++++++------- .../src/ui-component/table/FlowListTable.jsx | 116 ++++++++++-------- .../ui-component/tooltip/MoreItemsTooltip.jsx | 40 ++++++ packages/ui/src/views/agentflows/index.jsx | 8 +- packages/ui/src/views/chatflows/index.jsx | 8 +- packages/ui/src/views/marketplaces/index.jsx | 8 +- 6 files changed, 182 insertions(+), 96 deletions(-) create mode 100644 packages/ui/src/ui-component/tooltip/MoreItemsTooltip.jsx diff --git a/packages/ui/src/ui-component/cards/ItemCard.jsx b/packages/ui/src/ui-component/cards/ItemCard.jsx index c2342c76..53b7e6c7 100644 --- a/packages/ui/src/ui-component/cards/ItemCard.jsx +++ b/packages/ui/src/ui-component/cards/ItemCard.jsx @@ -3,10 +3,11 @@ import { useSelector } from 'react-redux' // material-ui 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 import MainCard from '@/ui-component/cards/MainCard' +import MoreItemsTooltip from '../tooltip/MoreItemsTooltip' const CardWrapper = styled(MainCard)(({ theme }) => ({ background: theme.palette.card.main, @@ -116,48 +117,63 @@ const ItemCard = ({ data, images, icons, onClick }) => { }} > {[ - ...(images || []).map((img) => ({ type: 'image', src: img })), - ...(icons || []).map((ic) => ({ type: 'icon', icon: ic.icon, color: ic.color })) + ...(images || []).map((img) => ({ type: 'image', src: img.imageSrc, label: img.label })), + ...(icons || []).map((ic) => ({ type: 'icon', icon: ic.icon, color: ic.color, label: ic.name })) ] .slice(0, 3) - .map((item, index) => - item.type === 'image' ? ( - - - - ) : ( -
- -
- ) - )} - {images?.length + (icons?.length || 0) > 3 && ( - - + {images?.length + (icons?.length || 0) - 3} More - + .map((item, index) => ( + + {item.type === 'image' ? ( + + + + ) : ( +
+ +
+ )} +
+ ))} + + {(images?.length || 0) + (icons?.length || 0) > 3 && ( + ({ label: ic.name })) + ]} + > + + + {(images?.length || 0) + (icons?.length || 0) - 3} More + + )} )} diff --git a/packages/ui/src/ui-component/table/FlowListTable.jsx b/packages/ui/src/ui-component/table/FlowListTable.jsx index 867fd24b..43087d61 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.jsx +++ b/packages/ui/src/ui-component/table/FlowListTable.jsx @@ -25,6 +25,8 @@ import FlowListMenu from '../button/FlowListMenu' import { Link } from 'react-router-dom' import { useAuth } from '@/hooks/useAuth' +import MoreItemsTooltip from '../tooltip/MoreItemsTooltip' + const StyledTableCell = styled(TableCell)(({ theme }) => ({ borderColor: theme.palette.grey[900] + 25, @@ -234,64 +236,80 @@ 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) => ({ type: 'icon', icon: ic.icon, - color: ic.color + color: ic.color, + title: ic.name })) ] .slice(0, 5) - .map((item, index) => - item.type === 'image' ? ( - - ( + + {item.type === 'image' ? ( + - - ) : ( -
- -
- ) - )} + > + +
+ ) : ( +
+ +
+ )} + + ))} + {(images[row.id]?.length || 0) + (icons[row.id]?.length || 0) > 5 && ( - ({ label: ic.name })) + ]} > - + {(images[row.id]?.length || 0) + (icons[row.id]?.length || 0) - 5} More - + + + {(images[row.id]?.length || 0) + (icons[row.id]?.length || 0) - 5} More + + )} )} diff --git a/packages/ui/src/ui-component/tooltip/MoreItemsTooltip.jsx b/packages/ui/src/ui-component/tooltip/MoreItemsTooltip.jsx new file mode 100644 index 00000000..26024045 --- /dev/null +++ b/packages/ui/src/ui-component/tooltip/MoreItemsTooltip.jsx @@ -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 ( + + {images.map((img) => ( + + {img.label} + + ))} + + } + placement='top' + > + {children} + + ) +} + +export default MoreItemsTooltip + +MoreItemsTooltip.propTypes = { + images: PropTypes.array, + children: PropTypes.node +} diff --git a/packages/ui/src/views/agentflows/index.jsx b/packages/ui/src/views/agentflows/index.jsx index 3af60591..cdd44d58 100644 --- a/packages/ui/src/views/agentflows/index.jsx +++ b/packages/ui/src/views/agentflows/index.jsx @@ -117,13 +117,17 @@ const Agentflows = () => { images[agentflows[i].id] = [] icons[agentflows[i].id] = [] 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) if (foundIcon) { icons[agentflows[i].id].push(foundIcon) } else { const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}` - if (!images[agentflows[i].id].includes(imageSrc)) { - images[agentflows[i].id].push(imageSrc) + if (!images[agentflows[i].id].some((img) => img.imageSrc === imageSrc)) { + images[agentflows[i].id].push({ + imageSrc, + label: nodes[j].data.label + }) } } } diff --git a/packages/ui/src/views/chatflows/index.jsx b/packages/ui/src/views/chatflows/index.jsx index db1cbbec..38fbef78 100644 --- a/packages/ui/src/views/chatflows/index.jsx +++ b/packages/ui/src/views/chatflows/index.jsx @@ -89,9 +89,13 @@ const Chatflows = () => { const nodes = flowData.nodes || [] images[chatflows[i].id] = [] 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}` - if (!images[chatflows[i].id].includes(imageSrc)) { - images[chatflows[i].id].push(imageSrc) + if (!images[chatflows[i].id].some((img) => img.imageSrc === imageSrc)) { + images[chatflows[i].id].push({ + imageSrc, + label: nodes[j].data.label + }) } } } diff --git a/packages/ui/src/views/marketplaces/index.jsx b/packages/ui/src/views/marketplaces/index.jsx index 21e283d6..82e91425 100644 --- a/packages/ui/src/views/marketplaces/index.jsx +++ b/packages/ui/src/views/marketplaces/index.jsx @@ -375,13 +375,17 @@ const Marketplace = () => { images[flows[i].id] = [] icons[flows[i].id] = [] 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) if (foundIcon) { icons[flows[i].id].push(foundIcon) } else { const imageSrc = `${baseURL}/api/v1/node-icon/${nodes[j].data.name}` - if (!images[flows[i].id].includes(imageSrc)) { - images[flows[i].id].push(imageSrc) + if (!images[flows[i].id].some((img) => img.imageSrc === imageSrc)) { + images[flows[i].id].push({ + imageSrc, + label: nodes[j].data.name + }) } } }