diff --git a/src/pages/routing/List.tsx b/src/pages/routing/List.tsx index 26b4fa1c10b8f8dde23dc7f0fe2929ecc82e0c92..8ac3de36b267bb675a7f7734ab614b7093454d0e 100644 --- a/src/pages/routing/List.tsx +++ b/src/pages/routing/List.tsx @@ -1,62 +1,48 @@ +import { useEffect, useState } from 'react'; +import { Link } from 'react-router'; import { Filter, Plus, Check, X, Pencil, Trash } from 'lucide-react'; +import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; -import { Link } from 'react-router'; - -const routings = [ - { - id: 1, - name: '아올다 프록시 매니저 콘솔', - created_at: '2021-09-01 11:43:00', - updated_at: '2021-09-01 12:00:00', - domain: 'console.ajou.app', - instance_ip: '10.16.0.10', - ssl_id: 10921, - is_cached: false, - }, - { - id: 2, - name: '아올다 블로그', - created_at: '2021-09-01 12:00:00', - updated_at: '2021-09-01 12:01:00', - domain: 'blog.ajou.app', - instance_ip: '10.16.0.11', - ssl_id: 10921, - is_cached: true, - }, - { - id: 3, - name: '개인 블로그', - created_at: '2021-09-01 12:01:00', - updated_at: '2021-09-01 13:00:00', - domain: 'blog.username.blog', - instance_ip: '10.16.3.23', - ssl_id: 10923, - is_cached: true, - }, - { - id: 4, - name: '아올다 테스트 서버', - created_at: '2021-09-01 13:00:00', - updated_at: '2021-09-02 12:00:00', - domain: 'test.aolda.app', - instance_ip: '10.16.32.1', - ssl_id: null, - is_cached: false, - }, -]; +import { Skeleton } from '@/components/ui/skeleton'; +import { useAuthStore } from '@/stores/authStore'; +import { Routing } from '@/types/routing'; export default function RoutingList() { + const { authFetch, selectedProject } = useAuthStore(); + const [routings, setRoutings] = useState<Routing[] | null>(null); + + useEffect(() => { + authFetch(`/api/routings?projectId=${selectedProject?.id}`) + .then((response) => { + if (!response.ok) { + toast.error('포트포워딩 정보를 조회할 수 없습니다.'); + return { contents: [] }; + } + + return response.json(); + }) + .then(({ contents }) => { + setRoutings(contents); + }); + }, [authFetch, selectedProject]); + return ( <div className="flex flex-1 flex-col gap-4 p-6"> <div className="flex justify-between mb-2"> <div> <h1 className="scroll-m-20 text-3xl font-semibold first:mt-0">웹 라우팅 설정</h1> - <p className="mt-1 text-base text-gray-500">현재 3개의 웹 프록시가 설정되어 있습니다.</p> + {routings === null ? ( + <Skeleton className="w-[24rem] h-[1rem] mt-2 rounded-full" /> + ) : ( + <p className="mt-1 text-base text-gray-500"> + <p className="mt-1 text-base text-gray-500">현재 {routings.length}개의 웹 프록시가 설정되어 있습니다.</p> + </p> + )} </div> <Button className="ml-2" asChild> <Link to="./create"> @@ -82,69 +68,95 @@ export default function RoutingList() { </TableRow> </TableHeader> <TableBody> - {routings.map((routing) => ( - <TableRow key={routing.id}> - <TableCell className="truncate max-w-48"> - <HoverCard> - <HoverCardTrigger>{routing.name}</HoverCardTrigger> - <HoverCardContent className="w-80 whitespace-normal"> - <div className="flex justify-between space-x-4"> - <div className="space-y-1"> - <p className="text-sm font-semibold">{routing.name}</p> - <p className="text-sm"> - {routing.domain} ({routing.instance_ip}) - </p> - <p className="text-xs text-muted-foreground mt-2">{routing.created_at} 생성</p> - <p className="text-xs text-muted-foreground">{routing.updated_at} 수정</p> - </div> - </div> - </HoverCardContent> - </HoverCard> - </TableCell> - <TableCell>{routing.domain}</TableCell> - <TableCell>{routing.instance_ip}</TableCell> - <TableCell> - <div className="flex justify-center items-center gap-1"> - {routing.ssl_id !== null ? ( - <Badge variant="secondary"> - <Check className="h-3 w-3" /> - SSL - </Badge> - ) : ( - <Badge variant="outline" className="text-gray-500"> - <X className="h-3 w-3" /> - SSL - </Badge> - )} - {routing.is_cached ? ( - <Badge variant="secondary"> - <Check className="h-3 w-3" /> - 캐시 - </Badge> - ) : ( - <Badge variant="outline" className="text-gray-500"> - <X className="h-3 w-3" /> - 캐시 - </Badge> - )} - </div> - </TableCell> - <TableCell> - <div className="flex justify-center items-center gap-2"> - <Button variant="secondary" className="size-8"> - <Link to={`./edit/${routing.id}`}> - <Pencil /> - </Link> - </Button> - <Button variant="secondary" className="size-8"> - <Link to={`./delete/${routing.id}`}> - <Trash /> - </Link> - </Button> - </div> + {routings === null ? ( + <> + <TableRow> + <TableCell colSpan={4}> + <Skeleton className="w-full h-[1rem] my-2 rounded-full" /> + </TableCell> + </TableRow> + <TableRow> + <TableCell colSpan={4}> + <Skeleton className="w-full h-[1rem] my-2 rounded-full" /> + </TableCell> + </TableRow> + <TableRow> + <TableCell colSpan={4}> + <Skeleton className="w-full h-[1rem] my-2 rounded-full" /> + </TableCell> + </TableRow> + </> + ) : routings.length === 0 ? ( + <TableRow> + <TableCell colSpan={4} className="text-center text-muted-foreground"> + 현재 프로젝트에 등록된 웹 프록시 설정이 없습니다. </TableCell> </TableRow> - ))} + ) : ( + routings.map((routing) => ( + <TableRow key={routing.id}> + <TableCell className="truncate max-w-48"> + <HoverCard> + <HoverCardTrigger>{routing.name}</HoverCardTrigger> + <HoverCardContent className="w-80 whitespace-normal"> + <div className="flex justify-between space-x-4"> + <div className="space-y-1"> + <p className="text-sm font-semibold">{routing.name}</p> + <p className="text-sm"> + {routing.domain} ({routing.ip}) + </p> + <p className="text-xs text-muted-foreground mt-2">{routing.createdAt} 생성</p> + <p className="text-xs text-muted-foreground">{routing.updatedAt} 수정</p> + </div> + </div> + </HoverCardContent> + </HoverCard> + </TableCell> + <TableCell>{routing.domain}</TableCell> + <TableCell>{routing.ip}</TableCell> + <TableCell> + <div className="flex justify-center items-center gap-1"> + {routing.certificateId !== undefined ? ( + <Badge variant="secondary"> + <Check className="h-3 w-3" /> + SSL + </Badge> + ) : ( + <Badge variant="outline" className="text-gray-500"> + <X className="h-3 w-3" /> + SSL + </Badge> + )} + {routing.caching ? ( + <Badge variant="secondary"> + <Check className="h-3 w-3" /> + 캐시 + </Badge> + ) : ( + <Badge variant="outline" className="text-gray-500"> + <X className="h-3 w-3" /> + 캐시 + </Badge> + )} + </div> + </TableCell> + <TableCell> + <div className="flex justify-center items-center gap-2"> + <Button variant="secondary" className="size-8"> + <Link to={`./edit/${routing.id}`}> + <Pencil /> + </Link> + </Button> + <Button variant="secondary" className="size-8"> + <Link to={`./delete/${routing.id}`}> + <Trash /> + </Link> + </Button> + </div> + </TableCell> + </TableRow> + )) + )} </TableBody> </Table> </CardContent> diff --git a/src/types/routing.ts b/src/types/routing.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe51a1b362a5f9039cb191f0d4d108b96fc133a4 --- /dev/null +++ b/src/types/routing.ts @@ -0,0 +1,11 @@ +export interface Routing { + id: number; + name: string; + domain: string; + ip: string; + port: number; + createdAt: string; + updatedAt: string; + certificateId: number | undefined; + caching: boolean; +}