feat(v2): add monitor health bar in list

This commit is contained in:
moonrailgun 2024-03-31 20:27:00 +08:00
parent d97c671913
commit 539f24244a
4 changed files with 72 additions and 7 deletions

View File

@ -88,7 +88,7 @@ export const CommonList: React.FC<CommonListProps> = React.memo((props) => {
</div> </div>
</div> </div>
</div> </div>
<div className="text-muted-foreground line-clamp-2 text-xs"> <div className="text-muted-foreground line-clamp-2 w-full text-xs">
{item.content} {item.content}
</div> </div>
{Array.isArray(item.tags) && item.tags.length > 0 ? ( {Array.isArray(item.tags) && item.tags.length > 0 ? (

View File

@ -8,6 +8,7 @@ import { useWatch } from '../../hooks/useWatch';
import { getMonitorProvider, getProviderDisplay } from './provider'; import { getMonitorProvider, getProviderDisplay } from './provider';
import { MonitorProvider } from './provider/types'; import { MonitorProvider } from './provider/types';
import { useTranslation } from '@i18next-toolkit/react'; import { useTranslation } from '@i18next-toolkit/react';
import clsx from 'clsx';
interface MonitorHealthBarProps { interface MonitorHealthBarProps {
workspaceId: string; workspaceId: string;
@ -16,6 +17,7 @@ interface MonitorHealthBarProps {
count?: number; count?: number;
size?: HealthBarProps['size']; size?: HealthBarProps['size'];
showCurrentStatus?: boolean; showCurrentStatus?: boolean;
showPercent?: boolean;
onBeatsItemUpdate?: ( onBeatsItemUpdate?: (
items: ({ value: number; createdAt: string | Date } | null)[] items: ({ value: number; createdAt: string | Date } | null)[]
) => void; ) => void;
@ -26,9 +28,10 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
const { const {
workspaceId, workspaceId,
monitorId, monitorId,
size, size = 'small',
count = 20, count = 20,
showCurrentStatus = false, showCurrentStatus = false,
showPercent = false,
} = props; } = props;
const { data: recent = [] } = trpc.monitor.recentData.useQuery({ const { data: recent = [] } = trpc.monitor.recentData.useQuery({
workspaceId, workspaceId,
@ -82,26 +85,78 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
}); });
}, [items, provider]); }, [items, provider]);
const upPercent = useMemo(() => {
let up = 0;
beats.forEach((b) => {
if (!b) {
return;
}
if (b.status === 'health') {
up++;
}
});
return parseFloat(((up / beats.length) * 100).toFixed(1));
}, [beats]);
useWatch([items], () => { useWatch([items], () => {
props.onBeatsItemUpdate?.(items); props.onBeatsItemUpdate?.(items);
}); });
return ( return (
<div className="flex items-center justify-between"> <div className="flex items-center">
<HealthBar size={size} beats={beats} /> {showPercent && (
<span
className={clsx(
'mr-2 inline-block min-w-[62px] rounded-full p-0.5 text-center text-white',
upPercent === 100 ? 'bg-green-400' : 'bg-amber-400',
{
'min-w-[50px] text-sm': size === 'small',
}
)}
>
{upPercent}%
</span>
)}
<div className="flex-1">
<HealthBar size={size} beats={beats} />
</div>
{showCurrentStatus && ( {showCurrentStatus && (
<> <>
{last(beats)?.status === 'health' ? ( {last(beats)?.status === 'health' ? (
<div className="rounded-full bg-green-500 px-4 py-1 text-lg font-bold text-white"> <div
className={clsx(
'rounded-full bg-green-500 px-4 py-1 text-lg font-bold text-white',
{
'text-sm': size === 'small',
}
)}
>
{t('UP')} {t('UP')}
</div> </div>
) : last(beats)?.status === 'error' ? ( ) : last(beats)?.status === 'error' ? (
<div className="rounded-full bg-red-600 px-4 py-1 text-lg font-bold text-white"> <div
className={clsx(
'rounded-full bg-red-600 px-4 py-1 text-lg font-bold text-white',
{
'text-sm': size === 'small',
}
)}
>
{t('DOWN')} {t('DOWN')}
</div> </div>
) : ( ) : (
<div className="rounded-full bg-gray-400 px-4 py-1 text-lg font-bold text-white"> <div
className={clsx(
'rounded-full bg-gray-400 px-4 py-1 text-lg font-bold text-white',
{
'text-sm': size === 'small',
}
)}
>
{t('NONE')} {t('NONE')}
</div> </div>
)} )}

View File

@ -85,6 +85,7 @@ export const MonitorListItem: React.FC<{
{upPercent}% {upPercent}%
</span> </span>
</div> </div>
<div className="flex-1 pl-2"> <div className="flex-1 pl-2">
<div className="text-base">{monitorName}</div> <div className="text-base">{monitorName}</div>
{/* <div> {/* <div>

View File

@ -2,6 +2,7 @@ import { trpc } from '@/api/trpc';
import { CommonHeader } from '@/components/CommonHeader'; import { CommonHeader } from '@/components/CommonHeader';
import { CommonList } from '@/components/CommonList'; import { CommonList } from '@/components/CommonList';
import { CommonWrapper } from '@/components/CommonWrapper'; import { CommonWrapper } from '@/components/CommonWrapper';
import { MonitorHealthBar } from '@/components/monitor/MonitorHealthBar';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { useDataReady } from '@/hooks/useDataReady'; import { useDataReady } from '@/hooks/useDataReady';
import { useEvent } from '@/hooks/useEvent'; import { useEvent } from '@/hooks/useEvent';
@ -35,6 +36,14 @@ function MonitorComponent() {
const items = data.map((item) => ({ const items = data.map((item) => ({
id: item.id, id: item.id,
title: item.name, title: item.name,
content: (
<MonitorHealthBar
workspaceId={workspaceId}
monitorId={item.id}
showPercent={true}
showCurrentStatus={true}
/>
),
tags: [item.type], tags: [item.type],
href: `/monitor/${item.id}`, href: `/monitor/${item.id}`,
})); }));