Skip to content

Commit 352ca13

Browse files
committed
Add github action, update packages and config.
1 parent 6a7bc31 commit 352ca13

24 files changed

+2281
-2134
lines changed

.config/.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*
22
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
33
*
4-
* In order to extend the configuration follow the steps in .config/README.md
4+
* In order to extend the configuration follow the steps in
5+
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-eslint-config
56
*/
67
{
78
"extends": ["@grafana/eslint-config"],

.config/.prettierrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ module.exports = {
1313
"singleQuote": true,
1414
"useTabs": false,
1515
"tabWidth": 2
16-
};
16+
};

.config/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
ARG grafana_version=latest
2+
ARG grafana_image=grafana-enterprise
23

3-
FROM grafana/grafana:9.5.1
4+
FROM grafana/${grafana_image}:${grafana_version}
45

56
# Make it as simple as possible to access the grafana instance for development purposes
67
# Do NOT enable these settings in a public facing / production grafana instance

.config/README.md

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ to issues around working with the project.
1616
Edit the `.eslintrc` file in the project root in order to extend the ESLint configuration.
1717

1818
**Example:**
19+
1920
```json
2021
{
2122
"extends": "./.config/.eslintrc",
2223
"rules": {
23-
"react/prop-types": "off"
24+
"react/prop-types": "off"
2425
}
2526
}
2627
```
@@ -32,10 +33,11 @@ Edit the `.eslintrc` file in the project root in order to extend the ESLint conf
3233
Edit the `.prettierrc.js` file in the project root in order to extend the Prettier configuration.
3334

