mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 22:29:24 +00:00
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 <40631091+ConnorYoh@users.noreply.github.com>
This commit is contained in:
parent
4b70ef1298
commit
95b3e22229
@ -2279,6 +2279,20 @@
|
|||||||
"description": "Configure the settings for this tool. These settings will be applied when the automation runs.",
|
"description": "Configure the settings for this tool. These settings will be applied when the automation runs.",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"save": "Save Configuration"
|
"save": "Save Configuration"
|
||||||
}
|
},
|
||||||
|
"copyToSaved": "Copy to Saved"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"automation": {
|
||||||
|
"suggested": {
|
||||||
|
"securePdfIngestion": "Secure PDF Ingestion",
|
||||||
|
"securePdfIngestionDesc": "Comprehensive PDF processing workflow that sanitises documents, applies OCR with cleanup, converts to PDF/A format for long-term archival, and optimises file size.",
|
||||||
|
"emailPreparation": "Email Preparation",
|
||||||
|
"emailPreparationDesc": "Optimises PDFs for email distribution by compressing files, splitting large documents into 20MB chunks for email compatibility, and removing metadata for privacy.",
|
||||||
|
"secureWorkflow": "Security Workflow",
|
||||||
|
"secureWorkflowDesc": "Secures PDF documents by removing potentially malicious content like JavaScript and embedded files, then adds password protection to prevent unauthorised access.",
|
||||||
|
"processImages": "Process Images",
|
||||||
|
"processImagesDesc": "Converts multiple image files into a single PDF document, then applies OCR technology to extract searchable text from the images."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2106,5 +2106,20 @@
|
|||||||
"results": {
|
"results": {
|
||||||
"title": "Decrypted PDFs"
|
"title": "Decrypted PDFs"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"automation": {
|
||||||
|
"suggested": {
|
||||||
|
"securePdfIngestion": "Secure PDF Ingestion",
|
||||||
|
"securePdfIngestionDesc": "Comprehensive PDF processing workflow that sanitizes documents, applies OCR with cleanup, converts to PDF/A format for long-term archival, and optimizes file size.",
|
||||||
|
"emailPreparation": "Email Preparation",
|
||||||
|
"emailPreparationDesc": "Optimizes PDFs for email distribution by compressing files, splitting large documents into 20MB chunks for email compatibility, and removing metadata for privacy.",
|
||||||
|
"secureWorkflow": "Security Workflow",
|
||||||
|
"secureWorkflowDesc": "Secures PDF documents by removing potentially malicious content like JavaScript and embedded files, then adds password protection to prevent unauthorized access.",
|
||||||
|
"processImages": "Process Images",
|
||||||
|
"processImagesDesc": "Converts multiple image files into a single PDF document, then applies OCR technology to extract searchable text from the images."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"automate": {
|
||||||
|
"copyToSaved": "Copy to Saved"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,14 @@ import { Button, Group, Text, ActionIcon, Menu, Box } from '@mantine/core';
|
|||||||
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
|
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||||
|
import { Tooltip } from '../../shared/Tooltip';
|
||||||
|
|
||||||
interface AutomationEntryProps {
|
interface AutomationEntryProps {
|
||||||
/** Optional title for the automation (usually for custom ones) */
|
/** Optional title for the automation (usually for custom ones) */
|
||||||
title?: string;
|
title?: string;
|
||||||
|
/** Optional description for tooltip */
|
||||||
|
description?: string;
|
||||||
/** MUI Icon component for the badge */
|
/** MUI Icon component for the badge */
|
||||||
badgeIcon?: React.ComponentType<any>;
|
badgeIcon?: React.ComponentType<any>;
|
||||||
/** Array of tool operation names in the workflow */
|
/** Array of tool operation names in the workflow */
|
||||||
@ -22,17 +26,21 @@ interface AutomationEntryProps {
|
|||||||
onEdit?: () => void;
|
onEdit?: () => void;
|
||||||
/** Delete handler */
|
/** Delete handler */
|
||||||
onDelete?: () => void;
|
onDelete?: () => void;
|
||||||
|
/** Copy handler (for suggested automations) */
|
||||||
|
onCopy?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AutomationEntry({
|
export default function AutomationEntry({
|
||||||
title,
|
title,
|
||||||
|
description,
|
||||||
badgeIcon: BadgeIcon,
|
badgeIcon: BadgeIcon,
|
||||||
operations,
|
operations,
|
||||||
onClick,
|
onClick,
|
||||||
keepIconColor = false,
|
keepIconColor = false,
|
||||||
showMenu = false,
|
showMenu = false,
|
||||||
onEdit,
|
onEdit,
|
||||||
onDelete
|
onDelete,
|
||||||
|
onCopy
|
||||||
}: AutomationEntryProps) {
|
}: AutomationEntryProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
@ -41,6 +49,47 @@ export default function AutomationEntry({
|
|||||||
// Keep item in hovered state if menu is open
|
// Keep item in hovered state if menu is open
|
||||||
const shouldShowHovered = isHovered || isMenuOpen;
|
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 = () => {
|
const renderContent = () => {
|
||||||
if (title) {
|
if (title) {
|
||||||
// Custom automation with title
|
// Custom automation with title
|
||||||
@ -89,7 +138,7 @@ export default function AutomationEntry({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
const boxContent = (
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: shouldShowHovered ? 'var(--mantine-color-gray-1)' : 'transparent',
|
backgroundColor: shouldShowHovered ? 'var(--mantine-color-gray-1)' : 'transparent',
|
||||||
@ -132,6 +181,17 @@ export default function AutomationEntry({
|
|||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
|
|
||||||
<Menu.Dropdown>
|
<Menu.Dropdown>
|
||||||
|
{onCopy && (
|
||||||
|
<Menu.Item
|
||||||
|
leftSection={<ContentCopyIcon style={{ fontSize: 16 }} />}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onCopy();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('automate.copyToSaved', 'Copy to Saved')}
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
{onEdit && (
|
{onEdit && (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
leftSection={<EditIcon style={{ fontSize: 16 }} />}
|
leftSection={<EditIcon style={{ fontSize: 16 }} />}
|
||||||
@ -160,4 +220,18 @@ export default function AutomationEntry({
|
|||||||
</Group>
|
</Group>
|
||||||
</Box>
|
</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 SettingsIcon from "@mui/icons-material/Settings";
|
||||||
import AutomationEntry from "./AutomationEntry";
|
import AutomationEntry from "./AutomationEntry";
|
||||||
import { useSuggestedAutomations } from "../../../hooks/tools/automate/useSuggestedAutomations";
|
import { useSuggestedAutomations } from "../../../hooks/tools/automate/useSuggestedAutomations";
|
||||||
import { AutomationConfig } from "../../../types/automation";
|
import { AutomationConfig, SuggestedAutomation } from "../../../types/automation";
|
||||||
|
|
||||||
interface AutomationSelectionProps {
|
interface AutomationSelectionProps {
|
||||||
savedAutomations: AutomationConfig[];
|
savedAutomations: AutomationConfig[];
|
||||||
@ -13,6 +13,7 @@ interface AutomationSelectionProps {
|
|||||||
onRun: (automation: AutomationConfig) => void;
|
onRun: (automation: AutomationConfig) => void;
|
||||||
onEdit: (automation: AutomationConfig) => void;
|
onEdit: (automation: AutomationConfig) => void;
|
||||||
onDelete: (automation: AutomationConfig) => void;
|
onDelete: (automation: AutomationConfig) => void;
|
||||||
|
onCopyFromSuggested: (automation: SuggestedAutomation) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AutomationSelection({
|
export default function AutomationSelection({
|
||||||
@ -20,7 +21,8 @@ export default function AutomationSelection({
|
|||||||
onCreateNew,
|
onCreateNew,
|
||||||
onRun,
|
onRun,
|
||||||
onEdit,
|
onEdit,
|
||||||
onDelete
|
onDelete,
|
||||||
|
onCopyFromSuggested
|
||||||
}: AutomationSelectionProps) {
|
}: AutomationSelectionProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const suggestedAutomations = useSuggestedAutomations();
|
const suggestedAutomations = useSuggestedAutomations();
|
||||||
@ -63,9 +65,13 @@ export default function AutomationSelection({
|
|||||||
{suggestedAutomations.map((automation) => (
|
{suggestedAutomations.map((automation) => (
|
||||||
<AutomationEntry
|
<AutomationEntry
|
||||||
key={automation.id}
|
key={automation.id}
|
||||||
|
title={automation.name}
|
||||||
|
description={automation.description}
|
||||||
badgeIcon={automation.icon}
|
badgeIcon={automation.icon}
|
||||||
operations={automation.operations.map(op => op.operation)}
|
operations={automation.operations.map(op => op.operation)}
|
||||||
onClick={() => onRun(automation)}
|
onClick={() => onRun(automation)}
|
||||||
|
showMenu={true}
|
||||||
|
onCopy={() => onCopyFromSuggested(automation)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { AutomationConfig } from '../../../services/automationStorage';
|
import { AutomationConfig } from '../../../services/automationStorage';
|
||||||
|
import { SuggestedAutomation } from '../../../types/automation';
|
||||||
|
|
||||||
export interface SavedAutomation extends AutomationConfig {}
|
export interface SavedAutomation extends AutomationConfig {}
|
||||||
|
|
||||||
@ -40,6 +41,26 @@ export function useSavedAutomations() {
|
|||||||
}
|
}
|
||||||
}, [refreshAutomations]);
|
}, [refreshAutomations]);
|
||||||
|
|
||||||
|
const copyFromSuggested = useCallback(async (suggestedAutomation: SuggestedAutomation) => {
|
||||||
|
try {
|
||||||
|
const { automationStorage } = await import('../../../services/automationStorage');
|
||||||
|
|
||||||
|
// Convert suggested automation to saved automation format
|
||||||
|
const savedAutomation = {
|
||||||
|
name: suggestedAutomation.name,
|
||||||
|
description: suggestedAutomation.description,
|
||||||
|
operations: suggestedAutomation.operations
|
||||||
|
};
|
||||||
|
|
||||||
|
await automationStorage.saveAutomation(savedAutomation);
|
||||||
|
// Refresh the list after saving
|
||||||
|
refreshAutomations();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error copying suggested automation:', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}, [refreshAutomations]);
|
||||||
|
|
||||||
// Load automations on mount
|
// Load automations on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadSavedAutomations();
|
loadSavedAutomations();
|
||||||
@ -50,6 +71,7 @@ export function useSavedAutomations() {
|
|||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
refreshAutomations,
|
refreshAutomations,
|
||||||
deleteAutomation
|
deleteAutomation,
|
||||||
|
copyFromSuggested
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -17,9 +17,60 @@ export function useSuggestedAutomations(): SuggestedAutomation[] {
|
|||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: "compress-and-split",
|
id: "secure-pdf-ingestion",
|
||||||
name: t("automation.suggested.compressAndSplit", "Compress & Split"),
|
name: t("automation.suggested.securePdfIngestion", "Secure PDF Ingestion"),
|
||||||
description: t("automation.suggested.compressAndSplitDesc", "Compress PDFs and split them by pages"),
|
description: t("automation.suggested.securePdfIngestionDesc", "Comprehensive PDF processing workflow that sanitizes documents, applies OCR with cleanup, converts to PDF/A format for long-term archival, and optimizes file size."),
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
operation: "sanitize",
|
||||||
|
parameters: {
|
||||||
|
removeJavaScript: true,
|
||||||
|
removeEmbeddedFiles: true,
|
||||||
|
removeXMPMetadata: true,
|
||||||
|
removeMetadata: true,
|
||||||
|
removeLinks: false,
|
||||||
|
removeFonts: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
operation: "ocr",
|
||||||
|
parameters: {
|
||||||
|
languages: ['eng'],
|
||||||
|
ocrType: 'skip-text',
|
||||||
|
ocrRenderType: 'hocr',
|
||||||
|
additionalOptions: ['clean', 'cleanFinal'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
operation: "convert",
|
||||||
|
parameters: {
|
||||||
|
fromExtension: 'pdf',
|
||||||
|
toExtension: 'pdfa',
|
||||||
|
pdfaOptions: {
|
||||||
|
outputFormat: 'pdfa-1',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
operation: "compress",
|
||||||
|
parameters: {
|
||||||
|
compressionLevel: 5,
|
||||||
|
grayscale: false,
|
||||||
|
expectedSize: '',
|
||||||
|
compressionMethod: 'quality',
|
||||||
|
fileSizeValue: '',
|
||||||
|
fileSizeUnit: 'MB',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
icon: SecurityIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "email-preparation",
|
||||||
|
name: t("automation.suggested.emailPreparation", "Email Preparation"),
|
||||||
|
description: t("automation.suggested.emailPreparationDesc", "Optimizes PDFs for email distribution by compressing files, splitting large documents into 20MB chunks for email compatibility, and removing metadata for privacy."),
|
||||||
operations: [
|
operations: [
|
||||||
{
|
{
|
||||||
operation: "compress",
|
operation: "compress",
|
||||||
@ -36,45 +87,37 @@ export function useSuggestedAutomations(): SuggestedAutomation[] {
|
|||||||
operation: "splitPdf",
|
operation: "splitPdf",
|
||||||
parameters: {
|
parameters: {
|
||||||
mode: 'bySizeOrCount',
|
mode: 'bySizeOrCount',
|
||||||
pages: '1',
|
pages: '',
|
||||||
hDiv: '2',
|
hDiv: '1',
|
||||||
vDiv: '2',
|
vDiv: '1',
|
||||||
merge: false,
|
merge: false,
|
||||||
splitType: 'pages',
|
splitType: 'size',
|
||||||
splitValue: '1',
|
splitValue: '20MB',
|
||||||
bookmarkLevel: '1',
|
bookmarkLevel: '1',
|
||||||
includeMetadata: false,
|
includeMetadata: false,
|
||||||
allowDuplicates: false,
|
allowDuplicates: false,
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
operation: "sanitize",
|
||||||
|
parameters: {
|
||||||
|
removeJavaScript: false,
|
||||||
|
removeEmbeddedFiles: false,
|
||||||
|
removeXMPMetadata: true,
|
||||||
|
removeMetadata: true,
|
||||||
|
removeLinks: false,
|
||||||
|
removeFonts: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
icon: CompressIcon,
|
icon: CompressIcon,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "ocr-workflow",
|
|
||||||
name: t("automation.suggested.ocrWorkflow", "OCR Processing"),
|
|
||||||
description: t("automation.suggested.ocrWorkflowDesc", "Extract text from PDFs using OCR technology"),
|
|
||||||
operations: [
|
|
||||||
{
|
|
||||||
operation: "ocr",
|
|
||||||
parameters: {
|
|
||||||
languages: ['eng'],
|
|
||||||
ocrType: 'skip-text',
|
|
||||||
ocrRenderType: 'hocr',
|
|
||||||
additionalOptions: [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
createdAt: now,
|
|
||||||
updatedAt: now,
|
|
||||||
icon: TextFieldsIcon,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "secure-workflow",
|
id: "secure-workflow",
|
||||||
name: t("automation.suggested.secureWorkflow", "Security Workflow"),
|
name: t("automation.suggested.secureWorkflow", "Security Workflow"),
|
||||||
description: t("automation.suggested.secureWorkflowDesc", "Sanitize PDFs and add password protection"),
|
description: t("automation.suggested.secureWorkflowDesc", "Secures PDF documents by removing potentially malicious content like JavaScript and embedded files, then adds password protection to prevent unauthorized access."),
|
||||||
operations: [
|
operations: [
|
||||||
{
|
{
|
||||||
operation: "sanitize",
|
operation: "sanitize",
|
||||||
@ -111,23 +154,32 @@ export function useSuggestedAutomations(): SuggestedAutomation[] {
|
|||||||
icon: SecurityIcon,
|
icon: SecurityIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "optimization-workflow",
|
id: "process-images",
|
||||||
name: t("automation.suggested.optimizationWorkflow", "Optimization Workflow"),
|
name: t("automation.suggested.processImages", "Process Images"),
|
||||||
description: t("automation.suggested.optimizationWorkflowDesc", "Repair and compress PDFs for better performance"),
|
description: t("automation.suggested.processImagesDesc", "Converts multiple image files into a single PDF document, then applies OCR technology to extract searchable text from the images."),
|
||||||
operations: [
|
operations: [
|
||||||
{
|
{
|
||||||
operation: "repair",
|
operation: "convert",
|
||||||
parameters: {}
|
parameters: {
|
||||||
|
fromExtension: 'image',
|
||||||
|
toExtension: 'pdf',
|
||||||
|
imageOptions: {
|
||||||
|
colorType: 'color',
|
||||||
|
dpi: 300,
|
||||||
|
singleOrMultiple: 'multiple',
|
||||||
|
fitOption: 'maintainAspectRatio',
|
||||||
|
autoRotate: true,
|
||||||
|
combineImages: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
operation: "compress",
|
operation: "ocr",
|
||||||
parameters: {
|
parameters: {
|
||||||
compressionLevel: 7,
|
languages: ['eng'],
|
||||||
grayscale: false,
|
ocrType: 'skip-text',
|
||||||
expectedSize: '',
|
ocrRenderType: 'hocr',
|
||||||
compressionMethod: 'quality',
|
additionalOptions: [],
|
||||||
fileSizeValue: '',
|
|
||||||
fileSizeUnit: 'MB',
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -28,7 +28,7 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
const automateOperation = useAutomateOperation();
|
const automateOperation = useAutomateOperation();
|
||||||
const toolRegistry = useFlatToolRegistry();
|
const toolRegistry = useFlatToolRegistry();
|
||||||
const hasResults = automateOperation.files.length > 0 || automateOperation.downloadUrl !== null;
|
const hasResults = automateOperation.files.length > 0 || automateOperation.downloadUrl !== null;
|
||||||
const { savedAutomations, deleteAutomation, refreshAutomations } = useSavedAutomations();
|
const { savedAutomations, deleteAutomation, refreshAutomations, copyFromSuggested } = useSavedAutomations();
|
||||||
|
|
||||||
const handleStepChange = (data: AutomationStepData) => {
|
const handleStepChange = (data: AutomationStepData) => {
|
||||||
// If navigating away from run step, reset automation results
|
// If navigating away from run step, reset automation results
|
||||||
@ -79,6 +79,14 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
onError?.(`Failed to delete automation: ${automation.name}`);
|
onError?.(`Failed to delete automation: ${automation.name}`);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
onCopyFromSuggested={async (suggestedAutomation) => {
|
||||||
|
try {
|
||||||
|
await copyFromSuggested(suggestedAutomation);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to copy suggested automation:', error);
|
||||||
|
onError?.(`Failed to copy automation: ${suggestedAutomation.name}`);
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user