Skip to content
Snippets Groups Projects
Commit 04704340 authored by 한동현's avatar 한동현
Browse files

feat: 웹 프록시 라우팅 목록 페이지 추가

parent 1fe8ed73
No related branches found
No related tags found
No related merge requests found
...@@ -20,6 +20,9 @@ importers: ...@@ -20,6 +20,9 @@ importers:
'@radix-ui/react-dropdown-menu': '@radix-ui/react-dropdown-menu':
specifier: ^2.1.6 specifier: ^2.1.6
version: 2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) version: 2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-hover-card':
specifier: ^1.1.6
version: 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-label': '@radix-ui/react-label':
specifier: ^2.1.2 specifier: ^2.1.2
version: 2.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) version: 2.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
...@@ -485,6 +488,19 @@ packages: ...@@ -485,6 +488,19 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-hover-card@1.1.6':
resolution: {integrity: sha512-E4ozl35jq0VRlrdc4dhHrNSV0JqBb4Jy73WAhBEK7JoYnQ83ED5r0Rb/XdVKw89ReAJN38N492BAPBZQ57VmqQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-id@1.1.0': '@radix-ui/react-id@1.1.0':
resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==}
peerDependencies: peerDependencies:
...@@ -1987,6 +2003,23 @@ snapshots: ...@@ -1987,6 +2003,23 @@ snapshots:
'@types/react': 19.0.10 '@types/react': 19.0.10
'@types/react-dom': 19.0.4(@types/react@19.0.10) '@types/react-dom': 19.0.4(@types/react@19.0.10)
'@radix-ui/react-hover-card@1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@radix-ui/primitive': 1.1.1
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
'@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
optionalDependencies:
'@types/react': 19.0.10
'@types/react-dom': 19.0.4(@types/react@19.0.10)
'@radix-ui/react-id@1.1.0(@types/react@19.0.10)(react@19.0.0)': '@radix-ui/react-id@1.1.0(@types/react@19.0.10)(react@19.0.0)':
dependencies: dependencies:
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
......
...@@ -25,13 +25,13 @@ const data = { ...@@ -25,13 +25,13 @@ const data = {
{ {
icon: ArrowLeftRight, icon: ArrowLeftRight,
title: '라우팅 설정', title: '라우팅 설정',
url: '#', url: 'routing',
isActive: true, isActive: true,
}, },
{ {
icon: ShieldCheck, icon: ShieldCheck,
title: 'SSL 인증서', title: 'SSL 인증서',
url: '#', url: 'certificate',
isActive: false, isActive: false,
}, },
], ],
...@@ -42,7 +42,7 @@ const data = { ...@@ -42,7 +42,7 @@ const data = {
{ {
icon: Server, icon: Server,
title: 'SSH 설정', title: 'SSH 설정',
url: '#', url: 'forwarding',
isActive: false, isActive: false,
}, },
], ],
...@@ -53,7 +53,7 @@ const data = { ...@@ -53,7 +53,7 @@ const data = {
{ {
icon: TextSearch, icon: TextSearch,
title: '설정 변경 내역', title: '설정 변경 내역',
url: '#', url: 'log',
isActive: false, isActive: false,
}, },
], ],
......
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const badgeVariants = cva(
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
secondary:
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
destructive:
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
outline:
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Badge({
className,
variant,
asChild = false,
...props
}: React.ComponentProps<"span"> &
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot : "span"
return (
<Comp
data-slot="badge"
className={cn(badgeVariants({ variant }), className)}
{...props}
/>
)
}
export { Badge, badgeVariants }
import * as React from "react"
import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
import { cn } from "@/lib/utils"
function HoverCard({
...props
}: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
}
function HoverCardTrigger({
...props
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
return (
<HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
)
}
function HoverCardContent({
className,
align = "center",
sideOffset = 4,
...props
}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
return (
<HoverCardPrimitive.Content
data-slot="hover-card-content"
align={align}
sideOffset={sideOffset}
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-64 rounded-md border p-4 shadow-md outline-hidden",
className
)}
{...props}
/>
)
}
export { HoverCard, HoverCardTrigger, HoverCardContent }
...@@ -33,7 +33,7 @@ const logs = [ ...@@ -33,7 +33,7 @@ const logs = [
export default function Home() { export default function Home() {
return ( return (
<div className="flex flex-1 flex-col gap-4 p-6"> <div className="flex flex-1 flex-col gap-4 p-6">
<h1 className="scroll-m-20 text-3xl font-semibold first:mt-0">Aolda Proxy Manager</h1> <h1 className="scroll-m-20 text-3xl font-semibold first:mt-0 mb-2">Aolda Proxy Manager</h1>
<div className="grid auto-rows-min gap-4 md:grid-cols-3"> <div className="grid auto-rows-min gap-4 md:grid-cols-3">
<Card> <Card>
<CardHeader> <CardHeader>
......
import { Filter, Plus, Check, X, Pencil, Trash } from 'lucide-react';
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,
},
];
export default function RoutingList() {
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>
</div>
<Button className="ml-2">
<Plus className="h-4 w-4" /> 새 프록시 추가
</Button>
</div>
<Card>
<CardContent>
<div className="flex w-full items-center space-x-2 mb-4">
<Filter className="mr-3" />
<Input placeholder="이름, 도메인, 인스턴스 IP로 검색..." />
<Button variant="secondary">검색</Button>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-48">이름</TableHead>
<TableHead>도메인</TableHead>
<TableHead>인스턴스 IP</TableHead>
<TableHead className="w-32 min-w-32 text-center">기타 설정</TableHead>
<TableHead className="w-32 min-w-32 text-center">작업</TableHead>
</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>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</div>
);
}
...@@ -2,6 +2,7 @@ import { Routes, Route } from 'react-router'; ...@@ -2,6 +2,7 @@ import { Routes, Route } from 'react-router';
import Root from '@/pages/Root'; import Root from '@/pages/Root';
import Home from '@/pages/Home'; import Home from '@/pages/Home';
import Login from '@/pages/Login'; import Login from '@/pages/Login';
import RoutingList from '@/pages/routing/List';
export default function AppRoutes() { export default function AppRoutes() {
return ( return (
...@@ -9,6 +10,9 @@ export default function AppRoutes() { ...@@ -9,6 +10,9 @@ export default function AppRoutes() {
<Route path="/" element={<Root />}> <Route path="/" element={<Root />}>
<Route index element={<Home />} /> <Route index element={<Home />} />
<Route path="login" element={<Login />} /> <Route path="login" element={<Login />} />
<Route path="routing">
<Route index element={<RoutingList />} />
</Route>
</Route> </Route>
</Routes> </Routes>
); );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment