cambios en datastage
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
// Consultar el estado de un task por task_id
|
||||
export async function fetchTaskStatus(task_id) {
|
||||
const url = `${import.meta.env.VITE_EFC_API_URL}/datastage/datastages/task-status/?task_id=${encodeURIComponent(task_id)}`;
|
||||
const res = await getWithAuth(url);
|
||||
if (!res.ok) throw new Error('Error al consultar el estado del task');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
import.meta.env;
|
||||
import { getWithAuth, postWithAuth, patchWithAuth, deleteWithAuth } from '../fetchWithAuth';
|
||||
|
||||
@@ -1,17 +1,124 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { fetchTaskStatus } from '../api/datastage.js';
|
||||
|
||||
export default function SuccessModal({ open, onClose, message = 'Descarga exitosa' }) {
|
||||
if (!open) return null;
|
||||
|
||||
// Detectar si es mensaje de procesamiento iniciado
|
||||
let isProcessing = false;
|
||||
let taskId = '';
|
||||
if (typeof message === 'string' && message.includes('Procesamiento iniciado.') && message.includes('Task ID:')) {
|
||||
isProcessing = true;
|
||||
// Extraer taskId
|
||||
const match = message.match(/Task ID: ([\w-]+)/);
|
||||
if (match) taskId = match[1];
|
||||
}
|
||||
|
||||
// Estado para mostrar status del task
|
||||
const [taskStatus, setTaskStatus] = useState(null);
|
||||
const [loadingStatus, setLoadingStatus] = useState(false);
|
||||
const [errorStatus, setErrorStatus] = useState('');
|
||||
// Estado para subtasks
|
||||
const [subtaskStatus, setSubtaskStatus] = useState({}); // { subtaskId: { loading, error, data } }
|
||||
|
||||
const handleCheckStatus = async () => {
|
||||
setLoadingStatus(true);
|
||||
setErrorStatus('');
|
||||
try {
|
||||
const res = await fetchTaskStatus(taskId);
|
||||
setTaskStatus(res);
|
||||
} catch (e) {
|
||||
setErrorStatus('Error al consultar el estado');
|
||||
}
|
||||
setLoadingStatus(false);
|
||||
};
|
||||
|
||||
const handleSubtaskClick = async (subId) => {
|
||||
setSubtaskStatus(prev => ({ ...prev, [subId]: { loading: true, error: '', data: null } }));
|
||||
try {
|
||||
const res = await fetchTaskStatus(subId);
|
||||
setSubtaskStatus(prev => ({ ...prev, [subId]: { loading: false, error: '', data: res } }));
|
||||
} catch (e) {
|
||||
setSubtaskStatus(prev => ({ ...prev, [subId]: { loading: false, error: 'Error al consultar el estado', data: null } }));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-40">
|
||||
<div className="bg-white rounded-xl shadow-2xl border border-green-200 p-8 max-w-sm w-full flex flex-col items-center animate-fade-in">
|
||||
<div className={`bg-white rounded-xl shadow-2xl border ${isProcessing ? 'border-blue-300' : 'border-green-200'} p-8 max-w-md w-full flex flex-col items-center animate-fade-in`}>
|
||||
{isProcessing ? (
|
||||
<>
|
||||
{/* Header decorativo */}
|
||||
<div className="w-full flex items-center gap-3 mb-4 bg-gradient-to-r from-blue-600 to-blue-800 rounded-t-xl p-4 relative">
|
||||
<div className="flex-shrink-0 bg-white/20 backdrop-blur-sm rounded-full p-2 shadow-lg">
|
||||
<svg className="h-7 w-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<ellipse cx="12" cy="7" rx="8" ry="3" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M4 7v10c0 1.657 3.582 3 8 3s8-1.343 8-3V7" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M4 17c0 1.657 3.582 3 8 3s8-1.343 8-3" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h2 className="text-lg sm:text-xl font-extrabold text-white tracking-tight">Procesamiento iniciado</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center mb-2 mt-2 w-full">
|
||||
<div
|
||||
className={`bg-blue-50 border border-blue-200 rounded-lg px-4 py-2 w-full text-center mb-2 cursor-pointer transition hover:bg-blue-100 ${loadingStatus ? 'opacity-60 pointer-events-none' : ''}`}
|
||||
title="Consultar estado"
|
||||
onClick={handleCheckStatus}
|
||||
>
|
||||
<span className="block text-xs text-blue-800 font-semibold tracking-wide">Task ID:</span>
|
||||
<span className="block text-sm font-mono text-blue-900 break-all underline hover:text-blue-700">{taskId}</span>
|
||||
{loadingStatus && <div className="text-xs text-blue-700 mt-1">Consultando estado...</div>}
|
||||
{errorStatus && <div className="text-red-600 text-xs mt-1">{errorStatus}</div>}
|
||||
{taskStatus && (
|
||||
<>
|
||||
<div className="mt-2 text-xs text-blue-800 font-semibold">Estado: <span className="font-mono text-blue-900">{taskStatus.status}</span></div>
|
||||
{taskStatus.result && (
|
||||
<div className="text-xs text-blue-800 mt-2 text-left">
|
||||
<div className="mb-1"><span className="font-semibold">Group ID:</span> <span className="font-mono text-blue-900 break-all">{taskStatus.result.group_id}</span></div>
|
||||
<div className="mb-1"><span className="font-semibold">Subtask IDs:</span>
|
||||
<ul className="list-disc list-inside ml-4 max-h-32 overflow-y-auto">
|
||||
{Array.isArray(taskStatus.result.subtask_ids) && taskStatus.result.subtask_ids.map(id => (
|
||||
<li key={id} className="font-mono text-blue-900 break-all text-xs cursor-pointer underline hover:text-blue-700"
|
||||
title="Consultar estado de subtask"
|
||||
onClick={() => handleSubtaskClick(id)}>
|
||||
{id}
|
||||
{subtaskStatus[id]?.loading && <span className="ml-2 text-blue-600">Consultando...</span>}
|
||||
{subtaskStatus[id]?.error && <div className="text-red-600 text-xs mt-1">{subtaskStatus[id].error}</div>}
|
||||
{subtaskStatus[id]?.data && (
|
||||
<div className="mt-1 text-xs text-blue-800 bg-blue-50 border border-blue-200 rounded p-2 text-left">
|
||||
<div><span className="font-semibold">Estado:</span> <span className="font-mono text-blue-900">{subtaskStatus[id].data.status}</span></div>
|
||||
{subtaskStatus[id].data.result && (
|
||||
<div className="mt-1"><span className="font-semibold">Resultado:</span> <span className="font-mono text-blue-900 break-all">{typeof subtaskStatus[id].data.result === 'object' ? JSON.stringify(subtaskStatus[id].data.result) : subtaskStatus[id].data.result}</span></div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
{taskStatus.result.detail && (
|
||||
<div className="mb-1"><span className="font-semibold">Detalle:</span> <span className="text-blue-900">{taskStatus.result.detail}</span></div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg className="h-12 w-12 text-green-500 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<h2 className="text-2xl font-bold text-green-700 mb-2">{message}</h2>
|
||||
</>
|
||||
)}
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="mt-4 px-6 py-2 bg-green-600 text-white rounded-lg font-semibold shadow hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-400"
|
||||
className={`mt-4 px-6 py-2 ${isProcessing ? 'bg-blue-600 hover:bg-blue-700 focus:ring-blue-400' : 'bg-green-600 hover:bg-green-700 focus:ring-green-400'} text-white rounded-lg font-semibold shadow focus:outline-none focus:ring-2`}
|
||||
>
|
||||
Cerrar
|
||||
</button>
|
||||
|
||||
@@ -84,6 +84,8 @@ async function procesarDatastage(item, setDatastages, setSuccess, setError, setR
|
||||
} else {
|
||||
setSuccess('Procesado correctamente');
|
||||
}
|
||||
// El modal de éxito se debe mostrar en el componente principal después de setSuccess
|
||||
// No se llama aquí
|
||||
if (data && data.registros_cargados) {
|
||||
setRegistrosCargados(data.registros_cargados);
|
||||
setShowRegistrosModal(true);
|
||||
@@ -136,6 +138,10 @@ export default function Datastage() {
|
||||
useLayoutEffect(() => { setShowAnimation(true); }, []);
|
||||
useEffect(() => { if (showAnimation && !hasAnimated) setTimeout(() => setHasAnimated(true), 800); }, [showAnimation, hasAnimated]);
|
||||
|
||||
// Mostrar modal de éxito cuando cambia el mensaje de success
|
||||
useEffect(() => {
|
||||
if (success) setShowSuccessModal(true);
|
||||
}, [success]);
|
||||
// Cargar lista
|
||||
const load = async () => {
|
||||
setLoading(true);
|
||||
|
||||
Reference in New Issue
Block a user