Almost all sections with mock data
This commit is contained in:
221
src/app/(dashboard)/rendimiento/page.tsx
Normal file
221
src/app/(dashboard)/rendimiento/page.tsx
Normal file
@@ -0,0 +1,221 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useMemo, useEffect, useCallback } from 'react'
|
||||
import { useSelectedClient } from '@/components/providers/SelectedClientProvider'
|
||||
import { trpc } from '@/lib/trpc-client'
|
||||
import MetricCard from '@/components/performance/MetricCard'
|
||||
import ProcessTable from '@/components/performance/ProcessTable'
|
||||
import type { ProcessItem } from '@/components/performance/ProcessRow'
|
||||
|
||||
const CHART_POINTS = 20
|
||||
const POLL_INTERVAL_MS = 2000
|
||||
|
||||
function randomIn(min: number, max: number) {
|
||||
return Math.round(min + Math.random() * (max - min))
|
||||
}
|
||||
|
||||
function generateMockProcesses(): ProcessItem[] {
|
||||
const names = [
|
||||
'chrome.exe',
|
||||
'Code.exe',
|
||||
'node.exe',
|
||||
'System',
|
||||
'svchost.exe',
|
||||
'explorer.exe',
|
||||
'MsMpEng.exe',
|
||||
'SearchHost.exe',
|
||||
'RuntimeBroker.exe',
|
||||
'dllhost.exe',
|
||||
]
|
||||
return names.slice(0, 10).map((name, i) => ({
|
||||
id: `p-${i}`,
|
||||
name,
|
||||
pid: 1000 + i * 100 + randomIn(0, 99),
|
||||
cpu: randomIn(0, 45),
|
||||
memory: `${randomIn(50, 800)} MB`,
|
||||
state: i % 3 === 0 ? 'En ejecución' : 'Activo',
|
||||
}))
|
||||
}
|
||||
|
||||
export default function RendimientoPage() {
|
||||
const { selectedClientId } = useSelectedClient()
|
||||
const clienteId = selectedClientId ?? undefined
|
||||
|
||||
const listQuery = trpc.equipos.list.useQuery(
|
||||
{ clienteId, limit: 100 },
|
||||
{ refetchOnWindowFocus: false }
|
||||
)
|
||||
|
||||
const devices = useMemo(
|
||||
() => (listQuery.data?.dispositivos ?? []).map((d) => ({ id: d.id, nombre: d.nombre })),
|
||||
[listQuery.data]
|
||||
)
|
||||
|
||||
const [selectedDeviceId, setSelectedDeviceId] = useState<string>('')
|
||||
const [metrics, setMetrics] = useState({
|
||||
cpu: 0,
|
||||
memory: 0,
|
||||
disk: 0,
|
||||
network: 0,
|
||||
})
|
||||
const [chartHistory, setChartHistory] = useState<{
|
||||
cpu: number[]
|
||||
memory: number[]
|
||||
disk: number[]
|
||||
network: number[]
|
||||
}>({
|
||||
cpu: [],
|
||||
memory: [],
|
||||
disk: [],
|
||||
network: [],
|
||||
})
|
||||
const [processes, setProcesses] = useState<ProcessItem[]>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const hasDevice = !!selectedDeviceId
|
||||
|
||||
const tick = useCallback(() => {
|
||||
const cpu = randomIn(15, 85)
|
||||
const memory = randomIn(40, 90)
|
||||
const disk = randomIn(25, 65)
|
||||
const network = randomIn(5, 120)
|
||||
setMetrics({ cpu, memory, disk, network })
|
||||
setChartHistory((prev) => ({
|
||||
cpu: [...prev.cpu, cpu].slice(-CHART_POINTS),
|
||||
memory: [...prev.memory, memory].slice(-CHART_POINTS),
|
||||
disk: [...prev.disk, disk].slice(-CHART_POINTS),
|
||||
network: [...prev.network, network].slice(-CHART_POINTS),
|
||||
}))
|
||||
setProcesses(generateMockProcesses())
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasDevice) {
|
||||
setMetrics({ cpu: 0, memory: 0, disk: 0, network: 0 })
|
||||
setChartHistory({ cpu: [], memory: [], disk: [], network: [] })
|
||||
setProcesses([])
|
||||
return
|
||||
}
|
||||
setLoading(true)
|
||||
tick()
|
||||
const t = setTimeout(() => setLoading(false), 400)
|
||||
const interval = setInterval(tick, POLL_INTERVAL_MS)
|
||||
return () => {
|
||||
clearTimeout(t)
|
||||
clearInterval(interval)
|
||||
}
|
||||
}, [hasDevice, tick])
|
||||
|
||||
const cpuFooter = hasDevice
|
||||
? [
|
||||
{ label: 'Procesos:', value: '142' },
|
||||
{ label: 'Hilos:', value: '2,840' },
|
||||
{ label: 'Velocidad:', value: '2.90 GHz' },
|
||||
]
|
||||
: [
|
||||
{ label: 'Procesos:', value: '—' },
|
||||
{ label: 'Hilos:', value: '—' },
|
||||
{ label: 'Velocidad:', value: '—' },
|
||||
]
|
||||
|
||||
const ramFooter = hasDevice
|
||||
? [
|
||||
{ label: 'En uso:', value: `${Math.round((metrics.memory / 100) * 16)} GB` },
|
||||
{ label: 'Disponible:', value: `${Math.round(((100 - metrics.memory) / 100) * 16)} GB` },
|
||||
{ label: 'Total:', value: '16 GB' },
|
||||
]
|
||||
: [
|
||||
{ label: 'En uso:', value: '—' },
|
||||
{ label: 'Disponible:', value: '—' },
|
||||
{ label: 'Total:', value: '—' },
|
||||
]
|
||||
|
||||
const diskFooter = hasDevice
|
||||
? [
|
||||
{ label: 'Lectura:', value: '12.5 MB/s' },
|
||||
{ label: 'Escritura:', value: '3.2 MB/s' },
|
||||
{ label: 'Activo:', value: 'Sí' },
|
||||
]
|
||||
: [
|
||||
{ label: 'Lectura:', value: '—' },
|
||||
{ label: 'Escritura:', value: '—' },
|
||||
{ label: 'Activo:', value: '—' },
|
||||
]
|
||||
|
||||
const networkFooter = hasDevice
|
||||
? [
|
||||
{ label: 'Enviado:', value: '1.2 GB' },
|
||||
{ label: 'Recibido:', value: '4.8 GB' },
|
||||
{ label: 'Adaptador:', value: 'Ethernet' },
|
||||
]
|
||||
: [
|
||||
{ label: 'Enviado:', value: '—' },
|
||||
{ label: 'Recibido:', value: '—' },
|
||||
{ label: 'Adaptador:', value: '—' },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<header className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-white sm:text-3xl">
|
||||
Rendimiento en Tiempo Real
|
||||
</h1>
|
||||
<p className="mt-1 text-gray-400">
|
||||
Monitorea recursos del sistema
|
||||
</p>
|
||||
</div>
|
||||
<div className="shrink-0">
|
||||
<select
|
||||
value={selectedDeviceId}
|
||||
onChange={(e) => setSelectedDeviceId(e.target.value)}
|
||||
className="w-64 rounded-lg border border-white/10 bg-dark-300 px-4 py-2.5 text-sm text-gray-200 transition-colors hover:border-white/20 focus:border-cyan-500/50 focus:outline-none focus:ring-2 focus:ring-cyan-500/20 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<option value="">-- Seleccionar dispositivo --</option>
|
||||
{devices.map((d) => (
|
||||
<option key={d.id} value={d.id}>
|
||||
{d.nombre}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||
<MetricCard
|
||||
title="CPU"
|
||||
value={hasDevice ? `${metrics.cpu}` : '—'}
|
||||
valueSuffix="%"
|
||||
footerStats={cpuFooter}
|
||||
chartData={chartHistory.cpu}
|
||||
highUsage={metrics.cpu > 80}
|
||||
/>
|
||||
<MetricCard
|
||||
title="Memoria RAM"
|
||||
value={hasDevice ? `${metrics.memory}` : '—'}
|
||||
valueSuffix="%"
|
||||
footerStats={ramFooter}
|
||||
chartData={chartHistory.memory}
|
||||
highUsage={metrics.memory > 80}
|
||||
/>
|
||||
<MetricCard
|
||||
title="Disco"
|
||||
value={hasDevice ? `${metrics.disk}` : '—'}
|
||||
valueSuffix="%"
|
||||
footerStats={diskFooter}
|
||||
chartData={chartHistory.disk}
|
||||
highUsage={metrics.disk > 80}
|
||||
/>
|
||||
<MetricCard
|
||||
title="Red"
|
||||
value={hasDevice ? `${metrics.network}` : '—'}
|
||||
valueSuffix="Mbps"
|
||||
footerStats={networkFooter}
|
||||
chartData={chartHistory.network}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ProcessTable processes={processes} noDevice={!hasDevice} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user