3435
**Example:**
36+
3537
```javascript
3638
module.exports = {
3739
// Prettier configuration provided by Grafana scaffolding
38-
...require("./.config/.prettierrc.js"),
40+
...require('./.config/.prettierrc.js'),
3941

4042
semi: false,
4143
};
@@ -50,7 +52,23 @@ There are two configuration in the project root that belong to Jest: `jest-setup
5052
**`jest-setup.js`:** A file that is run before each test file in the suite is executed. We are using it to
5153
set up the Jest DOM for the testing library and to apply some polyfills. ([link to Jest docs](https://jestjs.io/docs/configuration#setupfilesafterenv-array))
5254

53-
**`jest.config.js`:** The main Jest configuration file that is extending our basic Grafana-tailored setup. ([link to Jest docs](https://jestjs.io/docs/configuration))
55+
**`jest.config.js`:** The main Jest configuration file that extends the Grafana recommended setup. ([link to Jest docs](https://jestjs.io/docs/configuration))
56+
57+
#### ESM errors with Jest
58+
59+
A common issue found with the current jest config involves importing an npm package which only offers an ESM build. These packages cause jest to error with `SyntaxError: Cannot use import statement outside a module`. To work around this we provide a list of known packages to pass to the `[transformIgnorePatterns](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring)` jest configuration property. If need be this can be extended in the following way:
60+
61+
```javascript
62+
process.env.TZ = 'UTC';
63+
const { grafanaESModules, nodeModulesToTransform } = require('./config/jest/utils');
64+
65+
module.exports = {
66+
// Jest configuration provided by Grafana
67+
...require('./.config/jest.config'),
68+
// Inform jest to only transform specific node_module packages.
69+
transformIgnorePatterns: [nodeModulesToTransform([...grafanaESModules, 'packageName'])],
70+
};
71+
```
5472

5573
---
5674

@@ -59,6 +77,7 @@ set up the Jest DOM for the testing library and to apply some polyfills. ([link
5977
Edit the `tsconfig.json` file in the project root in order to extend the TypeScript configuration.
6078

6179
**Example:**
80+
6281
```json
6382
{
6483
"extends": "./.config/tsconfig.json",
@@ -80,6 +99,7 @@ Create a new config file that is going to extend the basic one provided by Grafa
8099
It can live in the project root, e.g. `webpack.config.ts`.
81100

82101
#### 2. Merge the basic config provided by Grafana and your custom setup
102+
83103
We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge) for this.
84104

85105
```typescript
@@ -100,21 +120,45 @@ const config = async (env): Promise<Configuration> => {
100120
};
101121

102122
export default config;
103-
104123
```
105124

106125
#### 3. Update the `package.json` to use the new Webpack config
107126

108127
We need to update the `scripts` in the `package.json` to use the extended Webpack configuration.
109128

110129
**Update for `build`:**
130+
111131
```diff
112132
-"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",
113133
+"build": "webpack -c ./webpack.config.ts --env production",
114134
```
115135

116136
**Update for `dev`:**
137+
117138
```diff
118139
-"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
119140
+"dev": "webpack -w -c ./webpack.config.ts --env development",
120141
```
142+
143+
### Configure grafana image to use when running docker
144+
145+
By default `grafana-enterprise` will be used as the docker image for all docker related commands. If you want to override this behaviour simply alter the `docker-compose.yaml` by adding the following build arg `grafana_image`.
146+
147+
**Example:**
148+
149+
```yaml
150+
version: '3.7'
151+
152+
services:
153+
grafana:
154+
container_name: 'myorg-basic-app'
155+
build:
156+
context: ./.config
157+
args:
158+
grafana_version: ${GRAFANA_VERSION:-9.1.2}
159+
grafana_image: ${GRAFANA_IMAGE:-grafana}
160+
```
161+
162+
In this example we are assigning the environment variable `GRAFANA_IMAGE` to the build arg `grafana_image` with a default value of `grafana`. This will give you the possibility to set the value while running the docker-compose commands which might be convinent in some scenarios.
163+
164+
---

.config/jest-setup.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*
22
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
33
*
4-
* In order to extend the configuration follow the steps in .config/README.md
4+
* In order to extend the configuration follow the steps in
5+
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-jest-config
56
*/
67

78
import '@testing-library/jest-dom';

.config/jest.config.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
/*
22
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
33
*
4-
* In order to extend the configuration follow the steps in .config/README.md
4+
* In order to extend the configuration follow the steps in
5+
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-jest-config
56
*/
67

8+
const path = require('path');
9+
const { grafanaESModules, nodeModulesToTransform } = require('./jest/utils');
10+
711
module.exports = {
812
moduleNameMapper: {
9-
"\\.(css|scss|sass)$": "identity-obj-proxy",
13+
'\\.(css|scss|sass)$': 'identity-obj-proxy',
14+
'react-inlinesvg': path.resolve(__dirname, 'jest', 'mocks', 'react-inlinesvg.tsx'),
1015
},
1116
modulePaths: ['<rootDir>/src'],
1217
setupFilesAfterEnv: ['<rootDir>/jest-setup.js'],
@@ -32,5 +37,7 @@ module.exports = {
3237
},
3338
],
3439
},
35-
transformIgnorePatterns: [],
40+
// Jest will throw `Cannot use import statement outside module` if it tries to load an
41+
// ES module without it being transformed first. ./config/README.md#esm-errors-with-jest
42+
transformIgnorePatterns: [nodeModulesToTransform(grafanaESModules)],
3643
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Due to the grafana/ui Icon component making fetch requests to
2+
// `/public/img/icon/<icon_name>.svg` we need to mock react-inlinesvg to prevent
3+
// the failed fetch requests from displaying errors in console.
4+
5+
import React from 'react';
6+
7+
type Callback = (...args: any[]) => void;
8+
9+
export interface StorageItem {
10+
content: string;
11+
queue: Callback[];
12+
status: string;
13+
}
14+
15+
export const cacheStore: { [key: string]: StorageItem } = Object.create(null);
16+
17+
const SVG_FILE_NAME_REGEX = /(.+)\/(.+)\.svg$/;
18+
19+
const InlineSVG = ({ src }: { src: string }) => {
20+
// testId will be the file name without extension (e.g. `public/img/icons/angle-double-down.svg` -> `angle-double-down`)
21+
const testId = src.replace(SVG_FILE_NAME_REGEX, '$2');
22+
return <svg xmlns="http://www.w3.org/2000/svg" data-testid={testId} viewBox="0 0 24 24" />;
23+
};
24+
25+
export default InlineSVG;

.config/jest/utils.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
3+
*
4+
* In order to extend the configuration follow the steps in .config/README.md
5+
*/
6+
7+
/*
8+
* This utility function is useful in combination with jest `transformIgnorePatterns` config
9+
* to transform specific packages (e.g.ES modules) in a projects node_modules folder.
10+
*/
11+
const nodeModulesToTransform = (moduleNames) => `node_modules\/(?!(${moduleNames.join('|')})\/)`;
12+
13+
// Array of known nested grafana package dependencies that only bundle an ESM version
14+
const grafanaESModules = [
15+
'.pnpm', // Support using pnpm symlinked packages
16+
'd3',
17+
'd3-color',
18+
'd3-force',
19+
'd3-interpolate',
20+
'd3-scale-chromatic',
21+
'ol',
22+
'react-colorful',
23+
'uuid',
24+
];
25+
26+
module.exports = {
27+
nodeModulesToTransform,
28+
grafanaESModules
29+
}

.config/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*
22
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
33
*
4-
* In order to extend the configuration follow the steps in .config/README.md
4+
* In order to extend the configuration follow the steps in
5+
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-typescript-config
56
*/
67
{
78
"compilerOptions": {

.config/webpack/utils.ts

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,40 @@
11
import fs from 'fs';
22
import path from 'path';
33
import util from 'util';
4-
import glob from 'glob';
4+
import { glob } from 'glob';
55
import { SOURCE_DIR } from './constants';
66

7-
const globAsync = util.promisify(glob);
8-
97
export function getPackageJson() {
108
return require(path.resolve(process.cwd(), 'package.json'));
119
}
1210

13-
export function getPluginId() {
14-
const { id } = require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));
15-
16-
return id;
11+
export function getPluginJson() {
12+
return require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));
1713
}
1814

1915
export function hasReadme() {
2016
return fs.existsSync(path.resolve(process.cwd(), SOURCE_DIR, 'README.md'));
2117
}
2218

19+
// Support bundling nested plugins by finding all plugin.json files in src directory
20+
// then checking for a sibling module.[jt]sx? file.
2321
export async function getEntries(): Promise<Record<string, string>> {
24-
const parent = '..';
25-
const pluginsJson = await globAsync('**/src/**/plugin.json');
26-
27-
const plugins = await Promise.all(pluginsJson.map(pluginJson => {
28-
const folder = path.dirname(pluginJson);
29-
return globAsync(`${folder}/module.{ts,tsx,js}`);
30-
}));
22+
const pluginsJson = await glob('**/src/**/plugin.json', { absolute: true });
23+
24+
const plugins = await Promise.all(pluginsJson.map((pluginJson) => {
25+
const folder = path.dirname(pluginJson);
26+
return glob(`${folder}/module.{ts,tsx,js,jsx}`, { absolute: true });
27+
})
28+
);
3129

3230
return plugins.reduce((result, modules) => {
3331
return modules.reduce((result, module) => {
34-
const pluginPath = path.resolve(path.dirname(module), parent);
35-
const pluginName = path.basename(pluginPath);
36-
const entryName = plugins.length > 1 ? `${pluginName}/module` : 'module';
37-
38-
result[entryName] = path.join(parent, module);
32+
const pluginPath = path.dirname(module);
33+
const pluginName = path.relative(process.cwd(), pluginPath).replace(/src\/?/i, '');
34+
const entryName = pluginName === '' ? 'module' : `${pluginName}/module`;
35+
36+
result[entryName] = module;
3937
return result;
4038
}, result);
4139
}, {});
42-
}
40+
}

.config/webpack/webpack.config.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/*
22
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
33
*
4-
* In order to extend the configuration follow the steps in .config/README.md
4+
* In order to extend the configuration follow the steps in
5+
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-webpack-config
56
*/
67

78
import CopyWebpackPlugin from 'copy-webpack-plugin';
@@ -12,9 +13,11 @@ import path from 'path';
1213
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
1314
import { Configuration } from 'webpack';
1415

15-
import { getPackageJson, getPluginId, hasReadme, getEntries } from './utils';
16+
import { getPackageJson, getPluginJson, hasReadme, getEntries } from './utils';
1617
import { SOURCE_DIR, DIST_DIR } from './constants';
1718

19+
const pluginJson = getPluginJson();
20+
1821
const config = async (env): Promise<Configuration> => ({
1922
cache: {
2023
type: 'filesystem',
@@ -96,7 +99,6 @@ const config = async (env): Promise<Configuration> => ({
9699
use: ["style-loader", "css-loader"]
97100
},
98101
{
99-
exclude: /(node_modules)/,
100102
test: /\.s[ac]ss$/,
101103
use: ['style-loader', 'css-loader', 'sass-loader'],
102104
},
@@ -105,7 +107,7 @@ const config = async (env): Promise<Configuration> => ({
105107
type: 'asset/resource',
106108
generator: {
107109
// Keep publicPath relative for host.com/grafana/ deployments
108-
publicPath: `public/plugins/${getPluginId()}/img/`,
110+
publicPath: `public/plugins/${pluginJson.id}/img/`,
109111
outputPath: 'img/',
110112
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
111113
},
@@ -115,7 +117,7 @@ const config = async (env): Promise<Configuration> => ({
115117
type: 'asset/resource',
116118
generator: {
117119
// Keep publicPath relative for host.com/grafana/ deployments
118-
publicPath: `public/plugins/${getPluginId()}/fonts`,
120+
publicPath: `public/plugins/${pluginJson.id}/fonts`,
119121
outputPath: 'fonts/',
120122
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
121123
},
@@ -125,7 +127,7 @@ const config = async (env): Promise<Configuration> => ({
125127

126128
output: {
127129
clean: {
128-
keep: /gpx_.*/,
130+
keep: new RegExp(`.*?_(amd64|arm(64)?)(.exe)?`),
129131
},
130132
filename: '[name].js',
131133
library: {
@@ -169,7 +171,7 @@ const config = async (env): Promise<Configuration> => ({
169171
},
170172
{
171173
search: /\%PLUGIN_ID\%/g,
172-
replace: getPluginId(),
174+
replace: pluginJson.id,
173175
},
174176
],
175177
},

0 commit comments

Comments
 (0)