This commit is contained in:
@@ -9,18 +9,19 @@ import { Button } from '@/components/ui/button'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from '@/components/ui/tooltip'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { useToast } from '@/components/ui/use-toast'
|
||||
import { BpmnCanvas, type BpmnElementCategory } from './BpmnCanvas'
|
||||
import { ActivityPanel } from './ActivityPanel'
|
||||
import { GatewayPanel, isXorSumValid } from './GatewayPanel'
|
||||
import { ResourcesPanel } from './ResourcesPanel'
|
||||
import { GlobalSettingsPanel } from './GlobalSettingsPanel'
|
||||
import { WorkspaceSkeleton } from './WorkspaceSkeleton'
|
||||
import { useProcessStore } from '@/store/process-store'
|
||||
import { useSimulationStore } from '@/store/simulation-store'
|
||||
import { useSimulate } from '../simulation/useSimulate'
|
||||
import { useLibraryStore } from '@/store/library-store'
|
||||
import { useAuth } from '@/auth/AuthContext'
|
||||
import { AppHeader } from '@/components/AppHeader'
|
||||
import { ErrorBoundary } from '@/components/ErrorBoundary'
|
||||
|
||||
type SelectedCategory = 'activity' | 'gateway' | null
|
||||
|
||||
@@ -30,7 +31,6 @@ export function WorkspacePage() {
|
||||
const { currentProcess, activities, isLoading, error, loadProcess, gateways, updateProcess } = useProcessStore()
|
||||
const { isRunning, resultActual, error: simError, selectActivity, loadLatestForProcess, lastPersistedExecutedAt } = useSimulationStore()
|
||||
const { simulate } = useSimulate()
|
||||
const { toast } = useToast()
|
||||
const { user } = useAuth()
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(true)
|
||||
@@ -50,31 +50,16 @@ export function WorkspacePage() {
|
||||
const [showTagSuggestions, setShowTagSuggestions] = useState(false)
|
||||
const getAllTags = useLibraryStore((state) => state.getAllTags)
|
||||
|
||||
// Usamos un ref para saber si loadProcess ya terminó al menos una vez.
|
||||
// Esto evita que el redirect se dispare en el render inicial donde
|
||||
// isLoading=false y currentProcess=null (antes del primer efecto).
|
||||
const hasLoadedOnce = useRef(false)
|
||||
|
||||
useEffect(() => { loadProcess(processId) }, [processId, loadProcess])
|
||||
|
||||
// Cargar el último executedAt persistido para comparar contra updatedAt (indicador stale)
|
||||
// Cargar el último executedAt persistido para comparar contra updatedAt (indicador stale).
|
||||
// Depende de currentProcess?.id (no del objeto) a propósito: evita re-disparar el efecto
|
||||
// en cada edición de campos del proceso, solo cuando cambia de proceso.
|
||||
useEffect(() => {
|
||||
if (currentProcess) loadLatestForProcess(currentProcess.id)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentProcess?.id, loadLatestForProcess])
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading) { hasLoadedOnce.current = true; return }
|
||||
if (!hasLoadedOnce.current) return // carga no iniciada aún
|
||||
if ((error || !currentProcess) && processId) {
|
||||
toast({
|
||||
title: 'Proceso no encontrado',
|
||||
description: 'El proceso que buscás no existe o fue eliminado.',
|
||||
variant: 'destructive',
|
||||
})
|
||||
navigate({ to: '/' })
|
||||
}
|
||||
}, [isLoading, error, currentProcess, processId, toast, navigate])
|
||||
|
||||
// Validación XOR: todos los gateways exclusivos deben sumar 1.0
|
||||
const xorValidation = useMemo(() => {
|
||||
const invalidIds = gateways
|
||||
@@ -166,16 +151,27 @@ export function WorkspacePage() {
|
||||
|
||||
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
||||
</div>
|
||||
)
|
||||
if (isLoading && !currentProcess) {
|
||||
return <WorkspaceSkeleton />
|
||||
}
|
||||
|
||||
if (error || !currentProcess) {
|
||||
return null // el useEffect ya inició el redirect con toast
|
||||
return (
|
||||
<div className="h-screen flex flex-col items-center justify-center gap-4">
|
||||
<AlertCircle className="h-8 w-8 text-muted-foreground" />
|
||||
<p className="text-sm text-muted-foreground max-w-sm text-center">
|
||||
{error ?? 'No se pudo cargar el proceso. Revisá tu conexión.'}
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" onClick={() => loadProcess(processId)}>
|
||||
Reintentar
|
||||
</Button>
|
||||
<Button variant="ghost" onClick={() => navigate({ to: '/' })}>
|
||||
Volver a la biblioteca
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Label del tab "elemento" según lo seleccionado
|
||||
@@ -483,3 +479,11 @@ export function WorkspacePage() {
|
||||
</TooltipProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export function WorkspacePageWithBoundary() {
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<WorkspacePage />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user