198 lines
6.9 KiB
JavaScript

import React, { useState } from 'react';
import { toast } from 'react-toastify';
import nodeService from '../../services/nodes';
import Modal from '../common/Modal';
import { PlayIcon, ArrowPathIcon } from '@heroicons/react/24/outline';
const NodeTester = ({ node, onClose }) => {
const [inputData, setInputData] = useState('{}');
const [testResults, setTestResults] = useState(null);
const [loading, setLoading] = useState(false);
const [inputError, setInputError] = useState(null);
// Test node configuration with provided input
const handleTestNode = async () => {
// Validate JSON input
try {
JSON.parse(inputData);
setInputError(null);
} catch (error) {
setInputError('Invalid JSON format');
return;
}
try {
setLoading(true);
const parsedInput = JSON.parse(inputData);
const response = await nodeService.testNodeConfig(
node.data.nodeType,
node.data.config || {},
parsedInput
);
setTestResults(response.data);
toast.success('Node test completed successfully');
} catch (error) {
console.error('Error testing node:', error);
toast.error('Failed to test node configuration');
// If we have error details from the API
if (error.response?.data?.error) {
setTestResults({
success: false,
error: error.response.data.error,
output: null
});
} else {
setTestResults({
success: false,
error: error.message || 'An unknown error occurred',
output: null
});
}
} finally {
setLoading(false);
}
};
// Format JSON for display
const formatJSON = (json) => {
try {
if (typeof json === 'string') {
return JSON.stringify(JSON.parse(json), null, 2);
}
return JSON.stringify(json, null, 2);
} catch (error) {
return json;
}
};
return (
<div className="bg-white shadow-xl rounded-lg overflow-hidden max-w-4xl w-full">
<div className="px-4 py-5 sm:px-6 border-b border-gray-200">
<h3 className="text-lg leading-6 font-medium text-gray-900">
Test Node: {node.data.label}
</h3>
<p className="mt-1 text-sm text-gray-500">
Test this node with sample input data
</p>
</div>
<div className="px-4 py-5 sm:p-6">
<div className="space-y-6">
{/* Input section */}
<div>
<label htmlFor="input-data" className="block text-sm font-medium text-gray-700">
Input Data (JSON)
</label>
<div className="mt-1">
<textarea
id="input-data"
name="input-data"
rows={5}
className={`shadow-sm block w-full focus:ring-primary-500 focus:border-primary-500 sm:text-sm border-gray-300 rounded-md font-mono ${
inputError ? 'border-red-300' : ''
}`}
value={inputData}
onChange={(e) => setInputData(e.target.value)}
placeholder='{"key": "value"}'
/>
{inputError && (
<p className="mt-1 text-sm text-red-600">{inputError}</p>
)}
</div>
<p className="mt-2 text-sm text-gray-500">
Enter sample input data in JSON format to test this node
</p>
</div>
{/* Test button */}
<div>
<button
type="button"
onClick={handleTestNode}
disabled={loading}
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 disabled:opacity-50"
>
{loading ? (
<>
<ArrowPathIcon className="h-5 w-5 mr-2 animate-spin" />
Testing...
</>
) : (
<>
<PlayIcon className="h-5 w-5 mr-2" />
Run Test
</>
)}
</button>
</div>
{/* Results section */}
{testResults && (
<div className="border rounded-md overflow-hidden">
<div className="bg-gray-50 px-4 py-3 border-b border-gray-200">
<h4 className="text-sm font-medium text-gray-900">Test Results</h4>
</div>
<div className="px-4 py-3">
<div className="space-y-4">
{/* Status */}
<div>
<div className="text-sm font-medium text-gray-700">Status:</div>
<div className={`mt-1 text-sm ${testResults.success ? 'text-green-600' : 'text-red-600'}`}>
{testResults.success ? 'Success' : 'Error'}
</div>
</div>
{/* Error (if any) */}
{testResults.error && (
<div>
<div className="text-sm font-medium text-gray-700">Error:</div>
<div className="mt-1 bg-red-50 text-red-700 p-3 rounded text-sm font-mono overflow-auto">
{testResults.error}
</div>
</div>
)}
{/* Output */}
{testResults.output !== null && (
<div>
<div className="text-sm font-medium text-gray-700">Output:</div>
<div className="mt-1 bg-gray-50 p-3 rounded text-sm font-mono overflow-auto">
<pre>{formatJSON(testResults.output)}</pre>
</div>
</div>
)}
{/* Execution time */}
{testResults.execution_time && (
<div>
<div className="text-sm font-medium text-gray-700">Execution Time:</div>
<div className="mt-1 text-sm text-gray-600">
{testResults.execution_time} ms
</div>
</div>
)}
</div>
</div>
</div>
)}
</div>
</div>
<div className="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button
type="button"
onClick={onClose}
className="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
>
Close
</button>
</div>
</div>
);
};
export default NodeTester;