import { swrFetcher } from "@/api/api" import { deleteServer, forceUpdateServer } from "@/api/server" import { ActionButtonGroup } from "@/components/action-button-group" import { BatchMoveServerIcon } from "@/components/batch-move-server-icon" import { CopyButton } from "@/components/copy-button" import { HeaderButtonGroup } from "@/components/header-button-group" import { InstallCommandsMenu } from "@/components/install-commands" import { NoteMenu } from "@/components/note-menu" import { ServerCard } from "@/components/server" import { ServerConfigCard } from "@/components/server-config" import { ServerConfigCardBatch } from "@/components/server-config-batch" import { Checkbox } from "@/components/ui/checkbox" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { IconButton } from "@/components/xui/icon-button" import { useServer } from "@/hooks/useServer" import { joinIP } from "@/lib/utils" import { ModelServerTaskResponse, ModelServer as Server } from "@/types" import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table" import { useEffect, useMemo } from "react" import { useTranslation } from "react-i18next" import { toast } from "sonner" import useSWR from "swr" export default function ServerPage() { const { t } = useTranslation() const { data, mutate, error, isLoading } = useSWR("/api/v1/server", swrFetcher, { revalidateOnFocus: false, }) const { serverGroups } = useServer() useEffect(() => { if (error) toast(t("Error"), { description: t("Results.ErrorFetchingResource", { error: error.message }), }) // eslint-disable-next-line react-hooks/exhaustive-deps }, [error]) const columns = useMemo[]>( () => [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" /> ), enableSorting: false, enableHiding: false, }, { header: "ID", accessorKey: "id", accessorFn: (row) => `${row.id}(${row.display_index})`, }, { header: t("Name"), accessorKey: "name", accessorFn: (row) => row.name, cell: ({ row }) => { const s = row.original return
{s.name}
}, }, { header: t("Group"), accessorKey: "groups", accessorFn: (row) => { return ( serverGroups ?.filter((sg) => sg.servers?.includes(row.id!)) .map((sg) => sg.group.id) || [] ) }, }, { id: "ip", header: "IP", cell: ({ row }) => { const s = row.original return (
{joinIP(s.geoip?.ip)}
) }, }, { header: t("Version"), accessorKey: "host.version", accessorFn: (row) => row.host?.version || t("Unknown"), }, { header: t("EnableDDNS"), accessorKey: "enableDDNS", accessorFn: (row) => row.enable_ddns ?? false, }, { header: t("HideForGuest"), accessorKey: "hideForGuest", accessorFn: (row) => row.hide_for_guest ?? false, }, { id: "note", header: t("Note"), cell: ({ row }) => { const s = row.original return }, }, { id: "uuid", header: "UUID", cell: ({ row }) => { const s = row.original return }, }, { id: "actions", header: t("Actions"), cell: ({ row }) => { const s = row.original return ( <> ) }, }, ], [t, mutate, serverGroups], ) const dataCache = useMemo(() => { return data ?? [] }, [data]) const table = useReactTable({ data: dataCache, columns, getCoreRowModel: getCoreRowModel(), }) const selectedRows = table.getSelectedRowModel().rows return (

{t("Server")}

r.original.id).filter(Boolean) as number[], mutate: mutate, }} > { const id = selectedRows.map((r) => r.original.id) as number[] if (id.length < 1) { toast(t("Error"), { description: t("Results.SelectAtLeastOneServer"), }) return } let resp: ModelServerTaskResponse = {} try { resp = await forceUpdateServer(id) } catch (e) { console.error(e) toast(t("Error"), { description: t("Results.UnExpectedError"), }) return } toast(t("Done"), { description: t("Results.ForceUpdate") + (resp.success?.length ? t(`Success`) + ` [${resp.success.join(",")}]` : "") + (resp.failure?.length ? t(`Failure`) + ` [${resp.failure.join(",")}]` : "") + (resp.offline?.length ? t(`Offline`) + ` [${resp.offline.join(",")}]` : ""), }) }} /> r.original.id) as number[]} /> r.original.id) as number[]} className="shadow-[inset_0_1px_0_rgba(255,255,255,0.2)] bg-yellow-600 text-white hover:bg-yellow-500 dark:hover:bg-yellow-700 rounded-lg" />
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { return ( {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext(), )} ) })} ))} {isLoading ? ( {t("Loading")}... ) : table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} )) ) : ( {t("NoResults")} )}
) }