Files
NexaVPN/admin-web/src/features/devices/DevicesPage.tsx
nessi 830491cb0d chore: initial project scaffold with admin web, backend, desktop client, and deployment setup
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
2026-03-15 16:32:34 +01:00

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>
);
}