Automation tolltip + new operations + copy to saved (#4292)

# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: ConnorYoh <[email protected]>
This commit is contained in:
Anthony Stirling
2025-08-26 11:19:15 +01:00
committed by GitHub
co-authored by ConnorYoh
parent 4b70ef1298
commit 95b3e22229
7 changed files with 238 additions and 47 deletions
@@ -4,10 +4,14 @@ import { Button, Group, Text, ActionIcon, Menu, 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';
interface AutomationEntryProps {
/** Optional title for the automation (usually for custom ones) */
title?: string;
/** Optional description for tooltip */
description?: string;
/** MUI Icon component for the badge */
badgeIcon?: React.ComponentType<any>;
/** Array of tool operation names in the workflow */
@@ -22,17 +26,21 @@ interface AutomationEntryProps {
onEdit?: () => void;
/** Delete handler */
onDelete?: () => void;
/** Copy handler (for suggested automations) */
onCopy?: () => void;
}
export default function AutomationEntry({
title,
description,
badgeIcon: BadgeIcon,
operations,
onClick,
keepIconColor = false,
showMenu = false,
onEdit,
onDelete
onDelete,
onCopy
}: AutomationEntryProps) {
const { t } = useTranslation();
const [isHovered, setIsHovered] = useState(false);
@@ -41,6 +49,47 @@ export default function AutomationEntry({
// Keep item in hovered state if menu is open
const shouldShowHovered = isHovered || isMenuOpen;
// Create tooltip content with description and tool chain
const createTooltipContent = () => {
if (!description) return null;
const toolChain = operations.map((op, index) => (
<React.Fragment key={`${op}-${index}`}>
<Text
component="span"
size="sm"
fw={600}
style={{
color: 'var(--mantine-primary-color-filled)',
background: 'var(--mantine-primary-color-light)',
padding: '2px 6px',
borderRadius: '4px',
fontSize: '0.75rem',
whiteSpace: 'nowrap'
}}
>
{t(`${op}.title`, op)}
</Text>
{index < operations.length - 1 && (
<Text component="span" size="sm" mx={4}>
</Text>
)}
</React.Fragment>
));
return (
<div style={{ minWidth: '400px', width: 'auto' }}>
<Text size="sm" mb={8} style={{ whiteSpace: 'normal', wordWrap: 'break-word' }}>
{description}
</Text>
<div style={{ display: 'flex', alignItems: 'center', gap: '4px', whiteSpace: 'nowrap' }}>
{toolChain}
</div>
</div>
);
};
const renderContent = () => {
if (title) {
// Custom automation with title
@@ -89,7 +138,7 @@ export default function AutomationEntry({
}
};
return (
const boxContent = (
<Box
style={{
backgroundColor: shouldShowHovered ? 'var(--mantine-color-gray-1)' : 'transparent',
@@ -132,6 +181,17 @@ export default function AutomationEntry({
</Menu.Target>
<Menu.Dropdown>
{onCopy && (
<Menu.Item
leftSection={<ContentCopyIcon style={{ fontSize: 16 }} />}
onClick={(e) => {
e.stopPropagation();
onCopy();
}}
>
{t('automate.copyToSaved', 'Copy to Saved')}
</Menu.Item>
)}
{onEdit && (
<Menu.Item
leftSection={<EditIcon style={{ fontSize: 16 }} />}
@@ -160,4 +220,18 @@ export default function AutomationEntry({
</Group>
</Box>
);
// Only show tooltip if description exists, otherwise return plain content
return description ? (
<Tooltip
content={createTooltipContent()}
position="right"
arrow={true}
delay={500}
>
{boxContent}
</Tooltip>
) : (
boxContent
);
}
@@ -5,7 +5,7 @@ import AddCircleOutline from "@mui/icons-material/AddCircleOutline";
import SettingsIcon from "@mui/icons-material/Settings";
import AutomationEntry from "./AutomationEntry";
import { useSuggestedAutomations } from "../../../hooks/tools/automate/useSuggestedAutomations";
import { AutomationConfig } from "../../../types/automation";
import { AutomationConfig, SuggestedAutomation } from "../../../types/automation";
interface AutomationSelectionProps {
savedAutomations: AutomationConfig[];
@@ -13,6 +13,7 @@ interface AutomationSelectionProps {
onRun: (automation: AutomationConfig) => void;
onEdit: (automation: AutomationConfig) => void;
onDelete: (automation: AutomationConfig) => void;
onCopyFromSuggested: (automation: SuggestedAutomation) => void;
}
export default function AutomationSelection({
@@ -20,7 +21,8 @@ export default function AutomationSelection({
onCreateNew,
onRun,
onEdit,
onDelete
onDelete,
onCopyFromSuggested
}: AutomationSelectionProps) {
const { t } = useTranslation();
const suggestedAutomations = useSuggestedAutomations();
@@ -63,9 +65,13 @@ export default function AutomationSelection({
{suggestedAutomations.map((automation) => (
<AutomationEntry
key={automation.id}
title={automation.name}
description={automation.description}
badgeIcon={automation.icon}
operations={automation.operations.map(op => op.operation)}
onClick={() => onRun(automation)}
showMenu={true}
onCopy={() => onCopyFromSuggested(automation)}
/>
))}
</Stack>