From 4956d6b4daf821f2f775ce0a895ad5682f791f1e Mon Sep 17 00:00:00 2001 From: Connor Yoh Date: Thu, 21 Aug 2025 12:53:28 +0100 Subject: [PATCH] Demo working for few tools --- .../tools/automate/AutomationRun.tsx | 164 +++++++----------- .../src/data/useTranslatedToolRegistry.tsx | 26 +-- .../tools/automate/useAutomateOperation.ts | 33 +++- frontend/src/tools/Automate.tsx | 3 +- 4 files changed, 103 insertions(+), 123 deletions(-) diff --git a/frontend/src/components/tools/automate/AutomationRun.tsx b/frontend/src/components/tools/automate/AutomationRun.tsx index c400bae22..a107b573f 100644 --- a/frontend/src/components/tools/automate/AutomationRun.tsx +++ b/frontend/src/components/tools/automate/AutomationRun.tsx @@ -1,27 +1,15 @@ -import React, { useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { - Button, - Text, - Title, - Stack, - Group, - ActionIcon, - Progress, - Card, - Alert -} from '@mantine/core'; -import ArrowBackIcon from '@mui/icons-material/ArrowBack'; -import PlayArrowIcon from '@mui/icons-material/PlayArrow'; -import CheckIcon from '@mui/icons-material/Check'; -import ErrorIcon from '@mui/icons-material/Error'; -import { useFileContext } from '../../../contexts/FileContext'; -import { useFlatToolRegistry } from '../../../data/useTranslatedToolRegistry'; -import { executeAutomationSequence } from '../../../utils/automationExecutor'; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Button, Text, Stack, Group, Progress, Card } from "@mantine/core"; +import PlayArrowIcon from "@mui/icons-material/PlayArrow"; +import CheckIcon from "@mui/icons-material/Check"; +import ErrorIcon from "@mui/icons-material/Error"; +import { useFileSelection } from "../../../contexts/FileSelectionContext"; +import { useFlatToolRegistry } from "../../../data/useTranslatedToolRegistry"; +import { executeAutomationSequence } from "../../../utils/automationExecutor"; interface AutomationRunProps { automation: any; - onBack: () => void; onComplete: () => void; automateOperation?: any; // Add the operation hook to store results } @@ -30,18 +18,17 @@ interface ExecutionStep { id: string; operation: string; name: string; - status: 'pending' | 'running' | 'completed' | 'error'; + status: "pending" | "running" | "completed" | "error"; error?: string; } -export default function AutomationRun({ automation, onBack, onComplete, automateOperation }: AutomationRunProps) { +export default function AutomationRun({ automation, onComplete, automateOperation }: AutomationRunProps) { const { t } = useTranslation(); - const { activeFiles, consumeFiles } = useFileContext(); + const { selectedFiles } = useFileSelection(); const toolRegistry = useFlatToolRegistry(); const [isExecuting, setIsExecuting] = useState(false); const [executionSteps, setExecutionSteps] = useState([]); const [currentStepIndex, setCurrentStepIndex] = useState(-1); - const [currentFiles, setCurrentFiles] = useState([]); // Initialize execution steps from automation React.useEffect(() => { @@ -52,74 +39,41 @@ export default function AutomationRun({ automation, onBack, onComplete, automate id: `${op.operation}-${index}`, operation: op.operation, name: tool?.name || op.operation, - status: 'pending' as const + status: "pending" as const, }; }); setExecutionSteps(steps); } }, [automation]); // Remove toolRegistry from dependencies to prevent infinite loops - // Initialize current files with active files (separate effect) - React.useEffect(() => { - if (activeFiles && activeFiles.length > 0) { - setCurrentFiles([...activeFiles]); - } - }, [activeFiles?.length]); // Only depend on length to avoid infinite loops - const executeAutomation = async () => { - if (!activeFiles || activeFiles.length === 0) { + if (!selectedFiles || selectedFiles.length === 0) { // Show error - need files to execute automation return; } + if (!automateOperation) { + console.error('No automateOperation provided'); + return; + } + setIsExecuting(true); setCurrentStepIndex(0); try { - // Execute the automation sequence using the new executor - const finalResults = await executeAutomationSequence( - automation, - activeFiles, - (stepIndex: number, operationName: string) => { - // Step started - setCurrentStepIndex(stepIndex); - setExecutionSteps(prev => prev.map((step, idx) => - idx === stepIndex ? { ...step, status: 'running' } : step - )); - }, - (stepIndex: number, resultFiles: File[]) => { - // Step completed - setExecutionSteps(prev => prev.map((step, idx) => - 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 - )); - } + // Use the automateOperation.executeOperation to handle file consumption properly + await automateOperation.executeOperation( + { automationConfig: automation }, + selectedFiles ); // All steps completed successfully setCurrentStepIndex(-1); setIsExecuting(false); - setCurrentFiles(finalResults); - - // Properly integrate results with FileContext - if (finalResults.length > 0) { - console.log(`🎨 Integrating ${finalResults.length} result files with FileContext`); - - // 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`); - } + console.log(`✅ Automation completed successfully`); } catch (error: any) { - console.error('Automation execution failed:', error); + console.error("Automation execution failed:", error); setIsExecuting(false); setCurrentStepIndex(-1); } @@ -127,24 +81,35 @@ export default function AutomationRun({ automation, onBack, onComplete, automate const getStepIcon = (step: ExecutionStep) => { switch (step.status) { - case 'completed': - return ; - case 'error': - return ; - case 'running': - return
; + case "completed": + return ; + case "error": + return ; + case "running": + return ( +
+ ); default: - return
; + return
; } }; const getProgress = () => { - const completedSteps = executionSteps.filter(step => step.status === 'completed').length; + const completedSteps = executionSteps.filter((step) => step.status === "completed").length; return (completedSteps / executionSteps.length) * 100; }; - const allStepsCompleted = executionSteps.every(step => step.status === 'completed'); - const hasErrors = executionSteps.some(step => step.status === 'error'); + const allStepsCompleted = executionSteps.every((step) => step.status === "completed"); + const hasErrors = executionSteps.some((step) => step.status === "error"); return (
@@ -152,10 +117,10 @@ export default function AutomationRun({ automation, onBack, onComplete, automate {/* Automation Info */} - {automation?.name || t('automate.sequence.unnamed', 'Unnamed Automation')} + {automation?.name || t("automate.sequence.unnamed", "Unnamed Automation")} - {t('automate.sequence.steps', '{{count}} steps', { count: executionSteps.length })} + {t("automate.sequence.steps", "{{count}} steps", { count: executionSteps.length })} @@ -163,9 +128,9 @@ export default function AutomationRun({ automation, onBack, onComplete, automate {isExecuting && (
- {t('automate.sequence.progress', 'Progress: {{current}}/{{total}}', { + {t("automate.sequence.progress", "Progress: {{current}}/{{total}}", { current: currentStepIndex + 1, - total: executionSteps.length + total: executionSteps.length, })} @@ -176,17 +141,20 @@ export default function AutomationRun({ automation, onBack, onComplete, automate {executionSteps.map((step, index) => ( - + {index + 1} {getStepIcon(step)}
- + {step.name} {step.error && ( @@ -204,23 +172,13 @@ export default function AutomationRun({ automation, onBack, onComplete, automate - - {(allStepsCompleted || hasErrors) && ( - - )} diff --git a/frontend/src/data/useTranslatedToolRegistry.tsx b/frontend/src/data/useTranslatedToolRegistry.tsx index d1596b0ca..f02914ee9 100644 --- a/frontend/src/data/useTranslatedToolRegistry.tsx +++ b/frontend/src/data/useTranslatedToolRegistry.tsx @@ -21,7 +21,8 @@ const showPlaceholderTools = false; // For development purposes. Allows seeing t export function useFlatToolRegistry(): ToolRegistry { const { t } = useTranslation(); - const allTools: ToolRegistry = { + return useMemo(() => { + const allTools: ToolRegistry = { // Signing "certSign": { @@ -620,15 +621,16 @@ export function useFlatToolRegistry(): ToolRegistry { }, }; - if (showPlaceholderTools) { - return allTools; - } else { - const filteredTools = Object.keys(allTools) - .filter(key => allTools[key].component !== null || allTools[key].link) - .reduce((obj, key) => { - obj[key] = allTools[key]; - return obj; - }, {} as ToolRegistry); - return filteredTools; - } + if (showPlaceholderTools) { + return allTools; + } else { + const filteredTools = Object.keys(allTools) + .filter(key => allTools[key].component !== null || allTools[key].link) + .reduce((obj, key) => { + obj[key] = allTools[key]; + return obj; + }, {} as ToolRegistry); + return filteredTools; + } + }, [t]); // Only re-compute when translations change } diff --git a/frontend/src/hooks/tools/automate/useAutomateOperation.ts b/frontend/src/hooks/tools/automate/useAutomateOperation.ts index 2baa40aa8..4e3a16fe1 100644 --- a/frontend/src/hooks/tools/automate/useAutomateOperation.ts +++ b/frontend/src/hooks/tools/automate/useAutomateOperation.ts @@ -1,5 +1,6 @@ import { useToolOperation } from '../shared/useToolOperation'; import { useCallback } from 'react'; +import { executeAutomationSequence } from '../../../utils/automationExecutor'; interface AutomateParameters { automationConfig?: any; @@ -7,16 +8,36 @@ interface AutomateParameters { export function useAutomateOperation() { const customProcessor = useCallback(async (params: AutomateParameters, files: File[]) => { - // For now, this is a placeholder - the automation execution will be implemented later - // This function would send the automation config to the backend pipeline endpoint - console.log('Automation execution not yet implemented', { params, files }); - throw new Error('Automation execution not yet implemented'); + console.log('🚀 Starting automation execution via customProcessor', { params, files }); + + if (!params.automationConfig) { + throw new Error('No automation configuration provided'); + } + + // Execute the automation sequence and return the final results + const finalResults = await executeAutomationSequence( + params.automationConfig, + files, + (stepIndex: number, operationName: string) => { + console.log(`Step ${stepIndex + 1} started: ${operationName}`); + }, + (stepIndex: number, resultFiles: File[]) => { + console.log(`Step ${stepIndex + 1} completed with ${resultFiles.length} files`); + }, + (stepIndex: number, error: string) => { + console.error(`Step ${stepIndex + 1} failed:`, error); + throw new Error(`Automation step ${stepIndex + 1} failed: ${error}`); + } + ); + + console.log(`✅ Automation completed, returning ${finalResults.length} files`); + return finalResults; }, []); return useToolOperation({ operationType: 'automate', - endpoint: '/api/v1/pipeline/handleData', - buildFormData: () => new FormData(), // Placeholder, not used with customProcessor + endpoint: '/api/v1/pipeline/handleData', // Not used with customProcessor + buildFormData: () => new FormData(), // Not used with customProcessor customProcessor, filePrefix: 'automated_' }); diff --git a/frontend/src/tools/Automate.tsx b/frontend/src/tools/Automate.tsx index 957dc560c..fd80aebb1 100644 --- a/frontend/src/tools/Automate.tsx +++ b/frontend/src/tools/Automate.tsx @@ -74,7 +74,6 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => { return ( handleStepChange({ step: 'selection'})} onComplete={handleComplete} automateOperation={automateOperation} /> @@ -121,7 +120,7 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => { // Run step createStep(t('automate.run.title', 'Run Automation'), { isVisible: currentStep === 'run', - isCollapsed: false + isCollapsed: hasResults, }, currentStep === 'run' ? renderCurrentStep() : null) ];