Legacy review guidelines
The Grafana team reviews all plugins that are published on Grafana.com. There are two areas we review, the metadata for the plugin and the plugin functionality.
Metadata
The plugin metadata consists of a The README.md file is shown on the plugins page in Grafana and the plugin page on Grafana.com. There are some differences between the GitHub markdown and the markdown allowed in Grafana/Grafana.com: The README should: The A minimal 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 Examples: The The The full file format for JavaScript, TypeScript, ES6 (or any other language) are all fine as long as the contents of the Here is a typical directory structure for a plugin. Most JavaScript projects have a build step. The generated JavaScript should be placed in the Directories: For the HTML on editor tabs, we recommend using the inbuilt Grafana styles rather than defining your own. This makes plugins feel like a more natural part of Grafana. If done correctly, the html will also be responsive and adapt to smaller screens. The Below is a minimal example of an editor row with one form group and two fields, a dropdown and a text input: Use the For more information about data sources, refer to the basic guide for data sources. It should be as easy as possible for a user to configure a URL. If the data source is using the The If possible, any passwords or secrets should be saved in the Read more here about how authentication for data sources works. If using the proxy feature, the Configuration page should use the Each query editor is unique and can have a unique style. It should be adapted to what the users of the data source are used to.plugin.json
file and the README.md file. The plugin.json
file is used by Grafana to load the plugin, and the README.md file is shown in the plugins section of Grafana and the plugins section of
README.md
Plugin.json
plugin.json
file is the same concept as the package.json
file for an npm package. When the Grafana server starts it will scan the plugin folders (all folders in the data/plugins subfolder) and load every folder that contains a plugin.json
file unless the folder contains a subfolder named dist
. In that case, the Grafana server will load the dist
folder instead.plugin.json
file:{
"type": "panel",
"name": "Clock",
"id": "yourorg-clock-panel",
"info": {
"description": "Clock panel for grafana",
"author": {
"name": "Author Name",
"url": "http://yourwebsite.com"
},
"keywords": ["clock", "panel"],
"version": "1.0.0",
"updated": "2018-03-24"
},
"dependencies": {
"grafanaVersion": "3.x.x",
"plugins": []
}
}
grafana
unless it is a plugin created by the Grafana core team.
type
field should be either datasource
app
or panel
.version
field should be in the form: x.x.x e.g. 1.0.0
or 0.4.1
.plugin.json
file is in plugin.json.Plugin Language
dist
subdirectory are transpiled to JavaScript (ES5).File and Directory Structure Conventions
johnnyb-awesome-datasource
|-- dist
|-- src
| |-- img
| | |-- logo.svg
| |-- partials
| | |-- annotations.editor.html
| | |-- config.html
| | |-- query.editor.html
| |-- datasource.js
| |-- module.js
| |-- plugin.json
| |-- query_ctrl.js
|-- Gruntfile.js
|-- LICENSE
|-- package.json
|-- README.md
dist
directory and the source code in the src
directory. We recommend that the plugin.json file be placed in the src directory and then copied over to the dist directory when building. The README.md
can be placed in the root or in the dist directory.
src/
contains plugin source files.src/partials
contains html templates.src/img
contains plugin logos and other images.dist/
contains built content.HTML and CSS
gf-form
css classes should be used for labels and inputs.<div class="editor-row">
<div class="section gf-form-group">
<h5 class="section-heading">My Plugin Options</h5>
<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>
</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
/>
</div>
</div>
</div>
</div>
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
Configuration Page Guidelines
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
).<datasource-http-settings current="ctrl.current" suggest-url="http://localhost:8080"> </datasource-http-settings>
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
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.secureJsonData
blob like this:
<input type="password" class="gf-form-input" ng-model='ctrl.current.secureJsonData.password' placeholder="password"></input>
<input type="password" class="gf-form-input" ng-model='ctrl.current.password' placeholder="password"></input>
Query Editor
gf-form
classes.hide
property - an example.