91 lines
3.5 KiB
Markdown
91 lines
3.5 KiB
Markdown
# radui — RADIUS Admin Portal
|
|
|
|
Web UI for the [`radapi`](../radapi) FreeRADIUS REST API. Manage **clients**
|
|
(customer MACs), **devices** (NAS/AP boxes seen in accounting), and **VLANs**
|
|
without touching SQL. Admins also manage **users**, **API keys**, and view an
|
|
**activity log**. Auth is a username/password login; the backend returns a session
|
|
token stored in the browser (`localStorage`) and sent as `Authorization: Bearer`
|
|
on every request.
|
|
|
|
## Stack
|
|
|
|
- React 19 + Vite + TypeScript
|
|
- Tailwind v4 + shadcn/ui-style components (Radix primitives)
|
|
- react-router-dom, sonner (toasts)
|
|
- Node provided via `shell.nix` (NixOS) — no global install needed
|
|
|
|
## Develop
|
|
|
|
```bash
|
|
nix-shell # drops you into a shell with node 22 + npm
|
|
npm install # first time only
|
|
npm run dev # http://localhost:5173
|
|
```
|
|
|
|
Or as a one-liner without entering the shell:
|
|
|
|
```bash
|
|
nix-shell --run "npm run dev -- --host 0.0.0.0"
|
|
```
|
|
|
|
### Talking to the API
|
|
|
|
In dev, Vite proxies `/api/*` to the backend so the browser makes same-origin
|
|
requests (no CORS) and the token is only ever sent as a header. The target defaults
|
|
to `http://10.0.1.235:8000`; override it:
|
|
|
|
```bash
|
|
VITE_API_TARGET=http://192.168.1.21:8000 npm run dev
|
|
```
|
|
|
|
Log in with **`admin` / `admin`** on first run (you'll be prompted to change the
|
|
password), then create real users from the **Users** page. A `401` from any request
|
|
clears the stored token and returns you to the login screen.
|
|
|
|
## Build
|
|
|
|
```bash
|
|
npm run build # tsc -b && vite build → dist/
|
|
npm run preview # serve the production build locally
|
|
```
|
|
|
|
For production the built `dist/` is static — serve it behind the same origin as the
|
|
API (or set `VITE_API_BASE` to the API's absolute URL at build time).
|
|
|
|
## Layout
|
|
|
|
```
|
|
src/
|
|
main.tsx providers (router, auth, toaster)
|
|
App.tsx auth gate + forced-password-change + nav (role-gated) + routes
|
|
auth/auth.tsx session auth context (login/logout, current user, 401 handling)
|
|
lib/api.ts typed API client (auth + users + apikeys + logs + client/device/vlan)
|
|
lib/utils.ts cn() helper
|
|
pages/
|
|
Login.tsx username/password login screen
|
|
ChangePassword.tsx change own password (also the forced first-login screen)
|
|
Users.tsx admin: list/create/delete users + reset password
|
|
ApiKeys.tsx admin: create (shown once) / list / revoke API keys
|
|
Logs.tsx admin: paginated activity log
|
|
Clients.tsx client list + add/edit/delete + CSV import/export dialogs
|
|
Devices.tsx NAS device list + editable alias
|
|
Vlans.tsx VLAN list + add/rename/delete dialogs
|
|
components/
|
|
ClientImportExport.tsx CSV import (preview/confirm) + export dialog
|
|
ui/ button, input, label, dialog, select, table, card, badge, sonner
|
|
```
|
|
|
|
## Notes
|
|
|
|
- **Clients** — add requires MAC, group (VLAN), name, phone; alias optional. The
|
|
group dropdown is populated from `GET /vlan/`. Edit changes any subset of group,
|
|
status, name, phone, alias.
|
|
- **CSV import** parses the file client-side, does a dry-run against
|
|
`POST /client/import` to preview valid/error rows, and only writes on confirm.
|
|
Export downloads all clients as CSV.
|
|
- **Devices** — lists NAS/AP boxes from accounting, one row per **AP MAC** (with its
|
|
NAS IP and all SSIDs — extra SSIDs collapse to `SSID1 (and N more…)` on hover). The
|
|
only editable field is the human `alias` (`PUT /device/{ap_mac}`).
|
|
- Validation/`4xx` errors from the API surface as toasts with the server's message
|
|
(422 field errors are flattened to `field: message`).
|