@grafana/create-plugin 1.0.0-canary.193.98effed.0 → 1.0.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 +41 -0
- package/package.json +2 -2
- package/templates/backend/pkg/plugin/datasource.go +4 -1
- package/templates/common/.config/Dockerfile +2 -1
- package/templates/common/.config/README.md +23 -0
- package/templates/datasource/src/components/ConfigEditor.tsx +31 -47
- package/templates/datasource/src/components/QueryEditor.tsx +16 -31
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
# v1.0.0 (Fri Feb 03 2023)
|
|
2
|
+
|
|
3
|
+
#### 💥 Breaking Change
|
|
4
|
+
|
|
5
|
+
- Introduce version commands [#193](https://github.com/grafana/plugin-tools/pull/193) ([@jackw](https://github.com/jackw))
|
|
6
|
+
|
|
7
|
+
#### Authors: 1
|
|
8
|
+
|
|
9
|
+
- Jack Westbrook ([@jackw](https://github.com/jackw))
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# v0.11.0 (Fri Feb 03 2023)
|
|
14
|
+
|
|
15
|
+
:tada: This release contains work from a new contributor! :tada:
|
|
16
|
+
|
|
17
|
+
Thank you, Isabella Siu ([@iwysiu](https://github.com/iwysiu)), for all your work!
|
|
18
|
+
|
|
19
|
+
#### 🚀 Enhancement
|
|
20
|
+
|
|
21
|
+
- Update datasource plugin template [#172](https://github.com/grafana/plugin-tools/pull/172) ([@iwysiu](https://github.com/iwysiu) [@jackw](https://github.com/jackw))
|
|
22
|
+
|
|
23
|
+
#### Authors: 2
|
|
24
|
+
|
|
25
|
+
- Isabella Siu ([@iwysiu](https://github.com/iwysiu))
|
|
26
|
+
- Jack Westbrook ([@jackw](https://github.com/jackw))
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
# v0.10.0 (Thu Feb 02 2023)
|
|
31
|
+
|
|
32
|
+
#### 🚀 Enhancement
|
|
33
|
+
|
|
34
|
+
- CreatePlugin: Change default docker image to grafana-enterprise [#197](https://github.com/grafana/plugin-tools/pull/197) ([@mckn](https://github.com/mckn))
|
|
35
|
+
|
|
36
|
+
#### Authors: 1
|
|
37
|
+
|
|
38
|
+
- Marcus Andersson ([@mckn](https://github.com/mckn))
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
1
42
|
# v0.9.1 (Thu Feb 02 2023)
|
|
2
43
|
|
|
3
44
|
#### 🐛 Bug Fix
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafana/create-plugin",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"directory": "packages/create-plugin",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=16"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "1b6746b0c95271772741cf1a8cba405919f53874"
|
|
64
64
|
}
|
|
@@ -3,6 +3,7 @@ package plugin
|
|
|
3
3
|
import (
|
|
4
4
|
"context"
|
|
5
5
|
"encoding/json"
|
|
6
|
+
"fmt"
|
|
6
7
|
"math/rand"
|
|
7
8
|
"time"
|
|
8
9
|
|
|
@@ -73,10 +74,12 @@ func (d *Datasource) query(_ context.Context, pCtx backend.PluginContext, query
|
|
|
73
74
|
|
|
74
75
|
err := json.Unmarshal(query.JSON, &qm)
|
|
75
76
|
if err != nil {
|
|
76
|
-
return backend.ErrDataResponse(backend.StatusBadRequest, "json unmarshal: "
|
|
77
|
+
return backend.ErrDataResponse(backend.StatusBadRequest, fmt.Sprintf("json unmarshal: %v", err.Error()))
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
// create data frame response.
|
|
81
|
+
// For an overview on data frames and how grafana handles them:
|
|
82
|
+
// https://grafana.com/docs/grafana/latest/developers/plugins/data-frames/
|
|
80
83
|
frame := data.NewFrame("response")
|
|
81
84
|
|
|
82
85
|
// add fields.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
ARG grafana_version=latest
|
|
2
|
+
ARG grafana_image=grafana-enterprise
|
|
2
3
|
|
|
3
|
-
FROM grafana
|
|
4
|
+
FROM grafana/${grafana_image}:${grafana_version}
|
|
4
5
|
|
|
5
6
|
# Make it as simple as possible to access the grafana instance for development purposes
|
|
6
7
|
# Do NOT enable these settings in a public facing / production grafana instance
|
|
@@ -139,3 +139,26 @@ We need to update the `scripts` in the `package.json` to use the extended Webpac
|
|
|
139
139
|
-"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
|
|
140
140
|
+"dev": "webpack -w -c ./webpack.config.ts --env development",
|
|
141
141
|
```
|
|
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
|
+
---
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import React, { ChangeEvent
|
|
2
|
-
import {
|
|
1
|
+
import React, { ChangeEvent } from 'react';
|
|
2
|
+
import { InlineField, Input, SecretInput } from '@grafana/ui';
|
|
3
3
|
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
|
4
4
|
import { MyDataSourceOptions, MySecureJsonData } from '../types';
|
|
5
5
|
|
|
6
|
-
const { SecretFormField, FormField } = LegacyForms;
|
|
7
|
-
|
|
8
6
|
interface Props extends DataSourcePluginOptionsEditorProps<MyDataSourceOptions> {}
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
onPathChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
14
|
-
const { onOptionsChange, options } = this.props;
|
|
8
|
+
export function ConfigEditor(props: Props) {
|
|
9
|
+
const { onOptionsChange, options } = props;
|
|
10
|
+
const onPathChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
15
11
|
const jsonData = {
|
|
16
12
|
...options.jsonData,
|
|
17
13
|
path: event.target.value,
|
|
@@ -20,8 +16,7 @@ export class ConfigEditor extends PureComponent<Props, State> {
|
|
|
20
16
|
};
|
|
21
17
|
|
|
22
18
|
// Secure field (only sent to the backend)
|
|
23
|
-
onAPIKeyChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
24
|
-
const { onOptionsChange, options } = this.props;
|
|
19
|
+
const onAPIKeyChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
25
20
|
onOptionsChange({
|
|
26
21
|
...options,
|
|
27
22
|
secureJsonData: {
|
|
@@ -30,8 +25,7 @@ export class ConfigEditor extends PureComponent<Props, State> {
|
|
|
30
25
|
});
|
|
31
26
|
};
|
|
32
27
|
|
|
33
|
-
onResetAPIKey = () => {
|
|
34
|
-
const { onOptionsChange, options } = this.props;
|
|
28
|
+
const onResetAPIKey = () => {
|
|
35
29
|
onOptionsChange({
|
|
36
30
|
...options,
|
|
37
31
|
secureJsonFields: {
|
|
@@ -45,39 +39,29 @@ export class ConfigEditor extends PureComponent<Props, State> {
|
|
|
45
39
|
});
|
|
46
40
|
};
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const { jsonData, secureJsonFields } = options;
|
|
51
|
-
const secureJsonData = (options.secureJsonData || {}) as MySecureJsonData;
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<div className="gf-form-group">
|
|
55
|
-
<div className="gf-form">
|
|
56
|
-
<FormField
|
|
57
|
-
label="Path"
|
|
58
|
-
labelWidth={6}
|
|
59
|
-
inputWidth={20}
|
|
60
|
-
onChange={this.onPathChange}
|
|
61
|
-
value={jsonData.path || ''}
|
|
62
|
-
placeholder="json field returned to frontend"
|
|
63
|
-
/>
|
|
64
|
-
</div>
|
|
42
|
+
const { jsonData, secureJsonFields } = options;
|
|
43
|
+
const secureJsonData = (options.secureJsonData || {}) as MySecureJsonData;
|
|
65
44
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
45
|
+
return (
|
|
46
|
+
<div className="gf-form-group">
|
|
47
|
+
<InlineField label="Path" labelWidth={12}>
|
|
48
|
+
<Input
|
|
49
|
+
onChange={onPathChange}
|
|
50
|
+
value={jsonData.path || ''}
|
|
51
|
+
placeholder="json field returned to frontend"
|
|
52
|
+
width={40}
|
|
53
|
+
/>
|
|
54
|
+
</InlineField>
|
|
55
|
+
<InlineField label="API Key" labelWidth={12}>
|
|
56
|
+
<SecretInput
|
|
57
|
+
isConfigured={(secureJsonFields && secureJsonFields.apiKey) as boolean}
|
|
58
|
+
value={secureJsonData.apiKey || ''}
|
|
59
|
+
placeholder="secure json field (backend only)"
|
|
60
|
+
width={40}
|
|
61
|
+
onReset={onResetAPIKey}
|
|
62
|
+
onChange={onAPIKeyChange}
|
|
63
|
+
/>
|
|
64
|
+
</InlineField>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
83
67
|
}
|
|
@@ -1,47 +1,32 @@
|
|
|
1
|
-
import React, { ChangeEvent
|
|
2
|
-
import {
|
|
1
|
+
import React, { ChangeEvent } from 'react';
|
|
2
|
+
import { InlineField, Input } from '@grafana/ui';
|
|
3
3
|
import { QueryEditorProps } from '@grafana/data';
|
|
4
4
|
import { DataSource } from '../datasource';
|
|
5
5
|
import { MyDataSourceOptions, MyQuery } from '../types';
|
|
6
6
|
|
|
7
|
-
const { FormField } = LegacyForms;
|
|
8
|
-
|
|
9
7
|
type Props = QueryEditorProps<DataSource, MyQuery, MyDataSourceOptions>;
|
|
10
8
|
|
|
11
|
-
export
|
|
12
|
-
onQueryTextChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
13
|
-
const { onChange, query } = this.props;
|
|
9
|
+
export function QueryEditor({ query, onChange, onRunQuery }: Props) {
|
|
10
|
+
const onQueryTextChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
14
11
|
onChange({ ...query, queryText: event.target.value });
|
|
15
12
|
};
|
|
16
13
|
|
|
17
|
-
onConstantChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
18
|
-
const { onChange, query, onRunQuery } = this.props;
|
|
14
|
+
const onConstantChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
19
15
|
onChange({ ...query, constant: parseFloat(event.target.value) });
|
|
20
16
|
// executes the query
|
|
21
17
|
onRunQuery();
|
|
22
18
|
};
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
const { queryText, constant } = this.props.query;
|
|
20
|
+
const { queryText, constant } = query;
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<FormField
|
|
38
|
-
labelWidth={8}
|
|
39
|
-
value={queryText || ''}
|
|
40
|
-
onChange={this.onQueryTextChange}
|
|
41
|
-
label="Query Text"
|
|
42
|
-
tooltip="Not used yet"
|
|
43
|
-
/>
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
}
|
|
22
|
+
return (
|
|
23
|
+
<div className="gf-form">
|
|
24
|
+
<InlineField label="Constant">
|
|
25
|
+
<Input onChange={onConstantChange} value={constant} width={8} type="number" step="0.1" />
|
|
26
|
+
</InlineField>
|
|
27
|
+
<InlineField label="Query Text" labelWidth={16} tooltip="Not used yet">
|
|
28
|
+
<Input onChange={onQueryTextChange} value={queryText || ''} />
|
|
29
|
+
</InlineField>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
47
32
|
}
|