@grafana/create-plugin 7.11.0 → 7.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [7.12.0](https://github.com/grafana/plugin-tools/compare/@grafana/create-plugin@7.11.0...@grafana/create-plugin@7.12.0) (2026-09-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * **deps:** bump grafana libs to latest in templates in create plugin ([#2893](https://github.com/grafana/plugin-tools/issues/2893)) ([d3c3f4b](https://github.com/grafana/plugin-tools/commit/d3c3f4b2a775d9bfcb0a9209a0c62a2ef16bbd58))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **create-plugin:** Improve experimental-app-sdk templates with RBAC guidance. ([#2892](https://github.com/grafana/plugin-tools/issues/2892)) ([ec59abe](https://github.com/grafana/plugin-tools/commit/ec59abe7f7508e6dc206a24a0658d121d64b3f1f))
14
+ * **create-plugin:** support @grafana/eslint-config v10 in scaffold ([#2873](https://github.com/grafana/plugin-tools/issues/2873)) ([67f6fec](https://github.com/grafana/plugin-tools/commit/67f6fec1321943ae8062e130745b37f3e45c1d72))
15
+
3
16
  ## [7.11.0](https://github.com/grafana/plugin-tools/compare/@grafana/create-plugin@7.10.1...@grafana/create-plugin@7.11.0) (2026-09-16)
4
17
 
5
18
 
@@ -78,6 +78,12 @@ var defaultMigrations = [
78
78
  version: "7.10.1",
79
79
  description: "Support @grafana/ui@13.2.0 in Jest by transforming @react-hookz/web and @ver0/deep-equal ESM dependencies.",
80
80
  scriptPath: import.meta.resolve("./scripts/013-jest-esmodules.js")
81
+ },
82
+ {
83
+ name: "014-eslint-config-v10",
84
+ version: "7.11.1",
85
+ description: "Update @grafana/eslint-config to v10: drop the removed ./flat.js subpath import and swap @stylistic/eslint-plugin-ts for @stylistic/eslint-plugin.",
86
+ scriptPath: import.meta.resolve("./scripts/014-eslint-config-v10.js")
81
87
  }
82
88
  // Do not use LEGACY_UPDATE_CUTOFF_VERSION for new migrations. It is only used above to force migrations to run
83
89
  // for those written before the switch to updates as migrations.
@@ -0,0 +1,35 @@
1
+ import { isVersionGreater, addDependenciesToPackageJson, removeDependenciesFromPackageJson } from '../../utils.js';
2
+
3
+ const OLD_IMPORT = "import grafanaConfig from '@grafana/eslint-config/flat.js';";
4
+ const NEW_IMPORT = "import grafanaConfig from '@grafana/eslint-config';";
5
+ const ESLINT_CONFIG_PATH = ".config/eslint.config.mjs";
6
+ function migrate(context) {
7
+ if (!context.doesFileExist("package.json")) {
8
+ return context;
9
+ }
10
+ const packageJson = JSON.parse(context.getFile("package.json") || "{}");
11
+ const currentVersion = packageJson.devDependencies?.["@grafana/eslint-config"];
12
+ if (!currentVersion || !isVersionGreater("^10.0.0", currentVersion)) {
13
+ return context;
14
+ }
15
+ if (context.doesFileExist(ESLINT_CONFIG_PATH)) {
16
+ const content = context.getFile(ESLINT_CONFIG_PATH) || "";
17
+ if (content.includes(OLD_IMPORT)) {
18
+ context.updateFile(ESLINT_CONFIG_PATH, content.replace(OLD_IMPORT, NEW_IMPORT));
19
+ }
20
+ }
21
+ addDependenciesToPackageJson(
22
+ context,
23
+ {},
24
+ {
25
+ "@grafana/eslint-config": "^10.0.0",
26
+ "@stylistic/eslint-plugin": "^5.10.0",
27
+ "eslint-config-prettier": "^10.1.0",
28
+ "eslint-plugin-react-hooks": "^7.1.0"
29
+ }
30
+ );
31
+ removeDependenciesFromPackageJson(context, [], ["@stylistic/eslint-plugin-ts"]);
32
+ return context;
33
+ }
34
+
35
+ export { migrate as default };
@@ -78,7 +78,7 @@ function getTemplateData(cliArgs) {
78
78
  isNPM: isNPM(packageManagerName),
79
79
  version: currentVersion,
80
80
  bundleGrafanaUI,
81
- scenesVersion: "^7.0.0",
81
+ scenesVersion: "^8.17.0",
82
82
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
83
83
  frontendBundler
84
84
  };
@@ -99,7 +99,7 @@ function getTemplateData(cliArgs) {
99
99
  isNPM: isNPM(packageManagerName),
100
100
  version: currentVersion,
101
101
  bundleGrafanaUI,
102
- scenesVersion: "^7.0.0",
102
+ scenesVersion: "^8.17.0",
103
103
  pluginExecutable: pluginJson.executable,
104
104
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
105
105
  frontendBundler
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/create-plugin",
3
- "version": "7.11.0",
3
+ "version": "7.12.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "directory": "packages/create-plugin",
@@ -91,6 +91,13 @@ export default [
91
91
  'Support @grafana/ui@13.2.0 in Jest by transforming @react-hookz/web and @ver0/deep-equal ESM dependencies.',
92
92
  scriptPath: import.meta.resolve('./scripts/013-jest-esmodules.js'),
93
93
  },
94
+ {
95
+ name: '014-eslint-config-v10',
96
+ version: '7.11.1',
97
+ description:
98
+ 'Update @grafana/eslint-config to v10: drop the removed ./flat.js subpath import and swap @stylistic/eslint-plugin-ts for @stylistic/eslint-plugin.',
99
+ scriptPath: import.meta.resolve('./scripts/014-eslint-config-v10.js'),
100
+ },
94
101
  // Do not use LEGACY_UPDATE_CUTOFF_VERSION for new migrations. It is only used above to force migrations to run
95
102
  // for those written before the switch to updates as migrations.
96
103
  ] satisfies Migration[];
@@ -0,0 +1,94 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import migrate from './014-eslint-config-v10.js';
3
+ import { Context } from '../../context.js';
4
+
5
+ const SCAFFOLD_ESLINT_CONFIG = `/*
6
+ * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY \`@grafana/create-plugin\`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
7
+ */
8
+
9
+ import { defineConfig } from 'eslint/config';
10
+ import grafanaConfig from '@grafana/eslint-config/flat.js';
11
+
12
+ export default defineConfig([...grafanaConfig]);
13
+ `;
14
+
15
+ function addPackageJson(context: Context, eslintConfigVersion = '^9.0.0') {
16
+ context.addFile(
17
+ 'package.json',
18
+ JSON.stringify({
19
+ devDependencies: {
20
+ '@grafana/eslint-config': eslintConfigVersion,
21
+ '@stylistic/eslint-plugin-ts': '^4.4.0',
22
+ 'eslint-config-prettier': '^8.8.0',
23
+ 'eslint-plugin-react-hooks': '^7.0.0',
24
+ },
25
+ })
26
+ );
27
+ }
28
+
29
+ describe('014-eslint-config-v10', () => {
30
+ it('should replace the removed flat.js subpath import', () => {
31
+ const context = new Context('/virtual');
32
+ context.addFile('.config/eslint.config.mjs', SCAFFOLD_ESLINT_CONFIG);
33
+ addPackageJson(context);
34
+
35
+ const result = migrate(context);
36
+ const content = result.getFile('.config/eslint.config.mjs') || '';
37
+
38
+ expect(content).toContain("import grafanaConfig from '@grafana/eslint-config';");
39
+ expect(content).not.toContain('@grafana/eslint-config/flat.js');
40
+ expect(content).toContain('DO NOT EDIT THIS FILE DIRECTLY');
41
+ });
42
+
43
+ it('should update package.json dependencies for eslint-config v10', () => {
44
+ const context = new Context('/virtual');
45
+ context.addFile('.config/eslint.config.mjs', SCAFFOLD_ESLINT_CONFIG);
46
+ addPackageJson(context);
47
+
48
+ const result = migrate(context);
49
+ const packageJson = JSON.parse(result.getFile('package.json') || '{}');
50
+
51
+ expect(packageJson.devDependencies['@grafana/eslint-config']).toBe('^10.0.0');
52
+ expect(packageJson.devDependencies['@stylistic/eslint-plugin']).toBe('^5.10.0');
53
+ expect(packageJson.devDependencies['@stylistic/eslint-plugin-ts']).toBeUndefined();
54
+ expect(packageJson.devDependencies['eslint-config-prettier']).toBe('^10.1.0');
55
+ expect(packageJson.devDependencies['eslint-plugin-react-hooks']).toBe('^7.1.0');
56
+ });
57
+
58
+ it('should not modify anything when package.json does not exist', () => {
59
+ const context = new Context('/virtual');
60
+
61
+ const result = migrate(context);
62
+
63
+ expect(result.hasChanges()).toBe(false);
64
+ });
65
+
66
+ it('should not modify anything when @grafana/eslint-config is already on v10', () => {
67
+ const context = new Context('/virtual');
68
+ context.addFile('.config/eslint.config.mjs', SCAFFOLD_ESLINT_CONFIG.replace('/flat.js', ''));
69
+ addPackageJson(context, '^10.0.0');
70
+
71
+ const initialChanges = context.listChanges();
72
+ migrate(context);
73
+
74
+ expect(context.listChanges()).toEqual(initialChanges);
75
+ });
76
+
77
+ it('should not modify anything when there are no devDependencies', () => {
78
+ const context = new Context('/virtual');
79
+ context.addFile('package.json', JSON.stringify({}));
80
+
81
+ const initialChanges = context.listChanges();
82
+ migrate(context);
83
+
84
+ expect(context.listChanges()).toEqual(initialChanges);
85
+ });
86
+
87
+ it('should be idempotent', async () => {
88
+ const context = new Context('/virtual');
89
+ context.addFile('.config/eslint.config.mjs', SCAFFOLD_ESLINT_CONFIG);
90
+ addPackageJson(context);
91
+
92
+ await expect(migrate).toBeIdempotent(context);
93
+ });
94
+ });
@@ -0,0 +1,40 @@
1
+ import type { Context } from '../../context.js';
2
+ import { addDependenciesToPackageJson, isVersionGreater, removeDependenciesFromPackageJson } from '../../utils.js';
3
+
4
+ const OLD_IMPORT = "import grafanaConfig from '@grafana/eslint-config/flat.js';";
5
+ const NEW_IMPORT = "import grafanaConfig from '@grafana/eslint-config';";
6
+ const ESLINT_CONFIG_PATH = '.config/eslint.config.mjs';
7
+
8
+ export default function migrate(context: Context) {
9
+ if (!context.doesFileExist('package.json')) {
10
+ return context;
11
+ }
12
+
13
+ const packageJson = JSON.parse(context.getFile('package.json') || '{}');
14
+ const currentVersion = packageJson.devDependencies?.['@grafana/eslint-config'];
15
+
16
+ if (!currentVersion || !isVersionGreater('^10.0.0', currentVersion)) {
17
+ return context;
18
+ }
19
+
20
+ if (context.doesFileExist(ESLINT_CONFIG_PATH)) {
21
+ const content = context.getFile(ESLINT_CONFIG_PATH) || '';
22
+ if (content.includes(OLD_IMPORT)) {
23
+ context.updateFile(ESLINT_CONFIG_PATH, content.replace(OLD_IMPORT, NEW_IMPORT));
24
+ }
25
+ }
26
+
27
+ addDependenciesToPackageJson(
28
+ context,
29
+ {},
30
+ {
31
+ '@grafana/eslint-config': '^10.0.0',
32
+ '@stylistic/eslint-plugin': '^5.10.0',
33
+ 'eslint-config-prettier': '^10.1.0',
34
+ 'eslint-plugin-react-hooks': '^7.1.0',
35
+ }
36
+ );
37
+ removeDependenciesFromPackageJson(context, [], ['@stylistic/eslint-plugin-ts']);
38
+
39
+ return context;
40
+ }
@@ -121,7 +121,7 @@ export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
121
121
  isNPM: isNPM(packageManagerName),
122
122
  version: currentVersion,
123
123
  bundleGrafanaUI,
124
- scenesVersion: '^7.0.0',
124
+ scenesVersion: '^8.17.0',
125
125
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
126
126
  frontendBundler,
127
127
  };
@@ -145,7 +145,7 @@ export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
145
145
  isNPM: isNPM(packageManagerName),
146
146
  version: currentVersion,
147
147
  bundleGrafanaUI,
148
- scenesVersion: '^7.0.0',
148
+ scenesVersion: '^8.17.0',
149
149
  pluginExecutable: pluginJson.executable,
150
150
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
151
151
  frontendBundler,
@@ -58,7 +58,7 @@
58
58
  }
59
59
  ],
