@grafana/create-plugin 4.5.0-canary.847.ba9d6ed.0 → 4.5.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/commands/generate.command.js +0 -3
  3. package/dist/constants.js +0 -1
  4. package/dist/utils/tests/utils.handlebars.test.js +1 -7
  5. package/dist/utils/tests/utils.templates.test.js +1 -1
  6. package/dist/utils/utils.files.js +0 -1
  7. package/dist/utils/utils.handlebars.js +0 -10
  8. package/dist/utils/utils.templates.js +0 -6
  9. package/package.json +2 -2
  10. package/src/commands/generate.command.ts +1 -6
  11. package/src/constants.ts +0 -1
  12. package/src/types.ts +0 -2
  13. package/src/utils/tests/utils.handlebars.test.ts +1 -8
  14. package/src/utils/tests/utils.templates.test.ts +1 -1
  15. package/src/utils/utils.config.ts +0 -1
  16. package/src/utils/utils.files.ts +0 -1
  17. package/src/utils/utils.handlebars.ts +0 -11
  18. package/src/utils/utils.templates.ts +2 -8
  19. package/templates/app/src/components/AppConfig/AppConfig.tsx +0 -2
  20. package/templates/backend/pkg/plugin/datasource.go +8 -15
  21. package/templates/common/.config/Dockerfile +19 -8
  22. package/templates/common/.config/entrypoint.sh +8 -0
  23. package/templates/common/_package.json +6 -8
  24. package/templates/common/cypress/integration/01-smoke.spec.ts +10 -0
  25. package/templates/common/cypress.json +3 -0
  26. package/templates/common/gitignore +4 -8
  27. package/templates/common/npmrc +2 -2
  28. package/templates/datasource/provisioning/datasources/datasources.yml +0 -4
  29. package/templates/datasource/src/datasource.ts +6 -47
  30. package/templates/datasource/src/types.ts +0 -9
  31. package/templates/github/ci/.github/workflows/ci.yml +3 -17
  32. package/templates/panel/provisioning/dashboards/dashboard.json +3 -35
  33. package/templates/panel/src/components/SimplePanel.tsx +3 -9
  34. package/templates/app/tests/appConfig.spec.ts +0 -19
  35. package/templates/app/tests/appNavigation.spec.ts +0 -32
  36. package/templates/app/tests/fixtures.ts +0 -19
  37. package/templates/backend/pkg/models/settings.go +0 -35
  38. package/templates/backend/tests/configEditor.spec.ts +0 -26
  39. package/templates/backend/tests/queryEditor.spec.ts +0 -22
  40. package/templates/common/playwright.config +0 -53
  41. package/templates/datasource/tests/configEditor.spec.ts +0 -33
  42. package/templates/datasource/tests/queryEditor.spec.ts +0 -11
  43. package/templates/panel/provisioning/datasources/datasources.yml +0 -7
  44. package/templates/panel/tests/panel.spec.ts +0 -39
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # v4.5.0 (Fri Apr 05 2024)
2
+
3
+ #### 🚀 Enhancement
4
+
5
+ - Create Plugins: Add feature to toggle docker development environment [#857](https://github.com/grafana/plugin-tools/pull/857) ([@oshirohugo](https://github.com/oshirohugo))
6
+
7
+ #### Authors: 1
8
+
9
+ - Hugo Kiyodi Oshiro ([@oshirohugo](https://github.com/oshirohugo))
10
+
11
+ ---
12
+
1
13
  # v4.4.6 (Wed Apr 03 2024)
2
14
 
3
15
  #### 🐛 Bug Fix
@@ -48,7 +48,6 @@ function getTemplateData(answers) {
48
48
  const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
49
49
  const isAppType = pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
50
50
  const useReactRouterV6 = features.useReactRouterV6 === true && pluginType === PLUGIN_TYPES.app;
51
- const usePlaywright = features.usePlaywright === true;
52
51
  const templateData = {
53
52
  ...answers,
54
53
  pluginId,
@@ -61,8 +60,6 @@ function getTemplateData(answers) {
61
60
  bundleGrafanaUI: features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI,
62
61
  useReactRouterV6,
63
62
  reactRouterVersion: useReactRouterV6 ? '6.22.0' : '5.2.0',
64
- usePlaywright,
65
- e2eTestCmd: 'playwright test',
66
63
  };
67
64
  return templateData;
68
65
  }
package/dist/constants.js CHANGED
@@ -34,7 +34,6 @@ export const EXTRA_TEMPLATE_VARIABLES = {
34
34
  export const DEFAULT_FEATURE_FLAGS = {
35
35
  useReactRouterV6: true,
36
36
  bundleGrafanaUI: false,
37
- usePlaywright: true,
38
37
  };
39
38
  export const GRAFANA_FE_PACKAGES = [
40
39
  '@grafana/data',
@@ -1,5 +1,5 @@
1
1
  import { PLUGIN_TYPES } from '../../constants.js';
2
- import { kebabToPascalKebab, normalizeId } from '../utils.handlebars.js';
2
+ import { normalizeId } from '../utils.handlebars.js';
3
3
  describe('Handlebars helpers', () => {
4
4
  describe('normalize id', () => {
5
5
  test.each([PLUGIN_TYPES.app, PLUGIN_TYPES.datasource, PLUGIN_TYPES.panel])('should return the id with the type appended', (type) => {
@@ -27,10 +27,4 @@ describe('Handlebars helpers', () => {
27
27
  expect(actual).toEqual(`myorg-myplugin-${type}`);
28
28
  });
29
29
  });
30
- describe('pascal to pascal kebab', () => {
31
- test('should convert pascal case to pascal kebab case', () => {
32
- const actual = kebabToPascalKebab('my-plugin');
33
- expect(actual).toEqual('My-Plugin');
34
- });
35
- });
36
30
  });
@@ -17,7 +17,7 @@ describe('Utils / Templates', () => {
17
17
  expect(templateFiles.length).toBe(0);
18
18
  });
19
19
  test('should be possible to filter for multiple different files', () => {
20
- const templateFiles = getTemplateFiles(PLUGIN_TYPES.app, ['.prettierrc.js', 'jest.config.js', 'tsconfig.json']);
20
+ const templateFiles = getTemplateFiles(PLUGIN_TYPES.app, ['.prettierrc.js', 'cypress.json', 'tsconfig.json']);
21
21
  expect(Array.isArray(templateFiles)).toBe(true);
22
22
  expect(templateFiles.length).toBe(3);
23
23
  });
@@ -68,7 +68,6 @@ const configFileNamesMap = {
68
68
  npmrc: '.npmrc',
69
69
  _eslintrc: '.eslintrc',
70
70
  '_package.json': 'package.json',
71
- 'playwright.config': 'playwright.config.ts',
72
71
  };
73
72
  export function isFileStartingWith(file, filter) {
74
73
  if (Array.isArray(filter)) {
@@ -14,15 +14,6 @@ export const normalizeId = (pluginName, orgName, type) => {
14
14
  const newOrgName = orgName.replace(nameRegex, '');
15
15
  return newOrgName.toLowerCase() + '-' + newPluginName.toLowerCase() + `-${type}`;
16
16
  };
17
- export const kebabToPascalKebab = (str) => {
18
- if (typeof str !== 'string') {
19
- return '';
20
- }
21
- return str
22
- .split('-')
23
- .map((word) => pascalCase(word))
24
- .join('-');
25
- };
26
17
  registerHandlebarsHelpers();
27
18
  registerHandlebarsPartials();
28
19
  function registerHandlebarsHelpers() {
@@ -39,7 +30,6 @@ function registerHandlebarsHelpers() {
39
30
  dashCase: kebabCase,
40
31
  kabobCase: kebabCase,
41
32
  kebabCase: kebabCase,
42
- kebabToPascalKebab: kebabToPascalKebab,
43
33
  properCase: pascalCase,
44
34
  pascalCase: pascalCase,
45
35
  if_eq: ifEq,
@@ -61,10 +61,6 @@ export function getTemplateData() {
61
61
  const useReactRouterV6 = features.useReactRouterV6 === true && pluginJson.type === PLUGIN_TYPES.app;
62
62
  const { packageManagerName, packageManagerVersion } = getPackageManagerWithFallback();
63
63
  const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
64
- const usePlaywright = features.usePlaywright === true || isFile(path.join(process.cwd(), 'playwright.config.ts'));
65
- const e2eTestCmd = usePlaywright
66
- ? 'playwright test'
67
- : `${packageManagerName} exec cypress install && ${packageManagerName} exec grafana-e2e run`;
68
64
  const templateData = {
69
65
  ...EXTRA_TEMPLATE_VARIABLES,
70
66
  pluginId: pluginJson.id,
@@ -82,8 +78,6 @@ export function getTemplateData() {
82
78
  bundleGrafanaUI: features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI,
83
79
  useReactRouterV6: useReactRouterV6,
84
80
  reactRouterVersion: useReactRouterV6 ? '6.22.0' : '5.2.0',
85
- usePlaywright,
86
- e2eTestCmd,
87
81
  };
88
82
  debug('\nTemplate data:\n' + JSON.stringify(templateData, null, 2));
89
83
  return templateData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/create-plugin",
3
- "version": "4.5.0-canary.847.ba9d6ed.0",
3
+ "version": "4.5.0",
4
4
  "repository": {
5
5
  "directory": "packages/create-plugin",
6
6
  "url": "https://github.com/grafana/plugin-tools"
@@ -87,5 +87,5 @@
87
87
  "engines": {
88
88
  "node": ">=20"
89
89
  },
90
- "gitHead": "ba9d6ed33eb4101da6f9b23719c088fa63c9d8f8"
90
+ "gitHead": "79b462dd77503ddb597debb3575a90e43316c865"
91
91
  }
@@ -59,10 +59,7 @@ function getTemplateData(answers: CliArgs) {
59
59
  const { packageManagerName, packageManagerVersion } = getPackageManagerFromUserAgent();
60
60
  const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
61
61
  const isAppType = pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
62
- // We don't enable this by default yet for new scenes plugins.
63
- const useReactRouterV6 = features.useReactRouterV6 === true && pluginType === PLUGIN_TYPES.app;
64
- const usePlaywright = features.usePlaywright === true;
65
-
62
+ const useReactRouterV6 = features.useReactRouterV6 === true && pluginType === PLUGIN_TYPES.app; // We don't enable this by default yet for new scenes plugins.
66
63
  const templateData: TemplateData = {
67
64
  ...answers,
68
65
  pluginId,
@@ -75,8 +72,6 @@ function getTemplateData(answers: CliArgs) {
75
72
  bundleGrafanaUI: features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI,
76
73
  useReactRouterV6,
77
74
  reactRouterVersion: useReactRouterV6 ? '6.22.0' : '5.2.0',
78
- usePlaywright,
79
- e2eTestCmd: 'playwright test',
80
75
  };
81
76
 
82
77
  return templateData;
package/src/constants.ts CHANGED
@@ -50,7 +50,6 @@ export const EXTRA_TEMPLATE_VARIABLES = {
50
50
  export const DEFAULT_FEATURE_FLAGS = {
51
51
  useReactRouterV6: true,
52
52
  bundleGrafanaUI: false,
53
- usePlaywright: true,
54
53
  };
55
54
 
56
55
  export const GRAFANA_FE_PACKAGES = [
package/src/types.ts CHANGED
@@ -21,6 +21,4 @@ export type TemplateData = {
21
21
  bundleGrafanaUI: boolean;
22
22
  useReactRouterV6: boolean;
23
23
  reactRouterVersion: string;
24
- usePlaywright: boolean;
25
- e2eTestCmd: string;
26
24
  };
@@ -1,5 +1,5 @@
1
1
  import { PLUGIN_TYPES } from '../../constants.js';
2
- import { kebabToPascalKebab, normalizeId } from '../utils.handlebars.js';
2
+ import { normalizeId } from '../utils.handlebars.js';
3
3
 
4
4
  describe('Handlebars helpers', () => {
5
5
  describe('normalize id', () => {
@@ -42,11 +42,4 @@ describe('Handlebars helpers', () => {
42
42
  }
43
43
  );
44
44
  });
45
-
46
- describe('pascal to pascal kebab', () => {
47
- test('should convert pascal case to pascal kebab case', () => {
48
- const actual = kebabToPascalKebab('my-plugin');
49
- expect(actual).toEqual('My-Plugin');
50
- });
51
- });
52
45
  });
@@ -28,7 +28,7 @@ describe('Utils / Templates', () => {
28
28
  });
29
29
 
30
30
  test('should be possible to filter for multiple different files', () => {
31
- const templateFiles = getTemplateFiles(PLUGIN_TYPES.app, ['.prettierrc.js', 'jest.config.js', 'tsconfig.json']);
31
+ const templateFiles = getTemplateFiles(PLUGIN_TYPES.app, ['.prettierrc.js', 'cypress.json', 'tsconfig.json']);
32
32
 
33
33
  expect(Array.isArray(templateFiles)).toBe(true);
34
34
  expect(templateFiles.length).toBe(3);
@@ -10,7 +10,6 @@ export type FeatureFlags = {
10
10
  // If set to true, the plugin will be scaffolded with React Router v6. Defaults to true.
11
11
  // (Attention! We always scaffold new projects with React Router v6, so if you are changing this to `false` manually you will need to make changes to the React code as well.)
12
12
  useReactRouterV6?: boolean;
13
- usePlaywright?: boolean;
14
13
  };
15
14
 
16
15
  export type CreatePluginConfig = UserConfig & {
@@ -91,7 +91,6 @@ const configFileNamesMap: Record<string, string> = {
91
91
  npmrc: '.npmrc',
92
92
  _eslintrc: '.eslintrc',
93
93
  '_package.json': 'package.json',
94
- 'playwright.config': 'playwright.config.ts',
95
94
  };
96
95
 
97
96
  /**
@@ -28,16 +28,6 @@ export const normalizeId = (pluginName: string, orgName: string, type: PLUGIN_TY
28
28
  return newOrgName.toLowerCase() + '-' + newPluginName.toLowerCase() + `-${type}`;
29
29
  };
30
30
 
31
- export const kebabToPascalKebab = (str: string) => {
32
- if (typeof str !== 'string') {
33
- return '';
34
- }
35
- return str
36
- .split('-')
37
- .map((word) => pascalCase(word))
38
- .join('-');
39
- };
40
-
41
31
  // Register our helpers and partials with handlebars.
42
32
  registerHandlebarsHelpers();
43
33
  registerHandlebarsPartials();
@@ -56,7 +46,6 @@ function registerHandlebarsHelpers() {
56
46
  dashCase: kebabCase,
57
47
  kabobCase: kebabCase,
58
48
  kebabCase: kebabCase,
59
- kebabToPascalKebab: kebabToPascalKebab,
60
49
  properCase: pascalCase,
61
50
  pascalCase: pascalCase,
62
51
  if_eq: ifEq,
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import fs from 'node:fs';
4
4
  import { mkdirp } from 'mkdirp';
5
5
  import createDebug from 'debug';
6
- import { directoryExists, filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
6
+ import { filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
7
7
  import { renderHandlebarsTemplate } from './utils.handlebars.js';
8
8
  import { getPluginJson } from './utils.plugin.js';
9
9
  import {
@@ -17,7 +17,7 @@ import { TemplateData } from '../types.js';
17
17
  import { getPackageManagerInstallCmd, getPackageManagerWithFallback } from './utils.packageManager.js';
18
18
  import { getExportFileName } from '../utils/utils.files.js';
19
19
  import { getVersion } from './utils.version.js';
20
- import { FeatureFlags, getConfig } from './utils.config.js';
20
+ import { getConfig } from './utils.config.js';
21
21
 
22
22
  const debug = createDebug('templates');
23
23
 
@@ -95,10 +95,6 @@ export function getTemplateData(): TemplateData {
95
95
  const useReactRouterV6 = features.useReactRouterV6 === true && pluginJson.type === PLUGIN_TYPES.app;
96
96
  const { packageManagerName, packageManagerVersion } = getPackageManagerWithFallback();
97
97
  const packageManagerInstallCmd = getPackageManagerInstallCmd(packageManagerName);
98
- const usePlaywright = features.usePlaywright === true || isFile(path.join(process.cwd(), 'playwright.config.ts'));
99
- const e2eTestCmd = usePlaywright
100
- ? 'playwright test'
101
- : `${packageManagerName} exec cypress install && ${packageManagerName} exec grafana-e2e run`;
102
98
 
103
99
  const templateData = {
104
100
  ...EXTRA_TEMPLATE_VARIABLES,
@@ -117,8 +113,6 @@ export function getTemplateData(): TemplateData {
117
113
  bundleGrafanaUI: features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI,
118
114
  useReactRouterV6: useReactRouterV6,
119
115
  reactRouterVersion: useReactRouterV6 ? '6.22.0' : '5.2.0',
120
- usePlaywright,
121
- e2eTestCmd,
122
116
  };
123
117
 
124
118
  debug('\nTemplate data:\n' + JSON.stringify(templateData, null, 2));
@@ -50,7 +50,6 @@ export const AppConfig = ({ plugin }: AppConfigProps) => {
50
50
  <Field label="API Key" description="A secret key for authenticating to our custom API">
51
51
  <SecretInput
52
52
  width={60}
53
- id="config-api-key"
54
53
  data-testid={testIds.appConfig.apiKey}
55
54
  name="apiKey"
56
55
  value={state.apiKey}
@@ -65,7 +64,6 @@ export const AppConfig = ({ plugin }: AppConfigProps) => {
65
64
  <Input
66
65
  width={60}
67
66
  name="apiUrl"
68
- id="config-api-url"
69
67
  data-testid={testIds.appConfig.apiUrl}
70
68
  value={state.apiUrl}
71
69
  placeholder={`E.g.: http://mywebsite.com/api/v1`}
@@ -4,12 +4,12 @@ import (
4
4
  "context"
5
5
  "encoding/json"
6
6
  "fmt"
7
+ "math/rand"
7
8
  "time"
8
9
 
9
10
  "github.com/grafana/grafana-plugin-sdk-go/backend"
10
11
  "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
11
12
  "github.com/grafana/grafana-plugin-sdk-go/data"
12
- "github.com/{{ kebabCase orgName }}/{{ kebabCase pluginName }}/pkg/models"
13
13
  )
14
14
 
15
15
  // Make sure Datasource implements required interfaces. This is important to do
@@ -94,23 +94,16 @@ func (d *Datasource) query(_ context.Context, pCtx backend.PluginContext, query
94
94
  // datasource configuration page which allows users to verify that
95
95
  // a datasource is working as expected.
96
96
  func (d *Datasource) CheckHealth(_ context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
97
- res := &backend.CheckHealthResult{}
98
- config, err := models.LoadPluginSettings(*req.PluginContext.DataSourceInstanceSettings)
97
+ var status = backend.HealthStatusOk
98
+ var message = "Data source is working"
99
99
 
100
- if err != nil {
101
- res.Status = backend.HealthStatusError
102
- res.Message = "Unable to load settings"
103
- return res, nil
104
- }
105
-
106
- if config.Secrets.ApiKey == "" {
107
- res.Status = backend.HealthStatusError
108
- res.Message = "API key is missing"
109
- return res, nil
100
+ if rand.Int()%2 == 0 {
101
+ status = backend.HealthStatusError
102
+ message = "randomized error"
110
103
  }
111
104
 
112
105
  return &backend.CheckHealthResult{
113
- Status: backend.HealthStatusOk,
114
- Message: "Data source is working",
106
+ Status: status,
107
+ Message: message,
115
108
  }, nil
116
109
  }
@@ -3,11 +3,15 @@ ARG grafana_image=grafana-enterprise
3
3
 
4
4
  FROM grafana/${grafana_image}:${grafana_version}
5
5
 
6
+ ARG development=true
7
+
6
8
  {{#if hasBackend}}
7
9
  ARG GO_VERSION=1.21.6
8
10
  ARG GO_ARCH=amd64
9
11
  {{/if}}
10
12
 
13
+ ENV DEV "${development}"
14
+
11
15
  # Make it as simple as possible to access the grafana instance for development purposes
12
16
  # Do NOT enable these settings in a public facing / production grafana instance
13
17
  ENV GF_AUTH_ANONYMOUS_ORG_ROLE "Admin"
@@ -24,10 +28,10 @@ WORKDIR $GF_PATHS_HOME
24
28
 
25
29
  USER root
26
30
 
27
-
28
31
  # Installing supervisor and inotify-tools
29
- RUN if grep -i -q alpine /etc/issue; then \
30
- apk add supervisor inotify-tools git; \
32
+ RUN if [ "${development}" = "true" ]; then \
33
+ if grep -i -q alpine /etc/issue; then \
34
+ apk add supervisor inotify-tools git; \
31
35
  elif grep -i -q ubuntu /etc/issue; then \
32
36
  DEBIAN_FRONTEND=noninteractive && \
33
37
  apt-get update && \
@@ -35,6 +39,7 @@ RUN if grep -i -q alpine /etc/issue; then \
35
39
  rm -rf /var/lib/apt/lists/*; \
36
40
  else \
37
41
  echo 'ERROR: Unsupported base image' && /bin/false; \
42
+ fi \
38
43
  fi
39
44
 
40
45
  COPY supervisord/supervisord.conf /etc/supervisor.d/supervisord.ini
@@ -43,20 +48,26 @@ COPY supervisord/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
43
48
 
44
49
  {{#if hasBackend}}
45
50
  # Installing Go
46
- RUN curl -O -L https://golang.org/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
51
+ RUN if [ "${development}" = "true" ]; then \
52
+ curl -O -L https://golang.org/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
47
53
  rm -rf /usr/local/go && \
48
54
  tar -C /usr/local -xzf go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
49
55
  echo "export PATH=$PATH:/usr/local/go/bin:~/go/bin" >> ~/.bashrc && \
50
- rm -f go${GO_VERSION}.linux-${GO_ARCH}.tar.gz
56
+ rm -f go${GO_VERSION}.linux-${GO_ARCH}.tar.gz; \
57
+ fi
51
58
 
52
59
  # Installing delve for debugging
53
- RUN /usr/local/go/bin/go install github.com/go-delve/delve/cmd/dlv@latest
60
+ RUN if [ "${development}" = "true" ]; then \
61
+ /usr/local/go/bin/go install github.com/go-delve/delve/cmd/dlv@latest; \
62
+ fi
54
63
 
55
64
  # Installing mage for plugin (re)building
56
- RUN git clone https://github.com/magefile/mage; \
65
+ RUN if [ "${development}" = "true" ]; then \
66
+ git clone https://github.com/magefile/mage; \
57
67
  cd mage; \
58
68
  export PATH=$PATH:/usr/local/go/bin; \
59
- go run bootstrap.go
69
+ go run bootstrap.go; \
70
+ fi
60
71
  {{/if}}
61
72
 
62
73
  # Inject livereload script into grafana index.html
@@ -1,5 +1,12 @@
1
1
  #!/bin/sh
2
2
 
3
+ if [ "${DEV}" = "false" ]; then
4
+ echo "Starting test mode"
5
+ exec /run.sh
6
+ fi
7
+
8
+ echo "Starting development mode"
9
+
3
10
  if grep -i -q alpine /etc/issue; then
4
11
  exec /usr/bin/supervisord -c /etc/supervisord.conf
5
12
  elif grep -i -q ubuntu /etc/issue; then
@@ -8,3 +15,4 @@ else
8
15
  echo 'ERROR: Unsupported base image'
9
16
  exit 1
10
17
  fi
18
+
@@ -10,21 +10,19 @@
10
10
  "typecheck": "tsc --noEmit",
11
11
  "lint": "eslint --cache --ignore-path ./.gitignore --ext .js,.jsx,.ts,.tsx .",
12
12
  "lint:fix": "{{ packageManagerName }} run lint{{#if isNPM}} --{{/if}} --fix",
13
- "e2e": "{{{ e2eTestCmd }}}",{{#unless usePlaywright}}
14
- "e2e:update": "{{ packageManagerName }} exec cypress install && {{ packageManagerName }} exec grafana-e2e run --update-screenshots",{{/unless}}
13
+ "e2e": "{{ packageManagerName }} exec cypress install && {{ packageManagerName }} exec grafana-e2e run",
14
+ "e2e:update": "{{ packageManagerName }} exec cypress install && {{ packageManagerName }} exec grafana-e2e run --update-screenshots",
15
15
  "server": "docker-compose up --build",
16
16
  "sign": "npx --yes @grafana/sign-plugin@latest"
17
17
  },
18
18
  "author": "{{ sentenceCase orgName }}",
19
19
  "license": "Apache-2.0",
20
20
  "devDependencies": {
21
- "@babel/core": "^7.21.4",{{#unless usePlaywright}}
21
+ "@babel/core": "^7.21.4",
22
22
  "@grafana/e2e": "{{ grafanaVersion }}",
23
- "@grafana/e2e-selectors": "{{ grafanaVersion }}",{{/unless}}
24
- "@grafana/eslint-config": "^7.0.0",{{#if usePlaywright}}
25
- "@grafana/plugin-e2e": "^0.27.0",{{/if}}
26
- "@grafana/tsconfig": "^1.2.0-rc1",{{#if usePlaywright}}
27
- "@playwright/test": "^1.41.2",{{/if}}
23
+ "@grafana/e2e-selectors": "{{ grafanaVersion }}",
24
+ "@grafana/eslint-config": "^7.0.0",
25
+ "@grafana/tsconfig": "^1.2.0-rc1",
28
26
  "@swc/core": "^1.3.90",
29
27
  "@swc/helpers": "^0.5.0",
30
28
  "@swc/jest": "^0.2.26",
@@ -0,0 +1,10 @@
1
+ import { e2e } from '@grafana/e2e';
2
+
3
+ e2e.scenario({
4
+ describeName: 'Smoke test',
5
+ itName: 'Smoke test',
6
+ scenario: () => {
7
+ e2e.pages.Home.visit();
8
+ e2e().contains('Welcome to Grafana').should('be.visible');
9
+ },
10
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "video": false
3
+ }
@@ -25,15 +25,11 @@ dist/
25
25
  artifacts/
26
26
  work/
27
27
  ci/
28
-
29
- # e2e test directories
30
- /test-results/
31
- /playwright-report/
32
- /blob-report/
33
- /playwright/.cache/
34
- /playwright/.auth/
28
+ e2e-results/
29
+ **/cypress/videos
30
+ **/cypress/report.json
35
31
 
36
32
  # Editor
37
33
  .idea
38
34
 
39
- .eslintcache
35
+ .eslintcache
@@ -9,6 +9,6 @@ public-hoist-pattern[]="*prettier*"
9
9
 
10
10
  # Hoist all types packages to the root for better TS support
11
11
  public-hoist-pattern[]="@types/*"
12
- {{#unless usePlaywright}}
12
+
13
13
  # @grafana/e2e expects cypress to exist in the root of the node_modules directory
14
- public-hoist-pattern[]="*cypress*"{{/unless}}
14
+ public-hoist-pattern[]="*cypress*"
@@ -8,7 +8,3 @@ datasources:
8
8
  orgId: 1
9
9
  version: 1
10
10
  editable: true
11
- jsonData:
12
- path: '/resources'
13
- secureJsonData:
14
- apiKey: 'api-key'
@@ -1,4 +1,3 @@
1
- import { getBackendSrv, isFetchError } from '@grafana/runtime';
2
1
  import {
3
2
  CoreApp,
4
3
  DataQueryRequest,
@@ -9,16 +8,11 @@ import {
9
8
  FieldType,
10
9
  } from '@grafana/data';
11
10
 
12
- import { MyQuery, MyDataSourceOptions, DEFAULT_QUERY, DataSourceResponse } from './types';
13
- import { lastValueFrom } from 'rxjs';
14
- import _ from 'lodash';
11
+ import { MyQuery, MyDataSourceOptions, DEFAULT_QUERY } from './types';
15
12
 
16
13
  export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
17
- baseUrl: string;
18
-
19
14
  constructor(instanceSettings: DataSourceInstanceSettings<MyDataSourceOptions>) {
20
15
  super(instanceSettings);
21
- this.baseUrl = instanceSettings.url!;
22
16
  }
23
17
 
24
18
  getDefaultQuery(_: CoreApp): Partial<MyQuery> {
@@ -49,46 +43,11 @@ export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
49
43
  return { data };
50
44
  }
51
45
 
52
- async request(url: string, params?: string) {
53
- const response = getBackendSrv().fetch<DataSourceResponse>({
54
- url: `${this.baseUrl}${url}${params?.length ? `?${params}` : ''}`,
55
- });
56
- return lastValueFrom(response);
57
- }
58
-
59
- /**
60
- * Checks whether we can connect to the API.
61
- */
62
46
  async testDatasource() {
63
- const defaultErrorMessage = 'Cannot connect to API';
64
-
65
- try {
66
- const response = await this.request('/health');
67
- if (response.status === 200) {
68
- return {
69
- status: 'success',
70
- message: 'Success',
71
- };
72
- } else {
73
- return {
74
- status: 'error',
75
- message: response.statusText ? response.statusText : defaultErrorMessage,
76
- };
77
- }
78
- } catch (err) {
79
- let message = '';
80
- if (_.isString(err)) {
81
- message = err;
82
- } else if (isFetchError(err)) {
83
- message = 'Fetch error: ' + (err.statusText ? err.statusText : defaultErrorMessage);
84
- if (err.data && err.data.error && err.data.error.code) {
85
- message += ': ' + err.data.error.code + '. ' + err.data.error.message;
86
- }
87
- }
88
- return {
89
- status: 'error',
90
- message,
91
- };
92
- }
47
+ // Implement a health check for your data source.
48
+ return {
49
+ status: 'success',
50
+ message: 'Success',
51
+ };
93
52
  }
94
53
  }
@@ -10,15 +10,6 @@ export const DEFAULT_QUERY: Partial<MyQuery> = {
10
10
  constant: 6.5,
11
11
  };
12
12
 
13
- export interface DataPoint {
14
- Time: number;
15
- Value: number;
16
- }
17
-
18
- export interface DataSourceResponse {
19
- datapoints: DataPoint[];
20
- }
21
-
22
13
  /**
23
14
  * These are options configured for each DataSource instance
24
15
  */
@@ -74,30 +74,16 @@ jobs:
74
74
  - name: Check for E2E
75
75
  id: check-for-e2e
76
76
  run: |
77
- if [ -f "playwright.config.ts" ]
77
+ if [ -d "cypress" ]
78
78
  then
79
79
  echo "has-e2e=true" >> $GITHUB_OUTPUT
80
80
  fi
81
81
 
82
- - name: Install Playwright Browsers
83
- if: steps.check-for-e2e.outputs.has-e2e == 'true'
84
- run: {{ packageManagerName }} exec playwright install --with-deps
85
-
86
82
  - name: Start grafana docker
87
83
  if: steps.check-for-e2e.outputs.has-e2e == 'true'
88
84
  run: docker-compose up -d
89
85
 
90
- - name: Wait for Grafana to start
91
- if: steps.check-for-e2e.outputs.has-e2e == 'true'
92
- uses: nev7n/wait_for_response@v1
93
- with:
94
- url: 'http://localhost:3000/'
95
- responseCode: 200
96
- timeout: 60000
97
- interval: 500
98
-
99
86
  - name: Run e2e tests
100
- id: run-e2e-tests
101
87
  if: steps.check-for-e2e.outputs.has-e2e == 'true'
102
88
  run: {{ packageManagerName }} run e2e
103
89
 
@@ -109,8 +95,8 @@ jobs:
109
95
  uses: actions/upload-artifact@v4
110
96
  if: steps.check-for-e2e.outputs.has-e2e == 'true' && steps.run-e2e-tests.outcome != 'success'
111
97
  with:
112
- name: playwright-report
113
- path: playwright-report/
98
+ name: cypress-videos
99
+ path: cypress/videos
114
100
  retention-days: 5
115
101
 
116
102
  - name: Sign plugin
@@ -18,7 +18,6 @@
18
18
  "editable": true,
19
19
  "fiscalYearStartMonth": 0,
20
20
  "graphTooltip": 0,
21
- "id": 1,
22
21
  "links": [],
23
22
  "liveNow": false,
24
23
  "panels": [
@@ -51,41 +50,11 @@
51
50
  ],
52
51
  "title": "Panel Title",
53
52
  "type": "{{ pluginId }}"
54
- },
55
- {
56
- "datasource": {
57
- "type": "grafana-testdata-datasource",
58
- "uid": "trlxrdZVk"
59
- },
60
- "gridPos": {
61
- "h": 8,
62
- "w": 12,
63
- "x": 12,
64
- "y": 0
65
- },
66
- "id": 2,
67
- "options": {
68
- "seriesCountSize": "sm",
69
- "showSeriesCount": false,
70
- "text": "Default value of text input option"
71
- },
72
- "targets": [
73
- {
74
- "alias": "",
75
- "datasource": {
76
- "type": "grafana-testdata-datasource",
77
- "uid": "db84e60d-b92a-4089-82cb-34842fb1754b"
78
- },
79
- "refId": "A",
80
- "scenarioId": "no_data_points"
81
- }
82
- ],
83
- "title": "Panel Title",
84
- "type": "{{ pluginId }}"
85
53
  }
86
54
  ],
87
55
  "refresh": "",
88
- "schemaVersion": 39,
56
+ "schemaVersion": 38,
57
+ "style": "dark",
89
58
  "tags": [],
90
59
  "templating": {
91
60
  "list": []
@@ -97,7 +66,6 @@
97
66
  "timepicker": {},
98
67
  "timezone": "",
99
68
  "title": "Provisioned {{ pluginName }} dashboard",
100
- "uid": "a538aeff-5a8a-42a5-901c-938d896fdd6f",
101
- "version": 1,
69
+ "version": 0,
102
70
  "weekStart": ""
103
71
  }
@@ -3,7 +3,6 @@ import { PanelProps } from '@grafana/data';
3
3
  import { SimpleOptions } from 'types';
4
4
  import { css, cx } from '@emotion/css';
5
5
  import { useStyles2, useTheme2 } from '@grafana/ui';
6
- import { PanelDataErrorView } from '@grafana/runtime';
7
6
 
8
7
  interface Props extends PanelProps<SimpleOptions> {}
9
8
 
@@ -27,14 +26,9 @@ const getStyles = () => {
27
26
  };
28
27
  };
29
28
 
30
- export const SimplePanel: React.FC<Props> = ({ options, data, width, height, fieldConfig, id }) => {
29
+ export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) => {
31
30
  const theme = useTheme2();
32
31
  const styles = useStyles2(getStyles);
33
-
34
- if (data.series.length === 0) {
35
- return <PanelDataErrorView fieldConfig={fieldConfig} panelId={id} data={data} needsStringField />;
36
- }
37
-
38
32
  return (
39
33
  <div
40
34
  className={cx(
@@ -55,12 +49,12 @@ export const SimplePanel: React.FC<Props> = ({ options, data, width, height, fie
55
49
  >
56
50
  <g>
57
51
  {{!-- /* 🚨 Escaping the following line because of Handlebars. (this comment is going to be removed after scaffolding) 🚨 */ --}}
58
- <circle data-testid="simple-panel-circle" style=\{{ fill: theme.colors.primary.main }} r={100} />
52
+ <circle style=\{{ fill: theme.colors.primary.main }} r={100} />
59
53
  </g>
60
54
  </svg>
61
55
 
62
56
  <div className={styles.textBox}>
63
- {options.showSeriesCount && <div data-testid="simple-panel-series-counter">Number of series: {data.series.length}</div>}
57
+ {options.showSeriesCount && <div>Number of series: {data.series.length}</div>}
64
58
  <div>Text option value: {options.text}</div>
65
59
  </div>
66
60
  </div>
@@ -1,19 +0,0 @@
1
- import { test, expect } from './fixtures';
2
-
3
- test('should be possible to save app configuration', async ({ appConfigPage, page }) => {
4
- const saveForm = page.getByRole('button', { name: /Save API settings/i });
5
-
6
- // reset the configured secret
7
- await page.getByRole('button', { name: /reset/i }).click();
8
-
9
- // enter some valid values
10
- await page.getByRole('textbox', { name: 'API Key' }).fill('secret-api-key');
11
- await page.getByRole('textbox', { name: 'API Url' }).clear();
12
- await page.getByRole('textbox', { name: 'API Url' }).fill('http://www.my-awsome-grafana-app.com/api');
13
-
14
- // listen for the server response on the saved form
15
- const saveResponse = appConfigPage.waitForSettingsResponse();
16
-
17
- await saveForm.click();
18
- await expect(saveResponse).toBeOK();
19
- });
@@ -1,32 +0,0 @@
1
- import pluginJson from '../src/plugin.json';
2
- import { test, expect } from '@grafana/plugin-e2e';
3
- import { ROUTES } from '../src/constants';
4
-
5
- test.describe('navigating app', () => {
6
- test('page one should render successfully', async ({ page }) => {
7
- await page.goto(`/a/${pluginJson.id}/${ROUTES.One}`);
8
- await expect(page.getByText('This is page one.')).toBeVisible();
9
- });
10
-
11
- test('page two should render successfully', async ({ page }) => {
12
- await page.goto(`/a/${pluginJson.id}/${ROUTES.Two}`);
13
- await expect(page.getByText('This is page two.')).toBeVisible();
14
- });
15
-
16
- test('page three should support an id parameter', async ({ page }) => {
17
- await page.goto(`/a/${pluginJson.id}/${ROUTES.Three}/123456`);
18
- await expect(page.getByText('ID: 123456')).toBeVisible();
19
- });
20
-
21
- test('page three should render sucessfully', async ({ page }) => {
22
- // wait for page to successfully render
23
- await page.goto(`/a/${pluginJson.id}/${ROUTES.One}`);
24
- await expect(page.getByText('This is page one.')).toBeVisible();
25
-
26
- // navigating to page four with full width layout without sidebar menu
27
- await page.getByText('Full-width page example').click();
28
-
29
- // navigate back to page one
30
- await page.getByRole('link', { name: 'Back', exact: true }).click();
31
- });
32
- });
@@ -1,19 +0,0 @@
1
- import { AppConfigPage, test as base } from '@grafana/plugin-e2e';
2
- import pluginJson from '../src/plugin.json';
3
-
4
- type AppTestFixture = { appConfigPage: AppConfigPage };
5
-
6
- export const test = base.extend<AppTestFixture>({
7
- appConfigPage: async ({ page, selectors, grafanaVersion, request }, use, testInfo) => {
8
- const configPage = new AppConfigPage(
9
- { page, selectors, grafanaVersion, request, testInfo },
10
- {
11
- pluginId: pluginJson.id,
12
- }
13
- );
14
- await configPage.goto();
15
- await use(configPage);
16
- },
17
- });
18
-
19
- export { expect } from '@grafana/plugin-e2e';
@@ -1,35 +0,0 @@
1
- package models
2
-
3
- import (
4
- "encoding/json"
5
- "fmt"
6
-
7
- "github.com/grafana/grafana-plugin-sdk-go/backend"
8
- )
9
-
10
- type PluginSettings struct {
11
- Path string `json:"path"`
12
- Secrets *SecretPluginSettings `json:"-"`
13
- }
14
-
15
- type SecretPluginSettings struct {
16
- ApiKey string `json:"apiKey"`
17
- }
18
-
19
- func LoadPluginSettings(source backend.DataSourceInstanceSettings) (*PluginSettings, error) {
20
- settings := PluginSettings{}
21
- err := json.Unmarshal(source.JSONData, &settings)
22
- if err != nil {
23
- return nil, fmt.Errorf("could not unmarshal PluginSettings json: %w", err)
24
- }
25
-
26
- settings.Secrets = loadSecretPluginSettings(source.DecryptedSecureJSONData)
27
-
28
- return &settings, nil
29
- }
30
-
31
- func loadSecretPluginSettings(source map[string]string) *SecretPluginSettings {
32
- return &SecretPluginSettings{
33
- ApiKey: source["apiKey"],
34
- }
35
- }
@@ -1,26 +0,0 @@
1
- import { test, expect } from '@grafana/plugin-e2e';
2
- import { MyDataSourceOptions, MySecureJsonData } from '../src/types';
3
-
4
- test('"Save & test" should be successful when configuration is valid', async ({
5
- createDataSourceConfigPage,
6
- readProvisionedDataSource,
7
- page,
8
- }) => {
9
- const ds = await readProvisionedDataSource<MyDataSourceOptions, MySecureJsonData>({ fileName: 'datasources.yml' });
10
- const configPage = await createDataSourceConfigPage({ type: ds.type });
11
- await page.getByRole('textbox', { name: 'Path' }).fill(ds.jsonData.path ?? '');
12
- await page.getByRole('textbox', { name: 'API Key' }).fill(ds.secureJsonData?.apiKey ?? '');
13
- await expect(configPage.saveAndTest()).toBeOK();
14
- });
15
-
16
- test('"Save & test" should fail when configuration is invalid', async ({
17
- createDataSourceConfigPage,
18
- readProvisionedDataSource,
19
- page,
20
- }) => {
21
- const ds = await readProvisionedDataSource<MyDataSourceOptions, MySecureJsonData>({ fileName: 'datasources.yml' });
22
- const configPage = await createDataSourceConfigPage({ type: ds.type });
23
- await page.getByRole('textbox', { name: 'Path' }).fill(ds.jsonData.path ?? '');
24
- await expect(configPage.saveAndTest()).not.toBeOK();
25
- await expect(configPage).toHaveAlert('error', { hasText: 'API key is missing' });
26
- });
@@ -1,22 +0,0 @@
1
- import { test, expect } from '@grafana/plugin-e2e';
2
-
3
- test('should trigger new query when Constant field is changed', async ({
4
- panelEditPage,
5
- readProvisionedDataSource,
6
- }) => {
7
- const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
8
- await panelEditPage.datasource.set(ds.name);
9
- await panelEditPage.getQueryEditorRow('A').getByRole('textbox', { name: 'Query Text' }).fill('test query');
10
- const queryReq = panelEditPage.waitForQueryDataRequest();
11
- await panelEditPage.getQueryEditorRow('A').getByRole('spinbutton').fill('10');
12
- await expect(await queryReq).toBeTruthy();
13
- });
14
-
15
- test('data query should return values 10 and 20', async ({ panelEditPage, readProvisionedDataSource }) => {
16
- const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
17
- await panelEditPage.datasource.set(ds.name);
18
- await panelEditPage.getQueryEditorRow('A').getByRole('textbox', { name: 'Query Text' }).fill('test query');
19
- await panelEditPage.setVisualization('Table');
20
- await expect(panelEditPage.refreshPanel()).toBeOK();
21
- await expect(panelEditPage.panel.data).toContainText(['10', '20']);
22
- });
@@ -1,53 +0,0 @@
1
- import type { PluginOptions } from '@grafana/plugin-e2e';
2
- import { defineConfig, devices } from '@playwright/test';
3
- import { dirname } from 'node:path';
4
-
5
- const pluginE2eAuth = `${dirname(require.resolve('@grafana/plugin-e2e'))}/auth`;
6
-
7
- /**
8
- * Read environment variables from file.
9
- * https://github.com/motdotla/dotenv
10
- */
11
- // require('dotenv').config();
12
-
13
- /**
14
- * See https://playwright.dev/docs/test-configuration.
15
- */
16
- export default defineConfig<PluginOptions>({
17
- testDir: './tests',
18
- /* Run tests in files in parallel */
19
- fullyParallel: true,
20
- /* Fail the build on CI if you accidentally left test.only in the source code. */
21
- forbidOnly: !!process.env.CI,
22
- /* Retry on CI only */
23
- retries: process.env.CI ? 2 : 0,
24
- /* Opt out of parallel tests on CI. */
25
- workers: process.env.CI ? 1 : undefined,
26
- /* Reporter to use. See https://playwright.dev/docs/test-reporters */
27
- reporter: 'html',
28
- /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
29
- use: {
30
- /* Base URL to use in actions like `await page.goto('/')`. */
31
- baseURL: 'http://localhost:3000',
32
-
33
- /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
34
- trace: 'on-first-retry',
35
- },
36
-
37
- /* Configure projects for major browsers */
38
- projects: [
39
- // 1. Login to Grafana and store the cookie on disk for use in other tests.
40
- {
41
- name: 'auth',
42
- testDir: pluginE2eAuth,
43
- testMatch: [/.*\.js/],
44
- },
45
- // 2. Run tests in Google Chrome. Every test will start authenticated as admin user.
46
- {
47
- name: 'chromium',
48
- use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/admin.json' },
49
- dependencies: ['auth'],
50
- },
51
- ],
52
-
53
- });
@@ -1,33 +0,0 @@
1
- import { test, expect } from '@grafana/plugin-e2e';
2
- import { MyDataSourceOptions, MySecureJsonData } from '../src/types';
3
-
4
- test('"Save & test" should be successful when configuration is valid', async ({
5
- createDataSourceConfigPage,
6
- readProvisionedDataSource,
7
- selectors,
8
- page,
9
- }) => {
10
- const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
11
- const configPage = await createDataSourceConfigPage({ type: ds.type });
12
- const healthCheckPath = `${selectors.apis.DataSource.proxy(
13
- configPage.datasource.uid,
14
- configPage.datasource.id.toString()
15
- )}/health`;
16
- await page.route(healthCheckPath, async (route) => await route.fulfill({ status: 200, body: 'OK' }));
17
- await expect(configPage.saveAndTest({ path: healthCheckPath })).toBeOK();
18
- });
19
-
20
- test('"Save & test" should display success alert box when config is valid', async ({
21
- createDataSourceConfigPage,
22
- readProvisionedDataSource,
23
- selectors,
24
- }) => {
25
- const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
26
- const configPage = await createDataSourceConfigPage({ type: ds.type });
27
- const healthCheckPath = `${selectors.apis.DataSource.proxy(
28
- configPage.datasource.uid,
29
- configPage.datasource.id.toString()
30
- )}/health`;
31
- await expect(configPage.saveAndTest({ path: healthCheckPath })).not.toBeOK();
32
- await expect(configPage).toHaveAlert('error');
33
- });
@@ -1,11 +0,0 @@
1
- import { test, expect } from '@grafana/plugin-e2e';
2
-
3
- test('data query should return a value', async ({ panelEditPage, readProvisionedDataSource }) => {
4
- const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
5
- await panelEditPage.datasource.set(ds.name);
6
- await panelEditPage.setVisualization('Table');
7
- await panelEditPage.getQueryEditorRow('A').getByRole('textbox', { name: 'Query Text' }).fill('test query');
8
- await panelEditPage.getQueryEditorRow('A').getByRole('spinbutton').fill('10');
9
- await expect(panelEditPage.panel.fieldNames).toContainText(['Time', 'Value']);
10
- await expect(panelEditPage.panel.data).toContainText(['10']);
11
- });
@@ -1,7 +0,0 @@
1
- apiVersion: 1
2
-
3
- datasources:
4
- - name: TestData DB
5
- type: testdata
6
- uid: trlxrdZVk
7
- isDefault: true
@@ -1,39 +0,0 @@
1
- import { test, expect } from '@grafana/plugin-e2e';
2
-
3
- test('should display "No data" in case panel data is empty', async ({
4
- gotoPanelEditPage,
5
- readProvisionedDashboard,
6
- }) => {
7
- const dashboard = await readProvisionedDashboard({ fileName: 'dashboard.json' });
8
- const panelEditPage = await gotoPanelEditPage({ dashboard, id: '2' });
9
- await expect(panelEditPage.panel.locator).toContainText('No data');
10
- });
11
-
12
- test('should display circle when data is passed to the panel', async ({
13
- panelEditPage,
14
- readProvisionedDataSource,
15
- page,
16
- }) => {
17
- const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
18
- await panelEditPage.datasource.set(ds.name);
19
- await panelEditPage.setVisualization('{{kebabToPascalKebab pluginName }}');
20
- await expect(page.getByTestId('simple-panel-circle')).toBeVisible();
21
- });
22
-
23
- test('should display series counter when "Show series counter" option is enabled', async ({
24
- panelEditPage,
25
- readProvisionedDataSource,
26
- page,
27
- selectors,
28
- }) => {
29
- const ds = await readProvisionedDataSource({ fileName: 'datasources.yml' });
30
- await panelEditPage.datasource.set(ds.name);
31
- await panelEditPage.setVisualization('{{kebabToPascalKebab pluginName }}');
32
- await panelEditPage.collapseSection('{{kebabToPascalKebab pluginName }}');
33
- await expect(page.getByTestId('simple-panel-circle')).toBeVisible();
34
- const showSeriesSwitch = panelEditPage
35
- .getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('{{kebabToPascalKebab pluginName }} Show series counter'))
36
- .getByLabel('Toggle switch');
37
- await showSeriesSwitch.click();
38
- await expect(page.getByTestId('simple-panel-series-counter')).toBeVisible();
39
- });