mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-15 05:29:28 +00:00
feat(webui): vue admin panel source
Vue 3 + TypeScript + Pinia + Tailwind v4 + shadcn-vue + Chart.js admin panel source under webui/, built with Vite. Views: Overview (providers, redis/cache/retry status, model aliases), Usage (per-user/per-group/total tables with tokensIn/tokensOut/cost + limits), Charts (scope selector, req/tokens(stacked in-out)/cost metric tabs, 24h/30d/12mo window switcher, fed by GET /admin/api/usage/history). Pinia stores: auth (sessionStorage key gate, x-api-key header, 401/403 re-prompt), dashboard (5s poll), history (fetch-on-selection + 30s refresh). Design: deliberate neutral warm-neutral palette with a signature teal accent (no default Inter/purple-gradient/glassmorphism), real typographic hierarchy via the platform UI/mono font stacks (zero external assets - no Google Fonts), dark+light via prefers-color-scheme (no class toggle, no theme switcher). Charts: zero-based bars, honest axes, Okabe-Ito colorblind-safe series, tokens-in/out as a distinguishable stacked pair. vite.config.ts: base '/admin/' (matches admin.go's route layout) and build.modulePreload.polyfill:false (no inline bootstrap script, so the tightened admin CSP needs no 'unsafe-inline'). Code-split: Chart.js (ChartsView) loads lazily, not in the initial bundle. generate.mjs reads dist/ after `vite build` and writes ../admin_assets_gen.go (not committed by this change) - base64-encodes every asset, decoded once at package-var init; documented rationale in the script's own header comment. Hygiene: webui/go.mod walls webui/ off from the repo root's `go build`/ `vet`/`test ./...` (npm's node_modules bundles a stray .go file that would otherwise be swept in); tools/yaegi-check/main.go excludes webui/ from its GOPATH copy for the same reason. webui/ export-ignored (.gitattributes) from release source tarballs; webui/node_modules/ gitignored. tsconfig.app.json/tsconfig.node.json's JSONC comments dropped (TS itself is fine with either; the global pre-commit JSON validator is not) - no config values changed.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
// Shared response shapes for the three /admin/api/* routes (admin.go). Kept
|
||||
// as one module so every store/component imports the identical types rather
|
||||
// than re-declaring them (vue.md: "share types once, import everywhere").
|
||||
|
||||
/** Mirrors Go's LimitsConfig (llmgateway.go) — every field is 0/omitted when unlimited. */
|
||||
export interface LimitsConfig {
|
||||
requestsPerMinute?: number
|
||||
requestsPerDay?: number
|
||||
tokensPerDay?: number
|
||||
tokensPerMonth?: number
|
||||
costPerDayUSD?: number
|
||||
costPerMonthUSD?: number
|
||||
}
|
||||
|
||||
export interface AdminProviderView {
|
||||
name: string
|
||||
type: string
|
||||
baseUrl: string
|
||||
lastRefresh: string
|
||||
lastErr?: string
|
||||
modelCount: number
|
||||
}
|
||||
|
||||
export interface AdminRedisView {
|
||||
lastErrAt: string
|
||||
lastErr?: string
|
||||
configured: boolean
|
||||
}
|
||||
|
||||
export interface AdminCacheView {
|
||||
ttl?: string
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
export interface AdminRetryView {
|
||||
backoff?: string
|
||||
enabled: boolean
|
||||
attempts?: number
|
||||
}
|
||||
|
||||
export interface AdminGroupView {
|
||||
limits?: LimitsConfig
|
||||
name: string
|
||||
memberCount: number
|
||||
}
|
||||
|
||||
export interface AdminAliasView {
|
||||
alias: string
|
||||
target: string
|
||||
}
|
||||
|
||||
/** GET /admin/api/overview (admin.go: adminOverviewResponse). */
|
||||
export interface AdminOverviewResponse {
|
||||
version: string
|
||||
providers: AdminProviderView[]
|
||||
groups: AdminGroupView[]
|
||||
aliases: AdminAliasView[]
|
||||
redis: AdminRedisView
|
||||
cache: AdminCacheView
|
||||
retry: AdminRetryView
|
||||
}
|
||||
|
||||
export interface AdminUsageEntryView {
|
||||
limits?: LimitsConfig
|
||||
kind: string
|
||||
id: string
|
||||
groupName?: string
|
||||
requestsPerMinute: number
|
||||
requestsPerDay: number
|
||||
tokensInPerDay: number
|
||||
tokensOutPerDay: number
|
||||
tokensInPerMonth: number
|
||||
tokensOutPerMonth: number
|
||||
costPerDayMicroUsd: number
|
||||
costPerMonthMicroUsd: number
|
||||
storeDown?: boolean
|
||||
}
|
||||
|
||||
/** GET /admin/api/usage (admin.go: adminUsageResponse). */
|
||||
export interface AdminUsageResponse {
|
||||
users: AdminUsageEntryView[]
|
||||
groups: AdminUsageEntryView[]
|
||||
total: AdminUsageEntryView
|
||||
}
|
||||
|
||||
/** The four metric values GET /admin/api/usage/history accepts. */
|
||||
export type HistoryMetric = 'req' | 'tokin' | 'tokout' | 'cost'
|
||||
|
||||
/** The three window values GET /admin/api/usage/history accepts. */
|
||||
export type HistoryWindow = 'hour' | 'day' | 'month'
|
||||
|
||||
export interface UsageHistoryPoint {
|
||||
bucket: string
|
||||
value: number
|
||||
}
|
||||
|
||||
/** GET /admin/api/usage/history (admin.go: usageHistoryResponse). */
|
||||
export interface UsageHistoryResponse {
|
||||
scope: string
|
||||
metric: string
|
||||
window: string
|
||||
points: UsageHistoryPoint[]
|
||||
}
|
||||
Reference in New Issue
Block a user