Files
OpenFlare/frontend/app/(main)/nodes/components/node-detail-primitives.tsx
T
ryan 63cd906cfc refactor(repo): consolidate openflare-server to root and move subprojects to internal/apps
- Merge all files inside openflare-server to the repository root directory.
- Relocate agent, relay, and flared subprojects from internal/ to internal/apps/.
- Combine docker-compose files and update build context paths to root.
- Update GitHub workflows and Dockerfiles to refer to new directories and package names.
- Rewrite Go package imports across all files.
- Resolve database renew test race condition and clean up docs.
2026-06-19 14:23:29 +08:00

79 lines
2.0 KiB
TypeScript

'use client';
import type {ReactNode} from 'react';
import type {LucideIcon} from 'lucide-react';
import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@/components/ui/card';
import {cn} from '@/lib/utils';
export function NodeInfoRow({
label,
children,
className,
}: {
label: string;
children: ReactNode;
className?: string;
}) {
return (
<div className={cn('flex items-start justify-between gap-4 py-2.5 text-sm', className)}>
<span className="shrink-0 text-muted-foreground">{label}</span>
<div className="min-w-0 text-right font-medium">{children}</div>
</div>
);
}
export function NodeKpiCard({
label,
value,
icon: Icon,
}: {
label: string;
value: ReactNode;
icon?: LucideIcon;
}) {
return (
<div className="rounded-xl border bg-card/60 px-4 py-3.5 backdrop-blur-sm">
<div className="flex items-center gap-2 text-xs text-muted-foreground">
{Icon ? <Icon className="size-3.5 opacity-70" /> : null}
<span>{label}</span>
</div>
<p className="mt-2 text-sm font-semibold tracking-tight break-all">{value}</p>
</div>
);
}
export function NodeSectionCard({
title,
description,
action,
children,
className,
}: {
title: string;
description?: string;
action?: React.ReactNode;
children: ReactNode;
className?: string;
}) {
return (
<Card className={cn('border shadow-none', className)}>
<CardHeader className={cn('pb-3', action ? 'flex-row items-start justify-between space-y-0' : '')}>
<div className="space-y-1">
<CardTitle className="text-base font-semibold">{title}</CardTitle>
{description ? <CardDescription>{description}</CardDescription> : null}
</div>
{action}
</CardHeader>
<CardContent>{children}</CardContent>
</Card>
);
}
export function NodeErrorBanner({ message }: { message: string }) {
return (
<div className="rounded-xl border border-destructive/25 bg-destructive/5 px-4 py-3 text-sm text-destructive">
{message}
</div>
);
}