mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 14:19:24 +00:00
First automation run
This commit is contained in:
parent
1136c00547
commit
fa5baf9371
@ -257,12 +257,24 @@ export default function AutomationCreation({ mode, existingAutomation, onBack, o
|
|||||||
key={`tool-selector-${tool.id}`}
|
key={`tool-selector-${tool.id}`}
|
||||||
onSelect={(newOperation) => {
|
onSelect={(newOperation) => {
|
||||||
const updatedTools = [...selectedTools];
|
const updatedTools = [...selectedTools];
|
||||||
|
|
||||||
|
// Get default parameters from the tool
|
||||||
|
let defaultParams = {};
|
||||||
|
const tool = toolRegistry?.[newOperation];
|
||||||
|
if (tool?.component && (tool.component as any).getDefaultParameters) {
|
||||||
|
try {
|
||||||
|
defaultParams = (tool.component as any).getDefaultParameters();
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Failed to get default parameters for ${newOperation}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updatedTools[index] = {
|
updatedTools[index] = {
|
||||||
...updatedTools[index],
|
...updatedTools[index],
|
||||||
operation: newOperation,
|
operation: newOperation,
|
||||||
name: getToolName(newOperation),
|
name: getToolName(newOperation),
|
||||||
configured: false,
|
configured: false,
|
||||||
parameters: {}
|
parameters: defaultParams
|
||||||
};
|
};
|
||||||
setSelectedTools(updatedTools);
|
setSelectedTools(updatedTools);
|
||||||
}}
|
}}
|
||||||
|
112
frontend/src/components/tools/automate/AutomationExecutor.tsx
Normal file
112
frontend/src/components/tools/automate/AutomationExecutor.tsx
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useFlatToolRegistry } from '../../../data/useTranslatedToolRegistry';
|
||||||
|
import { ToolComponent } from '../../../types/tool';
|
||||||
|
|
||||||
|
interface AutomationExecutorProps {
|
||||||
|
automation: any;
|
||||||
|
files: File[];
|
||||||
|
onStepStart: (stepIndex: number) => void;
|
||||||
|
onStepComplete: (stepIndex: number, results: File[]) => void;
|
||||||
|
onStepError: (stepIndex: number, error: string) => void;
|
||||||
|
onComplete: (finalResults: File[]) => void;
|
||||||
|
shouldExecute: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that manages the execution of automation steps using real tool hooks.
|
||||||
|
* This component creates operation hook instances for each tool in the automation.
|
||||||
|
*/
|
||||||
|
export const AutomationExecutor: React.FC<AutomationExecutorProps> = ({
|
||||||
|
automation,
|
||||||
|
files,
|
||||||
|
onStepStart,
|
||||||
|
onStepComplete,
|
||||||
|
onStepError,
|
||||||
|
onComplete,
|
||||||
|
shouldExecute
|
||||||
|
}) => {
|
||||||
|
const toolRegistry = useFlatToolRegistry();
|
||||||
|
const [currentStepIndex, setCurrentStepIndex] = useState(-1);
|
||||||
|
const [currentFiles, setCurrentFiles] = useState<File[]>(files);
|
||||||
|
const [isExecuting, setIsExecuting] = useState(false);
|
||||||
|
|
||||||
|
// Create operation hooks for all tools in the automation
|
||||||
|
const operationHooks = React.useMemo(() => {
|
||||||
|
if (!automation?.operations) return {};
|
||||||
|
|
||||||
|
const hooks: Record<string, any> = {};
|
||||||
|
automation.operations.forEach((op: any, index: number) => {
|
||||||
|
const tool = toolRegistry[op.operation];
|
||||||
|
if (tool?.component) {
|
||||||
|
const toolComponent = tool.component as ToolComponent;
|
||||||
|
if (toolComponent.tool) {
|
||||||
|
// We still can't call the hook here dynamically
|
||||||
|
// This approach also won't work
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return hooks;
|
||||||
|
}, [automation, toolRegistry]);
|
||||||
|
|
||||||
|
// Execute automation when shouldExecute becomes true
|
||||||
|
useEffect(() => {
|
||||||
|
if (shouldExecute && !isExecuting && automation?.operations?.length > 0) {
|
||||||
|
executeAutomation();
|
||||||
|
}
|
||||||
|
}, [shouldExecute, isExecuting, automation]);
|
||||||
|
|
||||||
|
const executeAutomation = async () => {
|
||||||
|
if (!automation?.operations || automation.operations.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsExecuting(true);
|
||||||
|
setCurrentFiles(files);
|
||||||
|
let filesToProcess = [...files];
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < automation.operations.length; i++) {
|
||||||
|
setCurrentStepIndex(i);
|
||||||
|
const operation = automation.operations[i];
|
||||||
|
|
||||||
|
onStepStart(i);
|
||||||
|
|
||||||
|
// Get the tool
|
||||||
|
const tool = toolRegistry[operation.operation];
|
||||||
|
if (!tool?.component) {
|
||||||
|
throw new Error(`Tool not found: ${operation.operation}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const toolComponent = tool.component as ToolComponent;
|
||||||
|
if (!toolComponent.tool) {
|
||||||
|
throw new Error(`Tool ${operation.operation} does not support automation`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, simulate the execution
|
||||||
|
// TODO: We need to find a way to actually execute the tool operation
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
|
|
||||||
|
// For now, assume the operation succeeded with the same files
|
||||||
|
const resultFiles = filesToProcess; // TODO: Get actual results
|
||||||
|
|
||||||
|
onStepComplete(i, resultFiles);
|
||||||
|
filesToProcess = resultFiles;
|
||||||
|
setCurrentFiles(resultFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
onComplete(filesToProcess);
|
||||||
|
setIsExecuting(false);
|
||||||
|
setCurrentStepIndex(-1);
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Automation execution failed:', error);
|
||||||
|
onStepError(currentStepIndex, error.message);
|
||||||
|
setIsExecuting(false);
|
||||||
|
setCurrentStepIndex(-1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This component doesn't render anything visible
|
||||||
|
return null;
|
||||||
|
};
|
@ -16,11 +16,14 @@ import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
|||||||
import CheckIcon from '@mui/icons-material/Check';
|
import CheckIcon from '@mui/icons-material/Check';
|
||||||
import ErrorIcon from '@mui/icons-material/Error';
|
import ErrorIcon from '@mui/icons-material/Error';
|
||||||
import { useFileContext } from '../../../contexts/FileContext';
|
import { useFileContext } from '../../../contexts/FileContext';
|
||||||
|
import { useFlatToolRegistry } from '../../../data/useTranslatedToolRegistry';
|
||||||
|
import { executeAutomationSequence } from '../../../utils/automationExecutor';
|
||||||
|
|
||||||
interface AutomationRunProps {
|
interface AutomationRunProps {
|
||||||
automation: any;
|
automation: any;
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
onComplete: () => void;
|
onComplete: () => void;
|
||||||
|
automateOperation?: any; // Add the operation hook to store results
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExecutionStep {
|
interface ExecutionStep {
|
||||||
@ -31,25 +34,34 @@ interface ExecutionStep {
|
|||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AutomationRun({ automation, onBack, onComplete }: AutomationRunProps) {
|
export default function AutomationRun({ automation, onBack, onComplete, automateOperation }: AutomationRunProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { activeFiles } = useFileContext();
|
const { activeFiles, consumeFiles } = useFileContext();
|
||||||
|
const toolRegistry = useFlatToolRegistry();
|
||||||
const [isExecuting, setIsExecuting] = useState(false);
|
const [isExecuting, setIsExecuting] = useState(false);
|
||||||
const [executionSteps, setExecutionSteps] = useState<ExecutionStep[]>([]);
|
const [executionSteps, setExecutionSteps] = useState<ExecutionStep[]>([]);
|
||||||
const [currentStepIndex, setCurrentStepIndex] = useState(-1);
|
const [currentStepIndex, setCurrentStepIndex] = useState(-1);
|
||||||
|
const [currentFiles, setCurrentFiles] = useState<File[]>([]);
|
||||||
|
|
||||||
// Initialize execution steps from automation
|
// Initialize execution steps from automation
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (automation?.operations) {
|
if (automation?.operations) {
|
||||||
const steps = automation.operations.map((op: any, index: number) => ({
|
const steps = automation.operations.map((op: any, index: number) => {
|
||||||
|
const tool = toolRegistry[op.operation];
|
||||||
|
return {
|
||||||
id: `${op.operation}-${index}`,
|
id: `${op.operation}-${index}`,
|
||||||
operation: op.operation,
|
operation: op.operation,
|
||||||
name: op.operation, // You might want to get the display name from tool registry
|
name: tool?.name || op.operation,
|
||||||
status: 'pending' as const
|
status: 'pending' as const
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
setExecutionSteps(steps);
|
setExecutionSteps(steps);
|
||||||
}
|
}
|
||||||
}, [automation]);
|
// Initialize current files with active files
|
||||||
|
if (activeFiles) {
|
||||||
|
setCurrentFiles([...activeFiles]);
|
||||||
|
}
|
||||||
|
}, [automation, toolRegistry, activeFiles]);
|
||||||
|
|
||||||
const executeAutomation = async () => {
|
const executeAutomation = async () => {
|
||||||
if (!activeFiles || activeFiles.length === 0) {
|
if (!activeFiles || activeFiles.length === 0) {
|
||||||
@ -61,33 +73,52 @@ export default function AutomationRun({ automation, onBack, onComplete }: Automa
|
|||||||
setCurrentStepIndex(0);
|
setCurrentStepIndex(0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (let i = 0; i < executionSteps.length; i++) {
|
// Execute the automation sequence using the new executor
|
||||||
setCurrentStepIndex(i);
|
const finalResults = await executeAutomationSequence(
|
||||||
|
automation,
|
||||||
// Update step status to running
|
activeFiles,
|
||||||
|
(stepIndex: number, operationName: string) => {
|
||||||
|
// Step started
|
||||||
|
setCurrentStepIndex(stepIndex);
|
||||||
setExecutionSteps(prev => prev.map((step, idx) =>
|
setExecutionSteps(prev => prev.map((step, idx) =>
|
||||||
idx === i ? { ...step, status: 'running' } : step
|
idx === stepIndex ? { ...step, status: 'running' } : step
|
||||||
));
|
));
|
||||||
|
},
|
||||||
// Simulate step execution (replace with actual tool execution)
|
(stepIndex: number, resultFiles: File[]) => {
|
||||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
// Step completed
|
||||||
|
|
||||||
// Update step status to completed
|
|
||||||
setExecutionSteps(prev => prev.map((step, idx) =>
|
setExecutionSteps(prev => prev.map((step, idx) =>
|
||||||
idx === i ? { ...step, status: 'completed' } : step
|
idx === stepIndex ? { ...step, status: 'completed' } : step
|
||||||
|
));
|
||||||
|
setCurrentFiles(resultFiles);
|
||||||
|
},
|
||||||
|
(stepIndex: number, error: string) => {
|
||||||
|
// Step failed
|
||||||
|
setExecutionSteps(prev => prev.map((step, idx) =>
|
||||||
|
idx === stepIndex ? { ...step, status: 'error', error } : step
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// All steps completed successfully
|
||||||
setCurrentStepIndex(-1);
|
setCurrentStepIndex(-1);
|
||||||
setIsExecuting(false);
|
setIsExecuting(false);
|
||||||
|
setCurrentFiles(finalResults);
|
||||||
|
|
||||||
// All steps completed - show success
|
// Properly integrate results with FileContext
|
||||||
} catch (error) {
|
if (finalResults.length > 0) {
|
||||||
// Handle error
|
console.log(`🎨 Integrating ${finalResults.length} result files with FileContext`);
|
||||||
setExecutionSteps(prev => prev.map((step, idx) =>
|
|
||||||
idx === currentStepIndex ? { ...step, status: 'error', error: error?.toString() } : step
|
// Use FileContext's consumeFiles to properly add results
|
||||||
));
|
// This replaces input files with output files (like other tools do)
|
||||||
|
await consumeFiles(activeFiles, finalResults);
|
||||||
|
|
||||||
|
console.log(`✅ Successfully integrated automation results with FileContext`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Automation execution failed:', error);
|
||||||
setIsExecuting(false);
|
setIsExecuting(false);
|
||||||
|
setCurrentStepIndex(-1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { type TFunction } from 'i18next';
|
import { type TFunction } from 'i18next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { ToolOperationHook } from '../hooks/tools/shared/useToolOperation';
|
||||||
|
|
||||||
export enum SubcategoryId {
|
export enum SubcategoryId {
|
||||||
SIGNING = 'signing',
|
SIGNING = 'signing',
|
||||||
@ -34,6 +35,8 @@ export type ToolRegistryEntry = {
|
|||||||
endpoints?: string[];
|
endpoints?: string[];
|
||||||
link?: string;
|
link?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
|
// Hook for automation execution
|
||||||
|
operationHook?: () => ToolOperationHook<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToolRegistry = Record<string, ToolRegistryEntry>;
|
export type ToolRegistry = Record<string, ToolRegistryEntry>;
|
||||||
|
141
frontend/src/hooks/tools/automate/useAutomationExecution.ts
Normal file
141
frontend/src/hooks/tools/automate/useAutomationExecution.ts
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import { useState, useCallback } from 'react';
|
||||||
|
import { useFlatToolRegistry } from '../../../data/useTranslatedToolRegistry';
|
||||||
|
import { ToolComponent } from '../../../types/tool';
|
||||||
|
|
||||||
|
interface ExecutionStep {
|
||||||
|
id: string;
|
||||||
|
operation: string;
|
||||||
|
name: string;
|
||||||
|
status: 'pending' | 'running' | 'completed' | 'error';
|
||||||
|
error?: string;
|
||||||
|
parameters?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AutomationExecutionState {
|
||||||
|
isExecuting: boolean;
|
||||||
|
currentStepIndex: number;
|
||||||
|
executionSteps: ExecutionStep[];
|
||||||
|
currentFiles: File[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for managing automation execution with real tool operations
|
||||||
|
*/
|
||||||
|
export const useAutomationExecution = () => {
|
||||||
|
const toolRegistry = useFlatToolRegistry();
|
||||||
|
const [state, setState] = useState<AutomationExecutionState>({
|
||||||
|
isExecuting: false,
|
||||||
|
currentStepIndex: -1,
|
||||||
|
executionSteps: [],
|
||||||
|
currentFiles: []
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store operation hook instances for the current automation
|
||||||
|
const [operationHooks, setOperationHooks] = useState<Record<string, any>>({});
|
||||||
|
|
||||||
|
const initializeAutomation = useCallback((automation: any, initialFiles: File[]) => {
|
||||||
|
if (!automation?.operations) return;
|
||||||
|
|
||||||
|
const steps = automation.operations.map((op: any, index: number) => {
|
||||||
|
const tool = toolRegistry[op.operation];
|
||||||
|
return {
|
||||||
|
id: `${op.operation}-${index}`,
|
||||||
|
operation: op.operation,
|
||||||
|
name: tool?.name || op.operation,
|
||||||
|
status: 'pending' as const,
|
||||||
|
parameters: op.parameters || {}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize operation hooks for all tools in the automation
|
||||||
|
const hooks: Record<string, any> = {};
|
||||||
|
steps.forEach((step) => {
|
||||||
|
const tool = toolRegistry[step.operation];
|
||||||
|
if (tool?.component) {
|
||||||
|
const toolComponent = tool.component as ToolComponent;
|
||||||
|
if (toolComponent.tool) {
|
||||||
|
const hookFactory = toolComponent.tool();
|
||||||
|
// We still can't call hooks here - this approach won't work
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setState({
|
||||||
|
isExecuting: false,
|
||||||
|
currentStepIndex: -1,
|
||||||
|
executionSteps: steps,
|
||||||
|
currentFiles: [...initialFiles]
|
||||||
|
});
|
||||||
|
}, [toolRegistry]);
|
||||||
|
|
||||||
|
const executeAutomation = useCallback(async () => {
|
||||||
|
if (state.executionSteps.length === 0 || state.currentFiles.length === 0) {
|
||||||
|
throw new Error('No steps or files to execute');
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(prev => ({ ...prev, isExecuting: true, currentStepIndex: 0 }));
|
||||||
|
let filesToProcess = [...state.currentFiles];
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < state.executionSteps.length; i++) {
|
||||||
|
setState(prev => ({ ...prev, currentStepIndex: i }));
|
||||||
|
const step = state.executionSteps[i];
|
||||||
|
|
||||||
|
// Update step status to running
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
executionSteps: prev.executionSteps.map((s, idx) =>
|
||||||
|
idx === i ? { ...s, status: 'running' } : s
|
||||||
|
)
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Get the tool and validate it supports automation
|
||||||
|
const tool = toolRegistry[step.operation];
|
||||||
|
if (!tool?.component) {
|
||||||
|
throw new Error(`Tool not found: ${step.operation}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const toolComponent = tool.component as ToolComponent;
|
||||||
|
if (!toolComponent.tool) {
|
||||||
|
throw new Error(`Tool ${step.operation} does not support automation`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, simulate execution until we solve the hook problem
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||||
|
|
||||||
|
// Update step status to completed
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
executionSteps: prev.executionSteps.map((s, idx) =>
|
||||||
|
idx === i ? { ...s, status: 'completed' } : s
|
||||||
|
)
|
||||||
|
}));
|
||||||
|
|
||||||
|
// TODO: Update filesToProcess with actual results
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
isExecuting: false,
|
||||||
|
currentStepIndex: -1,
|
||||||
|
currentFiles: filesToProcess
|
||||||
|
}));
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Automation execution failed:', error);
|
||||||
|
setState(prev => ({
|
||||||
|
...prev,
|
||||||
|
isExecuting: false,
|
||||||
|
executionSteps: prev.executionSteps.map((s, idx) =>
|
||||||
|
idx === prev.currentStepIndex ? { ...s, status: 'error', error: error.message } : s
|
||||||
|
)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}, [state.executionSteps, state.currentFiles, toolRegistry]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
initializeAutomation,
|
||||||
|
executeAutomation
|
||||||
|
};
|
||||||
|
};
|
@ -9,7 +9,7 @@ export interface CompressParametersHook {
|
|||||||
getEndpointName: () => string;
|
getEndpointName: () => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialParameters: CompressParameters = {
|
export const initialParameters: CompressParameters = {
|
||||||
compressionLevel: 5,
|
compressionLevel: 5,
|
||||||
grayscale: false,
|
grayscale: false,
|
||||||
expectedSize: '',
|
expectedSize: '',
|
||||||
|
@ -9,11 +9,11 @@ import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
|||||||
import AddPasswordSettings from "../components/tools/addPassword/AddPasswordSettings";
|
import AddPasswordSettings from "../components/tools/addPassword/AddPasswordSettings";
|
||||||
import ChangePermissionsSettings from "../components/tools/changePermissions/ChangePermissionsSettings";
|
import ChangePermissionsSettings from "../components/tools/changePermissions/ChangePermissionsSettings";
|
||||||
|
|
||||||
import { useAddPasswordParameters } from "../hooks/tools/addPassword/useAddPasswordParameters";
|
import { useAddPasswordParameters, defaultParameters } from "../hooks/tools/addPassword/useAddPasswordParameters";
|
||||||
import { useAddPasswordOperation } from "../hooks/tools/addPassword/useAddPasswordOperation";
|
import { useAddPasswordOperation } from "../hooks/tools/addPassword/useAddPasswordOperation";
|
||||||
import { useAddPasswordTips } from "../components/tooltips/useAddPasswordTips";
|
import { useAddPasswordTips } from "../components/tooltips/useAddPasswordTips";
|
||||||
import { useAddPasswordPermissionsTips } from "../components/tooltips/useAddPasswordPermissionsTips";
|
import { useAddPasswordPermissionsTips } from "../components/tooltips/useAddPasswordPermissionsTips";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const AddPassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const AddPassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -114,4 +114,12 @@ const AddPassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddPassword;
|
// Static method to get the operation hook for automation
|
||||||
|
AddPassword.tool = () => useAddPasswordOperation;
|
||||||
|
|
||||||
|
// Static method to get default parameters for automation
|
||||||
|
AddPassword.getDefaultParameters = () => {
|
||||||
|
return defaultParameters;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddPassword as ToolComponent;
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
useWatermarkFileTips,
|
useWatermarkFileTips,
|
||||||
useWatermarkFormattingTips,
|
useWatermarkFormattingTips,
|
||||||
} from "../components/tooltips/useWatermarkTips";
|
} from "../components/tooltips/useWatermarkTips";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -209,4 +209,7 @@ const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =>
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddWatermark;
|
// Static method to get the operation hook for automation
|
||||||
|
AddWatermark.tool = () => useAddWatermarkOperation;
|
||||||
|
|
||||||
|
export default AddWatermark as ToolComponent;
|
||||||
|
@ -76,6 +76,7 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
automation={stepData.automation}
|
automation={stepData.automation}
|
||||||
onBack={() => handleStepChange({ step: 'selection'})}
|
onBack={() => handleStepChange({ step: 'selection'})}
|
||||||
onComplete={handleComplete}
|
onComplete={handleComplete}
|
||||||
|
automateOperation={automateOperation}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -132,7 +133,7 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
},
|
},
|
||||||
steps: automationSteps,
|
steps: automationSteps,
|
||||||
review: {
|
review: {
|
||||||
isVisible: hasResults,
|
isVisible: true,
|
||||||
operation: automateOperation,
|
operation: automateOperation,
|
||||||
title: t('automate.reviewTitle', 'Automation Results')
|
title: t('automate.reviewTitle', 'Automation Results')
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import ChangePermissionsSettings from "../components/tools/changePermissions/Cha
|
|||||||
import { useChangePermissionsParameters } from "../hooks/tools/changePermissions/useChangePermissionsParameters";
|
import { useChangePermissionsParameters } from "../hooks/tools/changePermissions/useChangePermissionsParameters";
|
||||||
import { useChangePermissionsOperation } from "../hooks/tools/changePermissions/useChangePermissionsOperation";
|
import { useChangePermissionsOperation } from "../hooks/tools/changePermissions/useChangePermissionsOperation";
|
||||||
import { useChangePermissionsTips } from "../components/tooltips/useChangePermissionsTips";
|
import { useChangePermissionsTips } from "../components/tooltips/useChangePermissionsTips";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const ChangePermissions = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const ChangePermissions = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -97,4 +97,7 @@ const ChangePermissions = ({ onPreviewFile, onComplete, onError }: BaseToolProps
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ChangePermissions;
|
// Static method to get the operation hook for automation
|
||||||
|
ChangePermissions.tool = () => useChangePermissionsOperation;
|
||||||
|
|
||||||
|
export default ChangePermissions as ToolComponent;
|
||||||
|
@ -8,9 +8,9 @@ import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
|||||||
|
|
||||||
import CompressSettings from "../components/tools/compress/CompressSettings";
|
import CompressSettings from "../components/tools/compress/CompressSettings";
|
||||||
|
|
||||||
import { useCompressParameters } from "../hooks/tools/compress/useCompressParameters";
|
import { useCompressParameters, initialParameters } from "../hooks/tools/compress/useCompressParameters";
|
||||||
import { useCompressOperation } from "../hooks/tools/compress/useCompressOperation";
|
import { useCompressOperation } from "../hooks/tools/compress/useCompressOperation";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
import { useCompressTips } from "../components/tooltips/useCompressTips";
|
import { useCompressTips } from "../components/tooltips/useCompressTips";
|
||||||
|
|
||||||
const Compress = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const Compress = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
@ -95,4 +95,12 @@ const Compress = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Compress;
|
// Static method to get the operation hook for automation
|
||||||
|
Compress.tool = () => useCompressOperation;
|
||||||
|
|
||||||
|
// Static method to get default parameters for automation
|
||||||
|
Compress.getDefaultParameters = () => {
|
||||||
|
return initialParameters;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Compress as ToolComponent;
|
||||||
|
@ -10,7 +10,7 @@ import ConvertSettings from "../components/tools/convert/ConvertSettings";
|
|||||||
|
|
||||||
import { useConvertParameters } from "../hooks/tools/convert/useConvertParameters";
|
import { useConvertParameters } from "../hooks/tools/convert/useConvertParameters";
|
||||||
import { useConvertOperation } from "../hooks/tools/convert/useConvertOperation";
|
import { useConvertOperation } from "../hooks/tools/convert/useConvertOperation";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -133,4 +133,7 @@ const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Convert;
|
// Static method to get the operation hook for automation
|
||||||
|
Convert.tool = () => useConvertOperation;
|
||||||
|
|
||||||
|
export default Convert as ToolComponent;
|
||||||
|
@ -11,7 +11,7 @@ import AdvancedOCRSettings from "../components/tools/ocr/AdvancedOCRSettings";
|
|||||||
|
|
||||||
import { useOCRParameters } from "../hooks/tools/ocr/useOCRParameters";
|
import { useOCRParameters } from "../hooks/tools/ocr/useOCRParameters";
|
||||||
import { useOCROperation } from "../hooks/tools/ocr/useOCROperation";
|
import { useOCROperation } from "../hooks/tools/ocr/useOCROperation";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
import { useOCRTips } from "../components/tooltips/useOCRTips";
|
import { useOCRTips } from "../components/tooltips/useOCRTips";
|
||||||
|
|
||||||
const OCR = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const OCR = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
@ -136,4 +136,7 @@ const OCR = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default OCR;
|
// Static method to get the operation hook for automation
|
||||||
|
OCR.tool = () => useOCROperation;
|
||||||
|
|
||||||
|
export default OCR as ToolComponent;
|
||||||
|
@ -8,7 +8,7 @@ import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
|||||||
|
|
||||||
import { useRemoveCertificateSignParameters } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters";
|
import { useRemoveCertificateSignParameters } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters";
|
||||||
import { useRemoveCertificateSignOperation } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation";
|
import { useRemoveCertificateSignOperation } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const RemoveCertificateSign = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const RemoveCertificateSign = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -77,4 +77,7 @@ const RemoveCertificateSign = ({ onPreviewFile, onComplete, onError }: BaseToolP
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RemoveCertificateSign;
|
// Static method to get the operation hook for automation
|
||||||
|
RemoveCertificateSign.tool = () => useRemoveCertificateSignOperation;
|
||||||
|
|
||||||
|
export default RemoveCertificateSign as ToolComponent;
|
@ -11,7 +11,7 @@ import RemovePasswordSettings from "../components/tools/removePassword/RemovePas
|
|||||||
import { useRemovePasswordParameters } from "../hooks/tools/removePassword/useRemovePasswordParameters";
|
import { useRemovePasswordParameters } from "../hooks/tools/removePassword/useRemovePasswordParameters";
|
||||||
import { useRemovePasswordOperation } from "../hooks/tools/removePassword/useRemovePasswordOperation";
|
import { useRemovePasswordOperation } from "../hooks/tools/removePassword/useRemovePasswordOperation";
|
||||||
import { useRemovePasswordTips } from "../components/tooltips/useRemovePasswordTips";
|
import { useRemovePasswordTips } from "../components/tooltips/useRemovePasswordTips";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const RemovePassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const RemovePassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -95,4 +95,7 @@ const RemovePassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RemovePassword;
|
// Static method to get the operation hook for automation
|
||||||
|
RemovePassword.tool = () => useRemovePasswordOperation;
|
||||||
|
|
||||||
|
export default RemovePassword as ToolComponent;
|
||||||
|
@ -8,7 +8,7 @@ import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
|||||||
|
|
||||||
import { useRepairParameters } from "../hooks/tools/repair/useRepairParameters";
|
import { useRepairParameters } from "../hooks/tools/repair/useRepairParameters";
|
||||||
import { useRepairOperation } from "../hooks/tools/repair/useRepairOperation";
|
import { useRepairOperation } from "../hooks/tools/repair/useRepairOperation";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const Repair = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const Repair = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -77,4 +77,7 @@ const Repair = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Repair;
|
// Static method to get the operation hook for automation
|
||||||
|
Repair.tool = () => useRepairOperation;
|
||||||
|
|
||||||
|
export default Repair as ToolComponent;
|
||||||
|
@ -8,7 +8,7 @@ import SanitizeSettings from "../components/tools/sanitize/SanitizeSettings";
|
|||||||
|
|
||||||
import { useSanitizeParameters } from "../hooks/tools/sanitize/useSanitizeParameters";
|
import { useSanitizeParameters } from "../hooks/tools/sanitize/useSanitizeParameters";
|
||||||
import { useSanitizeOperation } from "../hooks/tools/sanitize/useSanitizeOperation";
|
import { useSanitizeOperation } from "../hooks/tools/sanitize/useSanitizeOperation";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
import { useFileContext } from "../contexts/FileContext";
|
import { useFileContext } from "../contexts/FileContext";
|
||||||
|
|
||||||
const Sanitize = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const Sanitize = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
@ -93,4 +93,7 @@ const Sanitize = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Sanitize;
|
// Static method to get the operation hook for automation
|
||||||
|
Sanitize.tool = () => useSanitizeOperation;
|
||||||
|
|
||||||
|
export default Sanitize as ToolComponent;
|
||||||
|
@ -8,7 +8,7 @@ import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
|||||||
|
|
||||||
import { useSingleLargePageParameters } from "../hooks/tools/singleLargePage/useSingleLargePageParameters";
|
import { useSingleLargePageParameters } from "../hooks/tools/singleLargePage/useSingleLargePageParameters";
|
||||||
import { useSingleLargePageOperation } from "../hooks/tools/singleLargePage/useSingleLargePageOperation";
|
import { useSingleLargePageOperation } from "../hooks/tools/singleLargePage/useSingleLargePageOperation";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const SingleLargePage = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const SingleLargePage = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -77,4 +77,7 @@ const SingleLargePage = ({ onPreviewFile, onComplete, onError }: BaseToolProps)
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SingleLargePage;
|
// Static method to get the operation hook for automation
|
||||||
|
SingleLargePage.tool = () => useSingleLargePageOperation;
|
||||||
|
|
||||||
|
export default SingleLargePage as ToolComponent;
|
@ -9,7 +9,7 @@ import SplitSettings from "../components/tools/split/SplitSettings";
|
|||||||
|
|
||||||
import { useSplitParameters } from "../hooks/tools/split/useSplitParameters";
|
import { useSplitParameters } from "../hooks/tools/split/useSplitParameters";
|
||||||
import { useSplitOperation } from "../hooks/tools/split/useSplitOperation";
|
import { useSplitOperation } from "../hooks/tools/split/useSplitOperation";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -92,4 +92,7 @@ const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Split;
|
// Static method to get the operation hook for automation
|
||||||
|
Split.tool = () => useSplitOperation;
|
||||||
|
|
||||||
|
export default Split as ToolComponent;
|
||||||
|
@ -8,7 +8,7 @@ import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
|||||||
|
|
||||||
import { useUnlockPdfFormsParameters } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsParameters";
|
import { useUnlockPdfFormsParameters } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsParameters";
|
||||||
import { useUnlockPdfFormsOperation } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsOperation";
|
import { useUnlockPdfFormsOperation } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsOperation";
|
||||||
import { BaseToolProps } from "../types/tool";
|
import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||||
|
|
||||||
const UnlockPdfForms = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
const UnlockPdfForms = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -77,4 +77,7 @@ const UnlockPdfForms = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UnlockPdfForms;
|
// Static method to get the operation hook for automation
|
||||||
|
UnlockPdfForms.tool = () => useUnlockPdfFormsOperation;
|
||||||
|
|
||||||
|
export default UnlockPdfForms as ToolComponent;
|
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { ToolOperationHook } from '../hooks/tools/shared/useToolOperation';
|
||||||
|
|
||||||
export type MaxFiles = number; // 1=single, >1=limited, -1=unlimited
|
export type MaxFiles = number; // 1=single, >1=limited, -1=unlimited
|
||||||
export type ToolCategory = 'manipulation' | 'conversion' | 'analysis' | 'utility' | 'optimization' | 'security';
|
export type ToolCategory = 'manipulation' | 'conversion' | 'analysis' | 'utility' | 'optimization' | 'security';
|
||||||
@ -11,6 +12,29 @@ export interface BaseToolProps {
|
|||||||
onPreviewFile?: (file: File | null) => void;
|
onPreviewFile?: (file: File | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for tool components that support automation.
|
||||||
|
* Tools implementing this interface can be used in automation workflows.
|
||||||
|
*/
|
||||||
|
export interface AutomationCapableTool {
|
||||||
|
/**
|
||||||
|
* Static method that returns the operation hook for this tool.
|
||||||
|
* This enables automation to execute the tool programmatically.
|
||||||
|
*/
|
||||||
|
tool: () => () => ToolOperationHook<any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static method that returns the default parameters for this tool.
|
||||||
|
* This enables automation creation to initialize tools with proper defaults.
|
||||||
|
*/
|
||||||
|
getDefaultParameters: () => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for tool components that can be used in automation
|
||||||
|
*/
|
||||||
|
export type ToolComponent = React.ComponentType<BaseToolProps> & AutomationCapableTool;
|
||||||
|
|
||||||
export interface ToolStepConfig {
|
export interface ToolStepConfig {
|
||||||
type: ToolStepType;
|
type: ToolStepType;
|
||||||
title: string;
|
title: string;
|
||||||
|
208
frontend/src/utils/automationExecutor.ts
Normal file
208
frontend/src/utils/automationExecutor.ts
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
// Tool operation configurations extracted from the hook implementations
|
||||||
|
const TOOL_CONFIGS: Record<string, any> = {
|
||||||
|
'compressPdfs': {
|
||||||
|
endpoint: '/api/v1/misc/compress-pdf',
|
||||||
|
multiFileEndpoint: false,
|
||||||
|
buildFormData: (parameters: any, file: File): FormData => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("fileInput", file);
|
||||||
|
|
||||||
|
if (parameters.compressionMethod === 'quality') {
|
||||||
|
formData.append("optimizeLevel", parameters.compressionLevel?.toString() || '1');
|
||||||
|
} else {
|
||||||
|
const fileSize = parameters.fileSizeValue ? `${parameters.fileSizeValue}${parameters.fileSizeUnit}` : '';
|
||||||
|
if (fileSize) {
|
||||||
|
formData.append("expectedOutputSize", fileSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formData.append("grayscale", parameters.grayscale?.toString() || 'false');
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'split': {
|
||||||
|
endpoint: (parameters: any): string => {
|
||||||
|
// Simplified endpoint selection - you'd need the full logic from useSplitOperation
|
||||||
|
return "/api/v1/general/split-pages";
|
||||||
|
},
|
||||||
|
multiFileEndpoint: true,
|
||||||
|
buildFormData: (parameters: any, files: File[]): FormData => {
|
||||||
|
const formData = new FormData();
|
||||||
|
files.forEach(file => {
|
||||||
|
formData.append("fileInput", file);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add split parameters - simplified version
|
||||||
|
if (parameters.pages) {
|
||||||
|
formData.append("pageNumbers", parameters.pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'addPassword': {
|
||||||
|
endpoint: '/api/v1/security/add-password',
|
||||||
|
multiFileEndpoint: false,
|
||||||
|
buildFormData: (parameters: any, file: File): FormData => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("fileInput", file);
|
||||||
|
|
||||||
|
if (parameters.password) {
|
||||||
|
formData.append("password", parameters.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add other password parameters as needed
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add configurations for other tools
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract zip files from response blob
|
||||||
|
*/
|
||||||
|
const extractZipFiles = async (blob: Blob): Promise<File[]> => {
|
||||||
|
// This would need the actual zip extraction logic from the codebase
|
||||||
|
// For now, create a single file from the blob
|
||||||
|
const file = new File([blob], `result_${Date.now()}.pdf`, { type: 'application/pdf' });
|
||||||
|
return [file];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a tool operation directly without using React hooks
|
||||||
|
*/
|
||||||
|
export const executeToolOperation = async (
|
||||||
|
operationName: string,
|
||||||
|
parameters: any,
|
||||||
|
files: File[]
|
||||||
|
): Promise<File[]> => {
|
||||||
|
console.log(`🔧 Executing tool: ${operationName}`, { parameters, fileCount: files.length });
|
||||||
|
|
||||||
|
const config = TOOL_CONFIGS[operationName];
|
||||||
|
if (!config) {
|
||||||
|
console.error(`❌ Tool operation not supported: ${operationName}`);
|
||||||
|
throw new Error(`Tool operation not supported: ${operationName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`📋 Using config:`, config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (config.multiFileEndpoint) {
|
||||||
|
// Multi-file processing - single API call with all files
|
||||||
|
const endpoint = typeof config.endpoint === 'function'
|
||||||
|
? config.endpoint(parameters)
|
||||||
|
: config.endpoint;
|
||||||
|
|
||||||
|
console.log(`🌐 Making multi-file request to: ${endpoint}`);
|
||||||
|
const formData = config.buildFormData(parameters, files);
|
||||||
|
console.log(`📤 FormData entries:`, Array.from(formData.entries()));
|
||||||
|
|
||||||
|
const response = await axios.post(endpoint, formData, {
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 300000 // 5 minute timeout for large files
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`📥 Response status: ${response.status}, size: ${response.data.size} bytes`);
|
||||||
|
|
||||||
|
// Multi-file responses are typically ZIP files
|
||||||
|
const resultFiles = await extractZipFiles(response.data);
|
||||||
|
console.log(`📁 Extracted ${resultFiles.length} files from response`);
|
||||||
|
return resultFiles;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Single-file processing - separate API call per file
|
||||||
|
console.log(`🔄 Processing ${files.length} files individually`);
|
||||||
|
const resultFiles: File[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
const file = files[i];
|
||||||
|
const endpoint = typeof config.endpoint === 'function'
|
||||||
|
? config.endpoint(parameters)
|
||||||
|
: config.endpoint;
|
||||||
|
|
||||||
|
console.log(`🌐 Making single-file request ${i+1}/${files.length} to: ${endpoint} for file: ${file.name}`);
|
||||||
|
const formData = config.buildFormData(parameters, file);
|
||||||
|
console.log(`📤 FormData entries:`, Array.from(formData.entries()));
|
||||||
|
|
||||||
|
const response = await axios.post(endpoint, formData, {
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: 300000 // 5 minute timeout for large files
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`📥 Response ${i+1} status: ${response.status}, size: ${response.data.size} bytes`);
|
||||||
|
|
||||||
|
// Create result file
|
||||||
|
const resultFile = new File(
|
||||||
|
[response.data],
|
||||||
|
`processed_${file.name}`,
|
||||||
|
{ type: 'application/pdf' }
|
||||||
|
);
|
||||||
|
resultFiles.push(resultFile);
|
||||||
|
console.log(`✅ Created result file: ${resultFile.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🎉 Single-file processing complete: ${resultFiles.length} files`);
|
||||||
|
return resultFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(`Tool operation ${operationName} failed:`, error);
|
||||||
|
throw new Error(`${operationName} operation failed: ${error.response?.data || error.message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an entire automation sequence
|
||||||
|
*/
|
||||||
|
export const executeAutomationSequence = async (
|
||||||
|
automation: any,
|
||||||
|
initialFiles: File[],
|
||||||
|
onStepStart?: (stepIndex: number, operationName: string) => void,
|
||||||
|
onStepComplete?: (stepIndex: number, resultFiles: File[]) => void,
|
||||||
|
onStepError?: (stepIndex: number, error: string) => void
|
||||||
|
): Promise<File[]> => {
|
||||||
|
console.log(`🚀 Starting automation sequence: ${automation.name || 'Unnamed'}`);
|
||||||
|
console.log(`📁 Initial files: ${initialFiles.length}`);
|
||||||
|
console.log(`🔧 Operations: ${automation.operations?.length || 0}`);
|
||||||
|
|
||||||
|
if (!automation?.operations || automation.operations.length === 0) {
|
||||||
|
throw new Error('No operations in automation');
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentFiles = [...initialFiles];
|
||||||
|
|
||||||
|
for (let i = 0; i < automation.operations.length; i++) {
|
||||||
|
const operation = automation.operations[i];
|
||||||
|
|
||||||
|
console.log(`📋 Step ${i + 1}/${automation.operations.length}: ${operation.operation}`);
|
||||||
|
console.log(`📄 Input files: ${currentFiles.length}`);
|
||||||
|
console.log(`⚙️ Parameters:`, operation.parameters || {});
|
||||||
|
|
||||||
|
try {
|
||||||
|
onStepStart?.(i, operation.operation);
|
||||||
|
|
||||||
|
const resultFiles = await executeToolOperation(
|
||||||
|
operation.operation,
|
||||||
|
operation.parameters || {},
|
||||||
|
currentFiles
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`✅ Step ${i + 1} completed: ${resultFiles.length} result files`);
|
||||||
|
currentFiles = resultFiles;
|
||||||
|
onStepComplete?.(i, resultFiles);
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(`❌ Step ${i + 1} failed:`, error);
|
||||||
|
onStepError?.(i, error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🎉 Automation sequence completed: ${currentFiles.length} final files`);
|
||||||
|
return currentFiles;
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user