mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 10:12:19 +08:00
PackageJson: Prettify markdown/mdx on commit with lint-staged (#37616)
* Format md,mdx files with prettier on lint-staged * Manually run prettier on docs/sources
This commit is contained in:
@ -45,15 +45,15 @@ The javascript object that communicates with the database and transforms data to
|
||||
The Data source should contain the following functions:
|
||||
|
||||
```javascript
|
||||
query(options) // used by panels to get data
|
||||
testDatasource() // used by data source configuration page to make sure the connection is working
|
||||
annotationQuery(options) // used by dashboards to get annotations
|
||||
metricFindQuery(options) // used by query editor to get metric suggestions.
|
||||
query(options); // used by panels to get data
|
||||
testDatasource(); // used by data source configuration page to make sure the connection is working
|
||||
annotationQuery(options); // used by dashboards to get annotations
|
||||
metricFindQuery(options); // used by query editor to get metric suggestions.
|
||||
```
|
||||
|
||||
### testDatasource
|
||||
|
||||
When a user clicks on the *Save & Test* button when adding a new data source, the details are first saved to the database and then the `testDatasource` function that is defined in your data source plugin will be called. It is recommended that this function makes a query to the data source that will also test that the authentication details are correct. This is so the data source is correctly configured when the user tries to write a query in a new dashboard.
|
||||
When a user clicks on the _Save & Test_ button when adding a new data source, the details are first saved to the database and then the `testDatasource` function that is defined in your data source plugin will be called. It is recommended that this function makes a query to the data source that will also test that the authentication details are correct. This is so the data source is correctly configured when the user tries to write a query in a new dashboard.
|
||||
|
||||
### Query
|
||||
|
||||
@ -81,15 +81,15 @@ An array of:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"target":"upper_75",
|
||||
"datapoints":[
|
||||
"target": "upper_75",
|
||||
"datapoints": [
|
||||
[622, 1450754160000],
|
||||
[365, 1450754220000]
|
||||
]
|
||||
},
|
||||
{
|
||||
"target":"upper_90",
|
||||
"datapoints":[
|
||||
"target": "upper_90",
|
||||
"datapoints": [
|
||||
[861, 1450754160000],
|
||||
[767, 1450754220000]
|
||||
]
|
||||
@ -118,16 +118,8 @@ An array of:
|
||||
}
|
||||
],
|
||||
"rows": [
|
||||
[
|
||||
1457425380000,
|
||||
null,
|
||||
null
|
||||
],
|
||||
[
|
||||
1457425370000,
|
||||
1002.76215352,
|
||||
1002.76215352
|
||||
]
|
||||
[1457425380000, null, null],
|
||||
[1457425370000, 1002.76215352, 1002.76215352]
|
||||
],
|
||||
"type": "table"
|
||||
}
|
||||
@ -141,7 +133,7 @@ Request object passed to datasource.annotationQuery function:
|
||||
```json
|
||||
{
|
||||
"range": { "from": "2016-03-04T04:07:55.144Z", "to": "2016-03-04T07:07:55.144Z" },
|
||||
"rangeRaw": { "from": "now-3h", to: "now" },
|
||||
"rangeRaw": { "from": "now-3h", "to": "now" },
|
||||
"annotation": {
|
||||
"datasource": "generic datasource",
|
||||
"enable": true,
|
||||
@ -160,7 +152,7 @@ Expected result from datasource.annotationQuery:
|
||||
"name": "annotation name", //should match the annotation name in grafana
|
||||
"enabled": true,
|
||||
"datasource": "generic datasource"
|
||||
},
|
||||
},
|
||||
"title": "Cluster outage",
|
||||
"time": 1457075272576,
|
||||
"text": "Joe causes brain split",
|
||||
|
@ -61,13 +61,13 @@ Grafana conventions mean all you need to do is to hook up an Angular template wi
|
||||
|
||||
## Using Events
|
||||
|
||||
To add an editor tab you need to hook into the event model so that the tab is added when the *init-edit-mode* event is triggered. The following code should be added to the constructor of the plugin Ctrl class:
|
||||
To add an editor tab you need to hook into the event model so that the tab is added when the _init-edit-mode_ event is triggered. The following code should be added to the constructor of the plugin Ctrl class:
|
||||
|
||||
```javascript
|
||||
this.events.on('init-edit-mode', this.onInitEditMode.bind(this));
|
||||
```
|
||||
|
||||
Then you need to create a handler function that is bound to the event. In the example above, the handler is called onInitEditMode. The tab is added by calling the controller function, *addEditorTab*. This function has three parameters; the tab name, the path to a html template for the new editor tab and the tab number. It can be a bit tricky to figure out the path, the path name will be based on the id that is specified in the plugin.json file - for example **grafana-clock-panel**. The code below hooks up an Angular template called editor.html that is located in the `src/partials` directory.
|
||||
Then you need to create a handler function that is bound to the event. In the example above, the handler is called onInitEditMode. The tab is added by calling the controller function, _addEditorTab_. This function has three parameters; the tab name, the path to a html template for the new editor tab and the tab number. It can be a bit tricky to figure out the path, the path name will be based on the id that is specified in the plugin.json file - for example **grafana-clock-panel**. The code below hooks up an Angular template called editor.html that is located in the `src/partials` directory.
|
||||
|
||||
```javascript
|
||||
onInitEditMode() {
|
||||
@ -82,31 +82,42 @@ For editor tabs html, it is best to use Grafana css styles rather than custom st
|
||||
Most editor tabs should use the [gf-form css class](https://github.com/grafana/grafana/blob/main/public/sass/components/_gf-form.scss) from Grafana. The example below has one row with a couple of columns and each column is wrapped in a div like this:
|
||||
|
||||
```html
|
||||
<div class="section gf-form-group">
|
||||
```
|
||||
<div class="section gf-form-group"></div>
|
||||
```
|
||||
|
||||
Then each pair, label and field is wrapped in a div with a gf-form class.
|
||||
|
||||
```html
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-8">Font Size</label>
|
||||
<input type="text" class="gf-form-input width-4" ng-model="ctrl.panel.fontSize" ng-change="ctrl.render()" ng-model-onblur>
|
||||
<input
|
||||
type="text"
|
||||
class="gf-form-input width-4"
|
||||
ng-model="ctrl.panel.fontSize"
|
||||
ng-change="ctrl.render()"
|
||||
ng-model-onblur
|
||||
/>
|
||||
</div>
|
||||
```
|
||||
|
||||
Note that there are some Angular attributes here. *ng-model* will update the panel data. *ng-change* will render the panel when you change the value. This change will occur on the onblur event due to the *ng-model-onblur* attribute. This means you can see the effect of your changes on the panel while editing.
|
||||
Note that there are some Angular attributes here. _ng-model_ will update the panel data. _ng-change_ will render the panel when you change the value. This change will occur on the onblur event due to the _ng-model-onblur_ attribute. This means you can see the effect of your changes on the panel while editing.
|
||||
|
||||
{{< figure class="float-right" src="/assets/img/blog/clock-panel-editor.png" caption="Panel Editor" >}}
|
||||
|
||||
On the editor tab we use a drop down for 12/24 hour clock, an input field for font size and a color picker for the background color.
|
||||
|
||||
The drop down/select has its own *gf-form-select-wrapper* css class and looks like this:
|
||||
The drop down/select has its own _gf-form-select-wrapper_ css class and looks like this:
|
||||
|
||||
```html
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-9">12 or 24 hour</label>
|
||||
<div class="gf-form-select-wrapper max-width-9">
|
||||
<select class="input-small gf-form-input" ng-model="ctrl.panel.clockType" ng-options="t for t in ['12 hour', '24 hour', 'custom']" ng-change="ctrl.render()"></select>
|
||||
<select
|
||||
class="input-small gf-form-input"
|
||||
ng-model="ctrl.panel.clockType"
|
||||
ng-options="t for t in ['12 hour', '24 hour', 'custom']"
|
||||
ng-change="ctrl.render()"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
@ -114,11 +125,11 @@ The drop down/select has its own *gf-form-select-wrapper* css class and looks li
|
||||
The color picker (or spectrum picker) is a component that already exists in Grafana. We use it like this for the background color:
|
||||
|
||||
```html
|
||||
<spectrum-picker class="gf-form-input" ng-model="ctrl.panel.bgColor" ng-change="ctrl.render()" ></spectrum-picker>
|
||||
<spectrum-picker class="gf-form-input" ng-model="ctrl.panel.bgColor" ng-change="ctrl.render()"></spectrum-picker>
|
||||
```
|
||||
|
||||
## Editor Tab Finished
|
||||
|
||||
To reiterate, this all ties together quite neatly. We specify properties and panel defaults in the constructor for the panel controller and these can then be changed in the editor. Grafana takes care of saving the changes.
|
||||
|
||||
One thing to be aware of is that panel defaults are used the first time a panel is created to set the initial values of the panel properties. After the panel is saved then the saved value will be used instead. So beware if you update panel defaults they will not automatically update the property in an existing panel. For example, if you set the default font size to 60px first and then in version 2 of the plugin change it to 50px, existing panels will still have 60px and only new panels will get the new 50px value.
|
||||
One thing to be aware of is that panel defaults are used the first time a panel is created to set the initial values of the panel properties. After the panel is saved then the saved value will be used instead. So beware if you update panel defaults they will not automatically update the property in an existing panel. For example, if you set the default font size to 60px first and then in version 2 of the plugin change it to 50px, existing panels will still have 60px and only new panels will get the new 50px value.
|
||||
|
@ -11,7 +11,8 @@ Panels are the main building blocks of dashboards.
|
||||
## Panel development
|
||||
|
||||
### Scrolling
|
||||
The grafana dashboard framework controls the panel height. To enable a scrollbar within the panel the PanelCtrl needs to set the scrollable static variable:
|
||||
|
||||
The grafana dashboard framework controls the panel height. To enable a scrollbar within the panel the PanelCtrl needs to set the scrollable static variable:
|
||||
|
||||
```javascript
|
||||
export class MyPanelCtrl extends PanelCtrl {
|
||||
@ -19,7 +20,7 @@ export class MyPanelCtrl extends PanelCtrl {
|
||||
...
|
||||
```
|
||||
|
||||
In this case, make sure the template has a single `<div>...</div>` root. The plugin loader will modify that element adding a scrollbar.
|
||||
In this case, make sure the template has a single `<div>...</div>` root. The plugin loader will modify that element adding a scrollbar.
|
||||
|
||||
### Examples
|
||||
|
||||
|
@ -48,20 +48,19 @@ A minimal `plugin.json` file:
|
||||
|
||||
"dependencies": {
|
||||
"grafanaVersion": "3.x.x",
|
||||
"plugins": [ ]
|
||||
"plugins": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- The convention for the plugin id is **[grafana.com username/org]-[plugin name]-[datasource|app|panel]** and it has to be unique. The org **cannot** be `grafana` unless it is a plugin created by the Grafana core team.
|
||||
|
||||
Examples:
|
||||
|
||||
- raintank-worldping-app
|
||||
- ryantxu-ajax-panel
|
||||
- alexanderzobnin-zabbix-app
|
||||
- hawkular-datasource
|
||||
Examples:
|
||||
|
||||
- raintank-worldping-app
|
||||
- ryantxu-ajax-panel
|
||||
- alexanderzobnin-zabbix-app
|
||||
- hawkular-datasource
|
||||
|
||||
- The `type` field should be either `datasource` `app` or `panel`.
|
||||
- The `version` field should be in the form: x.x.x e.g. `1.0.0` or `0.4.1`.
|
||||
@ -118,11 +117,23 @@ Below is a minimal example of an editor row with one form group and two fields,
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-10">Label1</label>
|
||||
<div class="gf-form-select-wrapper max-width-10">
|
||||
<select class="input-small gf-form-input" ng-model="ctrl.panel.mySelectProperty" ng-options="t for t in ['option1', 'option2', 'option3']" ng-change="ctrl.onSelectChange()"></select>
|
||||
<select
|
||||
class="input-small gf-form-input"
|
||||
ng-model="ctrl.panel.mySelectProperty"
|
||||
ng-options="t for t in ['option1', 'option2', 'option3']"
|
||||
ng-change="ctrl.onSelectChange()"
|
||||
></select>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-10">Label2</label>
|
||||
<input type="text" class="input-small gf-form-input width-10" ng-model="ctrl.panel.myProperty" ng-change="ctrl.onFieldChange()" placeholder="suggestion for user" ng-model-onblur />
|
||||
<input
|
||||
type="text"
|
||||
class="input-small gf-form-input width-10"
|
||||
ng-model="ctrl.panel.myProperty"
|
||||
ng-change="ctrl.onFieldChange()"
|
||||
placeholder="suggestion for user"
|
||||
ng-model-onblur
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -132,22 +143,19 @@ Below is a minimal example of an editor row with one form group and two fields,
|
||||
Use the `width-x` and `max-width-x` classes to control the width of your labels and input fields. Try to get labels and input fields to line up neatly by having the same width for all the labels in a group and the same width for all inputs in a group if possible.
|
||||
|
||||
## Data Sources
|
||||
|
||||
For more information about data sources, refer to the [basic guide for data sources](http://docs.grafana.org/plugins/developing/datasources/).
|
||||
|
||||
### Configuration Page Guidelines
|
||||
|
||||
- It should be as easy as possible for a user to configure a URL. If the data source is using the `datasource-http-settings` component, it should use the `suggest-url` attribute to suggest the default URL or a URL that is similar to what it should be (especially important if the URL refers to a REST endpoint that is not common knowledge for most users e.g. `https://yourserver:4000/api/custom-endpoint`).
|
||||
|
||||
```html
|
||||
<datasource-http-settings
|
||||
current="ctrl.current"
|
||||
suggest-url="http://localhost:8080">
|
||||
</datasource-http-settings>
|
||||
```
|
||||
```html
|
||||
<datasource-http-settings current="ctrl.current" suggest-url="http://localhost:8080"> </datasource-http-settings>
|
||||
```
|
||||
|
||||
- The `testDatasource` function should make a query to the data source that will also test that the authentication details are correct. This is so the data source is correctly configured when the user tries to write a query in a new dashboard.
|
||||
|
||||
|
||||
#### Password Security
|
||||
|
||||
If possible, any passwords or secrets should be saved in the `secureJsonData` blob. To encrypt sensitive data, the Grafana server's proxy feature must be used. The Grafana server has support for token authentication (OAuth) and HTTP Header authentication. If the calls have to be sent directly from the browser to a third-party API, this will not be possible and sensitive data will not be encrypted.
|
||||
@ -156,9 +164,8 @@ Read more here about how [authentication for data sources]({{< relref "../add-au
|
||||
|
||||
If using the proxy feature, the Configuration page should use the `secureJsonData` blob like this:
|
||||
|
||||
- good: `<input type="password" class="gf-form-input" ng-model='ctrl.current.secureJsonData.password' placeholder="password"></input>`
|
||||
- bad: `<input type="password" class="gf-form-input" ng-model='ctrl.current.password' placeholder="password"></input>`
|
||||
|
||||
- good: `<input type="password" class="gf-form-input" ng-model='ctrl.current.secureJsonData.password' placeholder="password"></input>`
|
||||
- bad: `<input type="password" class="gf-form-input" ng-model='ctrl.current.password' placeholder="password"></input>`
|
||||
|
||||
### Query Editor
|
||||
|
||||
|
Reference in New Issue
Block a user