Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ jobs:
go-version-file: go.mod

- name: Run tests with coverage
run: go test ./internal/... -coverprofile=coverage.out -count=1
# node_modules can ship stray Go packages (e.g. flatted) that would
# enter the pattern and dilute the coverage total.
run: go test $(go list ./internal/... | grep -v /node_modules/) -coverprofile=coverage.out -count=1

- name: Check coverage threshold
run: |
Expand Down
20 changes: 19 additions & 1 deletion .github/workflows/pr-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,31 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: internal/web/frontend/package-lock.json

# The Go build embeds frontend/dist, so the frontend must be linted
# and built before any Go package compiles.
- name: Build frontend
working-directory: internal/web/frontend
run: |
npm ci
npm run lint
npm run build

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Run tests with coverage
run: go test ./internal/... -coverprofile=coverage.out -count=1
# node_modules can ship stray Go packages (e.g. flatted) that would
# enter the pattern and dilute the coverage total.
run: go test $(go list ./internal/... | grep -v /node_modules/) -coverprofile=coverage.out -count=1

- name: Check coverage threshold
run: |
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,11 @@ llm-proxy/
├── proxy/forwarder.go # Upstream request forwarding + guardrail enforcement
└── web/
├── spa.go # SPA handler (embeds frontend/dist/)
└── frontend/ # React app (Vite + TypeScript + MUI Joy)
└── frontend/ # React app (Vite + TypeScript + Tailwind + shadcn/ui)
├── src/
│ ├── api/client.ts # API client for /admin/* endpoints
│ ├── context/ # Auth context (localStorage token)
│ ├── components/ # Layout (sidebar), DismissibleAlert
│ ├── components/ # Layout, brand marks, shadcn/ui primitives
│ └── pages/ # Providers, Keys, Usage, Guardrails, Playground
├── vite.config.ts
└── package.json
Expand Down
Binary file modified docs/screenshots/api_keys.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/guardrails.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/providers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/screenshots/usage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 28 additions & 71 deletions internal/web/frontend/README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,30 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)

## React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...

// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,

// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
# llm-proxy dashboard

The admin console for llm-proxy, following the lab34 brand guidelines: React 19 +
TypeScript on Vite, styled with Tailwind CSS v4 and [shadcn/ui](https://ui.shadcn.com)
components (Radix primitives + `class-variance-authority`).

## Stack

- **Fonts** — IBM Plex Sans (interface copy) and IBM Plex Mono (logotype, labels,
tables, figures, code), self-hosted via `@fontsource` so the built binary works
offline. Medium 500 is the heaviest weight in use — no bold anywhere.
- **Theme tokens** — `src/index.css` maps the lab34 palette (bone `#F3F2F2`,
ink `#201F1D`, brass `#B68235`, grey `#9B9797`, carbon `#2D2B2B`) onto shadcn's
CSS variables for both light (ink on bone) and dark (bone on ink/carbon) modes.
Brass appears as stroke — rules, focus rings, small marks — never as a fill.
- **Components** — `src/components/ui/` holds the shadcn primitives
(`components.json` is configured, so `npx shadcn@latest add <component>` works);
`src/components/brand/` holds the lab34 wordmark lockup and «34» monogram.

## Development

```bash
npm ci
npm run dev # Vite dev server on :5173, proxying /admin and /v1 to :8080
npm run lint
npm run build # emits dist/, embedded into the Go binary via go:embed
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
From the repository root, `./development.sh` starts this dev server together with
the Go backend.
21 changes: 21 additions & 0 deletions internal/web/frontend/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
9 changes: 9 additions & 0 deletions internal/web/frontend/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,13 @@ export default defineConfig([
globals: globals.browser,
},
},
{
// shadcn/ui components export their cva variants, and context modules
// export their hook next to the provider — both intentional patterns
// that only affect HMR granularity.
files: ['src/components/ui/**', 'src/context/**', 'src/lib/theme.tsx'],
rules: {
'react-refresh/only-export-components': 'off',
},
},
])
4 changes: 3 additions & 1 deletion internal/web/frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LLM Proxy Dashboard</title>
<meta name="description" content="lab34/proxy — self-hosted LLM proxy console" />
<title>lab34/proxy — console</title>
</head>
<body>
<div id="root"></div>
Expand Down
Loading
Loading