From c2e25f217c025d39d50b79b12e3d85a899da1db9 Mon Sep 17 00:00:00 2001 From: Zihan Dai <99155080+PDGGK@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:10:36 +1000 Subject: [PATCH 1/3] Migrate the Grafana plugin build from grafana-toolkit to create-plugin @grafana/toolkit was archived by Grafana and no longer receives updates, so the plugin could not be built with a supported toolchain. This moves the frontend build to @grafana/create-plugin: webpack, SWC/Jest, the flat ESLint config, Playwright for e2e, and a package-lock.json replacing the yarn.lock. The generated .config directory is checked in as create-plugin intends and is not hand-edited; it can be refreshed with 'npx @grafana/create-plugin update'. The plugin's own CI workflow is updated in the same change, because it is what the migration breaks: it pinned Node 14, installed with 'yarn install --frozen-lockfile' and keyed both caches on yarn.lock, which this change removes. It now reads the Node version from the plugin's .nvmrc, caches on package-lock.json and runs 'npm ci && npm run build'. The Go backend step is untouched. grafanaDependency moves from >=9.3.0 to >=12.3.0. The plugin builds and is tested against the @grafana/data, @grafana/ui and @grafana/runtime 13.1.0 packages the new toolchain pulls in. Those are webpack externals resolved from the host Grafana at runtime, so an API present in the 13.1.0 types but absent on an older host fails at runtime rather than at build time, which is exactly why the declared floor should be the one we build and test against. The stricter ESLint config reports two errors in the tree-model query editors, where an array is mutated in place and the same reference is then handed to onChange. Both are changed to pass a new array instead. The same append, and two splice-based removals, remain a few lines away where the rule does not flag them; those are left for a separate change with tests rather than altering untested UI behaviour here. docker-compose.yaml also starts a standalone IoTDB alongside Grafana and ./provisioning wires the datasource to it, so 'npm run server' brings up a working plugin against a real server rather than an empty Grafana. Signed-off-by: Zihan Dai <99155080+PDGGK@users.noreply.github.com> --- .github/workflows/grafana-plugin.yml | 32 +- connectors/grafana-plugin/.config/.cprc.json | 3 + .../grafana-plugin/.config/.prettierrc.js | 16 + .../.config/AGENTS/e2e-testing.md | 165 + .../.config/AGENTS/instructions.md | 34 + .../.config/AGENTS/skills/build-plugin.md | 53 + .../.config/AGENTS/skills/validate-plugin.md | 64 + connectors/grafana-plugin/.config/Dockerfile | 77 + connectors/grafana-plugin/.config/README.md | 176 + .../.config/bundler/constants.ts | 2 + .../.config/bundler/copyFiles.ts | 23 + .../.config/bundler/externals.ts | 45 + .../grafana-plugin/.config/bundler/utils.ts | 68 + .../.config/docker-compose-base.yaml | 31 + .../grafana-plugin/.config/entrypoint.sh | 18 + .../grafana-plugin/.config/eslint.config.mjs | 38 + .../grafana-plugin/.config/jest-setup.js | 28 + .../grafana-plugin/.config/jest.config.js | 44 + .../.config/jest/mocks/react-inlinesvg.tsx | 25 + .../grafana-plugin/.config/jest/utils.js | 37 + .../.config/supervisord/supervisord.conf | 47 + .../grafana-plugin/.config/tsconfig.json | 29 + .../.config/types/bundler-rules.d.ts | 37 + .../.config/types/setupTests.d.ts | 1 + .../.config/types/webpack-plugins.d.ts | 83 + .../.config/webpack/BuildModeWebpackPlugin.ts | 33 + .../.config/webpack/webpack.config.ts | 239 + connectors/grafana-plugin/.cprc.json | 6 + connectors/grafana-plugin/.gitignore | 9 + connectors/grafana-plugin/.golangci.yml | 5 + connectors/grafana-plugin/.npmrc | 5 + connectors/grafana-plugin/.nvmrc | 1 + connectors/grafana-plugin/.prettierrc.js | 20 +- connectors/grafana-plugin/docker-compose.yaml | 39 + connectors/grafana-plugin/eslint.config.mjs | 39 + connectors/grafana-plugin/jest-setup.js | 2 + connectors/grafana-plugin/jest.config.js | 30 +- connectors/grafana-plugin/package-lock.json | 16642 ++++++++++++++++ connectors/grafana-plugin/package.json | 87 +- .../grafana-plugin/playwright.config.ts | 53 + .../grafana-plugin/provisioning/README.md | 1 + .../provisioning/datasources/.gitkeep | 0 .../provisioning/datasources/datasources.yml | 39 + .../src/componments/FromValue.tsx | 3 +- .../src/componments/SelectValue.tsx | 3 +- connectors/grafana-plugin/src/plugin.json | 2 +- connectors/grafana-plugin/tsconfig.json | 8 +- connectors/grafana-plugin/yarn.lock | 11348 ----------- 48 files changed, 18346 insertions(+), 11444 deletions(-) create mode 100644 connectors/grafana-plugin/.config/.cprc.json create mode 100644 connectors/grafana-plugin/.config/.prettierrc.js create mode 100644 connectors/grafana-plugin/.config/AGENTS/e2e-testing.md create mode 100644 connectors/grafana-plugin/.config/AGENTS/instructions.md create mode 100644 connectors/grafana-plugin/.config/AGENTS/skills/build-plugin.md create mode 100644 connectors/grafana-plugin/.config/AGENTS/skills/validate-plugin.md create mode 100644 connectors/grafana-plugin/.config/Dockerfile create mode 100644 connectors/grafana-plugin/.config/README.md create mode 100644 connectors/grafana-plugin/.config/bundler/constants.ts create mode 100644 connectors/grafana-plugin/.config/bundler/copyFiles.ts create mode 100644 connectors/grafana-plugin/.config/bundler/externals.ts create mode 100644 connectors/grafana-plugin/.config/bundler/utils.ts create mode 100644 connectors/grafana-plugin/.config/docker-compose-base.yaml create mode 100644 connectors/grafana-plugin/.config/entrypoint.sh create mode 100644 connectors/grafana-plugin/.config/eslint.config.mjs create mode 100644 connectors/grafana-plugin/.config/jest-setup.js create mode 100644 connectors/grafana-plugin/.config/jest.config.js create mode 100644 connectors/grafana-plugin/.config/jest/mocks/react-inlinesvg.tsx create mode 100644 connectors/grafana-plugin/.config/jest/utils.js create mode 100644 connectors/grafana-plugin/.config/supervisord/supervisord.conf create mode 100644 connectors/grafana-plugin/.config/tsconfig.json create mode 100644 connectors/grafana-plugin/.config/types/bundler-rules.d.ts create mode 100644 connectors/grafana-plugin/.config/types/setupTests.d.ts create mode 100644 connectors/grafana-plugin/.config/types/webpack-plugins.d.ts create mode 100644 connectors/grafana-plugin/.config/webpack/BuildModeWebpackPlugin.ts create mode 100644 connectors/grafana-plugin/.config/webpack/webpack.config.ts create mode 100644 connectors/grafana-plugin/.cprc.json create mode 100644 connectors/grafana-plugin/.golangci.yml create mode 100644 connectors/grafana-plugin/.npmrc create mode 100644 connectors/grafana-plugin/.nvmrc create mode 100644 connectors/grafana-plugin/docker-compose.yaml create mode 100644 connectors/grafana-plugin/eslint.config.mjs create mode 100644 connectors/grafana-plugin/jest-setup.js create mode 100644 connectors/grafana-plugin/package-lock.json create mode 100644 connectors/grafana-plugin/playwright.config.ts create mode 100644 connectors/grafana-plugin/provisioning/README.md create mode 100644 connectors/grafana-plugin/provisioning/datasources/.gitkeep create mode 100644 connectors/grafana-plugin/provisioning/datasources/datasources.yml delete mode 100644 connectors/grafana-plugin/yarn.lock diff --git a/.github/workflows/grafana-plugin.yml b/.github/workflows/grafana-plugin.yml index 2a354efd..2111450b 100644 --- a/.github/workflows/grafana-plugin.yml +++ b/.github/workflows/grafana-plugin.yml @@ -25,43 +25,25 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + # The Node version comes from the plugin's .nvmrc so it cannot drift away + # from the toolchain again; npm caching is keyed on the lockfile. - name: Setup Node.js environment uses: actions/setup-node@v4 with: - node-version: "14.x" + node-version-file: connectors/grafana-plugin/.nvmrc + cache: 'npm' + cache-dependency-path: connectors/grafana-plugin/package-lock.json - name: Setup Go environment uses: actions/setup-go@v5 with: go-version: "1.21" - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - - name: Cache yarn cache - uses: actions/cache@v4 - id: cache-yarn-cache - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Cache node_modules - id: cache-node-modules - uses: actions/cache@v4 - with: - path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-nodemodules-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.node-version }}-nodemodules- - - name: Install dependencies and Build and test frontend run: | cd connectors/grafana-plugin/ - yarn install --frozen-lockfile - yarn build + npm ci + npm run build - name: Install dependencies and Build backend run: | diff --git a/connectors/grafana-plugin/.config/.cprc.json b/connectors/grafana-plugin/.config/.cprc.json new file mode 100644 index 00000000..23cda165 --- /dev/null +++ b/connectors/grafana-plugin/.config/.cprc.json @@ -0,0 +1,3 @@ +{ + "version": "7.9.0" +} diff --git a/connectors/grafana-plugin/.config/.prettierrc.js b/connectors/grafana-plugin/.config/.prettierrc.js new file mode 100644 index 00000000..bf506f5c --- /dev/null +++ b/connectors/grafana-plugin/.config/.prettierrc.js @@ -0,0 +1,16 @@ +/* + * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️ + * + * In order to extend the configuration follow the steps in .config/README.md + */ + +module.exports = { + endOfLine: 'auto', + printWidth: 120, + trailingComma: 'es5', + semi: true, + jsxSingleQuote: false, + singleQuote: true, + useTabs: false, + tabWidth: 2, +}; diff --git a/connectors/grafana-plugin/.config/AGENTS/e2e-testing.md b/connectors/grafana-plugin/.config/AGENTS/e2e-testing.md new file mode 100644 index 00000000..3d3fe5ea --- /dev/null +++ b/connectors/grafana-plugin/.config/AGENTS/e2e-testing.md @@ -0,0 +1,165 @@ +--- +name: e2e testing instructions for a grafana plugin +description: Guides how to write e2e tests using @grafana/plugin-e2e +--- + +# E2E testing a Grafana plugin + +This plugin uses `@grafana/plugin-e2e` and Playwright for end-to-end testing. + +- Import `test` and `expect` from `@grafana/plugin-e2e`, or from your project's fixtures entrypoint (for example `./fixtures`) if it re-exports them. Do not import them from `@playwright/test` directly. +- Always use `@grafana/plugin-e2e` fixtures and page models instead of raw Playwright navigation. They handle Grafana version differences automatically. +- Place test files in `tests/` as `*.spec.ts`. +- Each test must be independent and assume fresh state. +- If tests fail against newer Grafana versions, update `@grafana/plugin-e2e` first. It evolves alongside Grafana core to handle selector and API changes. + +## Selecting elements + +### Grafana selectors + +- Use Grafana e2e-selectors whenever possible. Always get them from the `selectors` fixture provided by `@grafana/plugin-e2e` - never import from `@grafana/e2e-selectors` directly. The fixture resolves the correct selectors for the Grafana version under test. +- Always use the `getByGrafanaSelector` method (exposed by all plugin-e2e page models) to resolve selectors to Playwright locators. It handles the `aria-label` vs `data-testid` difference across Grafana versions automatically. + ```typescript + panelEditPage.getByGrafanaSelector(selectors.components.CodeEditor.container).click(); + ``` + +### Scoping locators + +Scope locators to the narrowest context possible. + +```typescript +// bad - matches any "URL" text on the page +page.getByText('URL').click(); +// good - scoped to the plugin's wrapper +page.getByTestId('plugin-url-wrapper').getByText('URL').click(); +``` + +### Form elements + +The `InlineField` and `Field` components can be used interchangeably in the examples below. + +**Input** - use `getByRole('textbox', { name: '