@grafana/create-plugin 0.0.1
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/.eslintrc +6 -0
- package/.github/workflows/create-release.yml +49 -0
- package/.github/workflows/npm-bump-version.yml +51 -0
- package/.github/workflows/test.yml +31 -0
- package/.prettierrc +10 -0
- package/CONTRIBUTING.md +42 -0
- package/README.md +143 -0
- package/dist/bin/run.js +17 -0
- package/dist/commands/generate.command.js +56 -0
- package/dist/commands/generate.plopfile.js +119 -0
- package/dist/commands/index.js +19 -0
- package/dist/commands/migrate.command.js +133 -0
- package/dist/commands/update.command.js +101 -0
- package/dist/constants.js +74 -0
- package/dist/utils/tests/utils.files.test.js +30 -0
- package/dist/utils/tests/utils.handlebars.test.js +26 -0
- package/dist/utils/tests/utils.npm.test.js +138 -0
- package/dist/utils/tests/utils.plugin.test.js +20 -0
- package/dist/utils/tests/utils.templates.test.js +32 -0
- package/dist/utils/utils.console.js +41 -0
- package/dist/utils/utils.files.js +61 -0
- package/dist/utils/utils.handlebars.js +73 -0
- package/dist/utils/utils.npm.js +162 -0
- package/dist/utils/utils.plugin.js +14 -0
- package/dist/utils/utils.templates.js +77 -0
- package/docs/example.mp4 +0 -0
- package/jest.config.js +20 -0
- package/package.json +69 -0
- package/src/bin/run.ts +15 -0
- package/src/commands/generate.command.ts +15 -0
- package/src/commands/generate.plopfile.ts +151 -0
- package/src/commands/index.ts +3 -0
- package/src/commands/migrate.command.ts +99 -0
- package/src/commands/update.command.ts +66 -0
- package/src/constants.ts +99 -0
- package/src/utils/tests/utils.files.test.ts +41 -0
- package/src/utils/tests/utils.handlebars.test.ts +35 -0
- package/src/utils/tests/utils.npm.test.ts +193 -0
- package/src/utils/tests/utils.plugin.test.ts +22 -0
- package/src/utils/tests/utils.templates.test.ts +44 -0
- package/src/utils/utils.console.ts +41 -0
- package/src/utils/utils.files.ts +65 -0
- package/src/utils/utils.handlebars.ts +47 -0
- package/src/utils/utils.npm.ts +189 -0
- package/src/utils/utils.plugin.ts +9 -0
- package/src/utils/utils.templates.ts +76 -0
- package/templates/_partials/backend-getting-started.md +20 -0
- package/templates/_partials/frontend-getting-started.md +59 -0
- package/templates/app/README.md +20 -0
- package/templates/app/src/components/App/App.test.tsx +32 -0
- package/templates/app/src/components/App/App.tsx +8 -0
- package/templates/app/src/components/App/index.tsx +1 -0
- package/templates/app/src/components/AppConfig/AppConfig.test.tsx +51 -0
- package/templates/app/src/components/AppConfig/AppConfig.tsx +92 -0
- package/templates/app/src/components/AppConfig/index.tsx +1 -0
- package/templates/app/src/module.ts +12 -0
- package/templates/app/src/plugin.json +33 -0
- package/templates/backend/Magefile.go +12 -0
- package/templates/backend/go.mod +5 -0
- package/templates/backend/go.sum +568 -0
- package/templates/backend/pkg/main.go +24 -0
- package/templates/backend/pkg/plugin/datasource.go +111 -0
- package/templates/backend/pkg/plugin/datasource_test.go +28 -0
- package/templates/common/.config/.eslintrc +12 -0
- package/templates/common/.config/.prettierrc.js +16 -0
- package/templates/common/.config/Dockerfile +15 -0
- package/templates/common/.config/README.md +115 -0
- package/templates/common/.config/jest-setup.js +24 -0
- package/templates/common/.config/jest.config.js +31 -0
- package/templates/common/.config/tsconfig.json +17 -0
- package/templates/common/.config/types/custom.d.ts +37 -0
- package/templates/common/.config/webpack/constants.ts +3 -0
- package/templates/common/.config/webpack/tsconfig.webpack.json +9 -0
- package/templates/common/.config/webpack/utils.ts +17 -0
- package/templates/common/.config/webpack/webpack.config.ts +187 -0
- package/templates/common/.eslintrc +3 -0
- package/templates/common/.nvmrc +1 -0
- package/templates/common/.prettierrc.js +4 -0
- package/templates/common/CHANGELOG.md +5 -0
- package/templates/common/LICENSE +201 -0
- package/templates/common/cypress/integration/01-smoke.spec.ts +10 -0
- package/templates/common/docker-compose.yaml +14 -0
- package/templates/common/jest-setup.js +2 -0
- package/templates/common/jest.config.js +4 -0
- package/templates/common/package.json +67 -0
- package/templates/common/src/README.md +5 -0
- package/templates/common/src/img/logo.svg +1 -0
- package/templates/common/tsconfig.json +3 -0
- package/templates/datasource/README.md +20 -0
- package/templates/datasource/src/components/ConfigEditor.tsx +83 -0
- package/templates/datasource/src/components/QueryEditor.tsx +50 -0
- package/templates/datasource/src/datasource.ts +46 -0
- package/templates/datasource/src/module.ts +9 -0
- package/templates/datasource/src/plugin.json +37 -0
- package/templates/datasource/src/types.ts +24 -0
- package/templates/github/ci/.github/workflows/ci.yml +76 -0
- package/templates/github/ci/.github/workflows/release.yml +165 -0
- package/templates/github/is-compatible/.github/workflows/is-compatible.yml +17 -0
- package/templates/panel/README.md +22 -0
- package/templates/panel/src/components/SimplePanel.tsx +62 -0
- package/templates/panel/src/module.test.ts +6 -0
- package/templates/panel/src/module.ts +40 -0
- package/templates/panel/src/plugin.json +33 -0
- package/templates/panel/src/types.ts +7 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
|
|
6
|
+
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
|
7
|
+
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
|
8
|
+
"github.com/{{ kebabCase orgName }}/{{ kebabCase pluginName }}/pkg/plugin"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
func main() {
|
|
12
|
+
// Start listening to requests sent from Grafana. This call is blocking so
|
|
13
|
+
// it won't finish until Grafana shuts down the process or the plugin choose
|
|
14
|
+
// to exit by itself using os.Exit. Manage automatically manages life cycle
|
|
15
|
+
// of datasource instances. It accepts datasource instance factory as first
|
|
16
|
+
// argument. This factory will be automatically called on incoming request
|
|
17
|
+
// from Grafana to create different instances of SampleDatasource (per datasource
|
|
18
|
+
// ID). When datasource configuration changed Dispose method will be called and
|
|
19
|
+
// new datasource instance created using NewSampleDatasource factory.
|
|
20
|
+
if err := datasource.Manage("{{ kebabCase orgName }}-{{ kebabCase pluginName }}", plugin.NewDatasource, datasource.ManageOpts{}); err != nil {
|
|
21
|
+
log.DefaultLogger.Error(err.Error())
|
|
22
|
+
os.Exit(1)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
package plugin
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"math/rand"
|
|
7
|
+
"time"
|
|
8
|
+
|
|
9
|
+
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
10
|
+
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
|
11
|
+
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
|
12
|
+
"github.com/grafana/grafana-plugin-sdk-go/data"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
// Make sure Datasource implements required interfaces. This is important to do
|
|
16
|
+
// since otherwise we will only get a not implemented error response from plugin in
|
|
17
|
+
// runtime. In this example datasource instance implements backend.QueryDataHandler,
|
|
18
|
+
// backend.CheckHealthHandler interfaces. Plugin should not implement all these
|
|
19
|
+
// interfaces- only those which are required for a particular task.
|
|
20
|
+
var (
|
|
21
|
+
_ backend.QueryDataHandler = (*Datasource)(nil)
|
|
22
|
+
_ backend.CheckHealthHandler = (*Datasource)(nil)
|
|
23
|
+
_ instancemgmt.InstanceDisposer = (*Datasource)(nil)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
// NewDatasource creates a new datasource instance.
|
|
27
|
+
func NewDatasource(_ backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
|
28
|
+
return &Datasource{}, nil
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Datasource is an example datasource which can respond to data queries, reports
|
|
32
|
+
// its health and has streaming skills.
|
|
33
|
+
type Datasource struct{}
|
|
34
|
+
|
|
35
|
+
// Dispose here tells plugin SDK that plugin wants to clean up resources when a new instance
|
|
36
|
+
// created. As soon as datasource settings change detected by SDK old datasource instance will
|
|
37
|
+
// be disposed and a new one will be created using NewSampleDatasource factory function.
|
|
38
|
+
func (d *Datasource) Dispose() {
|
|
39
|
+
// Clean up datasource instance resources.
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// QueryData handles multiple queries and returns multiple responses.
|
|
43
|
+
// req contains the queries []DataQuery (where each query contains RefID as a unique identifier).
|
|
44
|
+
// The QueryDataResponse contains a map of RefID to the response for each query, and each response
|
|
45
|
+
// contains Frames ([]*Frame).
|
|
46
|
+
func (d *Datasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
|
47
|
+
log.DefaultLogger.Info("QueryData called", "request", req)
|
|
48
|
+
|
|
49
|
+
// create response struct
|
|
50
|
+
response := backend.NewQueryDataResponse()
|
|
51
|
+
|
|
52
|
+
// loop over queries and execute them individually.
|
|
53
|
+
for _, q := range req.Queries {
|
|
54
|
+
res := d.query(ctx, req.PluginContext, q)
|
|
55
|
+
|
|
56
|
+
// save the response in a hashmap
|
|
57
|
+
// based on with RefID as identifier
|
|
58
|
+
response.Responses[q.RefID] = res
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return response, nil
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type queryModel struct{}
|
|
65
|
+
|
|
66
|
+
func (d *Datasource) query(_ context.Context, pCtx backend.PluginContext, query backend.DataQuery) backend.DataResponse {
|
|
67
|
+
response := backend.DataResponse{}
|
|
68
|
+
|
|
69
|
+
// Unmarshal the JSON into our queryModel.
|
|
70
|
+
var qm queryModel
|
|
71
|
+
|
|
72
|
+
response.Error = json.Unmarshal(query.JSON, &qm)
|
|
73
|
+
if response.Error != nil {
|
|
74
|
+
return response
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// create data frame response.
|
|
78
|
+
frame := data.NewFrame("response")
|
|
79
|
+
|
|
80
|
+
// add fields.
|
|
81
|
+
frame.Fields = append(frame.Fields,
|
|
82
|
+
data.NewField("time", nil, []time.Time{query.TimeRange.From, query.TimeRange.To}),
|
|
83
|
+
data.NewField("values", nil, []int64{10, 20}),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
// add the frames to the response.
|
|
87
|
+
response.Frames = append(response.Frames, frame)
|
|
88
|
+
|
|
89
|
+
return response
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// CheckHealth handles health checks sent from Grafana to the plugin.
|
|
93
|
+
// The main use case for these health checks is the test button on the
|
|
94
|
+
// datasource configuration page which allows users to verify that
|
|
95
|
+
// a datasource is working as expected.
|
|
96
|
+
func (d *Datasource) CheckHealth(_ context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
|
97
|
+
log.DefaultLogger.Info("CheckHealth called", "request", req)
|
|
98
|
+
|
|
99
|
+
var status = backend.HealthStatusOk
|
|
100
|
+
var message = "Data source is working"
|
|
101
|
+
|
|
102
|
+
if rand.Int()%2 == 0 {
|
|
103
|
+
status = backend.HealthStatusError
|
|
104
|
+
message = "randomized error"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return &backend.CheckHealthResult{
|
|
108
|
+
Status: status,
|
|
109
|
+
Message: message,
|
|
110
|
+
}, nil
|
|
111
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package plugin
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"testing"
|
|
6
|
+
|
|
7
|
+
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func TestQueryData(t *testing.T) {
|
|
11
|
+
ds := Datasource{}
|
|
12
|
+
|
|
13
|
+
resp, err := ds.QueryData(
|
|
14
|
+
context.Background(),
|
|
15
|
+
&backend.QueryDataRequest{
|
|
16
|
+
Queries: []backend.DataQuery{
|
|
17
|
+
{RefID: "A"},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
)
|
|
21
|
+
if err != nil {
|
|
22
|
+
t.Error(err)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if len(resp.Responses) != 1 {
|
|
26
|
+
t.Fatal("QueryData must return a response")
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
"extends": ["@grafana/eslint-config"],
|
|
8
|
+
"root": true,
|
|
9
|
+
"rules": {
|
|
10
|
+
"react/prop-types": "off"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
module.exports = {
|
|
8
|
+
"endOfLine": "auto",
|
|
9
|
+
"printWidth": 120,
|
|
10
|
+
"trailingComma": "es5",
|
|
11
|
+
"semi": true,
|
|
12
|
+
"jsxSingleQuote": false,
|
|
13
|
+
"singleQuote": true,
|
|
14
|
+
"useTabs": false,
|
|
15
|
+
"tabWidth": 2
|
|
16
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ARG grafana_version=latest
|
|
2
|
+
|
|
3
|
+
FROM grafana/grafana:${grafana_version}
|
|
4
|
+
|
|
5
|
+
# Make it as simple as possible to access the grafana instance for development purposes
|
|
6
|
+
# Do NOT enable these settings in a public facing / production grafana instance
|
|
7
|
+
ENV GF_AUTH_ANONYMOUS_ORG_ROLE "Admin"
|
|
8
|
+
ENV GF_AUTH_ANONYMOUS_ENABLED "true"
|
|
9
|
+
ENV GF_AUTH_BASIC_ENABLED "false"
|
|
10
|
+
# Set development mode so plugins can be loaded without the need to sign
|
|
11
|
+
ENV GF_DEFAULT_APP_MODE "development"
|
|
12
|
+
|
|
13
|
+
# Inject livereload script into grafana index.html
|
|
14
|
+
USER root
|
|
15
|
+
RUN sed -i 's/<\/body><\/html>/<script src=\"http:\/\/localhost:35729\/livereload.js\"><\/script><\/body><\/html>/g' /usr/share/grafana/public/views/index.html
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Default build configuration by Grafana
|
|
2
|
+
|
|
3
|
+
**This is an auto-generated directory and is not intended to be changed! ⚠️**
|
|
4
|
+
|
|
5
|
+
The `.config/` directory holds basic configuration for the different tools
|
|
6
|
+
that are used to develop, test and build the project. In order to make it updates easier we ask you to
|
|
7
|
+
not edit files in this folder to extend configuration.
|
|
8
|
+
|
|
9
|
+
## How to extend the basic configs?
|
|
10
|
+
|
|
11
|
+
Bear in mind that you are doing it at your own risk, and that extending any of the basic configuration can lead
|
|
12
|
+
to issues around working with the project.
|
|
13
|
+
|
|
14
|
+
### Extending the ESLint config
|
|
15
|
+
|
|
16
|
+
Edit the `.eslintrc` file in the project root in order to extend the ESLint configuration.
|
|
17
|
+
|
|
18
|
+
**Example:**
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"extends": "./.config/.eslintrc",
|
|
22
|
+
"rules": {
|
|
23
|
+
"react/prop-types": "off"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
### Extending the Prettier config
|
|
31
|
+
|
|
32
|
+
Edit the `.prettierrc.js` file in the project root in order to extend the Prettier configuration.
|
|
33
|
+
|
|
34
|
+
**Example:**
|
|
35
|
+
```javascript
|
|
36
|
+
module.exports = {
|
|
37
|
+
// Prettier configuration provided by Grafana scaffolding
|
|
38
|
+
...require("./.config/.prettierrc.js"),
|
|
39
|
+
|
|
40
|
+
semi: false,
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### Extending the Jest config
|
|
47
|
+
|
|
48
|
+
There are two configuration in the project root that belong to Jest: `jest-setup.js` and `jest.config.js`.
|
|
49
|
+
|
|
50
|
+
**`jest-setup.js`:** A file that is run before each test file in the suite is executed. We are using it to
|
|
51
|
+
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))
|
|
52
|
+
|
|
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))
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
### Extending the TypeScript config
|
|
58
|
+
|
|
59
|
+
Edit the `tsconfig.json` file in the project root in order to extend the TypeScript configuration.
|
|
60
|
+
|
|
61
|
+
**Example:**
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"extends": "./.config/tsconfig.json",
|
|
65
|
+
"compilerOptions": {
|
|
66
|
+
"preserveConstEnums": true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### Extending the Webpack config
|
|
74
|
+
|
|
75
|
+
Follow these steps to extend the basic Webpack configuration that lives under `.config/`:
|
|
76
|
+
|
|
77
|
+
#### 1. Create a new Webpack configuration file
|
|
78
|
+
|
|
79
|
+
Create a new config file that is going to extend the basic one provided by Grafana.
|
|
80
|
+
It can live in the project root, e.g. `webpack.config.ts`.
|
|
81
|
+
|
|
82
|
+
#### 2. Merge the basic config provided by Grafana and your custom setup
|
|
83
|
+
We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge) for this.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// webpack.config.ts
|
|
87
|
+
import { merge } from 'webpack-merge';
|
|
88
|
+
import grafanaConfig from './.config/webpack/webpack.config';
|
|
89
|
+
|
|
90
|
+
const config = (env) =>
|
|
91
|
+
merge(grafanaConfig(env), {
|
|
92
|
+
// Add custom config here...
|
|
93
|
+
output: {
|
|
94
|
+
asyncChunks: true,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
export default config;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### 3. Update the `package.json` to use the new Webpack config
|
|
102
|
+
|
|
103
|
+
We need to update the `scripts` in the `package.json` to use the extended Webpack configuration.
|
|
104
|
+
|
|
105
|
+
**Update for `build`:**
|
|
106
|
+
```diff
|
|
107
|
+
-"build": "TS_NODE_PROJECT=\"./.config/webpack/tsconfig.webpack.json\" webpack -c ./.config/webpack/webpack.config.ts --env production",
|
|
108
|
+
+"build": "TS_NODE_PROJECT=\"./.config/webpack/tsconfig.webpack.json\" webpack -c ./webpack.config.ts --env production",
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Update for `dev`:**
|
|
112
|
+
```diff
|
|
113
|
+
-"dev": "TS_NODE_PROJECT=\"./.config/webpack/tsconfig.webpack.json\" webpack -w -c ./.config/webpack/webpack.config.ts --env development",
|
|
114
|
+
+"dev": "TS_NODE_PROJECT=\"./.config/webpack/tsconfig.webpack.json\" webpack -w -c ./webpack.config.ts --env development",
|
|
115
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
import '@testing-library/jest-dom';
|
|
8
|
+
|
|
9
|
+
// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
|
|
10
|
+
Object.defineProperty(global, 'matchMedia', {
|
|
11
|
+
writable: true,
|
|
12
|
+
value: jest.fn().mockImplementation((query) => ({
|
|
13
|
+
matches: false,
|
|
14
|
+
media: query,
|
|
15
|
+
onchange: null,
|
|
16
|
+
addListener: jest.fn(), // deprecated
|
|
17
|
+
removeListener: jest.fn(), // deprecated
|
|
18
|
+
addEventListener: jest.fn(),
|
|
19
|
+
removeEventListener: jest.fn(),
|
|
20
|
+
dispatchEvent: jest.fn(),
|
|
21
|
+
})),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
HTMLCanvasElement.prototype.getContext = () => {};
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
module.exports = {
|
|
8
|
+
testEnvironment: 'jest-environment-jsdom',
|
|
9
|
+
testMatch: [
|
|
10
|
+
'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',
|
|
11
|
+
'<rootDir>/src/**/*.{spec,test,jest}.{js,jsx,ts,tsx}',
|
|
12
|
+
'<rootDir>/src/**/*.{spec,test,jest}.{js,jsx,ts,tsx}',
|
|
13
|
+
],
|
|
14
|
+
transform: {
|
|
15
|
+
'^.+\\.(t|j)sx?$': [
|
|
16
|
+
'@swc/jest',
|
|
17
|
+
{
|
|
18
|
+
sourceMaps: true,
|
|
19
|
+
jsc: {
|
|
20
|
+
parser: {
|
|
21
|
+
syntax: 'typescript',
|
|
22
|
+
tsx: true,
|
|
23
|
+
decorators: false,
|
|
24
|
+
dynamicImport: true,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
setupFilesAfterEnv: ['<rootDir>/jest-setup.js'],
|
|
31
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
"compilerOptions": {
|
|
8
|
+
"alwaysStrict": true,
|
|
9
|
+
"declaration": false,
|
|
10
|
+
"rootDir": "../src",
|
|
11
|
+
"baseUrl": "../src",
|
|
12
|
+
"typeRoots": ["../node_modules/@types"],
|
|
13
|
+
"resolveJsonModule": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["../src", "./types"],
|
|
16
|
+
"extends": "@grafana/tsconfig"
|
|
17
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Image declarations
|
|
2
|
+
declare module '*.gif' {
|
|
3
|
+
const src: string;
|
|
4
|
+
export default src;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
declare module '*.jpg' {
|
|
8
|
+
const src: string;
|
|
9
|
+
export default src;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare module '*.jpeg' {
|
|
13
|
+
const src: string;
|
|
14
|
+
export default src;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare module '*.png' {
|
|
18
|
+
const src: string;
|
|
19
|
+
export default src;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare module '*.webp' {
|
|
23
|
+
const src: string;
|
|
24
|
+
export default src;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
declare module '*.svg' {
|
|
28
|
+
const content: string;
|
|
29
|
+
export default content;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Font declarations
|
|
33
|
+
declare module '*.woff';
|
|
34
|
+
declare module '*.woff2';
|
|
35
|
+
declare module '*.eot';
|
|
36
|
+
declare module '*.ttf';
|
|
37
|
+
declare module '*.otf';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { SOURCE_DIR } from './constants';
|
|
4
|
+
|
|
5
|
+
export function getPackageJson() {
|
|
6
|
+
return require(path.resolve(process.cwd(), 'package.json'));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getPluginId() {
|
|
10
|
+
const { id } = require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));
|
|
11
|
+
|
|
12
|
+
return id;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function hasReadme() {
|
|
16
|
+
return fs.existsSync(path.resolve(process.cwd(), SOURCE_DIR, 'README.md'));
|
|
17
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
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
|
+
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
|
8
|
+
import ESLintPlugin from 'eslint-webpack-plugin';
|
|
9
|
+
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
|
10
|
+
import LiveReloadPlugin from 'webpack-livereload-plugin';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
|
|
13
|
+
import { Configuration } from 'webpack';
|
|
14
|
+
|
|
15
|
+
import { getPackageJson, getPluginId, hasReadme } from './utils';
|
|
16
|
+
import { SOURCE_DIR, DIST_DIR, ENTRY_FILE } from './constants';
|
|
17
|
+
|
|
18
|
+
const config = (env): Configuration => ({
|
|
19
|
+
cache: {
|
|
20
|
+
type: 'filesystem',
|
|
21
|
+
buildDependencies: {
|
|
22
|
+
config: [__filename],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
context: path.join(process.cwd(), SOURCE_DIR),
|
|
27
|
+
|
|
28
|
+
devtool: env.production ? 'source-map' : 'eval-source-map',
|
|
29
|
+
|
|
30
|
+
entry: {
|
|
31
|
+
module: path.resolve(process.cwd(), ENTRY_FILE),
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
externals: [
|
|
35
|
+
'lodash',
|
|
36
|
+
'jquery',
|
|
37
|
+
'moment',
|
|
38
|
+
'slate',
|
|
39
|
+
'emotion',
|
|
40
|
+
'@emotion/react',
|
|
41
|
+
'@emotion/css',
|
|
42
|
+
'prismjs',
|
|
43
|
+
'slate-plain-serializer',
|
|
44
|
+
'@grafana/slate-react',
|
|
45
|
+
'react',
|
|
46
|
+
'react-dom',
|
|
47
|
+
'react-redux',
|
|
48
|
+
'redux',
|
|
49
|
+
'rxjs',
|
|
50
|
+
'react-router-dom',
|
|
51
|
+
'd3',
|
|
52
|
+
'angular',
|
|
53
|
+
'@grafana/ui',
|
|
54
|
+
'@grafana/runtime',
|
|
55
|
+
'@grafana/data',
|
|
56
|
+
|
|
57
|
+
// Mark legacy SDK imports as external if their name starts with the "grafana/" prefix
|
|
58
|
+
({ request }, callback) => {
|
|
59
|
+
const prefix = 'grafana/';
|
|
60
|
+
const hasPrefix = (request) => request.indexOf(prefix) === 0;
|
|
61
|
+
const stripPrefix = (request) => request.substr(prefix.length);
|
|
62
|
+
|
|
63
|
+
if (hasPrefix(request)) {
|
|
64
|
+
return callback(null, stripPrefix(request));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
callback();
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
|
|
71
|
+
mode: env.production ? 'production' : 'development',
|
|
72
|
+
|
|
73
|
+
module: {
|
|
74
|
+
rules: [
|
|
75
|
+
{
|
|
76
|
+
exclude: /(node_modules)/,
|
|
77
|
+
test: /\.[tj]sx?$/,
|
|
78
|
+
use: {
|
|
79
|
+
loader: 'swc-loader',
|
|
80
|
+
options: {
|
|
81
|
+
jsc: {
|
|
82
|
+
baseUrl: './src',
|
|
83
|
+
target: 'es2015',
|
|
84
|
+
loose: false,
|
|
85
|
+
parser: {
|
|
86
|
+
syntax: 'typescript',
|
|
87
|
+
tsx: true,
|
|
88
|
+
decorators: false,
|
|
89
|
+
dynamicImport: true,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
test: /\.(png|jpe?g|gif|svg)$/,
|
|
97
|
+
use: [
|
|
98
|
+
{
|
|
99
|
+
loader: 'asset/resource',
|
|
100
|
+
options: {
|
|
101
|
+
outputPath: '/',
|
|
102
|
+
name: Boolean(env.production) ? '[path][hash].[ext]' : '[path][name].[ext]',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
test: /\.(woff|woff2|eot|ttf|otf)(\?v=\d+\.\d+\.\d+)?$/,
|
|
109
|
+
loader: 'asset/resource',
|
|
110
|
+
options: {
|
|
111
|
+
// Keep publicPath relative for host.com/grafana/ deployments
|
|
112
|
+
publicPath: `public/plugins/${getPluginId()}/fonts`,
|
|
113
|
+
outputPath: 'fonts',
|
|
114
|
+
name: Boolean(env.production) ? '[hash].[ext]' : '[name].[ext]',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
output: {
|
|
121
|
+
clean: true,
|
|
122
|
+
filename: '[name].js',
|
|
123
|
+
libraryTarget: 'amd',
|
|
124
|
+
path: path.resolve(process.cwd(), DIST_DIR),
|
|
125
|
+
publicPath: '/',
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
plugins: [
|
|
129
|
+
new CopyWebpackPlugin({
|
|
130
|
+
patterns: [
|
|
131
|
+
// If src/README.md exists use it; otherwise the root README
|
|
132
|
+
// To `compiler.options.output`
|
|
133
|
+
{ from: hasReadme() ? 'README.md' : '../README.md', to: '.', force: true },
|
|
134
|
+
{ from: 'plugin.json', to: '.' },
|
|
135
|
+
{ from: '../LICENSE', to: '.' },
|
|
136
|
+
{ from: '../CHANGELOG.md', to: '.', force: true },
|
|
137
|
+
{ from: '**/*.json', to: '.' }, // TODO<Add an error for checking the basic structure of the repo>
|
|
138
|
+
{ from: '**/*.svg', to: '.', noErrorOnMissing: true }, // Optional
|
|
139
|
+
{ from: '**/*.png', to: '.', noErrorOnMissing: true }, // Optional
|
|
140
|
+
{ from: '**/*.html', to: '.', noErrorOnMissing: true }, // Optional
|
|
141
|
+
{ from: 'img/**/*', to: '.', noErrorOnMissing: true }, // Optional
|
|
142
|
+
{ from: 'libs/**/*', to: '.', noErrorOnMissing: true }, // Optional
|
|
143
|
+
{ from: 'static/**/*', to: '.', noErrorOnMissing: true }, // Optional
|
|
144
|
+
],
|
|
145
|
+
}),
|
|
146
|
+
// Replace certain template-variables in the README and plugin.json
|
|
147
|
+
new ReplaceInFileWebpackPlugin([
|
|
148
|
+
{
|
|
149
|
+
dir: DIST_DIR,
|
|
150
|
+
files: ['plugin.json', 'README.md'],
|
|
151
|
+
rules: [
|
|
152
|
+
{
|
|
153
|
+
search: /\%VERSION\%/g,
|
|
154
|
+
replace: getPackageJson().version,
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
search: /\%TODAY\%/g,
|
|
158
|
+
replace: new Date().toISOString().substring(0, 10),
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
search: /\%PLUGIN_ID\%/g,
|
|
162
|
+
replace: getPluginId(),
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
]),
|
|
167
|
+
new ForkTsCheckerWebpackPlugin({
|
|
168
|
+
async: Boolean(env.development),
|
|
169
|
+
issue: {
|
|
170
|
+
include: [{ file: '**/*.{ts,tsx}' }],
|
|
171
|
+
},
|
|
172
|
+
typescript: { configFile: path.join(process.cwd(), 'tsconfig.json') },
|
|
173
|
+
}),
|
|
174
|
+
new ESLintPlugin({
|
|
175
|
+
extensions: ['.ts', '.tsx'],
|
|
176
|
+
lintDirtyModulesOnly: Boolean(env.development), // don't lint on start, only lint changed files
|
|
177
|
+
}),
|
|
178
|
+
...(env.development ? [new LiveReloadPlugin()] : []),
|
|
179
|
+
],
|
|
180
|
+
|
|
181
|
+
resolve: {
|
|
182
|
+
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
183
|
+
unsafeCache: true,
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
export default config;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
14
|