Docs: Plugin doc review changes from chunk 1-B with corrected set of files (#67164)

* Re-pushing doc review changes from 1-B with fewer files

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Fix for URL examples

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Data frames fixes

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Fixes from doc review

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* More doc review changes

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Doc fixes

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Doc fix

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Prettier

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Fix migration index

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Fix screenshot

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Doc fixes

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

* Quick fix

Signed-off-by: Joe Perez <joseph.perez@grafana.com>

---------

Signed-off-by: Joe Perez <joseph.perez@grafana.com>
This commit is contained in:
Joseph Perez 2023-05-09 13:53:11 -07:00 committed by GitHub
parent 13603c7d71
commit d6ba522c3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 159 additions and 85 deletions

View File

@ -12,39 +12,59 @@ The data frame structure is a concept that's borrowed from data analysis tools l
This document gives an overview of the data frame structure, and of how data is handled within Grafana.
## The data frame
### Data frame fields
A data frame is a columnar-oriented table structure, which means it stores data by column and not by row. To understand what this means, lets look at the TypeScript definition used by Grafana:
A data frame is a collection of _fields_, where each field corresponds to a column. Each field, in turn, consists of a collection of values and metadata, such as the data type of those values.
```ts
interface DataFrame {
name?: string;
// reference to query that create the frame
refId?: string;
fields: []Field;
}
```
In essence, a data frame is a collection of _fields_, where each field corresponds to a column. Each field, in turn, consists of a collection of values, along with meta information, such as the data type of those values.
```ts
interface Field {
export interface Field<T = any, V = Vector<T>> {
/**
* Name of the field (column)
*/
name: string;
// Prometheus like Labels / Tags
labels?: Record<string, string>;
// For example string, number, time (or more specific primitives in the backend)
/**
* Field value type (string, number, and so on)
*/
type: FieldType;
// Array of values all of the same type
values: Vector<T>;
// Optional display data for the field (e.g. unit, name over-ride, etc)
/**
* Meta info about how field and how to display it
*/
config: FieldConfig;
/**
* The raw field values
* In Grafana 10, this accepts both simple arrays and the Vector interface
* In Grafana 11, the Vector interface will be removed
*/
values: V | T[];
/**
* When type === FieldType.Time, this can optionally store
* the nanosecond-precison fractions as integers between
* 0 and 999999.
*/
nanos?: number[];
labels?: Labels;
/**
* Cached values with appropriate display and id values
*/
state?: FieldState | null;
/**
* Convert a value for display
*/
display?: DisplayProcessor;
/**
* Get value data links with variables interpolated
*/
getLinks?: (config: ValueLinkConfig) => Array<LinkModel<Field>>;
}
```
Let's look at an example. The table below demonstrates a data frame with two fields, _time_ and _temperature_.
Let's look at an example. The following table demonstrates a data frame with two fields, _time_ and _temperature_:
| time | temperature |
| ------------------- | ----------- |
@ -52,22 +72,24 @@ Let's look at an example. The table below demonstrates a data frame with two fie
| 2020-01-02 03:05:00 | 47.0 |
| 2020-01-02 03:06:00 | 48.0 |
Each field has three values, and each value in a field must share the same type. In this case, all values in the time field are timestamps, and all values in the temperature field are numbers.
Each field has three values, and each value in a field must share the same type. In this case, all values in the `time` field are timestamps, and all values in the `temperature` field are numbers.
One restriction on data frames is that all fields in the frame must be of the same length to be a valid data frame.
### Field configuration
### Field configurations
Each field in a data frame contains optional information about the values in the field, such as units, scaling, and so on.
By adding field configurations to a data frame, Grafana can configure visualizations automatically. For example, you could configure Grafana to automatically set the unit provided by the data source.
## Transformations
## Data transformations
Along with the type information, field configs enable _data transformations_ within Grafana.
We have seen how field configs contain type information, and they also have another role. Data frame fields enable _data transformations_ within Grafana.
A data transformation is any function that accepts a data frame as input, and returns another data frame as output. By using data frames in your plugin, you get a range of transformations for free.
To learn more about data transformations in Grafana, refer to [Transform data](https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/transform-data/).
## Data frames as time series
A data frame with at least one time field is considered a _time series_.
@ -76,9 +98,9 @@ For more information on time series, refer to our [Introduction to time series](
### Wide format
When a collection of time series shares the same _time index_—the time fields in each time series are identical—they can be stored together, in a _wide_ format. By reusing the time field, we can reduce the amount of data being sent to the browser.
When a collection of time series shares the same _time index_—the time fields in each time series are identical—they can be stored together, in a _wide_ format. By reusing the time field, less data is sent to the browser.
In this example, the `cpu` usage from each host share the time index, so we can store them in the same data frame.
In this example, the `cpu` usage from each host shares the time index, so we can store them in the same data frame:
```text
Name: Wide
@ -93,7 +115,7 @@ Dimensions: 3 fields by 2 rows
+---------------------+-----------------+-----------------+
```
However, if the two time series don't share the same time values, they are represented as two distinct data frames.
However, if the two time series don't share the same time values, they are represented as two distinct data frames:
```text
Name: cpu
@ -119,17 +141,17 @@ Dimensions: 2 fields by 2 rows
+---------------------+-----------------+
```
The wide format can typically be used when multiple time series are collected by the same process. In this case, every measurement is made at the same interval and will therefore share the same time values.
A typical use for the wide format is when multiple time series are collected by the same process. In this case, every measurement is made at the same interval and therefore shares the same time values.
### Long format
Some data sources return data in a _long_ format (also called _narrow_ format). This is common format returned by, for example, SQL databases.
Some data sources return data in a _long_ format (also called _narrow_ format). This is a common format returned by, for example, SQL databases.
In long format, string values are represented as separate fields rather than as labels. As a result, a data form in long form may have duplicated time values.
In the long format, string values are represented as separate fields rather than as labels. As a result, a data form in long form may have duplicated time values.
Grafana can detect and convert data frames in long format into wide format.
For example, the following data frame in long format:
For example, the following data frame appears in long format:
```text
Name: Long
@ -146,7 +168,7 @@ Dimensions: 4 fields by 4 rows
+---------------------+-----------------+-----------------+----------------+
```
can be converted into a data frame in wide format:
The above table can be converted into a data frame in wide format like this:
```text
Name: Wide
@ -161,11 +183,11 @@ Dimensions: 5 fields by 2 rows
+---------------------+------------------+------------------+------------------+------------------+
```
> **Note:** Not all panels support the wide time series data frame format. To keep full backward compatibility we've introduced a transformation that can be used to convert from the wide to the long format. For usage information, refer to the [Prepare time series-transformation]({{< relref "../../panels-visualizations/query-transform-data/transform-data/#prepare-time-series" >}}).
> **Note:** Not all panels support the wide time series data frame format. To keep full backward compatibility Grafana has introduced a transformation that you can use to convert from the wide to the long format. For usage information, refer to the [Prepare time series-transformation]({{< relref "../../panels-visualizations/query-transform-data/transform-data/#prepare-time-series" >}}).
## Technical references
This section contains links to technical reference and implementations of data frames.
The concept of a data frame in Grafana is borrowed from data analysis tools like the [R programming language](https://www.r-project.org), and [Pandas](https://pandas.pydata.org/). Other technical references are provided below.
### Apache Arrow

View File

@ -1,10 +1,10 @@
---
title: Error handling
title: Work with error handling
---
# Error handling
# Work with error handling
This guide explains how to handle errors in plugins.
This guide explains how to handle errors in plugins and provides suggestions for common scenarios.
## Provide usable defaults
@ -33,7 +33,7 @@ Grafana displays the error message in the top-left corner of the panel.
{{< figure src="/static/img/docs/panel_error.png" class="docs-image--no-shadow" max-width="850px" >}}
Avoid displaying overly-technical error messages to the user. If you want to let technical users report an error, consider logging it instead.
We recommend that you avoid displaying overly technical error messages to the user. If you want to let technical users report an error, consider logging it to the console instead.
```ts
try {
@ -44,7 +44,9 @@ try {
}
```
> **Note:** Grafana displays the exception message in the UI as written, so we recommend using grammatically correct sentences. For more information, refer to the [Documentation style guide](https://github.com/grafana/grafana/blob/main/contribute/style-guides/documentation-style-guide.md).
> **Note:** Grafana displays the exception message in the UI as written, so use grammatically correct sentences. For more information, refer to the [Documentation style guide](https://github.com/grafana/grafana/blob/main/contribute/style-guides/documentation-style-guide.md).
## Common error scenarios
Here are some examples of situations where you might want to display an error to the user.

View File

@ -13,31 +13,17 @@ weight: 1000
# Migrate a plugin from AngularJS to React
If youre looking to migrate a plugin to the new plugin platform, then we recommend that you release it under a new major version. Consider keeping a release branch for the previous version to be able to roll out patch releases for versions prior to Grafana 7.
If you want to migrate a plugin to Grafana's React-based plugin platform, then we recommend that you release it under a new major version. Consider keeping a release branch for the previous version to be able to roll out patch releases for versions prior to Grafana 7.
While there's no 1-to-1 migration path from an Angular plugin to the new React platform, from early adopters, weve learned that one of the easiest ways to migrate is to:
While there's no standard migration path from an Angular plugin to the new React platform, weve learned that one of the easiest ways to migrate is to:
1. Create a new branch called `migrate-to-react`.
1. Start from scratch with one of the templates provided by Grafana Toolkit.
1. Start from scratch with one of the templates provided by the [Create-plugin](https://www.npmjs.com/package/@grafana/create-plugin) tool.
1. Move the existing code into the new plugin incrementally, one component at a time.
## Migrate a panel plugin
Prior to Grafana 7.0, you would export a MetricsPanelCtrl from module.ts.
**src/module.ts**
```ts
import { MetricsPanelCtrl } from 'grafana/app/plugins/sdk';
class MyPanelCtrl extends MetricsPanelCtrl {
// ...
}
export { MyPanelCtrl as PanelCtrl };
```
Starting with 7.0, plugins now export a PanelPlugin from module.ts where MyPanel is a React component containing the props from PanelProps.
Starting with Grafana 7.0, plugins export a `PanelPlugin` from `module.ts` where `MyPanel`is a React component containing the props from `PanelProps`.
**src/module.ts**
@ -64,8 +50,8 @@ export function MyPanel({ options, data, width, height }: Props) {
While all plugins are different, we'd like to share a migration process that has worked for some of our users.
1. Define your configuration model and `ConfigEditor`. For many plugins, the configuration editor is the simplest component so it's a good candidate to start with.
1. Implement the `testDatasource()` method on the class that extends `DataSourceApi` using the settings in your configuration model to make sure you can successfully configure and access the external API.
1. Implement the `query()` method. At this point, you can hard-code your query, because we havent yet implemented the query editor. The `query()` method supports both the new data frame response and the old TimeSeries response, so dont worry about converting to the new format just yet.
1. Implement the `testDatasource()` method on the class that extends `DataSourceApi`. Use the settings in your configuration model to make sure that you can successfully configure and access the external API.
1. Implement the `query()` method. At this point, you can hard-code your query, because we havent yet implemented the query editor. The `query()` method supports both the new data frame response and the old `TimeSeries` response, so dont worry about converting to the new format just yet.
1. Implement the `QueryEditor`. How much work this requires depends on how complex your query model is.
By now, you should be able to release your new version.

View File

@ -0,0 +1,67 @@
---
description: How to package a plugin
title: Package a plugin
---
By packaging a plugin, you can organize the plugin code and make it ready for use in your organization.
## Package a plugin for distribution
1. Build the plugin
```
yarn install --pure-lockfile
yarn build
```
1. Optional: If your data source plugin has a backend plugin, build it as well.
```
mage
```
Make sure that all the binaries are executable and have a `0755` (`-rwxr-xr-x`) permission.
1. Sign the plugin. To learn more, refer to [Sign the plugin]({{< relref "./sign-a-plugin" >}}).
1. Rename the `dist` directory to match your plugin ID, and then create a ZIP archive.
```
mv dist/ myorg-simple-panel
zip myorg-simple-panel-1.0.0.zip myorg-simple-panel -r
```
1. Optional: Verify that your plugin is packaged correctly using [zipinfo](https://linux.die.net/man/1/zipinfo).
It should look like this:
```
zipinfo grafana-clickhouse-datasource-1.1.2.zip
Archive: grafana-clickhouse-datasource-1.1.2.zip
Zip file size: 34324077 bytes, number of entries: 22
drwxr-xr-x 0 bx stor 22-Mar-24 23:23 grafana-clickhouse-datasource/
-rw-r--r-- 1654 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/CHANGELOG.md
-rw-r--r-- 11357 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/LICENSE
-rw-r--r-- 2468 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/MANIFEST.txt
-rw-r--r-- 8678 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/README.md
drwxr-xr-x 0 bx stor 22-Mar-24 23:23 grafana-clickhouse-datasource/dashboards/
-rw-r--r-- 42973 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/dashboards/cluster-analysis.json
-rw-r--r-- 56759 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/dashboards/data-analysis.json
-rw-r--r-- 39406 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/dashboards/query-analysis.json
-rwxr-xr-x 16469136 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/gpx_clickhouse_darwin_amd64
-rwxr-xr-x 16397666 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/gpx_clickhouse_darwin_arm64
-rwxr-xr-x 14942208 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/gpx_clickhouse_linux_amd64
-rwxr-xr-x 14155776 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/gpx_clickhouse_linux_arm
-rwxr-xr-x 14548992 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/gpx_clickhouse_linux_arm64
-rwxr-xr-x 15209472 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/gpx_clickhouse_windows_amd64.exe
drwxr-xr-x 0 bx stor 22-Mar-24 23:23 grafana-clickhouse-datasource/img/
-rw-r--r-- 304 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/img/logo.png
-rw-r--r-- 1587 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/img/logo.svg
-rw-r--r-- 138400 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/module.js
-rw-r--r-- 808 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/module.js.LICENSE.txt
-rw-r--r-- 487395 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/module.js.map
-rw-r--r-- 1616 bX defN 22-Mar-24 23:23 grafana-clickhouse-datasource/plugin.json
22 files, 92516655 bytes uncompressed, 34319591 bytes compressed: 62.9%
```
When you've packaged your plugin, you can proceed to [publishing a plugin]({{< relref "publish-a-plugin.md" >}}) or [installing a packaged plugin](https://grafana.com/docs/grafana/latest/administration/plugin-management/#install-a-packaged-plugin).

View File

@ -39,7 +39,7 @@ Follow these steps to publish your plugin for the first time.
1. [Sign in](/auth/sign-in) to your Grafana Cloud account.
1. In the left menu, under **Org settings**, click **My Plugins**.
1. Click **Submit Plugin**. The Create Plugin Submission form appears.
1. Click **Submit Plugin**. The Create Plugin Submission dialog appears.
{{< figure src="/static/img/docs/plugins/plugins-submission-create2.png" class="docs-image--no-shadow" max-width="650px" >}}
@ -54,10 +54,9 @@ Follow these steps to publish your plugin for the first time.
- The remaining questions help us determine the [signature level]({{< relref "./sign-a-plugin#plugin-signature-levels" >}}) for your plugin.
1. Click **Submit**.
After you submit your plugin, we run an automated validation to make sure it adheres to our guidelines.
Your submission is placed in the review queue after the submission is validated.
All submissions are manually inspected by a plugin reviewer.
For every new plugin, we perform a manual review that includes the following checks:
Once your submission passes the validation, it's placed in a review queue.
All submissions are manually inspected by a plugin reviewer.
For every new plugin, we perform a manual review that includes the following checks:
- **Code review:** For quality and security purposes, we review the source code for the plugin.
If you're unable to make the source code publicly available, let us know in a comment on your plugin submission.
@ -71,10 +70,8 @@ To submit an **update** for an already published plugin:
1. [Sign in](/auth/sign-in) to your Grafana Cloud account.
1. In the left menu, under **Org settings**, click **My Plugins**.
1. Click **Submit Update** for the plugin you want to update. The Create Plugin Submission form appears.
1. Click **Submit Update** for the plugin you want to update. The Create Plugin Submission dialog appears.
{{< figure src="/static/img/docs/plugins/plugins-submission-create2.png" class="docs-image--no-shadow" max-width="650px" >}}
1. Enter the information requested by the form.
- **OS & Architecture:**
- Select **Single** if your plugin archive contains binaries for multiple architectures.
@ -110,7 +107,7 @@ To submit an **update** for an already published plugin:
### Can I unlist my plugin from the Grafana plugin catalog in case of a bug?
- In the event of a bug, unlisting the plugin from our catalog may be possible in exceptional cases, such as security concerns. However, we don't have control over the specific instances where the plugin is installed.
- In the event of a bug, unlisting the plugin from our catalog may be possible in exceptional cases, such as security concerns. However, we don't have control over the instances where the plugin is installed.
### Can I distribute my plugin somewhere else other than the Grafana plugin catalog?
@ -127,5 +124,5 @@ To submit an **update** for an already published plugin:
### What source code URL formats are supported?
- Using a tag or branch: `https://github.com/grafana/clock-panel/tree/v2.1.3`
- A tag or branch and the code is in a subdirectory (important for mono repos): `https://github.com/grafana/clock-panel/tree/v2.1.3/plugin/` (here, the plugin contains the plugin code)
- Using a tag or branch and the code is in a subdirectory (important for mono repos): `https://github.com/grafana/clock-panel/tree/v2.1.3/plugin/` (here, the plugin contains the plugin code)
- Using the latest main or master branch commit: `https://github.com/grafana/clock-panel/` (not recommended, it's better to pass a tag or branch)

View File

@ -1,20 +1,20 @@
---
title: Working with data frames
title: Work with data frames
---
# Working with data frames
# Work with data frames
The data frame is a columnar data structure which allows efficient querying of large amounts of data. Since data frames are a central concept when developing plugins for Grafana, in this guide we'll look at some ways you can use them.
The [data frame]({{< relref "data-frames" >}}) is a columnar data structure that allows for efficient querying of large amounts of data. Since data frames are a central concept when developing plugins for Grafana, in this guide we'll look at some ways you can use them.
The DataFrame interface contains a `name` and an array of `fields` where each field contains the name, type, and the values for the field.
The `DataFrame` interface contains a `name` and an array of `fields` where each field contains the name, type, and the values for the field.
> **Note:** If you're looking to migrate an existing plugin to use the data frame format, refer to [Migrate to data frames]({{< relref "migration-guide/#migrate-to-data-frames" >}}).
> **Note:** If you want to migrate an existing plugin to use the data frame format, refer to [Migrate to data frames]({{< relref "migration-guide/#migrate-to-data-frames" >}}).
## Create a data frame
If you build a data source plugin, then you'll most likely want to convert a response from an external API to a data frame. Let's look at how to create a data frame.
If you build a data source plugin, then you'll most likely want to convert a response from an external API to a data frame. Let's look at how to do this.
Let's start with creating a simple data frame that represents a time series. The easiest way to create a data frame is to use the toDataFrame function.
Let's start with creating a simple data frame that represents a time series. The easiest way to create a data frame is to use the `toDataFrame` function.
```ts
// Need to be of the same length.
@ -31,9 +31,9 @@ const frame = toDataFrame({
});
```
> **Note:** Data frames representing time series contain at least a `time` field, and a `number` field. By convention, built-in plugins use `Time` and `Value` as field names for data frames containing time series data.
> **Note:** Data frames representing time series contain at least a `time` field and a `number` field. By convention, built-in plugins use `Time` and `Value` as field names for data frames containing time series data.
As you can see from the example, creating data frames like this requires that your data is already stored as columnar data. If you already have the records in the form of an array of objects, then you can pass it to `toDataFrame` which tries to guess the schema based on the types and names of the objects in the array. If you're creating complex data frames this way, then be sure to verify that you get the schema you expect.
As you can see from the example, to create data frames like this, your data must already be stored as columnar data. If you already have the records in the form of an array of objects, then you can pass it to `toDataFrame`. In this case, `toDataFrame` tries to guess the schema based on the types and names of the objects in the array. To create complex data frames this way, be sure to verify that you get the schema you expect.
```ts
const series = [
@ -57,7 +57,7 @@ function SimplePanel({ data: Props }) {
}
```
Before you start reading the data, think about what data you expect. For example, to visualize a time series we'd need at least one time field, and one number field.
Before you start reading the data, think about what data you expect. For example, to visualize a time series you need at least one time field and one number field.
```ts
const timeField = frame.fields.find((field) => field.type === FieldType.time);
@ -78,7 +78,7 @@ for (let i = 0; i < frame.length; i++) {
}
```
Alternatively, you can use the DataFrameView, which gives you an array of objects that contain a property for each field in the frame.
Alternatively, you can use the `DataFrameView`, which gives you an array of objects that contain a property for each field in the frame.
```ts
const view = new DataFrameView(frame);
@ -113,7 +113,7 @@ return (
);
```
To apply field options to the name of a field, use getFieldDisplayName.
To apply field options to the name of a field, use `getFieldDisplayName`.
```ts
const valueField = frame.fields.find((field) => field.type === FieldType.number);