mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 14:19:24 +00:00
Demo working for few tools
This commit is contained in:
parent
555d937921
commit
4956d6b4da
@ -1,27 +1,15 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from "react-i18next";
|
||||||
import {
|
import { Button, Text, Stack, Group, Progress, Card } from "@mantine/core";
|
||||||
Button,
|
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
||||||
Text,
|
import CheckIcon from "@mui/icons-material/Check";
|
||||||
Title,
|
import ErrorIcon from "@mui/icons-material/Error";
|
||||||
Stack,
|
import { useFileSelection } from "../../../contexts/FileSelectionContext";
|
||||||
Group,
|
import { useFlatToolRegistry } from "../../../data/useTranslatedToolRegistry";
|
||||||
ActionIcon,
|
import { executeAutomationSequence } from "../../../utils/automationExecutor";
|
||||||
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';
|
|
||||||
|
|
||||||
interface AutomationRunProps {
|
interface AutomationRunProps {
|
||||||
automation: any;
|
automation: any;
|
||||||
onBack: () => void;
|
|
||||||
onComplete: () => void;
|
onComplete: () => void;
|
||||||
automateOperation?: any; // Add the operation hook to store results
|
automateOperation?: any; // Add the operation hook to store results
|
||||||
}
|
}
|
||||||
@ -30,18 +18,17 @@ interface ExecutionStep {
|
|||||||
id: string;
|
id: string;
|
||||||
operation: string;
|
operation: string;
|
||||||
name: string;
|
name: string;
|
||||||
status: 'pending' | 'running' | 'completed' | 'error';
|
status: "pending" | "running" | "completed" | "error";
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AutomationRun({ automation, onBack, onComplete, automateOperation }: AutomationRunProps) {
|
export default function AutomationRun({ automation, onComplete, automateOperation }: AutomationRunProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { activeFiles, consumeFiles } = useFileContext();
|
const { selectedFiles } = useFileSelection();
|
||||||
const toolRegistry = useFlatToolRegistry();
|
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(() => {
|
||||||
@ -52,74 +39,41 @@ export default function AutomationRun({ automation, onBack, onComplete, automate
|
|||||||
id: `${op.operation}-${index}`,
|
id: `${op.operation}-${index}`,
|
||||||
operation: op.operation,
|
operation: op.operation,
|
||||||
name: tool?.name || op.operation,
|
name: tool?.name || op.operation,
|
||||||
status: 'pending' as const
|
status: "pending" as const,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
setExecutionSteps(steps);
|
setExecutionSteps(steps);
|
||||||
}
|
}
|
||||||
}, [automation]); // Remove toolRegistry from dependencies to prevent infinite loops
|
}, [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 () => {
|
const executeAutomation = async () => {
|
||||||
if (!activeFiles || activeFiles.length === 0) {
|
if (!selectedFiles || selectedFiles.length === 0) {
|
||||||
// Show error - need files to execute automation
|
// Show error - need files to execute automation
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!automateOperation) {
|
||||||
|
console.error('No automateOperation provided');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsExecuting(true);
|
setIsExecuting(true);
|
||||||
setCurrentStepIndex(0);
|
setCurrentStepIndex(0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Execute the automation sequence using the new executor
|
// Use the automateOperation.executeOperation to handle file consumption properly
|
||||||
const finalResults = await executeAutomationSequence(
|
await automateOperation.executeOperation(
|
||||||
automation,
|
{ automationConfig: automation },
|
||||||
activeFiles,
|
selectedFiles
|
||||||
(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
|
|
||||||
));
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// All steps completed successfully
|
// All steps completed successfully
|
||||||
setCurrentStepIndex(-1);
|
setCurrentStepIndex(-1);
|
||||||
setIsExecuting(false);
|
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) {
|
} catch (error: any) {
|
||||||
console.error('Automation execution failed:', error);
|
console.error("Automation execution failed:", error);
|
||||||
setIsExecuting(false);
|
setIsExecuting(false);
|
||||||
setCurrentStepIndex(-1);
|
setCurrentStepIndex(-1);
|
||||||
}
|
}
|
||||||
@ -127,24 +81,35 @@ export default function AutomationRun({ automation, onBack, onComplete, automate
|
|||||||
|
|
||||||
const getStepIcon = (step: ExecutionStep) => {
|
const getStepIcon = (step: ExecutionStep) => {
|
||||||
switch (step.status) {
|
switch (step.status) {
|
||||||
case 'completed':
|
case "completed":
|
||||||
return <CheckIcon style={{ fontSize: 16, color: 'green' }} />;
|
return <CheckIcon style={{ fontSize: 16, color: "green" }} />;
|
||||||
case 'error':
|
case "error":
|
||||||
return <ErrorIcon style={{ fontSize: 16, color: 'red' }} />;
|
return <ErrorIcon style={{ fontSize: 16, color: "red" }} />;
|
||||||
case 'running':
|
case "running":
|
||||||
return <div style={{ width: 16, height: 16, border: '2px solid #ccc', borderTop: '2px solid #007bff', borderRadius: '50%', animation: 'spin 1s linear infinite' }} />;
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
border: "2px solid #ccc",
|
||||||
|
borderTop: "2px solid #007bff",
|
||||||
|
borderRadius: "50%",
|
||||||
|
animation: "spin 1s linear infinite",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return <div style={{ width: 16, height: 16, border: '2px solid #ccc', borderRadius: '50%' }} />;
|
return <div style={{ width: 16, height: 16, border: "2px solid #ccc", borderRadius: "50%" }} />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProgress = () => {
|
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;
|
return (completedSteps / executionSteps.length) * 100;
|
||||||
};
|
};
|
||||||
|
|
||||||
const allStepsCompleted = executionSteps.every(step => step.status === 'completed');
|
const allStepsCompleted = executionSteps.every((step) => step.status === "completed");
|
||||||
const hasErrors = executionSteps.some(step => step.status === 'error');
|
const hasErrors = executionSteps.some((step) => step.status === "error");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -152,10 +117,10 @@ export default function AutomationRun({ automation, onBack, onComplete, automate
|
|||||||
{/* Automation Info */}
|
{/* Automation Info */}
|
||||||
<Card padding="md" withBorder>
|
<Card padding="md" withBorder>
|
||||||
<Text size="sm" fw={500} mb="xs">
|
<Text size="sm" fw={500} mb="xs">
|
||||||
{automation?.name || t('automate.sequence.unnamed', 'Unnamed Automation')}
|
{automation?.name || t("automate.sequence.unnamed", "Unnamed Automation")}
|
||||||
</Text>
|
</Text>
|
||||||
<Text size="xs" c="dimmed">
|
<Text size="xs" c="dimmed">
|
||||||
{t('automate.sequence.steps', '{{count}} steps', { count: executionSteps.length })}
|
{t("automate.sequence.steps", "{{count}} steps", { count: executionSteps.length })}
|
||||||
</Text>
|
</Text>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
@ -163,9 +128,9 @@ export default function AutomationRun({ automation, onBack, onComplete, automate
|
|||||||
{isExecuting && (
|
{isExecuting && (
|
||||||
<div>
|
<div>
|
||||||
<Text size="sm" mb="xs">
|
<Text size="sm" mb="xs">
|
||||||
{t('automate.sequence.progress', 'Progress: {{current}}/{{total}}', {
|
{t("automate.sequence.progress", "Progress: {{current}}/{{total}}", {
|
||||||
current: currentStepIndex + 1,
|
current: currentStepIndex + 1,
|
||||||
total: executionSteps.length
|
total: executionSteps.length,
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
<Progress value={getProgress()} size="lg" />
|
<Progress value={getProgress()} size="lg" />
|
||||||
@ -176,17 +141,20 @@ export default function AutomationRun({ automation, onBack, onComplete, automate
|
|||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
{executionSteps.map((step, index) => (
|
{executionSteps.map((step, index) => (
|
||||||
<Group key={step.id} gap="sm" align="center">
|
<Group key={step.id} gap="sm" align="center">
|
||||||
<Text size="xs" c="dimmed" style={{ minWidth: '1rem', textAlign: 'center' }}>
|
<Text size="xs" c="dimmed" style={{ minWidth: "1rem", textAlign: "center" }}>
|
||||||
{index + 1}
|
{index + 1}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{getStepIcon(step)}
|
{getStepIcon(step)}
|
||||||
|
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<Text size="sm" style={{
|
<Text
|
||||||
color: step.status === 'running' ? 'var(--mantine-color-blue-6)' : 'var(--mantine-color-text)',
|
size="sm"
|
||||||
fontWeight: step.status === 'running' ? 500 : 400
|
style={{
|
||||||
}}>
|
color: step.status === "running" ? "var(--mantine-color-blue-6)" : "var(--mantine-color-text)",
|
||||||
|
fontWeight: step.status === "running" ? 500 : 400,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{step.name}
|
{step.name}
|
||||||
</Text>
|
</Text>
|
||||||
{step.error && (
|
{step.error && (
|
||||||
@ -204,23 +172,13 @@ export default function AutomationRun({ automation, onBack, onComplete, automate
|
|||||||
<Button
|
<Button
|
||||||
leftSection={<PlayArrowIcon />}
|
leftSection={<PlayArrowIcon />}
|
||||||
onClick={executeAutomation}
|
onClick={executeAutomation}
|
||||||
disabled={isExecuting || !activeFiles || activeFiles.length === 0}
|
disabled={isExecuting || !selectedFiles || selectedFiles.length === 0}
|
||||||
loading={isExecuting}
|
loading={isExecuting}
|
||||||
>
|
>
|
||||||
{isExecuting
|
{isExecuting
|
||||||
? t('automate.sequence.running', 'Running Automation...')
|
? t("automate.sequence.running", "Running Automation...")
|
||||||
: t('automate.sequence.run', 'Run Automation')
|
: t("automate.sequence.run", "Run Automation")}
|
||||||
}
|
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{(allStepsCompleted || hasErrors) && (
|
|
||||||
<Button
|
|
||||||
variant="light"
|
|
||||||
onClick={onComplete}
|
|
||||||
>
|
|
||||||
{t('automate.sequence.finish', 'Finish')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ const showPlaceholderTools = false; // For development purposes. Allows seeing t
|
|||||||
export function useFlatToolRegistry(): ToolRegistry {
|
export function useFlatToolRegistry(): ToolRegistry {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const allTools: ToolRegistry = {
|
return useMemo(() => {
|
||||||
|
const allTools: ToolRegistry = {
|
||||||
// Signing
|
// Signing
|
||||||
|
|
||||||
"certSign": {
|
"certSign": {
|
||||||
@ -620,15 +621,16 @@ export function useFlatToolRegistry(): ToolRegistry {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (showPlaceholderTools) {
|
if (showPlaceholderTools) {
|
||||||
return allTools;
|
return allTools;
|
||||||
} else {
|
} else {
|
||||||
const filteredTools = Object.keys(allTools)
|
const filteredTools = Object.keys(allTools)
|
||||||
.filter(key => allTools[key].component !== null || allTools[key].link)
|
.filter(key => allTools[key].component !== null || allTools[key].link)
|
||||||
.reduce((obj, key) => {
|
.reduce((obj, key) => {
|
||||||
obj[key] = allTools[key];
|
obj[key] = allTools[key];
|
||||||
return obj;
|
return obj;
|
||||||
}, {} as ToolRegistry);
|
}, {} as ToolRegistry);
|
||||||
return filteredTools;
|
return filteredTools;
|
||||||
}
|
}
|
||||||
|
}, [t]); // Only re-compute when translations change
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useToolOperation } from '../shared/useToolOperation';
|
import { useToolOperation } from '../shared/useToolOperation';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { executeAutomationSequence } from '../../../utils/automationExecutor';
|
||||||
|
|
||||||
interface AutomateParameters {
|
interface AutomateParameters {
|
||||||
automationConfig?: any;
|
automationConfig?: any;
|
||||||
@ -7,16 +8,36 @@ interface AutomateParameters {
|
|||||||
|
|
||||||
export function useAutomateOperation() {
|
export function useAutomateOperation() {
|
||||||
const customProcessor = useCallback(async (params: AutomateParameters, files: File[]) => {
|
const customProcessor = useCallback(async (params: AutomateParameters, files: File[]) => {
|
||||||
// For now, this is a placeholder - the automation execution will be implemented later
|
console.log('🚀 Starting automation execution via customProcessor', { params, files });
|
||||||
// This function would send the automation config to the backend pipeline endpoint
|
|
||||||
console.log('Automation execution not yet implemented', { params, files });
|
if (!params.automationConfig) {
|
||||||
throw new Error('Automation execution not yet implemented');
|
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<AutomateParameters>({
|
return useToolOperation<AutomateParameters>({
|
||||||
operationType: 'automate',
|
operationType: 'automate',
|
||||||
endpoint: '/api/v1/pipeline/handleData',
|
endpoint: '/api/v1/pipeline/handleData', // Not used with customProcessor
|
||||||
buildFormData: () => new FormData(), // Placeholder, not used with customProcessor
|
buildFormData: () => new FormData(), // Not used with customProcessor
|
||||||
customProcessor,
|
customProcessor,
|
||||||
filePrefix: 'automated_'
|
filePrefix: 'automated_'
|
||||||
});
|
});
|
||||||
|
@ -74,7 +74,6 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
return (
|
return (
|
||||||
<AutomationRun
|
<AutomationRun
|
||||||
automation={stepData.automation}
|
automation={stepData.automation}
|
||||||
onBack={() => handleStepChange({ step: 'selection'})}
|
|
||||||
onComplete={handleComplete}
|
onComplete={handleComplete}
|
||||||
automateOperation={automateOperation}
|
automateOperation={automateOperation}
|
||||||
/>
|
/>
|
||||||
@ -121,7 +120,7 @@ const Automate = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
|||||||
// Run step
|
// Run step
|
||||||
createStep(t('automate.run.title', 'Run Automation'), {
|
createStep(t('automate.run.title', 'Run Automation'), {
|
||||||
isVisible: currentStep === 'run',
|
isVisible: currentStep === 'run',
|
||||||
isCollapsed: false
|
isCollapsed: hasResults,
|
||||||
}, currentStep === 'run' ? renderCurrentStep() : null)
|
}, currentStep === 'run' ? renderCurrentStep() : null)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user