60
60
  "dependencies": {
61
- "grafanaDependency": ">=12.3.0",
61
+ "grafanaDependency": ">=13.2.0",
62
62
  "plugins": []
63
63
  }
64
64
  }
@@ -22,8 +22,8 @@ TypeScript types and an app manifest that Grafana reads from the plugin bundle.
22
22
  ```
23
23
  - **Generated code is committed.** Commit the regenerated files alongside the CUE change so schema
24
24
  changes are reviewable and a fresh clone builds without running code generation.
25
- - **This plugin generates no Go code.** `kinds/config.cue` sets `codegen: goEnabled: false`, so
26
- generation emits only TypeScript and the JSON definitions. Do not add Go output paths or a Go
25
+ - **Go code generation follows `kinds/config.cue`'s `codegen.goEnabled` setting.** If it's `false`,
26
+ generation emits only TypeScript and the JSON definitions — don't add Go output paths or a Go
27
27
  backend to work around a generation problem.
28
28
  - **Do not set `GRAFANA_APP_SDK_BIN`.** It overrides the pinned CLI with a local build, and is meant
29
29
  for people working on the app-sdk itself. Code generated with it can differ from what `VERSION` in
@@ -31,6 +31,18 @@ TypeScript types and an app manifest that Grafana reads from the plugin bundle.
31
31
  `generate:kinds` without it.
32
32
  - **Do not add code generation to the build.** It is a schema-change-time step, not a build step. The
33
33
  frontend build must keep working without a Go toolchain.
34
+ - **Never write authorization/permission checks in app code.** Access is declared in the manifest and
35
+ enforced by Grafana's API server, not by this plugin.
36
+ - **A `Namespaced` kind is folder-scoped by default:** callers need the Stack Role *and* folder access,
37
+ and every write must set the `grafana.app/folder` annotation to a real folder the caller can access —
38
+ this applies to anything your backend writes on a user's behalf too. Set `folderScoped: false` on the
39
+ kind if it shouldn't be gated by folders (writes then skip the annotation).
40
+ - **Every role needs a `roleBindings` entry to be granted to anyone.** Defining a role in
41
+ `kinds/manifest.cue` without binding it to a basic role (`viewer`/`editor`/`admin`) leaves it unused.
42
+ - **Set `appDisplayName` in `kinds/manifest.cue`** so the app's roles show a readable name in Grafana's
43
+ role picker, instead of the raw `appName`.
44
+ - **`admin` currently grants the same actions as `editor`.** Don't design a feature assuming admin has
45
+ extra permissions today.
34
46
 
35
47
  ## Layout
36
48
 
@@ -83,5 +95,5 @@ Resources are served under a Kubernetes-style path:
83
95
  The namespace is deployment-dependent — `default` on single-tenant Grafana, `stacks-<id>` on Grafana
84
96
  Cloud. Read it from `config.namespace` in `@grafana/runtime`; never hardcode it.
85
97
 
86
- This plugin has no Go backend, and does not need one for storage or CRUD. Admission (validation and
87
- mutation), conversion between versions, and custom routes would require adding one.
98
+ No backend is needed for storage or CRUD — that comes from the manifest alone. Admission (validation
99
+ and mutation), conversion between versions, and custom routes require a backend.
@@ -58,3 +58,69 @@ be required for:
58
58
  - Controller logic (informers, watchers, or any other background work)
59
59
 
60
60
  If this plugin has a backend, `pkg/provider/provider.go` is where you wire those up as your app grows.
61
+
62
+ ## Authorization & RBAC
63
+
64
+ You don't write permission checks in code. You declare roles and scoping in the manifest, and Grafana's
65
+ aggregated API server enforces them for every caller (kubectl, Terraform, generated clients, your
66
+ frontend). This only applies to requests from users (UI, Service Account tokens) — requests from a
67
+ Service Identity (another internal operator) are less strict.
68
+
69
+ ### Folder scoping
70
+
71
+ Namespaced kinds (set in `kinds/*.cue`, see `example.cue`) are **folder-scoped by default**. Access
72
+ requires *both* the right Stack Role (see below) *and* folder access on the resource's
73
+ `grafana.app/folder`. If your kind's data doesn't belong in folders, opt out with
74
+ `folderScoped: false` — access then comes down to the Stack Role alone, and adding a folder annotation
75
+ to a request is rejected.
76
+
77
+ ```cue
78
+ examplev1alpha1: exampleKind & {
79
+ // Opt this kind out of folder-scoped access.
80
+ folderScoped: false
81
+ schema: {
82
+ spec: {
83
+ title: string
84
+ description: string
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ ### Roles and role bindings
91
+
92
+ Declare custom roles in `kinds/manifest.cue`. A role name follows `<app>:<role>` and grants one of three
93
+ tiers — `viewer` (read), `editor` (read + write), or `admin` (currently identical to `editor` — don't
94
+ design around admin having extra powers yet). Role bindings attach your app's roles to Grafana's basic
95
+ roles (`viewer`, `editor`, `admin`), so every Grafana user inherits the matching app role automatically.
96
+ Set `appDisplayName` so your app shows up with a readable name in the Grafana UI's role picker, instead
97
+ of the raw `appName`.
98
+
99
+ ```cue
100
+ manifest: {
101
+ appName: "{{ pluginId }}"
102
+ appDisplayName: "{{ pluginId }}"
103
+ versions: {
104
+ "v1alpha1": v1alpha1
105
+ }
106
+ extraPermissions: {
107
+ accessKinds: []
108
+ }
109
+ // roles your app grants, and which Grafana basic role gets each one by default.
110
+ roles: [
111
+ {
112
+ name: "{{ pluginId }}:editor"
113
+ permissionSet: "editor"
114
+ },
115
+ ]
116
+ roleBindings: [
117
+ {
118
+ roleName: "{{ pluginId }}:editor"
119
+ basicRole: "editor"
120
+ },
121
+ ]
122
+ }
123
+ ```
124
+
125
+ Without a `roleBindings` entry, a role you define is never granted to anyone — add one for every role you
126
+ want users to actually have.
@@ -7,6 +7,9 @@ exampleKind: {
7
7
  pluralName: "Examples"
8
8
  // Namespaced resources are created per-tenant. Use "Cluster" for global resources.
9
9
  scope: "Namespaced"
10
+ // Namespaced kinds are folder-scoped by default: callers need both the Stack Role (see roles in
11
+ // manifest.cue) and folder access. Uncomment to opt this kind out of folder scoping.
12
+ // folderScoped: false
10
13
  codegen: {
11
14
  ts: {
12
15
  enabled: true
@@ -7,6 +7,10 @@ manifest: {
7
7
  // different group.
8
8
  appName: "{{ pluginId }}"
9
9
 
10
+ // appDisplayName is the human-readable name shown for your app's roles in Grafana's role picker.
11
+ // Set it to something more readable than appName.
12
+ appDisplayName: "{{ pluginId }}"
13
+
10
14
  // versions maps each version your app serves to the kinds it exposes. Version names follow the
11
15
  // format "v<integer>" or "v<integer>(alpha|beta)<integer>".
12
16
  versions: {
@@ -18,6 +22,26 @@ manifest: {
18
22
  extraPermissions: {
19
23
  accessKinds: []
20
24
  }
25
+
26
+ // roles declares custom RBAC roles for your app. Each role name follows "<app>:<role>" and grants
27
+ // one of three tiers: "viewer" (read), "editor" (read + write), or "admin" (currently identical
28
+ // to "editor"). A role you define here is never granted to anyone without a matching entry in
29
+ // roleBindings below.
30
+ // roles: [
31
+ // {
32
+ // name: "{{ pluginId }}:editor"
33
+ // permissionSet: "editor"
34
+ // },
35
+ // ]
36
+
37
+ // roleBindings attaches your app's roles to Grafana's basic roles (viewer/editor/admin), so every
38
+ // Grafana user with that basic role automatically inherits the matching app role.
39
+ // roleBindings: [
40
+ // {
41
+ // roleName: "{{ pluginId }}:editor"
42
+ // basicRole: "editor"
43
+ // },
44
+ // ]
21
45
  }
22
46
 
23
47
  // v1alpha1 is the v1alpha1 version of the app's API.
@@ -7,7 +7,7 @@ services:
7
7
  context: .
8
8
  args:
9
9
  grafana_image: ${GRAFANA_IMAGE:-{{~grafanaImage~}} }
10
- grafana_version: ${GRAFANA_VERSION:-13.1.0}
10
+ grafana_version: ${GRAFANA_VERSION:-13.2.2}
11
11
  development: ${DEVELOPMENT:-false}
12
12
  anonymous_auth_enabled: ${ANONYMOUS_AUTH_ENABLED:-true}
13
13
  ports:
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { defineConfig } from 'eslint/config';
9
- import grafanaConfig from '@grafana/eslint-config/flat.js';
9
+ import grafanaConfig from '@grafana/eslint-config';
10
10
 
11
11
  export default defineConfig([
12
12
  ...grafanaConfig,
@@ -7,8 +7,10 @@
7
7
 
8
8
  import '@testing-library/jest-dom';
9
9
  import { TextEncoder, TextDecoder } from 'util';
10
+ import { MessageChannel, MessagePort } from 'worker_threads';
10
11
 
11
- Object.assign(global, { TextDecoder, TextEncoder });
12
+ // React 19's scheduler relies on MessageChannel, which jsdom does not implement.
13
+ Object.assign(global, { TextDecoder, TextEncoder, MessageChannel, MessagePort });
12
14
 
13
15
  // https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
14
16
  Object.defineProperty(global, 'matchMedia', {
@@ -16,14 +16,14 @@
16
16
  "author": "{{ sentenceCase orgName }}",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "@grafana/eslint-config": "^9.0.0",
19
+ "@grafana/eslint-config": "^10.0.0",
20
20
  "@grafana/plugin-e2e": "^3.12.0",
21
21
  "@grafana/sign-plugin": "^3.3.3",
22
22
  "@grafana/tsconfig": "^2.2.0",
23
23
  "@playwright/test": "^1.62.1",{{#if useExperimentalRspack}}
24
24
  "@rspack/core": "^1.6.0",
25
25
  "@rspack/cli": "^1.6.0",{{/if}}
26
- "@stylistic/eslint-plugin-ts": "^4.4.0",
26
+ "@stylistic/eslint-plugin": "^5.10.0",
27
27
  "@swc/core": "^1.15.0",
28
28
  "@swc/helpers": "^0.5.0",
29
29
  "@swc/jest": "^0.2.0",
@@ -31,8 +31,8 @@
31
31
  "@testing-library/react": "^16.3.0",
32
32
  "@types/jest": "^29.5.0",
33
33
  "@types/node": "^24.0.0",
34
- "@types/react": "^18.3.0",
35
- "@types/react-dom": "^18.3.0",{{#if useExperimentalRspack}}
34
+ "@types/react": "^19.0.0",
35
+ "@types/react-dom": "^19.0.0",{{#if useExperimentalRspack}}
36
36
  "@types/ws": "^8.18.1",{{/if}}
37
37
  "@typescript-eslint/eslint-plugin": "^8.38.0",
38
38
  "@typescript-eslint/parser": "^8.38.0",{{#unless useExperimentalRspack}}
@@ -42,7 +42,7 @@
42
42
  "eslint-config-prettier": "^10.1.0",
43
43
  "eslint-plugin-jsdoc": "^52.0.0",
44
44
  "eslint-plugin-react": "^7.37.0",
45
- "eslint-plugin-react-hooks": "^7.0.0",
45
+ "eslint-plugin-react-hooks": "^7.1.0",
46
46
  "eslint-webpack-plugin": "^5.0.0",{{#unless useExperimentalRspack}}
47
47
  "fork-ts-checker-webpack-plugin": "^9.1.0",{{/unless}}
48
48
  "glob": "^11.1.0",
@@ -74,14 +74,14 @@
74
74
  },
75
75
  "dependencies": {
76
76
  "@emotion/css": "11.10.6",
77
- "@grafana/data": "13.1.0",
78
- "@grafana/i18n": "13.1.0",
79
- "@grafana/runtime": "13.1.0",
80
- "@grafana/ui": "13.1.0",
81
- "@grafana/schema": "13.1.0",{{#if_eq pluginType "scenesapp" }}
77
+ "@grafana/data": "13.2.2",
78
+ "@grafana/i18n": "13.2.2",
79
+ "@grafana/runtime": "13.2.2",
80
+ "@grafana/ui": "13.2.2",
81
+ "@grafana/schema": "13.2.2",{{#if_eq pluginType "scenesapp" }}
82
82
  "@grafana/scenes": "{{ scenesVersion }}",{{/if_eq}}
83
- "react": "^18.3.0",
84
- "react-dom": "^18.3.0"{{#if isAppType}},
83
+ "react": "^19.0.0",
84
+ "react-dom": "^19.0.0"{{#if isAppType}},
85
85
  "react-router-dom": "^6.22.0",
86
86
  "rxjs": "7.8.2"{{/if}}
87
87
  },
@@ -22,7 +22,7 @@
22
22
  "updated": "%TODAY%"
23
23
  },
24
24
  "dependencies": {
25
- "grafanaDependency": ">=12.3.0",
25
+ "grafanaDependency": ">=13.2.0",
26
26
  "plugins": []
27
27
  }
28
28
  }
@@ -19,7 +19,7 @@
19
19
  "updated": "%TODAY%"
20
20
  },
21
21
  "dependencies": {
22
- "grafanaDependency": ">=12.3.0",
22
+ "grafanaDependency": ">=13.2.0",
23
23
  "plugins": []
24
24
  }
25
25
  }
@@ -52,7 +52,7 @@
52
52
  }
53
53
  ],
54
54
  "dependencies": {
55
- "grafanaDependency": ">=12.3.0",
55
+ "grafanaDependency": ">=13.2.0",
56
56
  "plugins": []
57
57
  }
58
58
  }