feat(node): Add NodeStatus

This commit is contained in:
web@ppanel
2024-12-13 14:51:55 +07:00
parent d0be6854e6
commit c712624930
7 changed files with 181 additions and 42 deletions
@@ -0,0 +1,94 @@
'use client';
import { formatDate } from '@repo/ui/utils';
import { Badge } from '@shadcn/ui/badge';
import { Progress } from '@shadcn/ui/progress';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@shadcn/ui/tooltip';
import { useTranslations } from 'next-intl';
export function formatPercentage(value: number): string {
return `${(value * 100).toFixed(1)}%`;
}
export function NodeStatusCell({ status }: { status: API.NodeStatus }) {
const t = useTranslations('server.node');
const {
last_at,
online_users,
status: serverStatus,
} = status || {
online_users: [],
status: {
cpu: 0,
mem: 0,
disk: 0,
updated_at: 0,
},
last_at: 0,
};
const isOnline = last_at > 0;
const badgeVariant = isOnline ? 'default' : 'destructive';
const badgeText = isOnline ? t('normal') : t('abnormal');
const onlineCount = Array.isArray(online_users) ? online_users.length : 0;
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div className='flex items-center space-x-2 rounded-md'>
<Badge variant={badgeVariant}>{badgeText}</Badge>
<span className='text-sm font-medium'>
{t('onlineCount')}: {onlineCount}
</span>
</div>
</TooltipTrigger>
<TooltipContent className='bg-muted text-foreground w-80'>
<div className='space-y-4'>
<>
<div className='space-y-2'>
<div className='space-y-1'>
<div className='flex justify-between text-xs'>
<span className='font-medium'>CPU</span>
<span>{formatPercentage(serverStatus?.cpu ?? 0)}</span>
</div>
<Progress value={(serverStatus?.cpu ?? 0) * 100} className='h-2' />
</div>
<div className='space-y-1'>
<div className='flex justify-between text-xs'>
<span className='font-medium'>{t('memory')}</span>
<span>{formatPercentage(serverStatus?.mem ?? 0)}</span>
</div>
<Progress value={(serverStatus?.mem ?? 0) * 100} className='h-2' />
</div>
<div className='space-y-1'>
<div className='flex justify-between text-xs'>
<span className='font-medium'>{t('disk')}</span>
<span>{formatPercentage(serverStatus?.disk ?? 0)}</span>
</div>
<Progress value={(serverStatus?.disk ?? 0) * 100} className='h-2' />
</div>
</div>
<div className='text-xs'>
{t('lastUpdated')}: {formatDate(serverStatus?.updated_at ?? 0)}
</div>
{isOnline && online_users.length > 0 && (
<div className='space-y-2'>
<h4 className='text-sm font-semibold'>{t('onlineUsers')}</h4>
<ScrollArea className='h-[400px] rounded-md border p-2'>
{online_users.map((user, index) => (
<div key={user.uid} className='py-1 text-xs'>
{user.ip} (UID: {user.uid})
</div>
))}
</ScrollArea>
</div>
)}
</>
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
+3 -14
View File
@@ -21,6 +21,7 @@ import { useQuery } from '@tanstack/react-query';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import NodeForm from './node-form';
import { NodeStatusCell } from './node-status';
export default function NodeTable() {
const t = useTranslations('server.node');
@@ -109,23 +110,11 @@ export default function NodeTable() {
);
},
},
{
accessorKey: 'last',
accessorKey: 'status',
header: t('status'),
cell: ({ row }) => {
const { last } = row.original;
return last ? (
<>
<Badge>{t('normal')}</Badge>
<span className='ml-2'>
{t('onlineCount')}: {last.count}
</span>
</>
) : (
<Badge variant='destructive'>{t('abnormal')}</Badge>
);
return <NodeStatusCell status={row.original?.status} />;
},
},
{