diff --git a/frontend/src/components/tools/automate/AutomationCreation.tsx b/frontend/src/components/tools/automate/AutomationCreation.tsx index 795d8e957..1b8d60741 100644 --- a/frontend/src/components/tools/automate/AutomationCreation.tsx +++ b/frontend/src/components/tools/automate/AutomationCreation.tsx @@ -13,6 +13,7 @@ import CheckIcon from '@mui/icons-material/Check'; import { ToolRegistryEntry } from '../../../data/toolsTaxonomy'; import ToolConfigurationModal from './ToolConfigurationModal'; import ToolList from './ToolList'; +import IconSelector from './IconSelector'; import { AutomationConfig, AutomationMode, AutomationTool } from '../../../types/automation'; import { useAutomationForm } from '../../../hooks/tools/automate/useAutomationForm'; @@ -31,6 +32,8 @@ export default function AutomationCreation({ mode, existingAutomation, onBack, o const { automationName, setAutomationName, + automationIcon, + setAutomationIcon, selectedTools, addTool, removeTool, @@ -101,6 +104,7 @@ export default function AutomationCreation({ mode, existingAutomation, onBack, o const automationData = { name: automationName.trim(), description: '', + icon: automationIcon, operations: selectedTools.map(tool => ({ operation: tool.operation, parameters: tool.parameters || {} @@ -149,18 +153,26 @@ export default function AutomationCreation({ mode, existingAutomation, onBack, o - {/* Automation Name */} - - - {t('automate.creation.name.label', 'Automation Name')} * - - setAutomationName(e.currentTarget.value)} - size="sm" - /> - + {/* Automation Name and Icon */} + + + + {t('automate.creation.name.label', 'Automation Name')} * + + setAutomationName(e.currentTarget.value)} + size="sm" + /> + + + + {/* Selected Tools List */} diff --git a/frontend/src/components/tools/automate/AutomationSelection.tsx b/frontend/src/components/tools/automate/AutomationSelection.tsx index 197a96b3e..7583feaae 100644 --- a/frontend/src/components/tools/automate/AutomationSelection.tsx +++ b/frontend/src/components/tools/automate/AutomationSelection.tsx @@ -6,6 +6,7 @@ import SettingsIcon from "@mui/icons-material/Settings"; import AutomationEntry from "./AutomationEntry"; import { useSuggestedAutomations } from "../../../hooks/tools/automate/useSuggestedAutomations"; import { AutomationConfig, SuggestedAutomation } from "../../../types/automation"; +import { iconMap } from './iconMap'; interface AutomationSelectionProps { savedAutomations: AutomationConfig[]; @@ -42,18 +43,21 @@ export default function AutomationSelection({ keepIconColor={true} /> {/* Saved Automations */} - {savedAutomations.map((automation) => ( - typeof op === 'string' ? op : op.operation)} - onClick={() => onRun(automation)} - showMenu={true} - onEdit={() => onEdit(automation)} - onDelete={() => onDelete(automation)} - /> - ))} + {savedAutomations.map((automation) => { + const IconComponent = automation.icon ? iconMap[automation.icon as keyof typeof iconMap] : SettingsIcon; + return ( + typeof op === 'string' ? op : op.operation)} + onClick={() => onRun(automation)} + showMenu={true} + onEdit={() => onEdit(automation)} + onDelete={() => onDelete(automation)} + /> + ); + })} {/* Suggested Automations */} diff --git a/frontend/src/components/tools/automate/IconSelector.tsx b/frontend/src/components/tools/automate/IconSelector.tsx new file mode 100644 index 000000000..1af38ee00 --- /dev/null +++ b/frontend/src/components/tools/automate/IconSelector.tsx @@ -0,0 +1,117 @@ +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Box, Text, Stack, Button, SimpleGrid, Tooltip, Popover } from "@mantine/core"; +import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; +import { iconMap, iconOptions } from './iconMap'; + +interface IconSelectorProps { + value?: string; + onChange?: (iconKey: string) => void; + size?: "sm" | "md" | "lg"; +} + +export default function IconSelector({ value = "SettingsIcon", onChange, size = "sm" }: IconSelectorProps) { + const { t } = useTranslation(); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + + const selectedIconComponent = iconMap[value as keyof typeof iconMap] || iconMap.SettingsIcon; + + const handleIconSelect = (iconKey: string) => { + onChange?.(iconKey); + setIsDropdownOpen(false); + }; + + const iconSize = size === "sm" ? 16 : size === "md" ? 18 : 20; + const actionIconSize = size === "sm" ? "sm" : size === "md" ? "md" : "lg"; + + return ( + + + {t("automate.creation.icon.label", "Icon")} + + + setIsDropdownOpen(false)} + onDismiss={() => setIsDropdownOpen(false)} + position="bottom-start" + withArrow + trapFocus + > + + + + + + + + {iconOptions.map((option) => { + const IconComponent = iconMap[option.value as keyof typeof iconMap]; + const isSelected = value === option.value; + + return ( + + handleIconSelect(option.value)} + style={{ + display: "flex", + alignItems: "center", + justifyContent: "center", + padding: "0.5rem", + borderRadius: "0.25rem", + cursor: "pointer", + backgroundColor: isSelected ? "var(--mantine-color-gray-1)" : "transparent", + }} + onMouseEnter={(e) => { + if (!isSelected) { + e.currentTarget.style.backgroundColor = "var(--mantine-color-gray-0)"; + } + }} + onMouseLeave={(e) => { + if (!isSelected) { + e.currentTarget.style.backgroundColor = "transparent"; + } + }} + > + + + + ); + })} + + + + + + ); +} diff --git a/frontend/src/components/tools/automate/iconMap.ts b/frontend/src/components/tools/automate/iconMap.ts new file mode 100644 index 000000000..cabd4f2da --- /dev/null +++ b/frontend/src/components/tools/automate/iconMap.ts @@ -0,0 +1,92 @@ +import SettingsIcon from '@mui/icons-material/Settings'; +import CompressIcon from '@mui/icons-material/Compress'; +import SwapHorizIcon from '@mui/icons-material/SwapHoriz'; +import CleaningServicesIcon from '@mui/icons-material/CleaningServices'; +import CropIcon from '@mui/icons-material/Crop'; +import TextFieldsIcon from '@mui/icons-material/TextFields'; +import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf'; +import EditIcon from '@mui/icons-material/Edit'; +import DeleteIcon from '@mui/icons-material/Delete'; +import FolderIcon from '@mui/icons-material/Folder'; +import CloudIcon from '@mui/icons-material/Cloud'; +import StorageIcon from '@mui/icons-material/Storage'; +import SearchIcon from '@mui/icons-material/Search'; +import DownloadIcon from '@mui/icons-material/Download'; +import UploadIcon from '@mui/icons-material/Upload'; +import PlayArrowIcon from '@mui/icons-material/PlayArrow'; +import RotateLeftIcon from '@mui/icons-material/RotateLeft'; +import RotateRightIcon from '@mui/icons-material/RotateRight'; +import VisibilityIcon from '@mui/icons-material/Visibility'; +import ContentCutIcon from '@mui/icons-material/ContentCut'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import WorkIcon from '@mui/icons-material/Work'; +import BuildIcon from '@mui/icons-material/Build'; +import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome'; +import SmartToyIcon from '@mui/icons-material/SmartToy'; +import CheckIcon from '@mui/icons-material/Check'; +import SecurityIcon from '@mui/icons-material/Security'; +import StarIcon from '@mui/icons-material/Star'; + +export const iconMap = { + SettingsIcon, + CompressIcon, + SwapHorizIcon, + CleaningServicesIcon, + CropIcon, + TextFieldsIcon, + PictureAsPdfIcon, + EditIcon, + DeleteIcon, + FolderIcon, + CloudIcon, + StorageIcon, + SearchIcon, + DownloadIcon, + UploadIcon, + PlayArrowIcon, + RotateLeftIcon, + RotateRightIcon, + VisibilityIcon, + ContentCutIcon, + ContentCopyIcon, + WorkIcon, + BuildIcon, + AutoAwesomeIcon, + SmartToyIcon, + CheckIcon, + SecurityIcon, + StarIcon +}; + +export const iconOptions = [ + { value: 'SettingsIcon', label: 'Settings' }, + { value: 'CompressIcon', label: 'Compress' }, + { value: 'SwapHorizIcon', label: 'Convert' }, + { value: 'CleaningServicesIcon', label: 'Clean' }, + { value: 'CropIcon', label: 'Crop' }, + { value: 'TextFieldsIcon', label: 'Text' }, + { value: 'PictureAsPdfIcon', label: 'PDF' }, + { value: 'EditIcon', label: 'Edit' }, + { value: 'DeleteIcon', label: 'Delete' }, + { value: 'FolderIcon', label: 'Folder' }, + { value: 'CloudIcon', label: 'Cloud' }, + { value: 'StorageIcon', label: 'Storage' }, + { value: 'SearchIcon', label: 'Search' }, + { value: 'DownloadIcon', label: 'Download' }, + { value: 'UploadIcon', label: 'Upload' }, + { value: 'PlayArrowIcon', label: 'Play' }, + { value: 'RotateLeftIcon', label: 'Rotate Left' }, + { value: 'RotateRightIcon', label: 'Rotate Right' }, + { value: 'VisibilityIcon', label: 'View' }, + { value: 'ContentCutIcon', label: 'Cut' }, + { value: 'ContentCopyIcon', label: 'Copy' }, + { value: 'WorkIcon', label: 'Work' }, + { value: 'BuildIcon', label: 'Build' }, + { value: 'AutoAwesomeIcon', label: 'Magic' }, + { value: 'SmartToyIcon', label: 'Robot' }, + { value: 'CheckIcon', label: 'Check' }, + { value: 'SecurityIcon', label: 'Security' }, + { value: 'StarIcon', label: 'Star' } +]; + +export type IconKey = keyof typeof iconMap; \ No newline at end of file diff --git a/frontend/src/hooks/tools/automate/useAutomationForm.ts b/frontend/src/hooks/tools/automate/useAutomationForm.ts index 7bbe14d9b..9a19f8b61 100644 --- a/frontend/src/hooks/tools/automate/useAutomationForm.ts +++ b/frontend/src/hooks/tools/automate/useAutomationForm.ts @@ -14,6 +14,7 @@ export function useAutomationForm({ mode, existingAutomation, toolRegistry }: Us const { t } = useTranslation(); const [automationName, setAutomationName] = useState(''); + const [automationIcon, setAutomationIcon] = useState(''); const [selectedTools, setSelectedTools] = useState([]); const getToolName = useCallback((operation: string) => { @@ -33,6 +34,7 @@ export function useAutomationForm({ mode, existingAutomation, toolRegistry }: Us useEffect(() => { if ((mode === AutomationMode.SUGGESTED || mode === AutomationMode.EDIT) && existingAutomation) { setAutomationName(existingAutomation.name || ''); + setAutomationIcon(existingAutomation.icon || ''); const operations = existingAutomation.operations || []; const tools = operations.map((op, index) => { @@ -101,6 +103,8 @@ export function useAutomationForm({ mode, existingAutomation, toolRegistry }: Us return { automationName, setAutomationName, + automationIcon, + setAutomationIcon, selectedTools, setSelectedTools, addTool, diff --git a/frontend/src/hooks/tools/automate/useSavedAutomations.ts b/frontend/src/hooks/tools/automate/useSavedAutomations.ts index 1f210b432..27466f55d 100644 --- a/frontend/src/hooks/tools/automate/useSavedAutomations.ts +++ b/frontend/src/hooks/tools/automate/useSavedAutomations.ts @@ -45,10 +45,27 @@ export function useSavedAutomations() { try { const { automationStorage } = await import('../../../services/automationStorage'); + // Map suggested automation icons to MUI icon keys + const getIconKey = (suggestedIcon: any): string => { + // Check the automation ID or name to determine the appropriate icon + switch (suggestedAutomation.id) { + case 'secure-pdf-ingestion': + case 'secure-workflow': + return 'SecurityIcon'; // Security icon for security workflows + case 'email-preparation': + return 'CompressIcon'; // Compression icon + case 'process-images': + return 'StarIcon'; // Star icon for process images + default: + return 'SettingsIcon'; // Default fallback + } + }; + // Convert suggested automation to saved automation format const savedAutomation = { name: suggestedAutomation.name, description: suggestedAutomation.description, + icon: getIconKey(suggestedAutomation.icon), operations: suggestedAutomation.operations }; diff --git a/frontend/src/types/automation.ts b/frontend/src/types/automation.ts index 8d2cb5ae8..8d9667fcf 100644 --- a/frontend/src/types/automation.ts +++ b/frontend/src/types/automation.ts @@ -11,6 +11,7 @@ export interface AutomationConfig { id: string; name: string; description?: string; + icon?: string; operations: AutomationOperation[]; createdAt: string; updatedAt: string;