Add React UI with Execution Explorer, auth, and standalone deployment
Some checks failed
CI / build (push) Failing after 1m53s
CI / docker (push) Has been skipped
CI / deploy (push) Has been skipped

- Scaffold Vite + React + TypeScript frontend in ui/ with full design
  system (dark/light themes) matching the HTML mockups
- Implement Execution Explorer page: search filters, results table with
  expandable processor tree and exchange detail sidebar, pagination
- Add UI authentication: UiAuthController (login/refresh endpoints),
  JWT filter handles ui: subject prefix, CORS configuration
- Shared components: StatusPill, DurationBar, StatCard, AppBadge,
  FilterChip, Pagination — all using CSS Modules with design tokens
- API client layer: openapi-fetch with auth middleware, TanStack Query
  hooks for search/detail/snapshot queries, Zustand for state
- Standalone deployment: Nginx Dockerfile, K8s Deployment + ConfigMap +
  NodePort (30080), runtime config.js for API base URL
- Embedded mode: maven-resources-plugin copies ui/dist into JAR static
  resources, SPA forward controller for client-side routing
- CI/CD: UI build step, Docker build/push for server-ui image, K8s
  deploy step for UI, UI credential secrets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-13 13:59:22 +01:00
parent 9c2391e5d4
commit 3eb83f97d3
65 changed files with 6449 additions and 22 deletions

33
ui/src/api/client.ts Normal file
View File

@@ -0,0 +1,33 @@
import createClient, { type Middleware } from 'openapi-fetch';
import type { paths } from './schema';
import { config } from '../config';
let getAccessToken: () => string | null = () => null;
let onUnauthorized: () => void = () => {};
export function configureAuth(opts: {
getAccessToken: () => string | null;
onUnauthorized: () => void;
}) {
getAccessToken = opts.getAccessToken;
onUnauthorized = opts.onUnauthorized;
}
const authMiddleware: Middleware = {
async onRequest({ request }) {
const token = getAccessToken();
if (token) {
request.headers.set('Authorization', `Bearer ${token}`);
}
return request;
},
async onResponse({ response }) {
if (response.status === 401) {
onUnauthorized();
}
return response;
},
};
export const api = createClient<paths>({ baseUrl: config.apiBaseUrl });
api.use(authMiddleware);