React-based admin UI for ContextForge MCP Gateway.
This UI targets ContextForge API v1.0.7, matching openapi.json committed at repo root.
- React 18 with TypeScript
- Vite - Build tool and dev server
- React Router - Client-side routing
- React Intl - Internationalization (i18n)
- Tailwind CSS - Utility-first styling
- shadcn/ui - Component library
- Node.js 20+ and npm
npm installThe client development workflow requires both the client dev server and the backend gateway:
-
Build the client assets:
npm run build
-
Start the client development server:
npm run dev
This starts the Vite dev server at
http://localhost:5173with hot module replacement. -
In another terminal, start the backend gateway:
make dev
-
Access the application: Open your browser and navigate to
http://localhost:8000/appto view the UI.
npm run buildBuilds the production bundle to dist/.
npm run previewTypeScript types and fetch clients under src/generated/ come from openapi.json via Orval. That file is committed and pinned to API v1.0.7 — not re-fetched at build time.
npm run generate # regenerate src/generated/ from ./openapi.jsonTo bump the API version, replace openapi.json with the new spec, update the version note above, then run npm run generate.
ESLint is configured with TypeScript support and Prettier integration.
# Check for linting errors
npm run lint
# Auto-fix linting errors
npm run lint:fixConfiguration: eslint.config.js
Prettier is configured for consistent code formatting.
# Format all files
npm run format
# Check formatting without changes
npm run format:checkConfiguration: .prettierrc
Key Settings:
- Trailing commas:
all(including function calls) - Semicolons:
true - Single quotes:
false(use double quotes) - Print width:
100
- Vitest - Fast unit test runner with jsdom environment
- React Testing Library - Component testing utilities
- MSW (Mock Service Worker) - API mocking
# Run tests in watch mode
npm run test
# Run tests once (CI mode)
npm run test:run
# Run tests with UI
npm run test:ui
# Generate coverage report
npm run test:coveragesrc/
├── test/
│ ├── setup.ts # Global test setup (MSW, matchers, mocks)
│ ├── setup.d.ts # TypeScript declarations for jest-dom
│ ├── test-utils.tsx # Custom render with providers (I18nProvider)
│ └── mocks/
│ ├── server.ts # MSW server setup
│ └── handlers.ts # API request handlers
└── **/*.test.tsx # Test files (co-located with components)
Tests use React Testing Library with jest-dom matchers:
import { describe, it, expect } from "vitest";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { renderWithProviders } from "./test/test-utils";
import { MyComponent } from "./MyComponent";
describe("MyComponent", () => {
it("renders and handles user interaction", async () => {
const user = userEvent.setup();
renderWithProviders(<MyComponent />);
const button = screen.getByRole("button", { name: /click me/i });
await user.click(button);
expect(screen.getByText(/success/i)).toBeInTheDocument();
});
});Key Points:
- Use
renderWithProviders()instead ofrender()to wrap components with I18nProvider - Use
userEventfor simulating user interactions (more realistic thanfireEvent) - Use
screenqueries with accessible roles and names - MSW automatically mocks API requests defined in
src/test/mocks/handlers.ts
Add handlers to src/test/mocks/handlers.ts:
import { http, HttpResponse } from "msw";
export const handlers = [
http.get("/api/users", () => {
return HttpResponse.json([
{ id: 1, name: "John Doe" },
{ id: 2, name: "Jane Smith" },
]);
}),
http.post("/api/users", async ({ request }) => {
const body = await request.json();
return HttpResponse.json({ id: 3, ...body }, { status: 201 });
}),
];Test-specific TypeScript configuration:
tsconfig.app.json- Includesvitest/globalsand@testing-library/jest-domtypessrc/vitest.d.ts- Global type declarations for test utilitiesvitest.config.ts- Vitest configuration with jsdom environment
End-to-end tests live in e2e/ and are written in TypeScript with
Playwright. They run against the Vite dev server and stub backend API calls
with page.route(), so no Python gateway is required.
npm run e2e:install # Install Playwright browsers (one-time)
npm run e2e # Headless run
npm run e2e:ui # Interactive UI mode
npm run e2e:debug # Playwright Inspector
npm run e2e:report # Open the last HTML reportSee e2e/README.md for layout, fixtures, and guidelines.
Tests and linting run automatically on pull requests via .github/workflows/client-lint-test.yml.
E2E tests run via .github/workflows/client-e2e.yml.
Workflow Steps:
- Install dependencies
- Run Prettier format check
- Run ESLint
- Run Vitest tests
Triggers:
- Push to
mainorepic/ui-rewritebranches - Pull requests to
mainorepic/ui-rewritebranches
client/
├── src/
│ ├── api/ # API client and types
│ ├── auth/ # Authentication context and hooks
│ ├── components/ # Reusable UI components
│ │ ├── layout/ # Layout components (Header, Sidebar, etc.)
│ │ └── ui/ # shadcn/ui components
│ ├── hooks/ # Custom React hooks
│ ├── i18n/ # Internationalization
│ │ └── locales/ # Translation files (en-US, es-ES, pt-BR)
│ ├── pages/ # Page components (Dashboard, Gateways, etc.)
│ ├── router/ # React Router configuration
│ ├── test/ # Test utilities and mocks
│ ├── App.tsx # Root component
│ └── main.tsx # Application entry point
├── public/ # Static assets
├── .prettierrc # Prettier configuration
├── .prettierignore # Prettier ignore patterns
├── eslint.config.js # ESLint configuration
├── vitest.config.ts # Vitest configuration
├── tsconfig.json # TypeScript base config
├── tsconfig.app.json # TypeScript app config
├── vite.config.ts # Vite configuration
└── package.json # Dependencies and scripts
| Script | Description |
|---|---|
npm run dev |
Start development server |
npm run build |
Build for production |
npm run generate |
Regenerate API types from openapi.json |
npm run preview |
Preview production build |
npm run lint |
Check for linting errors |
npm run lint:fix |
Auto-fix linting errors |
npm run format |
Format all files with Prettier |
npm run format:check |
Check formatting without changes |
npm run test |
Run tests in watch mode |
npm run test:run |
Run tests once (CI mode) |
npm run test:ui |
Run tests with UI |
npm run test:coverage |
Generate coverage report |
npm run e2e |
Run Playwright E2E tests |
npm run e2e:ui |
Playwright UI mode |
npm run e2e:debug |
Playwright Inspector |
npm run e2e:install |
Install Playwright browsers |
npm run e2e:report |
Open last Playwright report |
The app supports multiple languages via React Intl:
- English (en-US) - Default
- Spanish (es-ES)
- Portuguese (pt-BR)
Translation files are located in src/i18n/locales/.
- Add keys to
src/i18n/locales/{locale}/[domain].json - Use in components:
import { useIntl } from "react-intl";
function MyComponent() {
const intl = useIntl();
return <h1>{intl.formatMessage({ id: "navigation.dashboard" })}</h1>;
}Ensure TypeScript types are properly configured:
- Check
tsconfig.app.jsonincludes"types": ["vitest/globals", "@testing-library/jest-dom"] - Verify
src/vitest.d.tsexists with proper type references
- Verify handlers are defined in
src/test/mocks/handlers.ts - Check that paths match exactly (e.g.,
/app/auth/loginnot/api/auth/login) - Ensure MSW server is started in
src/test/setup.ts
The test setup includes a mock for window.matchMedia in src/test/setup.ts. If you see errors, verify the mock is properly configured.
- Follow the existing code style (enforced by ESLint and Prettier)
- Write tests for new features
- Ensure all tests pass:
npm run test:run - Ensure linting passes:
npm run lint - Ensure formatting is correct:
npm run format:check