87 lines
4.3 KiB
TypeScript
87 lines
4.3 KiB
TypeScript
import { Activity, MoreHorizontal, Search, SlidersHorizontal } from 'lucide-react';
|
|
import { Badge, Button, Card, CardHeader } from '../../components/ui';
|
|
import { PageTitle } from '../../layout/AppLayout';
|
|
import { agentDevices } from '../../data/mock';
|
|
|
|
function getTone(status: string) {
|
|
if (['정상', '활성', '성공', '운영', 'Running'].includes(status)) return 'green';
|
|
if (['주의', '예약됨', '대기', '준비중', '카나리', 'Pending'].includes(status)) return 'amber';
|
|
if (['오류', '실패', '비활성', '만료', 'Error', 'Failed'].includes(status)) return 'red';
|
|
if (['검수', '동기화'].includes(status)) return 'blue';
|
|
return 'neutral';
|
|
}
|
|
|
|
export function RuntimeDeviceControlPage() {
|
|
return (
|
|
<>
|
|
<PageTitle eyebrow="Agent" title="장비 제어" description="운영 장비의 런타임 시작, 중지, 재시작, 상태 조회 명령을 관리합니다." />
|
|
<Card className="min-w-0 overflow-hidden">
|
|
<CardHeader
|
|
title="장비 목록"
|
|
description="Agent가 연결된 장비를 목록으로 확인하고 필요한 제어 명령을 실행합니다."
|
|
action={
|
|
<div className="flex gap-2">
|
|
<Button variant="outline" className="h-8 px-3 text-[13px]">
|
|
<SlidersHorizontal className="size-4" />
|
|
상태 필터
|
|
</Button>
|
|
<Button className="h-8 px-3 text-[13px]">
|
|
<Activity className="size-4" />
|
|
상태 갱신
|
|
</Button>
|
|
</div>
|
|
}
|
|
/>
|
|
<div className="border-b border-border px-5 pb-4">
|
|
<div className="relative max-w-md">
|
|
<Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
|
|
<input
|
|
className="h-9 w-full rounded-md border border-input bg-background pl-9 pr-3 text-sm outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring"
|
|
placeholder="장비명, 계정, 워크스페이스 검색"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="max-h-[620px] overflow-x-auto overflow-y-auto">
|
|
<table className="w-full min-w-[1040px] text-left text-sm">
|
|
<thead className="sticky top-0 z-10 border-b border-border bg-card text-xs text-muted-foreground">
|
|
<tr>
|
|
<th className="px-5 py-3 font-medium">장비</th>
|
|
<th className="px-5 py-3 font-medium">계정</th>
|
|
<th className="px-5 py-3 font-medium">Workspace</th>
|
|
<th className="px-5 py-3 font-medium">SSH 키</th>
|
|
<th className="px-5 py-3 font-medium">Last Seen</th>
|
|
<th className="px-5 py-3 font-medium">상태</th>
|
|
<th className="px-5 py-3 text-right font-medium">명령</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-border">
|
|
{agentDevices.map((device) => (
|
|
<tr key={device.name} className="hover:bg-muted/20">
|
|
<td className="px-5 py-3 font-medium">{device.name}</td>
|
|
<td className="px-5 py-3 text-muted-foreground">{device.account}</td>
|
|
<td className="px-5 py-3 text-muted-foreground">{device.workspace}</td>
|
|
<td className="px-5 py-3">{device.sshKey}</td>
|
|
<td className="px-5 py-3 text-muted-foreground">{device.lastSeen}</td>
|
|
<td className="px-5 py-3">
|
|
<Badge tone={getTone(device.status)}>{device.status}</Badge>
|
|
</td>
|
|
<td className="px-5 py-3">
|
|
<div className="flex justify-end gap-2">
|
|
<Button variant="outline" className="h-8 px-3 text-[13px]">시작</Button>
|
|
<Button variant="outline" className="h-8 px-3 text-[13px]">중지</Button>
|
|
<Button variant="outline" className="h-8 px-3 text-[13px]">재시작</Button>
|
|
<Button variant="ghost" className="size-8 px-0">
|
|
<MoreHorizontal className="size-4" />
|
|
</Button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</Card>
|
|
</>
|
|
);
|
|
}
|