1---2name: frontend-overlay3description: Product-specific frontend wrappers, API clients, and paths for ansible-ui. Use when implementing or reviewing UI in this monorepo.4---56# Overlay — ansible-ui78## Stack910- React 18, not 19 — no `ref`-as-prop, no `use(Context)` (exact version in `package.json`)11- PatternFly 6 (exact version in `package.json`)12- Node 20+ and npm 8+ (`engines` in `package.json`)13- Monorepo/build tooling: Nx14- Server state: SWR15- Router: react-router1617## Paths1819- UI package root: repo root (npm workspaces)20- Components: `framework/` (shared), `frontend/{awx,eda,hub,chatbot}/`, `platform/`21- Hooks: workspace `hooks/` or `frontend/common/hooks/`22- API helpers: `awxAPI` / `edaAPI` / `hubAPI` / `gatewayAPI` (not a generated typed client)23- Mock API handlers: MSW in Vitest. Playwright also has a mock project24- E2E: `playwright/` (`playwright.config.ts`, `commands/`, `tests/`, `utils/`)25- Storybook command and port: N/A — no Storybook26- Check command: `npm test` (eslint + tsc + prettier + vitest). There is no `npm run check`27- Test command: `npm run vitest` (unit); Playwright from `playwright/`28- Dev server: `npm start` (from `platform/`)29- Build all workspaces: `npm run build`30- Fix lint + formatting: `npm run fix` (`npm run prettier:fix` for formatting only)31- Instruction files: `CLAUDE.md` (symlink `AGENTS.md`)3233## Wrappers (use these, not raw PatternFly)3435Global/shared components live in the `framework/` package — search there first36before reaching for raw PatternFly or writing a new component.3738| Pattern | Component / hook | Notes |39| ----------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- |40| Page shell | `PageLayout` | `framework/` |41| Page header | `PageHeader` | `framework/` |42| Content panel | `Page` helpers in `framework/` | Search `framework/` before new components |43| List + table + pagination | `PageTable` + `useAwxView` / `useEdaView` / `useHubView` | Workspace view hook |44| Empty (no data / no filter / error) | framework empty states | |45| Confirmation | framework dialog / PF Modal | Reversible vs destructive |46| Error with retry | workspace error adapter | See coding_standards |47| Forms | `AwxPageForm` / `EdaPageForm` / `HubPageForm` / `PlatformPageForm` | See `framework/PageForm/` for shared primitives; use the workspace wrapper, not raw `PageForm` |48| Toast / alert helper | framework alerts | `addAlert({ variant, title, children? })` — body is `children`, not `description`; always set `variant` |4950## API5152- Call the backend with workspace tagged templates + SWR / CRUD hooks (`useGet`, `usePostRequest`, …)53- Forbidden: hardcoded `/api/...` paths (ESLint-enforced — custom rule); mocking `requestGet` instead of MSW54- Error shape: per-workspace adapters (not RFC 9457 everywhere)5556## Permissions5758- Hook names: workspace RBAC helpers in coding_standards59- Disabled-with-tooltip: existing page action patterns60- Nav / route guards: workspace routing6162## Icons6364- PatternFly icons or existing framework icons in `framework/`6566## Router6768- `react-router`. Use `<Link>` for in-app navigation, `<Button>` for actions6970## Docs links7172- N/A as a single helper — follow existing `docsLinks` patterns in-tree7374## Visual regression7576- Page registry path: `playwright/tests/visual/` (one spec per representative page)77- Check-baselines command: `npx playwright test tests/visual/ --project "live chromium"` from `playwright/`78- Never block PRs on full-page screenshots (on-demand + weekly; live-only `@not_mock`)79- Snapshot directory: `playwright/tests/visual/` Linux `-linux.png` suffix80- Overlay module (`vr.overlay.ts`): N/A8182## E2E (see testing_guidelines for write rules)8384- Playwright config path: `playwright/playwright.config.ts`85- Default mode: live (`npm run live` in `playwright/`) or mock (`npx playwright test --project 'mock chromium'`)86- UI URL: `PLATFORM_UI` in `playwright/.env` (typically `https://localhost:4100`, HTTPS in browser)87- Extra env (shell): `PLATFORM_SERVER=https://localhost:443`; optional `AWX_SERVER`, `EDA_SERVER`, `HUB_SERVER`88- Secret file path: `playwright/.env` (`PLATFORM_USERNAME`, `PLATFORM_PASSWORD`). Never print values89- How to check the stack is up: UI listens on 4100; do not start a second copy90- Commands (from `playwright/`):91 - `npm run live` — live chromium92 - `npx playwright test --project 'mock chromium'`93 - `npx playwright test tests/path/to/test.spec.ts --project 'live chromium'`94 - Fail-fast: add `--max-failures=1 --retries=0`95 - Debug: `--debug`; traces: `npx playwright show-trace trace.zip`96- Write rules, table helpers, MCP SSL bypass (`thisisunsafe`): `.claude/skills/testing_guidelines.md`97- Unique-name helper: `createE2EName()` in `playwright/commands/`98- Cleanup helper: `setupAfter`, resource `*.api.delete`, `confirmAndAssertDeletion`99100## Troubleshooting101102- Build errors: `npm run clean` then `npm ci`103- Type errors: check the TypeScript config in the relevant workspace104- Logs: platform → platform server logs; dev → browser console + terminal105 output; tests → Playwright reports and traces106107## Review remainder (not currently linted)108109| Miss | Grep / check |110| -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |111| Raw `PageForm` in a workspace UI | `PageForm` import from framework in `frontend/` or `platform/` |112| `fireEvent` in tests | `fireEvent` in `*.test.tsx` |113| Translated string used in logic | `if (t(` or `=== t(` |114| Alert body in `description`, or `addAlert` without `variant` | `rg "addAlert\(\{" -A8 --glob '!*.test.*' \| rg "description:"` (any hit) — body goes in `children`; every `addAlert` sets `variant` (`title:` may push `children:` several lines down) |115| Resource `use*Actions/Filters/Columns` hook not under a `hooks/` dir | `fd "use.*(Actions\|Filters\|Columns)\.tsx$" \| rg -v "/hooks/"` (≈95% live under `hooks/`) |116| Test placed in a `__tests__/` dir instead of colocated `*.test.tsx` | `fd -t d "__tests__"` (repo has none; unit tests colocate beside source) |117| `userEvent` used without a `userEvent.setup()` handle | test uses `userEvent.click/type` but has no `const user = userEvent.setup()` (≈94% use `setup()`) |118| Raw string path in `navigate('/...')` | `rg "navigate\('/" -g '*.tsx' -g '!*.test.tsx'` — use `usePageNavigate` + route enum, or `<Link>` |119120## Review harvest121122- Default GitHub repos: `ansible/ansible-ui`123- Default `--since` window: 90 days124- Recurring reviewer logins: N/A