Design changes
This commit is contained in:
parent
3b00fd2ec0
commit
aa1f7b25cf
7 changed files with 127 additions and 37 deletions
3
.env
Normal file
3
.env
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#This file current does nothing, but is here for future use.
|
||||||
|
URL=http://caddy.example.com
|
||||||
|
CADDY_API=http://192.168.1.69:2019
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -20,6 +20,8 @@ package-lock.json
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.pem
|
*.pem
|
||||||
|
|
||||||
|
.env
|
||||||
|
|
||||||
# debug
|
# debug
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
|
|
|
||||||
18
app/page.tsx
18
app/page.tsx
|
|
@ -1,6 +1,3 @@
|
||||||
"use client"
|
|
||||||
|
|
||||||
|
|
||||||
import { useRoutes } from '@/lib/clientActions';
|
import { useRoutes } from '@/lib/clientActions';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Loading from '@/components/Loading';
|
import Loading from '@/components/Loading';
|
||||||
|
|
@ -9,25 +6,20 @@ import { useState } from 'react';
|
||||||
import { RouteDialog } from '@/components/RouteDialog';
|
import { RouteDialog } from '@/components/RouteDialog';
|
||||||
import Header from '@/components/Header';
|
import Header from '@/components/Header';
|
||||||
import RouteCards from '@/components/RouteCards';
|
import RouteCards from '@/components/RouteCards';
|
||||||
|
import { SWRConfig } from 'swr';
|
||||||
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
|
||||||
const { data: routes, error, isLoading } = useRoutes();
|
|
||||||
let routesMap: Route[] = routes as Route[];
|
|
||||||
|
|
||||||
if (error) return <Error />
|
|
||||||
if (isLoading) return <Loading />
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Header routes={routesMap} />
|
<Header />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='grid grid-flow-row-dense md:grid-cols-6 sm:grid-cols-2 p-2'>
|
<div className='flex flex-grid p-2 flex-wrap justify-center gap-2'>
|
||||||
<RouteCards routes={routesMap} />
|
<RouteCards />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,17 @@ export default function Error() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-center'>
|
<div className='flex justify-center'>
|
||||||
<Card>
|
<div className="flex justify-center items-center min-h-screen h-[90vh]">
|
||||||
<CardHeader>
|
<Card>
|
||||||
<CardTitle>Error</CardTitle>
|
<CardHeader>
|
||||||
<CardDescription>There was an error fetching your data</CardDescription>
|
<CardTitle>Error</CardTitle>
|
||||||
</CardHeader>
|
<CardDescription>There was an error fetching your data</CardDescription>
|
||||||
<CardFooter className="flex justify-center">
|
</CardHeader>
|
||||||
<Button onClick={handleRefresh}>Retry</Button>
|
<CardFooter className="flex justify-center">
|
||||||
</CardFooter>
|
<Button onClick={handleRefresh}>Retry</Button>
|
||||||
</Card>
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
68
components/Header.tsx
Normal file
68
components/Header.tsx
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import { CardTitle, Card, CardDescription, CardHeader, CardContent, CardFooter } from '@/components/ui/card';
|
||||||
|
import RouteCards from '@/components/RouteCards';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useRoutes } from '@/lib/clientActions';
|
||||||
|
import Error from './Error';
|
||||||
|
import Loading from './Loading';
|
||||||
|
import { RouteDialog } from './RouteDialog';
|
||||||
|
|
||||||
|
export default function Header() {
|
||||||
|
|
||||||
|
const { data: routes, error, isLoading } = useRoutes();
|
||||||
|
let routesMap: Route[] = routes as Route[];
|
||||||
|
|
||||||
|
const [route, setRoute] = useState<Route>();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{route && <RouteDialog open={open} onOpenChange={setOpen} route={route} routesMap={routesMap} />}
|
||||||
|
|
||||||
|
<div className='flex items-center justify-center py-6'>
|
||||||
|
<Card className='flex'>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Active Routes</CardTitle>
|
||||||
|
<CardDescription>Amount of configured routes</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className='flex items-center'>
|
||||||
|
<div>
|
||||||
|
<p className='text-xl font-semibold translate-y-2'>{routesMap?.length}</p>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
<CardFooter>
|
||||||
|
<Button onClick={() => {
|
||||||
|
setRoute({
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "subroute",
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "reverse_proxy",
|
||||||
|
"upstreams": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
})
|
||||||
|
setOpen(true);
|
||||||
|
}} className='translate-y-2.5'>Create</Button>
|
||||||
|
</CardFooter>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -3,8 +3,10 @@ import Image from "next/image";
|
||||||
export default function Loading() {
|
export default function Loading() {
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-center'>
|
<div className='flex justify-center'>
|
||||||
<Image src="/loading.svg" alt="Loading" width={25} height={25} />
|
<div className="flex items-center min-h-screen h-[90vh]">
|
||||||
<p className='p-2'>Loading</p>
|
<Image src="/loading.svg" alt="Loading" width={25} height={25} />
|
||||||
|
<p className='p-2'>Loading</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -2,18 +2,24 @@
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "./ui/card";
|
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "./ui/card";
|
||||||
import { getHosts, getRouteUpstreams } from '@/lib/utils';
|
import { getHandler, getHosts, getRouteUpstreams } from '@/lib/utils';
|
||||||
import { toast } from './ui/use-toast';
|
import { toast } from './ui/use-toast';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import useSWRMutation from 'swr/mutation';
|
import useSWRMutation from 'swr/mutation';
|
||||||
import { deleteRoute } from '@/lib/clientActions';
|
import { deleteRoute, useRoutes } from '@/lib/clientActions';
|
||||||
import { RouteDialog } from './RouteDialog';
|
import { RouteDialog } from './RouteDialog';
|
||||||
|
import Error from './Error';
|
||||||
|
import Loading from './Loading';
|
||||||
|
|
||||||
export default function RouteCards({ routes }: { routes: Route[] }) {
|
export default function RouteCards() {
|
||||||
|
|
||||||
|
const { data: routes, error, isLoading } = useRoutes();
|
||||||
|
let routesMap: Route[] = routes as Route[];
|
||||||
|
|
||||||
const [route, setRoute] = useState<Route>();
|
const [route, setRoute] = useState<Route>();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
const { trigger: handleDelete } = useSWRMutation("/api/caddy/routes", deleteRoute, {
|
const { trigger: handleDelete } = useSWRMutation("/api/caddy/routes", deleteRoute, {
|
||||||
onError: () => {
|
onError: () => {
|
||||||
return toast({
|
return toast({
|
||||||
|
|
@ -36,29 +42,44 @@ export default function RouteCards({ routes }: { routes: Route[] }) {
|
||||||
setRoute(route);
|
setRoute(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (error) return <Error />
|
||||||
|
if (isLoading) return <Loading />
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{route && <RouteDialog open={open} onOpenChange={setOpen} route={route} routesMap={routes} />}
|
{route && <RouteDialog open={open} onOpenChange={setOpen} route={route} routesMap={routesMap} />}
|
||||||
{
|
{
|
||||||
routes.map((route, index) => (
|
routesMap.map((route, index) => (
|
||||||
<div key={index} className='p-2'>
|
<div key={index}>
|
||||||
<Card key={index} className='w-[15vw]'>
|
<Card key={index}>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>{getHosts(route)!.values().next().value}</CardTitle>
|
<CardTitle>{getHosts(route)!.values().next().value}</CardTitle>
|
||||||
{getHosts(route)!.map((route => <CardDescription key={route}>{route}</ CardDescription>))}
|
{getHosts(route)!.map((route => <CardDescription key={route}>{route}</ CardDescription>))}
|
||||||
<CardDescription></CardDescription>
|
<CardDescription></CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<p className="text-sm font-medium leading-none">
|
<div className='flex flex-grid gap-6 items-center justify-center'>
|
||||||
Tunneling to
|
<div>
|
||||||
</p>
|
<p className='text-sm font-mdeium leading-none'>
|
||||||
<p className="text-sm text-muted-foreground">{getRouteUpstreams(route)?.map((upstream => upstream.dial))}</p>
|
Type
|
||||||
|
</p>
|
||||||
|
<p className='text-sm text-muted-foreground'>{getHandler(route)}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium leading-none">
|
||||||
|
Tunneling to
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-muted-foreground">{getRouteUpstreams(route)?.map((upstream => upstream.dial))}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardFooter className="flex justify-between">
|
<CardFooter className="flex justify-between">
|
||||||
<Button onClick={() => {
|
<Button onClick={() => {
|
||||||
editRoute(route)
|
editRoute(route)
|
||||||
setOpen(true)
|
setOpen(true)
|
||||||
}}>Edit</Button>
|
}}>Edit</Button>
|
||||||
<Button variant="destructive" onClick={() => { handleDelete(route) }}>Delete</Button>
|
<Button variant="destructive" onClick={() => { handleDelete(route) }}>Delete</Button>
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue