Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .devcontainer/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ run: run-all ## Aliased to "run-all"
echo "run is aliased to run-all"

ui-setup: ## Install UI dependencies
cd ui && yarn install
cd ui && pnpm install

run-ui: ui-setup setup-livereload ## Start vite dev server for UI with HMR
mv /srv/grafana/plugins/pmm-compat-app /srv/grafana/plugins/pmm-compat-app.bak; \
ln -sfn $(CURDIR)/ui/apps/pmm-compat/dist /srv/grafana/plugins/pmm-compat-app; \
supervisorctl restart grafana; \
trap 'rm -f /srv/grafana/plugins/pmm-compat-app; mv /srv/grafana/plugins/pmm-compat-app.bak /srv/grafana/plugins/pmm-compat-app; supervisorctl restart grafana' EXIT; \
cd ui && yarn dev
cd ui && pnpm dev

build-ui: ui-setup ## Build UI and deploy to system dirs
cd ui && yarn build
cd ui && pnpm build
rm -rf /usr/share/pmm-ui
cp -r ui/apps/pmm/dist /usr/share/pmm-ui
rm -rf /usr/share/percona-dashboards/panels/pmm-compat-app /srv/grafana/plugins/pmm-compat-app
Expand Down
5 changes: 4 additions & 1 deletion .devcontainer/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ install_go() {
go env
}

# Installs Node.js 22 and Yarn.
# Installs Node.js 22, pnpm (for ui/) and Yarn (for dashboards/pmm-app).
install_node() {
dnf module enable -y nodejs:22
dnf install -y nodejs npm
npm install -g yarn@1.22.22
# pnpm is not pinned here: corepack resolves it from the `packageManager`
# field in ui/package.json on first use.
corepack enable pnpm
node --version
yarn --version
}
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,15 @@ jobs:
- name: Check out code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Enable corepack
run: corepack enable

- name: Setup nodejs
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: ui/.nvmrc
cache: yarn
cache-dependency-path: ui/yarn.lock
cache: pnpm
cache-dependency-path: ui/pnpm-lock.yaml

Comment thread
nachodd marked this conversation as resolved.
- name: Check formatting
run: make format-check
Expand Down
13 changes: 7 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ These differ from generic Go/React advice. Match **surrounding code** in the fil
- **UI wire format:** camelCase in TypeScript; JSON on the wire is snake_case (`axios-case-converter` in `ui/apps/pmm/src/api/api.ts`)
- **Generated code:** edit `.proto` / reform models / interfaces — run `make gen`; never hand-edit `*.pb.go`, `*_reform.go`, swagger clients

Mechanical style (imports, formatting, ESLint rules) is enforced by `make check`, `cd ui && make lint`, and CI — see [Linting decision tree](#linting-decision-tree).
Mechanical style (imports, formatting, lint rules) is enforced by `make check` for Go, `cd ui && make lint && make format-check` for the UI, and CI — see [Linting decision tree](#linting-decision-tree).

---

Expand All @@ -124,7 +124,7 @@ PMM has three test layers ([`CONTRIBUTING.md`](CONTRIBUTING.md)): unit, API inte
| `managed/models` or DB schema/migrations | Unit tests in `managed/`; use `testdb.Open` only when fixtures or migrations matter ([`managed/AGENTS.md`](managed/AGENTS.md)) |
| `.proto` or gRPC/REST definitions | `make gen`, then `make check`; update handlers in `managed/` and UI hooks if user-facing |
| REST behavior end-to-end | `make env-up`, then `make api-test` ([`api-tests/AGENTS.md`](api-tests/AGENTS.md)) |
| UI (`ui/apps/pmm`) | `cd ui && make lint && make test` |
| UI (anything under `ui/`) | `cd ui && make lint && make test` |
| Grafana dashboard JSON (`dashboards/dashboards/`) | `python3 dashboards/misc/cleanup-dash.py --check-only <file>` (or run cleanup without `--check-only`); CI enforces this in `dashboards.yml` ([`dashboards/dashboards/AGENTS.md`](dashboards/dashboards/AGENTS.md)) |
| User-visible feature / bugfix | Create or update a Feature Build; link it in the PR ([`CONTRIBUTING.md`](CONTRIBUTING.md#feature-build)) |

Expand All @@ -138,8 +138,8 @@ CI runs separate linters per area. `make prepare-pr` covers **Go only** — it d
|-----------------|-----|
| Go backend (`managed/`, `agent/`, `admin/`, `qan-api2/`, `vmproxy/`, shared packages) | `make prepare-pr` from repo root (or `make check` after `make gen` for a quicker pass) |
| `.proto` only | `make gen`, then `make check` (`buf lint`, `golangci-lint`, `go-sumtype`) |
| UI (`ui/apps/pmm`, `ui/packages/shared`) | `cd ui && make lint` (ESLint; same as CI `ui.yml`) |
| Grafana dashboard JSON (`dashboards/dashboards/`) | `python3 dashboards/misc/cleanup-dash.py --check-only <file>` before commit (CI `dashboards.yml`; no separate ESLint) |
| UI (anything under `ui/`) | `cd ui && make lint && make format-check` (oxlint + oxfmt across every workspace package; same as CI `ui.yml`) |
| Grafana dashboard JSON (`dashboards/dashboards/`) | `python3 dashboards/misc/cleanup-dash.py --check-only <file>` before commit (CI `dashboards.yml`; no separate JS linter) |
| Grafana plugin / QAN app (`dashboards/pmm-app`) | `cd dashboards/pmm-app && yarn lint:check` (and `yarn typecheck` if TypeScript changed) |
| Before any PR | Run the row(s) that match **every** area you touched; fix errors, not just warnings, unless CI allows them |

Expand Down Expand Up @@ -408,7 +408,7 @@ PMM Server talks to pmm-agents and API clients already deployed in the field, so

### Dependencies and new files
- Prefer the standard library and deps already in `go.mod` / `ui/package.json`; a new dependency needs justification and an AGPL-3-compatible license (CI runs a license check).
- Go: `go get` then `go mod tidy` (both in `make prepare-pr`). UI: `yarn add` from `ui/`.
- Go: `go get` then `go mod tidy` (both in `make prepare-pr`). UI: `pnpm add` from `ui/` (or `pnpm --filter <pkg> add` for one workspace package).
- New Go source files need the AGPL-3 Percona license header — copy it from an existing `.go` file or run `go tool license-eye -c .licenserc.yaml header fix`. Enforced by `make check-license` (exemptions: `agent/`, `admin/`, `utils/`, mocks).

### Graceful Shutdown
Expand Down Expand Up @@ -442,7 +442,8 @@ All long-running daemons expose on `127.0.0.1`:
| `make test-common` | Run common unit tests |
| `make api-test` | Run API integration tests |
| `make prepare-pr` | Go/API pre-PR pipeline: `gen` + `check-all` (license + linters) + `format` + `go mod tidy` |
| `cd ui && make lint` | ESLint for PMM UI (required for UI changes; not part of `prepare-pr`) |
| `cd ui && make lint` | oxlint for PMM UI (required for UI changes; not part of `prepare-pr`) |
| `cd ui && make format-check` | oxfmt check for PMM UI (what CI runs; `make format` writes) |

## Key Files to Reference

Expand Down
6 changes: 6 additions & 0 deletions build/docker/rpmbuild/Dockerfile.el8
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ RUN dnf update -y && \
dnf install -y --enablerepo=ol8_codeready_builder glibc-static && \
dnf clean all && rm -rf /var/cache/dnf

# The UI workspace (ui/) builds with pnpm; the QAN Grafana plugin (dashboards/pmm-app)
# is still on yarn 1, so both are needed. corepack ships with nodesource's nodejs 22
# and resolves pnpm from the `packageManager` field in ui/package.json, so the version
# is pinned in exactly one place and needs no change here on a bump.
RUN corepack enable

# Copy Go from official golang image to avoid QEMU extraction issues
COPY --from=golang /usr/local/go /usr/local/go

Expand Down
6 changes: 6 additions & 0 deletions build/docker/rpmbuild/Dockerfile.el9
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ RUN dnf update -y && \
dnf install -y --enablerepo=ol9_codeready_builder glibc-static && \
dnf clean all && rm -rf /var/cache/dnf

# The UI workspace (ui/) builds with pnpm; the QAN Grafana plugin (dashboards/pmm-app)
# is still on yarn 1, so both are needed. corepack ships with nodesource's nodejs 22
# and resolves pnpm from the `packageManager` field in ui/package.json, so the version
# is pinned in exactly one place and needs no change here on a bump.
RUN corepack enable

# Copy Go from official golang image to avoid QEMU extraction issues
COPY --from=golang /usr/local/go /usr/local/go

Expand Down
6 changes: 6 additions & 0 deletions build/docker/rpmbuild/Dockerfile.hetzner-el9
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ RUN dnf update -y && \
dnf install -y --enablerepo=crb glibc-static && \
dnf clean all && rm -rf /var/cache/dnf

# The UI workspace (ui/) builds with pnpm; the QAN Grafana plugin (dashboards/pmm-app)
# is still on yarn 1, so both are needed. corepack ships with nodesource's nodejs 22
# and resolves pnpm from the `packageManager` field in ui/package.json, so the version
# is pinned in exactly one place and needs no change here on a bump.
RUN corepack enable

# Configure EPEL to use European mirror
RUN sed -i 's|metalink=|#metalink=|g' /etc/yum.repos.d/epel*.repo && \
sed -i 's|#baseurl=.*|baseurl=https://ftp.fau.de/epel/9/Everything/$basearch/|g' /etc/yum.repos.d/epel.repo || true
Expand Down
18 changes: 18 additions & 0 deletions ui/.oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"printWidth": 80,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf",
"ignorePatterns": [
"dist",
"node_modules",
"pnpm-lock.yaml",
"storybook-static",
"**/.config/**"
]
}
7 changes: 2 additions & 5 deletions ui/.vscode/settings.json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall this dir .vscode be in repo at all?

Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
{
"typescript.preferences.autoImportSpecifierExcludeRegexes": ["^@mui/[^/]+$"],
"eslint.workingDirectories": [
{
"mode": "auto"
}
]
"oxc.configPath": "oxlintrc.json",
"oxc.fmt.experimental": true
}
30 changes: 27 additions & 3 deletions ui/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The `/ui` directory contains the PMM web frontend — a React/TypeScript applica

### Monorepo Structure

The UI uses a **Yarn workspaces + Turborepo** monorepo with three packages:
The UI uses a **pnpm workspaces + Turborepo** monorepo with three packages:

| Package | Path | Purpose |
| --------------- | --------------------- | ------------------------------------------------------------- |
Expand All @@ -32,6 +32,10 @@ The UI uses a **Yarn workspaces + Turborepo** monorepo with three packages:
| **Jest** | Unit testing (shared package) |
| **Webpack** | Build for Grafana plugin (pmm-compat) |
| **Rollup** | Build for shared package |
| **pnpm (via Corepack)** | Package manager and workspaces |
| **Turborepo** | Task runner across the workspace |
| **oxlint** | Linting (`ui/oxlintrc.json`) |
| **oxfmt** | Formatting (`ui/.oxfmtrc.json`) |

### Communication with Grafana

Expand Down Expand Up @@ -126,13 +130,29 @@ The app is wrapped in `ThemeContextProvider` (see `App.tsx`); style with the the
- **Pattern**: co-located `*.test.tsx` / `*.test.ts` files next to components
- **Run**: `make test` or via Turborepo (`turbo test`)

## Linting and Formatting

- **Linter**: oxlint, configured in `ui/oxlintrc.json`. `plugins` lists every
built-in plugin the rules rely on — setting it replaces oxlint's default set,
and a rule whose plugin is missing is silently inert.
- **Formatter**: oxfmt, configured in `ui/.oxfmtrc.json`. It owns formatting;
there is no Prettier and no formatting rule in the linter.
- **Scope**: build/test config files (`vite.config.ts`, `vitest.config.ts`,
`webpack.config.ts`, `jest.config.js`) are linted like any other source. The
only exclusion is `apps/pmm-compat/.config/`, Grafana's auto-generated plugin
scaffold, which upstream regenerates and tells you not to edit.
- **Run**: `make lint`, `make format` (or `make format-check`, which is what CI
runs in `.github/workflows/ui.yml`).

## Development Workflow

```bash
# Prerequisites: Node 22, Yarn
# Prerequisites: Node 22. pnpm comes from Corepack, which `make setup`
# enables — the version is pinned by `packageManager` in ui/package.json,
# so never install pnpm separately.
cd ui

# Install dependencies
# Enable Corepack + install dependencies
make setup

# Start dev server
Expand All @@ -143,6 +163,10 @@ make build

# Run tests
make test

# Lint (oxlint) and format (oxfmt)
make lint
make format # make format-check in CI
```

Inside the PMM devcontainer (`make env-up` then `make env` from the repo root), `make run-ui` (main UI HMR via Vite on port 5173) and `make run-qan-ui` (QAN livereload on port 35730) replace `make dev` and wire the dev servers into the bundled Grafana automatically. See `ui/README.md` for details.
Expand Down
22 changes: 14 additions & 8 deletions ui/Makefile
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
.PHONY: dev ci format format-check lint test setup build release clean

dev:
yarn dev
pnpm dev

ci: setup format-check lint test build

format: setup
yarn format
pnpm format

format-check: setup
yarn format:check
pnpm format:check

lint: setup
yarn lint
pnpm lint

test: setup
yarn test
pnpm test

setup:
yarn install
# corepack ships with Node 22 and resolves pnpm from the `packageManager`
# field in package.json, so the version is pinned in exactly one place.
# The sudo fallback covers images where corepack's shim dir is root-owned.
corepack enable pnpm 2>/dev/null || sudo corepack enable pnpm
pnpm install
Comment thread
nachodd marked this conversation as resolved.

build: setup
yarn build
pnpm build

release: build

clean:
yarn clean
pnpm clean
Comment thread
coderabbitai[bot] marked this conversation as resolved.
8 changes: 4 additions & 4 deletions ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ See the [PMM Documentation](https://www.percona.com/doc/percona-monitoring-and-m

This repo uses the following stack across its packages:

- Yarn (https://yarnpkg.com/)
- pnpm (https://pnpm.io/)
- Turborepo (https://turborepo.com/)
- Typescript (https://www.typescriptlang.org/)
- React (https://react.dev/)
Expand All @@ -32,7 +32,7 @@ This repo uses the following stack across its packages:

## Run in the devcontainer (recommended)

The PMM devcontainer (see the root `CONTRIBUTING.md`) now ships Node 22 + Yarn and a Vite dev server that runs end-to-end with the rest of PMM Server. From the repo root **on the host**:
The PMM devcontainer (see the root `CONTRIBUTING.md`) now ships Node 22 + pnpm (via Corepack) and a Vite dev server that runs end-to-end with the rest of PMM Server. From the repo root **on the host**:

```bash
make env-up # first run only; reuses the container afterwards
Expand Down Expand Up @@ -94,10 +94,10 @@ Use this when you want to drive Vite from your IDE without `make env`. You still
Prerequisites:

- [Node 22](https://nodejs.org/en) (e.g. via [nvm](https://github.com/nvm-sh/nvm))
- [Yarn](https://yarnpkg.com/) 1.x
- [pnpm](https://pnpm.io/) 11.x (`corepack enable pnpm` picks up the pinned version)

```bash
make setup # yarn install across the workspace
make setup # pnpm install across the workspace
make dev # turbo dev → Vite on https://localhost:5174 (or 5173 if nginx certs are present)
```

Expand Down
5 changes: 0 additions & 5 deletions ui/apps/pmm-compat/.config/webpack/webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/

import CopyWebpackPlugin from 'copy-webpack-plugin';
import ESLintPlugin from 'eslint-webpack-plugin';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import path from 'path';
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
Expand Down Expand Up @@ -247,10 +246,6 @@ const config = async (env): Promise<Configuration> => {
},
typescript: { configFile: path.join(process.cwd(), 'tsconfig.json') },
}),
new ESLintPlugin({
extensions: ['.ts', '.tsx'],
lintDirtyModulesOnly: Boolean(env.development), // don't lint on start, only lint changed files
}),
]
: []),
],
Expand Down
3 changes: 0 additions & 3 deletions ui/apps/pmm-compat/.eslintrc

This file was deleted.

4 changes: 0 additions & 4 deletions ui/apps/pmm-compat/.prettierrc.js

This file was deleted.

Loading
Loading