diff --git a/frontend/src/components/shared/ToolIcon.tsx b/frontend/src/components/shared/ToolIcon.tsx new file mode 100644 index 000000000..75ab249ba --- /dev/null +++ b/frontend/src/components/shared/ToolIcon.tsx @@ -0,0 +1,34 @@ +import React from "react"; + +interface ToolIconProps { + icon: React.ReactNode; + opacity?: number; + color?: string; + marginRight?: string; +} + +/** + * Shared icon component for consistent tool icon styling across the application. + * Uses the same visual pattern as ToolButton: scaled to 0.8, centered transform, consistent spacing. + */ +export const ToolIcon: React.FC = ({ + icon, + opacity = 1, + color = "var(--tools-text-and-icon-color)", + marginRight = "0.5rem" +}) => { + return ( +
+ {icon} +
+ ); +}; diff --git a/frontend/src/components/tools/automate/AutomationEntry.tsx b/frontend/src/components/tools/automate/AutomationEntry.tsx index 30c280491..8f739bcbf 100644 --- a/frontend/src/components/tools/automate/AutomationEntry.tsx +++ b/frontend/src/components/tools/automate/AutomationEntry.tsx @@ -1,11 +1,12 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Group, Text, ActionIcon, Menu, Box } from '@mantine/core'; +import { Group, Text, ActionIcon, Menu, Button, Box } from '@mantine/core'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import EditIcon from '@mui/icons-material/Edit'; import DeleteIcon from '@mui/icons-material/Delete'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import { Tooltip } from '../../shared/Tooltip'; +import { ToolIcon } from '../../shared/ToolIcon'; import { ToolRegistryEntry } from '../../../data/toolsTaxonomy'; interface AutomationEntryProps { @@ -50,8 +51,7 @@ export default function AutomationEntry({ const [isHovered, setIsHovered] = useState(false); const [isMenuOpen, setIsMenuOpen] = useState(false); - // Keep item in hovered state if menu is open - const shouldShowHovered = isHovered || isMenuOpen; + const shouldShowMenu = isHovered || isMenuOpen; // Helper function to resolve tool display names const getToolDisplayName = (operation: string): string => { @@ -108,134 +108,135 @@ export default function AutomationEntry({ ); }; - const renderContent = () => { - if (title) { - // Custom automation with title - return ( - - {BadgeIcon && ( - - )} - + const buttonContent = ( + <> + {BadgeIcon && ( + } + {...(keepIconColor && { color: 'var(--mantine-primary-color-filled)' })} + /> + )} +
+ {title ? ( + // Custom automation with title + {title} - - ); - } else { - // Suggested automation showing tool chain - return ( - - {BadgeIcon && ( - - )} + ) : ( + // Suggested automation showing tool chain {operations.map((op, index) => ( - + {getToolDisplayName(op)} - {index < operations.length - 1 && ( - + )} ))} - - ); - } - }; + )} +
+ + ); - const boxContent = ( + const wrapperContent = ( setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > - -
- {renderContent()} -
+ + {showMenu && ( + setIsMenuOpen(true)} + onClose={() => setIsMenuOpen(false)} + > + + e.stopPropagation()} + style={{ + position: 'absolute', + right: '0.5rem', + top: '50%', + transform: 'translateY(-50%)', + zIndex: 1, + opacity: shouldShowMenu ? 1 : 0, + transition: 'opacity 0.2s ease', + pointerEvents: shouldShowMenu ? 'auto' : 'none' + }} + > + + + - {showMenu && ( - setIsMenuOpen(true)} - onClose={() => setIsMenuOpen(false)} - > - - e.stopPropagation()} - style={{ - opacity: shouldShowHovered ? 1 : 0, - transform: shouldShowHovered ? 'scale(1)' : 'scale(0.8)', - transition: 'opacity 0.3s ease, transform 0.3s ease', - pointerEvents: shouldShowHovered ? 'auto' : 'none' + + {onCopy && ( + } + onClick={(e) => { + e.stopPropagation(); + onCopy(); }} > - - - - - - {onCopy && ( - } - onClick={(e) => { - e.stopPropagation(); - onCopy(); - }} - > - {t('automate.copyToSaved', 'Copy to Saved')} - - )} - {onEdit && ( - } - onClick={(e) => { - e.stopPropagation(); - onEdit(); - }} - > - {t('edit', 'Edit')} - - )} - {onDelete && ( - } - onClick={(e) => { - e.stopPropagation(); - onDelete(); - }} - > - {t('delete', 'Delete')} - - )} - - - )} - + {t('automate.copyToSaved', 'Copy to Saved')} + + )} + {onEdit && ( + } + onClick={(e) => { + e.stopPropagation(); + onEdit(); + }} + > + {t('edit', 'Edit')} + + )} + {onDelete && ( + } + onClick={(e) => { + e.stopPropagation(); + onDelete(); + }} + > + {t('delete', 'Delete')} + + )} + + + )}
); @@ -249,9 +250,9 @@ export default function AutomationEntry({ arrow={true} delay={500} > - {boxContent} + {wrapperContent} ) : ( - boxContent + wrapperContent ); } diff --git a/frontend/src/components/tools/shared/SuggestedToolsSection.tsx b/frontend/src/components/tools/shared/SuggestedToolsSection.tsx index 18cf8a0d5..ad8720f19 100644 --- a/frontend/src/components/tools/shared/SuggestedToolsSection.tsx +++ b/frontend/src/components/tools/shared/SuggestedToolsSection.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { Stack, Text, Divider, Card, Group, Anchor } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import { useSuggestedTools } from '../../../hooks/useSuggestedTools'; +import { ToolIcon } from '../../shared/ToolIcon'; export function SuggestedToolsSection(): React.ReactElement { const { t } = useTranslation(); @@ -31,7 +32,7 @@ export function SuggestedToolsSection(): React.ReactElement { style={{ cursor: 'pointer' }} > - + } /> {tool.title} diff --git a/frontend/src/components/tools/toolPicker/ToolButton.tsx b/frontend/src/components/tools/toolPicker/ToolButton.tsx index 40cee33a7..467ce6738 100644 --- a/frontend/src/components/tools/toolPicker/ToolButton.tsx +++ b/frontend/src/components/tools/toolPicker/ToolButton.tsx @@ -2,6 +2,7 @@ import React from "react"; import { Button } from "@mantine/core"; import { useTranslation } from "react-i18next"; import { Tooltip } from "../../shared/Tooltip"; +import { ToolIcon } from "../../shared/ToolIcon"; import { ToolRegistryEntry } from "../../../data/toolsTaxonomy"; import { useToolNavigation } from "../../../hooks/useToolNavigation"; import { handleUnlessSpecialClick } from "../../../utils/clickHandlers"; @@ -57,7 +58,10 @@ const ToolButton: React.FC = ({ id, tool, isSelected, onSelect, const buttonContent = ( <> -
{tool.icon}
+
= ({ id, tool, isSelected, onSelect, style={{ display: 'inline-block', maxWidth: '100%', opacity: isUnavailable ? 0.25 : 1 }} /> {matchedSynonym && ( -