Files
lukaszraczylo 227200316d fix(webui): keep charts consistent with the current selection
Chart and ranking fetches carry a request id, and a superseded response
is dropped. Changing a selection clears the old data at once, so old
numbers never show under new labels or units. The auto-refresh tick
skips while a fetch is still in flight. "Loading..." shows only until
the first result for a selection arrives. Dashboard polls do not
overlap.

Users in several groups are counted and searched in every group. The
Models tab labels its windows as the current UTC bucket. Hour labels
are marked UTC. The Members column sorts numerically. Target access
shows "All groups" for null and "No groups" for []. The UI shows the
server's own error message. Cost axis ticks use the currency
formatter. npm run dev proxies /admin/api. Nine unused shadcn
components are removed.

admin_assets_gen.go is regenerated from the new build.

Claude-Session: https://claude.ai/code/session_01V5jYJNxpDFdJkyyExpADrv
2026-09-23 09:44:32 +01:00

68 lines
3.2 KiB
TypeScript

import { fileURLToPath, URL } from 'node:url'
import tailwindcss from '@tailwindcss/vite'
import vue from '@vitejs/plugin-vue'
// vitest/config's defineConfig is vite's own, augmented with the `test`
// field's types — importing from here (not 'vite') is what lets the
// `test` block below type-check under vue-tsc -b without a separate
// vitest.config.ts or a triple-slash type reference.
import { defineConfig } from 'vitest/config'
// https://vite.dev/config/
export default defineConfig({
// admin.go serves this build's index.html at GET /admin and every hashed
// asset at GET /admin/assets/{hashedname} — the base must match so the
// emitted index.html's own <script>/<link> references resolve correctly
// regardless of what path the browser first loaded the page from.
base: '/admin/',
plugins: [vue(), tailwindcss()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
build: {
// No inline bootstrap script in the emitted index.html (admin.go's CSP
// ships script-src 'self' with no 'unsafe-inline' — see the Go-side
// asset-serving comment for the full rationale): Vite's module-preload
// polyfill is otherwise inlined as a <script> tag, which that CSP would
// block. Disabling it leaves only <link rel="modulepreload"> hints,
// which need no script-src allowance at all. The admin panel only ever
// targets current evergreen browsers (native ES module support), so the
// polyfill has nothing to do here anyway.
modulePreload: { polyfill: false },
},
server: {
// `npm run dev` serves this app at :5173 (or whatever Vite picks), but
// every fetch('/admin/api/...') (lib/api.ts) is a same-origin, relative
// path — without a proxy it hits Vite itself, which has no such route
// and answers with a 404 or the index.html SPA fallback, so the dev
// build can never actually load data. Proxying just the API path (not
// '/admin' itself) leaves Vite serving this project's own index.html/
// HMR client at '/admin/' as usual. The target is env-configurable
// (ADMIN_API_PROXY_TARGET) rather than hardcoded, since which gateway
// instance a developer is pointed at varies by machine; the fallback
// matches this repo's own `run-local`/integration default port.
proxy: {
'/admin/api': {
target: process.env.ADMIN_API_PROXY_TARGET ?? 'http://localhost:8080',
changeOrigin: true,
},
},
},
test: {
// Deliberately narrow: lib/'s pure modules (search-expand.ts,
// usage-search.ts) plus, since review round 2 (v0.21), stores/
// dashboard.ts's own refresh() action — a Pinia store is plain
// reactive state and actions, no DOM or component mount involved, so
// it fits this same environment. Still no snapshot/DOM/component
// (.vue mount) testing. 'node' is enough since nothing under test
// touches a real browser global — dashboard.spec.ts mocks lib/api.ts
// entirely, so even sessionStorage access (auth.ts) never actually
// runs; jsdom is not pulled in as a dependency for modules that don't
// need it.
environment: 'node',
include: ['src/**/*.spec.ts'],
},
})