Files
shihaam 2957347583
build-and-push / build (push) Failing after 54s
new ui + search clients
2026-08-01 13:31:46 +05:00
..
2026-08-01 00:51:08 +05:00
2026-08-01 13:31:46 +05:00
2026-08-01 00:51:49 +05:00
2026-08-01 01:47:42 +05:00
2026-08-01 01:47:42 +05:00

radui — RADIUS Admin Portal

Web UI for the 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

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:

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:

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

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).