Parent guide: AGENTS.md — product overview, architecture, domain model, global conventions Related: api/AGENTS.md (API definitions consumed by UI) · managed/AGENTS.md (server backend)
The /ui directory contains the PMM web frontend — a React/TypeScript application that provides the primary user interface for Percona Monitoring and Management. It runs inside a Grafana iframe on PMM Server and also hosts standalone pages for updates, RTA, and help.
The UI uses a Yarn workspaces + Turborepo monorepo with three packages:
| Package | Path | Purpose |
|---|---|---|
| pmm | ui/apps/pmm/ |
Main PMM UI application (Vite + React) |
| pmm-compat | ui/apps/pmm-compat/ |
Grafana plugin for PMM ↔ Grafana integration (Webpack) |
| @pmm/shared | ui/packages/shared/ |
Shared code: cross-frame messaging, types, utilities (Rollup) |
| Technology | Role |
|---|---|
| React 18 | UI framework |
| TypeScript | Type-safe development |
| Vite | Dev server and production build (main app) |
| MUI (Material UI) | Component library |
| @percona/percona-ui | Percona's shared UI component library and theme |
| TanStack Query (React Query) | Server state management (API caching, mutations) |
| React Context | UI/auth state (AuthProvider, SettingsProvider, etc.) |
| Vitest | Unit testing (main app) |
| Jest | Unit testing (shared package) |
| Webpack | Build for Grafana plugin (pmm-compat) |
| Rollup | Build for shared package |
PMM UI runs inside a Grafana iframe. Cross-frame communication uses CrossFrameMessenger from @pmm/shared:
- Navigation events
- Theme synchronization
- Authentication state
Routes are defined in ui/apps/pmm/src/router.tsx using React Router's createBrowserRouter with basename: '/pmm-ui':
| Route | Page |
|---|---|
/ |
Redirects to /graph (Grafana) |
/updates |
PMM Server updates |
/updates/clients |
Client updates |
/help |
Help center |
/rta |
Real-Time Analytics tab |
/rta/selection |
RTA service selection |
/rta/sessions |
RTA sessions list |
/rta/overview |
RTA overview |
/graph/* |
Grafana iframe |
* |
404 fallback |
API data is managed with React Query hooks:
// Custom hooks wrap useQuery/useMutation per API endpoint
const { data: services } = useServices(params);
const { data: user } = useUser();
const { data: settings } = useSettings();Query keys follow the pattern: ['domain:action', params] (e.g., ['services:list', params], ['services:getTypes']).
Providers are composed in Providers.tsx:
AuthProvider— authentication stateUserProvider— current user infoSettingsProvider— PMM Server settingsUpdatesProvider— update availabilityGrafanaProvider— Grafana integration stateNavigationProvider— sidebar navigationTourProvider— onboarding tourThemeContextProvider— theme from@percona/percona-ui
API calls are organized in src/api/ using axios. Each API module provides typed request/response functions that are consumed by custom hooks in src/hooks/.
- Use TanStack Query (
useQuery,useMutation) for all server state - Create custom hooks per API domain in
src/hooks/ - Use MUI and
@percona/percona-uicomponents for consistent styling - Use TypeScript strict mode — define types in
src/types/ - Co-locate test files next to components (
*.test.tsx) - Use
CrossFrameMessengerfor communication with the Grafana iframe
- Don't use Redux or other state management — TanStack Query + Context covers all needs
- Don't bypass React Query for API calls — it handles caching, deduplication, and background refetch
- Don't use CSS-in-JS directly — use MUI's
sxprop or theme-aware styled components - Don't hardcode URLs — use constants from
src/lib/constants.ts - Don't add Grafana-specific code to the main
pmmapp — usepmm-compatfor Grafana plugin logic
- Framework: Vitest (main app), Jest (shared package)
- Libraries:
@testing-library/react,@testing-library/jest-dom - Setup:
src/setupTests.tsprovides global mocks (clipboard,navigator.isSecureContext) - Config:
vitest.config.ts— jsdom environment,globals: true - Pattern: co-located
*.test.tsx/*.test.tsfiles next to components - Run:
make testor via Turborepo (turbo test)
# Prerequisites: Node 22, Yarn
cd ui
# Install dependencies
make setup
# Start dev server
make dev
# Production build
make build
# Run tests
make testui/package.json— workspace root, scripts, dependenciesui/turbo.json— Turborepo pipeline configurationui/apps/pmm/src/router.tsx— route definitionsui/apps/pmm/src/Providers.tsx— context provider compositionui/apps/pmm/src/api/— API client functionsui/apps/pmm/src/hooks/— React Query hooks per API domainui/apps/pmm/vite.config.ts— build configurationui/packages/shared/src/messenger.ts— cross-frame communication