Add monorepo structure for NexaVPN WireGuard control plane including: - .gitignore for node_modules, build artifacts, and environment files - README with project overview, monorepo layout, and quick start guide - Admin web UI with React, Vite, TypeScript, and nginx reverse proxy - API client with type definitions for users, devices, policies, gateways, and audit logs - Admin pages for dashboard, users, devices, policies, g
40 lines
1.1 KiB
TypeScript
40 lines
1.1 KiB
TypeScript
import { useQuery } from "@tanstack/react-query";
|
|
|
|
import { api } from "../../api/client";
|
|
import { Page } from "../../components/Page";
|
|
import { Table } from "../../components/Table";
|
|
|
|
const columns = [
|
|
{ key: "name", label: "Device" },
|
|
{ key: "owner", label: "Owner" },
|
|
{ key: "platform", label: "Platform" },
|
|
{ key: "ip", label: "VPN IP" },
|
|
{ key: "status", label: "Status" }
|
|
];
|
|
|
|
export function DevicesPage() {
|
|
const query = useQuery({
|
|
queryKey: ["devices"],
|
|
queryFn: api.devices
|
|
});
|
|
|
|
const rows = query.data?.map((device) => ({
|
|
name: device.name,
|
|
owner: device.user_id ?? "assigned user",
|
|
platform: device.platform,
|
|
ip: device.assigned_ip ?? "-",
|
|
status: device.status
|
|
})) ?? [];
|
|
|
|
return (
|
|
<Page title="Devices" subtitle="Inspect enrolled clients, assignments, and profile lifecycle.">
|
|
{query.isError ? <p className="notice">Unable to load devices from the API.</p> : null}
|
|
<Table
|
|
columns={columns}
|
|
rows={rows}
|
|
renderCell={(row, column) => <span>{row[column.key as keyof (typeof rows)[number]]}</span>}
|
|
/>
|
|
</Page>
|
|
);
|
|
}
|