Corrección 1 — Delete de proceso restaurado +
This commit is contained in:
@@ -4,8 +4,9 @@ import { UploadCloud, FileText, Loader2, FlaskConical } from 'lucide-react'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import { parseBpmnXml, extractActivityElements, extractGatewayElements, BpmnParseError } from '@/domain/bpmn-parser'
|
||||
import { activityRepo, gatewayRepo } from '@/persistence/repositories'
|
||||
import { supabaseProcessRepo } from '@/persistence/supabase/process-repo'
|
||||
import { supabaseActivityRepo } from '@/persistence/supabase/activity-repo'
|
||||
import { supabaseGatewayRepo } from '@/persistence/supabase/gateway-repo'
|
||||
import type { Process, Activity, GatewayConfig } from '@/domain/types'
|
||||
import { bpmnTypeToGatewayType } from '@/domain/types'
|
||||
import { useToast } from '@/components/ui/use-toast'
|
||||
@@ -114,10 +115,20 @@ export function ImportPage() {
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
supabaseProcessRepo.save(process, user!.id),
|
||||
activityRepo.saveMany(activities),
|
||||
gatewayRepo.saveMany(gateways),
|
||||
await Promise.race([
|
||||
(async () => {
|
||||
await supabaseProcessRepo.save(process, user!.id)
|
||||
await Promise.all([
|
||||
supabaseActivityRepo.saveMany(activities, user!.id),
|
||||
supabaseGatewayRepo.saveMany(gateways),
|
||||
])
|
||||
})(),
|
||||
new Promise<never>((_, reject) =>
|
||||
setTimeout(
|
||||
() => reject(new Error('Timeout: Supabase no respondió en 20s — verificá tu conexión')),
|
||||
20_000,
|
||||
)
|
||||
),
|
||||
])
|
||||
|
||||
toast({
|
||||
|
||||
@@ -312,7 +312,7 @@ function HomeView({
|
||||
onNavigateToGroup: (groupId: string | null) => void
|
||||
onImport: (groupId?: string) => void
|
||||
}) {
|
||||
const { groups, processes, settings, createGroup } = useLibraryStore()
|
||||
const { groups, processes, settings, createGroup, isLoading } = useLibraryStore()
|
||||
const { user } = useAuth()
|
||||
const [search, setSearch] = useState('')
|
||||
const [activeTags, setActiveTags] = useState<string[]>([])
|
||||
@@ -330,7 +330,26 @@ function HomeView({
|
||||
setActiveTags((prev) => prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag])
|
||||
}
|
||||
|
||||
// Empty state: sin grupos ni procesos
|
||||
// Skeleton mientras carga y aún no hay datos (evita flash de empty state)
|
||||
if (isLoading && groups.length === 0 && processes.length === 0) {
|
||||
return (
|
||||
<div className="space-y-5 animate-pulse">
|
||||
<div className="h-4 w-32 bg-slate-100 rounded" />
|
||||
<div className="grid gap-2.5" style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(160px, 1fr))' }}>
|
||||
{[1, 2, 3].map((i) => (
|
||||
<div key={i} className="h-20 rounded-xl bg-slate-100" />
|
||||
))}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{[1, 2].map((i) => (
|
||||
<div key={i} className="h-14 rounded-xl bg-slate-100" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Empty state: sin grupos ni procesos (ya terminó de cargar)
|
||||
if (groups.length === 0 && processes.length === 0) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center py-24 gap-4">
|
||||
@@ -601,7 +620,7 @@ function GroupView({
|
||||
|
||||
export function LibraryPage() {
|
||||
const navigate = useNavigate()
|
||||
const { load, isLoading, processes, groups, settings } = useLibraryStore()
|
||||
const { load, processes, groups, settings } = useLibraryStore()
|
||||
const [view, setView] = useState<'home' | 'group'>('home')
|
||||
const [activeGroupId, setActiveGroupId] = useState<string | null>(null)
|
||||
const [transitioning, setTransitioning] = useState(false)
|
||||
@@ -670,29 +689,23 @@ export function LibraryPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Contenido con transición */}
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center py-24">
|
||||
<div className="h-6 w-6 rounded-full border-2 border-primary border-t-transparent animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className="transition-all duration-150"
|
||||
style={{ opacity: transitioning ? 0 : 1, transform: transitioning ? 'translateY(6px)' : 'translateY(0)' }}
|
||||
>
|
||||
{view === 'home' ? (
|
||||
<HomeView
|
||||
onNavigateToGroup={navigateToGroup}
|
||||
onImport={handleImport}
|
||||
/>
|
||||
) : (
|
||||
<GroupView
|
||||
groupId={activeGroupId}
|
||||
onBack={navigateHome}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{/* Contenido — sin spinner bloqueante: skeleton dentro de HomeView */}
|
||||
<div
|
||||
className="transition-all duration-150"
|
||||
style={{ opacity: transitioning ? 0 : 1, transform: transitioning ? 'translateY(6px)' : 'translateY(0)' }}
|
||||
>
|
||||
{view === 'home' ? (
|
||||
<HomeView
|
||||
onNavigateToGroup={navigateToGroup}
|
||||
onImport={handleImport}
|
||||
/>
|
||||
) : (
|
||||
<GroupView
|
||||
groupId={activeGroupId}
|
||||
onBack={navigateHome}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { activityRepo, resourceRepo, simulationRepo } from '@/persistence/repositories'
|
||||
import { supabaseActivityRepo } from '@/persistence/supabase/activity-repo'
|
||||
import { supabaseResourceRepo } from '@/persistence/supabase/resource-repo'
|
||||
import { supabaseProcessRepo } from '@/persistence/supabase/process-repo'
|
||||
import { simulationRepo } from '@/persistence/repositories'
|
||||
import type { Process, Activity, Resource, Simulation } from '@/domain/types'
|
||||
|
||||
interface ReportData {
|
||||
@@ -30,8 +32,8 @@ export function useReportData(processId: string): ReportData {
|
||||
const [proc, sim, acts, res] = await Promise.all([
|
||||
supabaseProcessRepo.getById(processId),
|
||||
simulationRepo.getLatestByProcess(processId),
|
||||
activityRepo.getByProcess(processId),
|
||||
resourceRepo.getByProcess(processId),
|
||||
supabaseActivityRepo.getByProcess(processId),
|
||||
supabaseResourceRepo.getAll(),
|
||||
])
|
||||
if (cancelled) return
|
||||
if (!proc) throw new Error('Proceso no encontrado en la base de datos local')
|
||||
|
||||
@@ -136,8 +136,11 @@ export function ActivityPanel({ selectedElementId }: ActivityPanelProps) {
|
||||
|
||||
if (!localActivity) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<p className="text-xs text-slate-400">Esta actividad no tiene configuración todavía</p>
|
||||
<div className="flex flex-col items-center justify-center h-full gap-2 px-6 text-center">
|
||||
<p className="text-xs text-slate-400">Actividad no encontrada en la base de datos.</p>
|
||||
<p className="text-[11px] text-slate-300">
|
||||
Si importaste este proceso antes de la última actualización, volvé a importar el archivo BPMN.
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ export function ResourcesPanel() {
|
||||
} else {
|
||||
const newResource: Resource = {
|
||||
id: uuidv4(),
|
||||
processId: currentProcess.id,
|
||||
name: form.name.trim(),
|
||||
type: form.type,
|
||||
costPerHour,
|
||||
|
||||
Reference in New Issue
Block a user