further implementing server page (#4)

* further implementing server page

* optimize icon button

* rename some unnecessary file extensions

* add terminal page & fm card
This commit is contained in:
UUBulb
2024-11-18 20:48:30 +08:00
committed by GitHub
parent 6e3f888792
commit fc923f3ab1
25 changed files with 1248 additions and 149 deletions

View File

@@ -4,8 +4,28 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
import { ModelServer as Server } from "@/types"
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table"
import useSWR from "swr"
import { HeaderButtonGroup } from "@/components/header-button-group"
import { deleteServer } from "@/api/server"
import { ServerCard } from "@/components/server"
import { Skeleton } from "@/components/ui/skeleton"
import { ActionButtonGroup } from "@/components/action-button-group"
import { useEffect } from "react"
import { toast } from "sonner"
import { IconButton } from "@/components/xui/icon-button"
import { InstallCommandsMenu } from "@/components/install-commands"
import { NoteMenu } from "@/components/note-menu"
import { TerminalButton } from "@/components/terminal"
export default function ServerPage() {
const { data, mutate, error, isLoading } = useSWR<Server[]>('/api/v1/server', swrFetcher);
useEffect(() => {
if (error)
toast("Error", {
description: `Error fetching resource: ${error.message}.`,
})
}, [error])
const columns: ColumnDef<Server>[] = [
{
id: "select",
@@ -32,85 +52,155 @@ export default function ServerPage() {
{
header: "ID",
accessorKey: "id",
accessorFn: (row) => row.id,
accessorFn: row => `${row.id}(${row.display_index})`,
},
{
header: "Name",
accessorKey: "name",
accessorFn: (row) => row.name,
cell: ({ row }) => {
const s = row.original;
return (
<div className="max-w-24 whitespace-normal break-words">
{s.name}
</div>
)
}
},
{
header: "Host",
header: "Groups",
accessorKey: "groups",
accessorFn: row => "stub",
},
{
id: "ip",
header: "IP",
accessorKey: "host.ip",
accessorFn: (row) => row.host?.ip,
cell: ({ row }) => {
const s = row.original;
return (
<div className="max-w-24 whitespace-normal break-words">
{s.host.ip}
</div>
)
}
},
{
header: "Version",
accessorKey: "host.version",
accessorFn: row => row.host.version || "Unknown",
},
{
header: "Enable DDNS",
accessorKey: "enableDDNS",
accessorFn: row => row.enable_ddns ?? false,
},
{
header: "Hide from Guest",
accessorKey: "hideForGuest",
accessorFn: row => row.hide_for_guest ?? false,
},
{
id: "installCommands",
header: "Install commands",
cell: () => <InstallCommandsMenu />,
},
{
id: "note",
header: "Note",
cell: ({ row }) => {
const s = row.original;
return <NoteMenu note={{ private: s.note, public: s.public_note }} />;
},
},
{
id: "actions",
header: "Actions",
cell: ({ row }) => {
const s = row.original
const s = row.original;
return (
<>{s.id}</>
<ActionButtonGroup className="flex gap-2" delete={{ fn: deleteServer, id: s.id, mutate: mutate }}>
<>
<TerminalButton id={s.id} />
<ServerCard mutate={mutate} data={s} />
</>
</ActionButtonGroup>
)
},
},
]
const { data, error, isLoading } = useSWR<Server[]>('/api/v1/server', swrFetcher)
const table = useReactTable({
data: data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
})
return <div className="px-9">
<div className="flex space-between mt-4 pb-4">
<h1 className="text-3xl font-bold tracking-tight">
Server
</h1>
</div>
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
const selectedRows = table.getSelectedRowModel().rows;
return (
<div className="px-8">
<div className="flex mt-6 mb-4">
<h1 className="text-3xl font-bold tracking-tight">
Server
</h1>
<HeaderButtonGroup className="flex-2 flex ml-auto gap-2" delete={{
fn: deleteServer,
id: selectedRows.map(r => r.original.id),
mutate: mutate,
}}>
<IconButton icon="update" />
</HeaderButtonGroup>
</div>
{isLoading ? (
<div className="flex flex-col items-center space-y-4">
<Skeleton className="h-[60px] w-[100%] rounded-lg" />
<Skeleton className="h-[60px] w-[100%] rounded-lg" />
<Skeleton className="h-[60px] w-[100%] rounded-lg" />
</div>
) : (
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id} className="text-sm">
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id} className="text-xsm">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
</TableRow>
)}
</TableBody>
</Table>
)}
</div>
)
}

View File

@@ -15,12 +15,12 @@ import { Skeleton } from "@/components/ui/skeleton"
import { toast } from "sonner"
export default function ServicePage() {
const { data, mutate, error, isLoading } = useSWR<ModelServiceResponse>('/api/v1/service', swrFetcher)
const { data, mutate, error, isLoading } = useSWR<ModelServiceResponse>('/api/v1/service', swrFetcher);
useEffect(() => {
if (error)
toast("Error", {
description: "Error fetching resource.",
description: `Error fetching resource: ${error.message}.`,
})
}, [error])
@@ -55,12 +55,26 @@ export default function ServicePage() {
{
header: "Name",
accessorKey: "service.name",
accessorFn: row => row.service.name,
cell: ({ row }) => {
const s = row.original;
return (
<div className="max-w-24 whitespace-normal break-words">
{s.service.name}
</div>
)
}
},
{
header: "Target",
accessorKey: "service.target",
accessorFn: row => row.service.target,
cell: ({ row }) => {
const s = row.original;
return (
<div className="max-w-24 whitespace-normal break-words">
{s.service.target}
</div>
)
}
},
{
header: "Coverage",
@@ -97,7 +111,7 @@ export default function ServicePage() {
accessorFn: row => row.service.notification_group_id,
},
{
header: "Enable Trigger Task",
header: "On Trigger",
accessorKey: "service.triggerTask",
accessorFn: row => row.service.enable_trigger_task ?? false,
},