diff --git a/docs/sources/developers/plugins/_index.md b/docs/sources/developers/plugins/_index.md
deleted file mode 100644
index 3cad4f77d70..00000000000
--- a/docs/sources/developers/plugins/_index.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-aliases:
- - ../plugins/developing/
-description: Resources for creating Grafana plugins
-title: Plugin developer's guide
-weight: 200
----
-
-# Grafana plugin developer's guide
-
-You can extend Grafana's built-in capabilities with plugins. Plugins enable Grafana to accomplish specialized tasks, custom-tailored to your requirements. By making a plugin for your organization, you can connect Grafana to other data sources, ticketing tools, and CI/CD tooling.
-
-You can create plugins for private use or contribute them to the open source community by publishing to the [Grafana plugin catalog](https://grafana.com/grafana/plugins/). This catalog has hundreds of other community and commercial plugins.
-
-If you are a Grafana plugin developer or want to become one, this plugin developer's guide contains the tutorials and reference materials to help you get started.
-
-## Plugin basics
-
-- **Panel plugins** - Visualize data and navigate between dashboards.
-- **Data source plugins** - Link to new databases or other sources of data.
-- **App plugins** - Create rich applications for custom out-of-the-box experiences.
-
-> **Note:** To learn more about the types of plugins you can build, refer to the [Plugin management]({{< relref "../../administration/plugin-management" >}}) documentation.
-
-## Contents of this developer's guide
-
-The following topics are covered in this guide:
-
-- **[Get started with plugins]({{< relref "./get-started-with-plugins" >}})** - Start developing Grafana plugins with the [Create-plugin](https://www.npmjs.com/package/@grafana/create-plugin) tool.
-- **[Introduction to plugin development]({{< relref "./introduction-to-plugin-development" >}})** - Learn the fundamentals of Grafana plugin development: frontend and backend development processes, data frames, error handling, and more.
-- **[Create a Grafana plugin]({{< relref "./create-a-grafana-plugin" >}})** - If you're familiar with plugin creation, use the tutorials for creating panel plugins, data source plugins, and more to deepen your knowledge.
-- **[Migrate a plugin]({{< relref "./migration-guide" >}})** - Learn how to upgrade from a previous version of a Grafana plugin, rewrite an old Angular plugin in React, or update to a newer version.
-- **[Publish a Grafana plugin]({{< relref "./publish-a-plugin" >}})** - Learn about publishing a plugin to the Grafana plugin catalog, including publishing criteria, packaging, and deployment.
-- **[Reference]({{< relref "metadata.md" >}})** - Description of the `plugin.json` schema and plugin metadata.
-
-## Go further
-
-Learn more about additional tools and see plugin type examples.
-
-### User interface creation
-
-> > > > > > > 13be068919 (Docs: Plugin doc review for chunk 1-A (#67070))
-
-Explore the many UI components in our [Grafana UI library](https://developers.grafana.com/ui).
-
-### Plugin examples
-
-Grafana Labs provides a number of best practice example plugins for different use cases to help you quickly get started. Browse our [plugin examples](https://github.com/grafana/grafana-plugin-examples).
-
-### SDK
-
-Learn more about [Grafana Plugin SDK for Go]({{< relref "./backend/grafana-plugin-sdk-for-go" >}}).
diff --git a/docs/sources/developers/plugins/add-anonymous-usage-reporting.md b/docs/sources/developers/plugins/add-anonymous-usage-reporting.md
deleted file mode 100644
index 25838afbe45..00000000000
--- a/docs/sources/developers/plugins/add-anonymous-usage-reporting.md
+++ /dev/null
@@ -1,166 +0,0 @@
----
-title: Add anonymous usage reporting
----
-
-# Add anonymous usage reporting
-
-Add anonymous usage tracking to your plugin to send [reporting events]({{< relref "../../setup-grafana/configure-grafana/#reporting_enabled" >}}) that describe how your plugin is being used to a tracking system configured by your Grafana server administrator.
-
-## Event reporting
-
-In this section, we show an example of tracking usage data from a query editor and receiving a report back from the analytics service.
-
-### Sample query editor
-
-Let's say you have a `QueryEditor` that looks similar to the example below. It has a `CodeEditor` field where you can write your query and a query type selector so you can select the kind of query result that you expect to return:
-
-```ts
-import React, { ReactElement } from 'react';
-import { InlineFieldRow, InlineField, Select, CodeEditor } from '@grafana/ui';
-import type { EditorProps } from './types';
-
-export function QueryEditor(props: EditorProps): ReactElement {
- const { datasource, query, onChange, onRunQuery } = props;
- const queryType = { value: query.value ?? 'timeseries' };
- const queryTypes = [
- {
- label: 'Timeseries',
- value: 'timeseries',
- },
- {
- label: 'Table',
- value: 'table',
- },
- ];
-
- const onChangeQueryType = (type: string) => {
- onChange({
- ...query,
- queryType: type,
- });
- runQuery();
- };
-
- const onChangeRawQuery = (rawQuery: string) => {
- onChange({
- ...query,
- rawQuery: type,
- });
- runQuery();
- };
-
- return (
- <>
-
-
-
-
-
-
-
-
- >
- );
-}
-```
-
-### Track usage with `usePluginInteractionReporter`
-
-Let's say that you want to track how the usage looks between time series and table queries.
-
-What you want to do is to add the `usePluginInteractionReporter` to fetch a report function that takes two arguments:
-
-- Required: An event name that begins with `grafana_plugin_`. It is used to identify the interaction being made.
-- Optional: Attached contextual data. In our example, that is the query type.
-
-```ts
-import React, { ReactElement } from 'react';
-import { InlineFieldRow, InlineField, Select, CodeEditor } from '@grafana/ui';
-import { usePluginInteractionReporter } from '@grafana/runtime';
-import type { EditorProps } from './types';
-
-export function QueryEditor(props: EditorProps): ReactElement {
- const { datasource, query, onChange, onRunQuery } = props;
- const report = usePluginInteractionReporter();
-
- const queryType = { value: query.value ?? 'timeseries' };
- const queryTypes = [
- {
- label: 'Timeseries',
- value: 'timeseries',
- },
- {
- label: 'Table',
- value: 'table',
- },
- ];
-
- const onChangeQueryType = (type: string) => {
- onChange({
- ...query,
- queryType: type,
- });
- runQuery();
- };
-
- const onChangeRawQuery = (rawQuery: string) => {
- onChange({
- ...query,
- rawQuery: type,
- });
-
- report('grafana_plugin_executed_query', {
- query_type: queryType.value,
- });
-
- runQuery();
- };
-
- return (
- <>
-
-
-
-
-
-
-
-
- >
- );
-}
-```
-
-### Data returned from the analytics service
-
-When you use `usePluginInteractionReporter`, the report function that is handed back to you automatically attaches contextual data about the plugin you are tracking to the events.
-
-In our example, the following information is sent to the analytics service configured by the Grafana server administrator:
-
-```ts
-{
- type: 'interaction',
- payload: {
- interactionName: 'grafana_plugin_executed_query',
- grafana_version: '9.2.1',
- plugin_type: 'datasource',
- plugin_version: '1.0.0',
- plugin_id: 'grafana-example-datasource',
- plugin_name: 'Example',
- datasource_uid: 'qeSI8VV7z', // will only be added for datasources
- query_type: 'timeseries'
- }
-}
-```
diff --git a/docs/sources/developers/plugins/add-authentication-for-data-source-plugins.md b/docs/sources/developers/plugins/add-authentication-for-data-source-plugins.md
deleted file mode 100644
index 853f5b5eab2..00000000000
--- a/docs/sources/developers/plugins/add-authentication-for-data-source-plugins.md
+++ /dev/null
@@ -1,459 +0,0 @@
----
-aliases:
- - ../../plugins/developing/auth-for-datasources/
- - /docs/grafana/next/developers/plugins/authentication/
-title: Add authentication for data source plugins
----
-
-# Add authentication for data source plugins
-
-Grafana plugins can perform authenticated requests against a third-party API by using the _data source proxy_ or through a custom a _backend plugin_.
-
-## Choose an authentication method
-
-Configure your data source plugin to authenticate against a third-party API in one of either of two ways:
-
-- Use the [_data source proxy_](#authenticate-using-the-data-source-proxy) method, or
-- Build a [_backend plugin_](#authenticate-using-a-backend-plugin).
-
-| Case | Use |
-| ----------------------------------------------------------------------------------------------- | ------------------------------- |
-| Do you need to authenticate your plugin using Basic Auth or API keys? | Use the data source proxy. |
-| Does your API support OAuth 2.0 using client credentials? | Use the data source proxy. |
-| Does your API use a custom authentication method that isn't supported by the data source proxy? | Use a backend plugin. |
-| Does your API communicate over a protocol other than HTTP? | Build and use a backend plugin. |
-| Does your plugin require alerting support? | Build and use a backend plugin. |
-
-## Encrypt data source configuration
-
-Data source plugins have two ways of storing custom configuration: `jsonData` and `secureJsonData`.
-
-Users with the Viewer role can access data source configuration such as the contents of `jsonData` in cleartext. If you've enabled anonymous access, anyone who can access Grafana in their browser can see the contents of `jsonData`.
-
-Users of [Grafana Enterprise](https://grafana.com/products/enterprise/grafana/) can restrict access to data sources to specific users and teams. For more information, refer to [Data source permissions](https://grafana.com/docs/grafana/latest/enterprise/datasource_permissions).
-
-> **Important:** Do not use `jsonData` with sensitive data such as password, tokens, and API keys. If you need to store sensitive information, use `secureJsonData` instead.
-
-> **Note:** You can see the settings that the current user has access to by entering `window.grafanaBootData` in the developer console of your browser.
-
-### Store configuration in `secureJsonData`
-
-If you need to store sensitive information, use `secureJsonData` instead of `jsonData`. Whenever the user saves the data source configuration, the secrets in `secureJsonData` are sent to the Grafana server and encrypted before they're stored.
-
-Once you have encrypted the secure configuration, it can no longer be accessed from the browser. The only way to access secrets after they've been saved is by using the [_data source proxy_](#authenticate-using-the-data-source-proxy).
-
-### Add secret configuration to your data source plugin
-
-To demonstrate how you can add secrets to a data source plugin, let's add support for configuring an API key.
-
-1. Create a new interface in `types.ts` to hold the API key:
- ```ts
- export interface MySecureJsonData {
- apiKey?: string;
- }
- ```
-1. Add type information to your `secureJsonData` object by updating the props for your `ConfigEditor` to accept the interface as a second type parameter. Access the value of the secret from the `options` prop inside your `ConfigEditor`:
-
- ```ts
- interface Props extends DataSourcePluginOptionsEditorProps {}
- ```
-
- ```ts
- const { secureJsonData, secureJsonFields } = options;
- const { apiKey } = secureJsonData;
- ```
-
- > **Note:** You can do this until the user saves the configuration; when the user saves the configuration, Grafana clears the value. After that, you can use `secureJsonFields` to determine whether the property has been configured.
-
-1. To securely update the secret in your plugin's configuration editor, update the `secureJsonData` object using the `onOptionsChange` prop:
-
- ```ts
- const onAPIKeyChange = (event: ChangeEvent) => {
- onOptionsChange({
- ...options,
- secureJsonData: {
- apiKey: event.target.value,
- },
- });
- };
- ```
-
-1. Define a component that can accept user input:
-
- ```ts
-
- ```
-
-1. Optional: If you want the user to be able to reset the API key, then you need to set the property to `false` in the `secureJsonFields` object:
-
- ```ts
- const onResetAPIKey = () => {
- onOptionsChange({
- ...options,
- secureJsonFields: {
- ...options.secureJsonFields,
- apiKey: false,
- },
- secureJsonData: {
- ...options.secureJsonData,
- apiKey: '',
- },
- });
- };
- ```
-
-Now that users can configure secrets, the next step is to see how we can add them to our requests.
-
-## Authenticate using the data source proxy
-
-Once the user has saved the configuration for a data source, the secret data source configuration will no longer be available in the browser. Encrypted secrets can only be accessed on the server. So how do you add them to your request?
-
-The Grafana server comes with a proxy that lets you define templates for your requests: _proxy routes_. Grafana sends the proxy route to the server, decrypts the secrets along with other configuration, and adds them to the request before sending it.
-
-> **Note:** Be sure not to confuse the data source proxy with the [auth proxy]({{< relref "../../setup-grafana/configure-security/configure-authentication/auth-proxy/" >}}). The data source proxy is used to authenticate a data source, while the auth proxy is used to log into Grafana itself.
-
-### Add a proxy route to your plugin
-
-To forward requests through the Grafana proxy, you need to configure one or more _proxy routes_. A proxy route is a template for any outgoing request that is handled by the proxy. You can configure proxy routes in the [plugin.json](https://grafana.com/docs/grafana/latest/developers/plugins/metadata/) file.
-
-1. Add the route to `plugin.json`:
-
- ```json
- "routes": [
- {
- "path": "example",
- "url": "https://api.example.com"
- }
- ]
- ```
-
- > **Note:** You need to restart the Grafana server every time you make a change to your `plugin.json` file.
-
-1. In the `DataSource`, extract the proxy URL from `instanceSettings` to a class property called `url`:
-
- ```ts
- export class DataSource extends DataSourceApi {
- url?: string;
-
- constructor(instanceSettings: DataSourceInstanceSettings) {
- super(instanceSettings);
-
- this.url = instanceSettings.url;
- }
-
- // ...
- }
- ```
-
-1. In the `query` method, make a request using `BackendSrv`. The first section of the URL path needs to match the `path` of your proxy route. The data source proxy replaces `this.url + routePath` with the `url` of the route. Based on our example, the URL for the request would be `https://api.example.com/v1/users`:
-
- ```ts
- import { getBackendSrv } from '@grafana/runtime';
- ```
-
- ```ts
- const routePath = '/example';
-
- getBackendSrv().datasourceRequest({
- url: this.url + routePath + '/v1/users',
- method: 'GET',
- });
- ```
-
-### Add a dynamic proxy route to your plugin
-
-Grafana sends the proxy route to the server, where the data source proxy decrypts any sensitive data and interpolates the template variables with the decrypted data before making the request.
-
-To add user-defined configuration to your routes:
-
-- Use `.JsonData` for configuration stored in `jsonData`. For example, where `projectId` is the name of a property in the `jsonData` object:
-
- ```json
- "routes": [
- {
- "path": "example",
- "url": "https://api.example.com/projects/{{ .JsonData.projectId }}"
- }
- ]
- ```
-
-- Use `.SecureJsonData` for sensitive data stored in `secureJsonData`. For example, where `password` is the name of a property in the `secureJsonData` object:
-
- ```json
- "routes": [
- {
- "path": "example",
- "url": "https://{{ .JsonData.username }}:{{ .SecureJsonData.password }}@api.example.com"
- }
- ]
- ```
-
-In addition to adding the URL to the proxy route, you can also add headers, URL parameters, and a request body.
-
-#### Add HTTP headers to a proxy route
-
-Here's an example of adding `name` and `content` as HTTP headers:
-
-```json
-"routes": [
- {
- "path": "example",
- "url": "https://api.example.com",
- "headers": [
- {
- "name": "Authorization",
- "content": "Bearer {{ .SecureJsonData.apiToken }}"
- }
- ]
- }
-]
-```
-
-#### Add URL parameters to a proxy route
-
-Here's an example of adding `name` and `content` as URL parameters:
-
-```json
-"routes": [
- {
- "path": "example",
- "url": "http://api.example.com",
- "urlParams": [
- {
- "name": "apiKey",
- "content": "{{ .SecureJsonData.apiKey }}"
- }
- ]
- }
-]
-```
-
-#### Add a request body to a proxy route
-
-Here's an example of adding `username` and `password` to the request body:
-
-```json
-"routes": [
- {
- "path": "example",
- "url": "http://api.example.com",
- "body": {
- "username": "{{ .JsonData.username }}",
- "password": "{{ .SecureJsonData.password }}"
- }
- }
-]
-```
-
-### Add an OAuth 2.0 proxy route to your plugin
-
-Since your request to each route is made server-side with OAuth 2.0 authentication, only machine-to-machine requests are supported. In order words, if you need to use a different grant than client credentials, you need to implement it yourself.
-
-To authenticate using OAuth 2.0, add a `tokenAuth` object to the proxy route definition. If necessary, Grafana performs a request to the URL defined in `tokenAuth` to retrieve a token before making the request to the URL in your proxy route. Grafana automatically renews the token when it expires.
-
-Any parameters defined in `tokenAuth.params` are encoded as `application/x-www-form-urlencoded` and sent to the token URL.
-
-```json
-{
- "routes": [
- {
- "path": "api",
- "url": "https://api.example.com/v1",
- "tokenAuth": {
- "url": "https://api.example.com/v1/oauth/token",
- "params": {
- "grant_type": "client_credentials",
- "client_id": "{{ .SecureJsonData.clientId }}",
- "client_secret": "{{ .SecureJsonData.clientSecret }}"
- }
- }
- }
- ]
-}
-```
-
-## Authenticate using a backend plugin
-
-While the data source proxy supports the most common authentication methods for HTTP APIs, using proxy routes has a few limitations:
-
-- Proxy routes only support HTTP or HTTPS.
-- Proxy routes don't support custom token authentication.
-
-If any of these limitations apply to your plugin, you need to add a [backend plugin]({{< relref "backend/" >}}). Because backend plugins run on the server, they can access decrypted secrets, which makes it easier to implement custom authentication methods.
-
-The decrypted secrets are available from the `DecryptedSecureJSONData` field in the instance settings.
-
-```go
-func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
- instanceSettings := req.PluginContext.DataSourceInstanceSettings
-
- if apiKey, exists := settings.DecryptedSecureJSONData["apiKey"]; exists {
- // Use the decrypted API key.
- }
-
- // ...
-}
-```
-
-## Forward OAuth identity for the logged-in user
-
-If your data source uses the same OAuth provider as Grafana itself, for example using [Generic OAuth Authentication]({{< relref "../../setup-grafana/configure-security/configure-authentication/generic-oauth/" >}}), then your data source plugin can reuse the access token for the logged-in Grafana user.
-
-To allow Grafana to pass the access token to the plugin, update the data source configuration and set the `jsonData.oauthPassThru` property to `true`. The [DataSourceHttpSettings](https://developers.grafana.com/ui/latest/index.html?path=/story/data-source-datasourcehttpsettings--basic) settings provide a toggle, the **Forward OAuth Identity** option, for this. You can also build an appropriate toggle to set `jsonData.oauthPassThru` in your data source configuration page UI.
-
-When configured, Grafana can forward authorization HTTP headers such as `Authorization` or `X-ID-Token` to a backend data source. This information is available across the `QueryData`, `CallResource` and `CheckHealth` requests.
-
-To get Grafana to forward the headers, create a HTTP client using the [Grafana plugin SDK for Go](https://pkg.go.dev/github.com/grafana/grafana-plugin-sdk-go/backend/httpclient) and set the `ForwardHTTPHeaders` option to `true` (by default, it's set to `false`). This package exposes request information which can be subsequently forwarded downstream and/or used directly within the plugin.
-
-```go
-func NewDatasource(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
- opts, err := settings.HTTPClientOptions()
- if err != nil {
- return nil, fmt.Errorf("http client options: %w", err)
- }
-
- // Important: Reuse the same client for each query to avoid using all available connections on a host.
-
- opts.ForwardHTTPHeaders = true
-
- cl, err := httpclient.New(opts)
- if err != nil {
- return nil, fmt.Errorf("httpclient new: %w", err)
- }
- return &Datasource{
- httpClient: cl,
- }, nil
-}
-
-func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
- // Necessary to keep the Context, since the injected middleware is configured there
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://some-url", nil)
- if err != nil {
- return nil, fmt.Errorf("new request with context: %w", err)
- }
- // Authorization header will be automatically injected if oauthPassThru is configured
- resp, err := ds.httpClient.Do(req)
- // ...
-}
-```
-
-You can see a full working plugin example here: [datasource-http-backend](https://github.com/grafana/grafana-plugin-examples/tree/main/examples/datasource-http-backend).
-
-### Extract a header from an HTTP request
-
-If you need to access the HTTP header information directly, you can also extract that information from the request:
-
-```go
-func (ds *dataSource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
- token := strings.Fields(req.GetHTTPHeader(backend.OAuthIdentityTokenHeaderName))
- var (
- tokenType = token[0]
- accessToken = token[1]
- )
- idToken := req.GetHTTPHeader(backend.OAuthIdentityIDTokenHeaderName) // present if user's token includes an ID token
-
- // ...
- return &backend.CheckHealthResult{Status: backend.HealthStatusOk}, nil
-}
-
-func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
- token := strings.Fields(req.GetHTTPHeader(backend.OAuthIdentityTokenHeaderName))
- var (
- tokenType = token[0]
- accessToken = token[1]
- )
- idToken := req.GetHTTPHeader(backend.OAuthIdentityIDTokenHeaderName)
-
- for _, q := range req.Queries {
- // ...
- }
-}
-
-func (ds *dataSource) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
- token := req.GetHTTPHeader(backend.OAuthIdentityTokenHeaderName)
- idToken := req.GetHTTPHeader(backend.OAuthIdentityIDTokenHeaderName)
-
- // ...
-}
-```
-
-## Work with cookies
-
-### Forward cookies for the logged-in user
-
-Your data source plugin can forward cookies for the logged-in Grafana user to the data source. Use the [DataSourceHttpSettings](https://developers.grafana.com/ui/latest/index.html?path=/story/data-source-datasourcehttpsettings--basic) component on the data source's configuration page. It provides the **Allowed cookies** option, where you can specify the cookie names.
-
-When configured, as with [authorization headers](#forward-oauth-identity-for-the-logged-in-user), these cookies are automatically injected if you use the SDK HTTP client.
-
-### Extract cookies for the logged-in user
-
-You can also extract the cookies in the `QueryData`, `CallResource` and `CheckHealth` requests if required.
-
-**`QueryData`**
-
-```go
-func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
- cookies:= req.GetHTTPHeader(backend.CookiesHeaderName)
-
- // ...
-}
-```
-
-**`CallResource`**
-
-```go
-func (ds *dataSource) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
- cookies:= req.GetHTTPHeader(backend.CookiesHeaderName)
-
- // ...
-}
-```
-
-**`CheckHealth`**
-
-```go
-func (ds *dataSource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
- cookies:= req.GetHTTPHeader(backend.CookiesHeaderName)
-
- // ...
-}
-```
-
-## Forward user header for the logged-in user
-
-When [send_user_header]({{< relref "../../setup-grafana/configure-grafana/_index.md#send_user_header" >}}) is enabled, Grafana passes the user header to the plugin using the `X-Grafana-User` header. You can forward this header as well as [authorization headers](#forward-oauth-identity-for-the-logged-in-user) or [configured cookies](#forward-cookies-for-the-logged-in-user).
-
-**`QueryData`**
-
-```go
-func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
- u := req.GetHTTPHeader("X-Grafana-User")
-
- // ...
-}
-```
-
-**`CallResource`**
-
-```go
-func (ds *dataSource) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
- u := req.GetHTTPHeader("X-Grafana-User")
-
- // ...
-}
-```
-
-**`CheckHealth`**
-
-```go
-func (ds *dataSource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
- u := req.GetHTTPHeader("X-Grafana-User")
-
- // ...
-}
-```
diff --git a/docs/sources/developers/plugins/add-distributed-tracing-for-backend-plugins.md b/docs/sources/developers/plugins/add-distributed-tracing-for-backend-plugins.md
deleted file mode 100644
index 9a3668c9fee..00000000000
--- a/docs/sources/developers/plugins/add-distributed-tracing-for-backend-plugins.md
+++ /dev/null
@@ -1,110 +0,0 @@
----
-title: Add distributed tracing for backend plugins
----
-
-# Add distributed tracing for backend plugins
-
-> **Note:** This feature requires at least Grafana 9.5.0, and your plugin needs to be built at least with grafana-plugins-sdk-go v0.157.0. If you run a plugin with tracing features on an older version of Grafana, tracing is disabled.
-
-Distributed tracing allows backend plugin developers to create custom spans in their plugins, and send them to the same endpoint and with the same propagation format as the main Grafana instance. The tracing context is also propagated from the Grafana instance to the plugin, so the plugin's spans will be correlated to the correct trace.
-
-## Plugin configuration
-
-Plugin tracing must be enabled manually on a per-plugin basis, by specifying `tracing = true` in the plugin's config section:
-
-```ini
-[plugin.myorg-myplugin-datasource]
-tracing = true
-```
-
-## OpenTelemetry configuration in Grafana
-
-Grafana supports [OpenTelemetry](https://opentelemetry.io/) for distributed tracing. If Grafana is configured to use a deprecated tracing system (Jaeger or OpenTracing), then tracing is disabled in the plugin provided by the SDK and configured when calling `datasource.Manage | app.Manage`.
-
-OpenTelemetry must be enabled and configured for the Grafana instance. Please refer to the [Grafana configuration documentation](
-{{< relref "../../setup-grafana/configure-grafana/#tracingopentelemetry" >}}) for more information.
-
-Refer to the [OpenTelemetry Go SDK](https://pkg.go.dev/go.opentelemetry.io/otel) for in-depth documentation about all the features provided by OpenTelemetry.
-
-> **Note:** If tracing is disabled in Grafana, `backend.DefaultTracer()` returns a no-op tracer.
-
-## Implement tracing in your plugin
-
-> **Note:** Make sure you are using at least grafana-plugin-sdk-go v0.157.0. You can update with `go get -u github.com/grafana/grafana-plugin-sdk-go`.
-
-### Configure a global tracer
-
-When OpenTelemetry tracing is enabled on the main Grafana instance and tracing is enabled for a plugin, the OpenTelemetry endpoint address and propagation format is passed to the plugin during startup. These parameters are used to configure a global tracer.
-
-1. Use `datasource.Manage` or `app.Manage` to run your plugin to automatically configure the global tracer. Specify any custom attributes for the default tracer using `CustomAttributes`:
-
- ```go
- func main() {
- if err := datasource.Manage("MY_PLUGIN_ID", plugin.NewDatasource, datasource.ManageOpts{
- TracingOpts: tracing.Opts{
- // Optional custom attributes attached to the tracer's resource.
- // The tracer will already have some SDK and runtime ones pre-populated.
- CustomAttributes: []attribute.KeyValue{
- attribute.String("my_plugin.my_attribute", "custom value"),
- },
- },
- }); err != nil {
- log.DefaultLogger.Error(err.Error())
- os.Exit(1)
- }
- }
- ```
-
-1. Once you have configured tracing, use the global tracer like this:
-
- ```go
- tracing.DefaultTracer()
- ```
-
- This returns an [OpenTelemetry `trace.Tracer`](https://pkg.go.dev/go.opentelemetry.io/otel/trace#Tracer) for creating spans.
-
- **Example:**
-
- ```go
- func (d *Datasource) query(ctx context.Context, pCtx backend.PluginContext, query backend.DataQuery) (backend.DataResponse, error) {
- ctx, span := tracing.DefaultTracer().Start(
- ctx,
- "query processing",
- trace.WithAttributes(
- attribute.String("query.ref_id", query.RefID),
- attribute.String("query.type", query.QueryType),
- attribute.Int64("query.max_data_points", query.MaxDataPoints),
- attribute.Int64("query.interval_ms", query.Interval.Milliseconds()),
- attribute.Int64("query.time_range.from", query.TimeRange.From.Unix()),
- attribute.Int64("query.time_range.to", query.TimeRange.To.Unix()),
- ),
- )
- defer span.End()
- log.DefaultLogger.Debug("query", "traceID", trace.SpanContextFromContext(ctx).TraceID())
-
- // ...
- }
- ```
-
-### Tracing gRPC calls
-
-When tracing is enabled, a new span is created automatically for each gRPC call (`QueryData`, `CheckHealth`, etc.), both on Grafana's side and on the plugin's side. The plugin SDK also injects the trace context into the `context.Context` that is passed to those methods.
-
-You can retrieve the [trace.SpanContext](https://pkg.go.dev/go.opentelemetry.io/otel/trace#SpanContext) with `tracing.SpanContextFromContext` by passing the original `context.Context` to it:
-
-```go
-func (d *Datasource) query(ctx context.Context, pCtx backend.PluginContext, query backend.DataQuery) (backend.DataResponse, error) {
- spanCtx := trace.SpanContextFromContext(ctx)
- traceID := spanCtx.TraceID()
-
- // ...
-}
-```
-
-### Tracing HTTP requests
-
-When tracing is enabled, a `TracingMiddleware` is also added to the default middleware stack to all HTTP clients created using the `httpclient.New` or `httpclient.NewProvider`, unless you specify custom middleware. This middleware creates spans for each outgoing HTTP request and provides some useful attributes and events related to the request's lifecycle.
-
-## Plugin example
-
-Refer to the [datasource-http-backend plugin example](https://github.com/grafana/grafana-plugin-examples/tree/main/examples/datasource-http-backend) for a complete example of a plugin with full distributed tracing support.
diff --git a/docs/sources/developers/plugins/add-query-editor-help.md b/docs/sources/developers/plugins/add-query-editor-help.md
deleted file mode 100644
index 815240966a4..00000000000
--- a/docs/sources/developers/plugins/add-query-editor-help.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: Add query editor help
----
-
-# Add query editor help
-
-Query editors support the addition of a help component to display examples of potential queries. When the user clicks on one of the examples, the query editor is automatically updated. This helps the user to make faster queries.
-
-1. In the `src` directory of your plugin, create a file `QueryEditorHelp.tsx` with the following content:
-
- ```ts
- import React from 'react';
- import { QueryEditorHelpProps } from '@grafana/data';
-
- export default (props: QueryEditorHelpProps) => {
- return
My cheat sheet
;
- };
- ```
-
-1. Configure the plugin to use `QueryEditorHelp`:
-
- ```ts
- import QueryEditorHelp from './QueryEditorHelp';
- ```
-
- ```ts
- export const plugin = new DataSourcePlugin(DataSource)
- .setConfigEditor(ConfigEditor)
- .setQueryEditor(QueryEditor)
- .setQueryEditorHelp(QueryEditorHelp);
- ```
-
-1. Create a few examples of potential queries:
-
- ```ts
- import React from 'react';
- import { QueryEditorHelpProps, DataQuery } from '@grafana/data';
-
- const examples = [
- {
- title: 'Addition',
- expression: '1 + 2',
- label: 'Add two integers',
- },
- {
- title: 'Subtraction',
- expression: '2 - 1',
- label: 'Subtract an integer from another',
- },
- ];
-
- export default (props: QueryEditorHelpProps) => {
- return (
-
- );
- };
- ```
diff --git a/docs/sources/developers/plugins/add-support-for-annotations.md b/docs/sources/developers/plugins/add-support-for-annotations.md
deleted file mode 100644
index 1d52491878a..00000000000
--- a/docs/sources/developers/plugins/add-support-for-annotations.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: Add support for annotations
----
-
-# Add support for annotations
-
-You can add support to your plugin for annotations that will insert information into Grafana alerts. This guide explains how to add support for [annotations]({{< relref "../../dashboards/build-dashboards/annotate-visualizations/#querying-other-data-sources " >}}) to a data source plugin.
-
-## Support annotations in your data source plugin
-
-To enable annotations, simply add two lines of code to your plugin. Grafana uses your default query editor for editing annotation queries.
-
-1. Add `"annotations": true` to the [plugin.json]({{< relref "metadata/" >}}) file to let Grafana know that your plugin supports annotations.
-
- **In `plugin.json`:**
-
- ```json
- {
- "annotations": true
- }
- ```
-
-2. In `datasource.ts`, override the `annotations` property from `DataSourceApi` (or `DataSourceWithBackend` for backend data sources). For the default behavior, set `annotations` to an empty object.
-
- **In `datasource.ts`:**
-
- ```ts
- annotations: {
- }
- ```
diff --git a/docs/sources/developers/plugins/add-support-for-explore-queries.md b/docs/sources/developers/plugins/add-support-for-explore-queries.md
deleted file mode 100644
index a19da47b388..00000000000
--- a/docs/sources/developers/plugins/add-support-for-explore-queries.md
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: Add features to Explore queries
----
-
-# Add features for Explore queries
-
-[Explore]({{< relref "../../explore/" >}}) allows users can make ad-hoc queries without the use of a dashboard. This is useful when they want to troubleshoot or learn more about the data.
-
-Your data source supports Explore by default and uses the existing query editor for the data source. This guide explains how to extend functionality for Explore queries in a data source plugin.
-
-## Add an Explore-specific query editor
-
-To extend Explore functionality for your data source, define an Explore-specific query editor.
-
-1. Create a file `ExploreQueryEditor.tsx` in the `src` directory of your plugin, with content similar to this:
-
- ```ts
- import React from 'react';
-
- import { QueryEditorProps } from '@grafana/data';
- import { QueryField } from '@grafana/ui';
- import { DataSource } from './DataSource';
- import { MyQuery, MyDataSourceOptions } from './types';
-
- type Props = QueryEditorProps;
-
- export default (props: Props) => {
- return
My Explore-specific query editor
;
- };
- ```
-
-1. Modify your base query editor in `QueryEditor.tsx` to render the Explore-specific query editor. For example:
-
- ```ts
- // [...]
- import { CoreApp } from '@grafana/data';
- import ExploreQueryEditor from './ExploreQueryEditor';
-
- type Props = QueryEditorProps;
-
- export default (props: Props) => {
- const { app } = props;
-
- switch (app) {
- case CoreApp.Explore:
- return ;
- default:
- return
My base query editor
;
- }
- };
- ```
-
-## Select a preferred visualization type
-
-By default, Explore should select an appropriate and useful visualization for your data. It can figure out whether the returned data is time series data or logs or something else, and creates the right type of visualization.
-
-However, if you want a custom visualization, you can add a hint to your returned data frame by setting the `meta' attribute to `preferredVisualisationType`.
-
-Construct a data frame with specific metadata like this:
-
-```
-const firstResult = new MutableDataFrame({
- fields: [...],
- meta: {
- preferredVisualisationType: 'logs',
- },
-});
-```
-
-For possible options, refer to [PreferredVisualisationType](https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/types/data.ts#L25).
diff --git a/docs/sources/developers/plugins/add-support-for-variables.md b/docs/sources/developers/plugins/add-support-for-variables.md
deleted file mode 100644
index dccd5b16491..00000000000
--- a/docs/sources/developers/plugins/add-support-for-variables.md
+++ /dev/null
@@ -1,198 +0,0 @@
----
-title: Add support for variables in plugins
----
-
-# Add support for variables in plugins
-
-Variables are placeholders for values, and you can use them to create templated queries, and dashboard or panel links. For more information on variables, refer to [Templates and variables]({{< relref "../../dashboards/variables/" >}}).
-
-In this guide, you'll see how you can turn a query string like this:
-
-```sql
-SELECT * FROM services WHERE id = "$service"
-```
-
-into
-
-```sql
-SELECT * FROM services WHERE id = "auth-api"
-```
-
-Grafana provides a couple of helper functions to interpolate variables in a string template. Let's see how you can use them in your plugin.
-
-## Interpolate variables in panel plugins
-
-For panels, the `replaceVariables` function is available in the `PanelProps`.
-
-Add `replaceVariables` to the argument list, and pass a user-defined template string to it:
-
-```ts
-export function SimplePanel({ options, data, width, height, replaceVariables }: Props) {
- const query = replaceVariables('Now displaying $service');
-
- return
{query}
;
-}
-```
-
-## Interpolate variables in data source plugins
-
-For data sources, you need to use the `getTemplateSrv`, which returns an instance of `TemplateSrv`.
-
-1. Import `getTemplateSrv` from the `runtime` package:
-
- ```ts
- import { getTemplateSrv } from '@grafana/runtime';
- ```
-
-1. In your `query` method, call the `replace` method with a user-defined template string:
-
- ```ts
- async query(options: DataQueryRequest): Promise {
- const query = getTemplateSrv().replace('SELECT * FROM services WHERE id = "$service"', options.scopedVars);
-
- const data = makeDbQuery(query);
-
- return { data };
- }
- ```
-
-## Format multi-value variables
-
-When a user selects multiple values for a variable, the value of the interpolated variable depends on the [variable format]({{< relref "../../dashboards/variables/variable-syntax/#advanced-variable-format-options" >}}).
-
-A data source plugin can define the default format option when no format is specified by adding a third argument to the interpolation function.
-
-Let's change the SQL query to use CSV format by default:
-
-```ts
-getTemplateSrv().replace('SELECT * FROM services WHERE id IN ($service)', options.scopedVars, 'csv');
-```
-
-Now, when users write `$service`, the query looks like this:
-
-```sql
-SELECT * FROM services WHERE id IN (admin,auth,billing)
-```
-
-For more information on the available variable formats, refer to [Advanced variable format options]({{< relref "../../dashboards/variables/variable-syntax/#advanced-variable-format-options" >}}).
-
-## Set a variable from your plugin
-
-Not only can you read the value of a variable, you can also update the variable from your plugin. Use `locationService.partial(query, replace)`.
-
-The following example shows how to update a variable called `service`.
-
-- `query` contains the query parameters you want to update. The query parameters that control variables are prefixed with `var-`.
-- `replace: true` tells Grafana to update the current URL state rather than creating a new history entry.
-
-```ts
-import { locationService } from '@grafana/runtime';
-```
-
-```ts
-locationService.partial({ 'var-service': 'billing' }, true);
-```
-
-> **Note:** Grafana queries your data source whenever you update a variable. Excessive updates to variables can slow down Grafana and lead to a poor user experience.
-
-## Add support for query variables to your data source
-
-A [query variable]({{< relref "../../dashboards/variables/add-template-variables/#add-a-query-variable" >}}) is a type of variable that allows you to query a data source for the values. By adding support for query variables to your data source plugin, users can create dynamic dashboards based on data from your data source.
-
-Let's start by defining a query model for the variable query:
-
-```ts
-export interface MyVariableQuery {
- namespace: string;
- rawQuery: string;
-}
-```
-
-For a data source to support query variables, override the `metricFindQuery` in your `DataSourceApi` class. The `metricFindQuery` function returns an array of `MetricFindValue` which has a single property, `text`:
-
-```ts
-async metricFindQuery(query: MyVariableQuery, options?: any) {
- // Retrieve DataQueryResponse based on query.
- const response = await this.fetchMetricNames(query.namespace, query.rawQuery);
-
- // Convert query results to a MetricFindValue[]
- const values = response.data.map(frame => ({ text: frame.name }));
-
- return values;
-}
-```
-
-> **Note:** By default, Grafana provides a basic query model and editor for simple text queries. If that's all you need, then leave the query type as `string`:
-
-```ts
-async metricFindQuery(query: string, options?: any)
-```
-
-Let's create a custom query editor to allow the user to edit the query model.
-
-1. Create a `VariableQueryEditor` component:
-
- ```ts
- import React, { useState } from 'react';
- import { MyVariableQuery } from './types';
-
- interface VariableQueryProps {
- query: MyVariableQuery;
- onChange: (query: MyVariableQuery, definition: string) => void;
- }
-
- export const VariableQueryEditor: React.FC = ({ onChange, query }) => {
- const [state, setState] = useState(query);
-
- const saveQuery = () => {
- onChange(state, `${state.query} (${state.namespace})`);
- };
-
- const handleChange = (event: React.FormEvent) =>
- setState({
- ...state,
- [event.currentTarget.name]: event.currentTarget.value,
- });
-
- return (
- <>
-
- Namespace
-
-
-
- Query
-
-
- >
- );
- };
- ```
-
- Grafana saves the query model whenever one of the text fields loses focus (`onBlur`) and then previews the values returned by `metricFindQuery`.
-
- The second argument to `onChange` allows you to set a text representation of the query that will appear next to the name of the variable in the variables list.
-
-1. Configure your plugin to use the query editor:
-
- ```ts
- import { VariableQueryEditor } from './VariableQueryEditor';
-
- export const plugin = new DataSourcePlugin(DataSource)
- .setQueryEditor(QueryEditor)
- .setVariableQueryEditor(VariableQueryEditor);
- ```
-
-That's it! You can now try out the plugin by adding a [query variable]({{< relref "../../dashboards/variables/add-template-variables/#add-a-query-variable" >}}) to your dashboard.
diff --git a/docs/sources/developers/plugins/backend/_index.md b/docs/sources/developers/plugins/backend/_index.md
deleted file mode 100644
index 44c228f7ca5..00000000000
--- a/docs/sources/developers/plugins/backend/_index.md
+++ /dev/null
@@ -1,97 +0,0 @@
----
-aliases:
- - ../../plugins/developing/backend-plugins-guide/
-keywords:
- - grafana
- - plugins
- - backend
- - plugin
- - backend-plugins
- - documentation
-title: Backend plugins
----
-
-# Backend plugins
-
-The Grafana plugin system for backend development allows you to integrate Grafana with virtually anything and offer custom visualizations. This document explains the system's background, use cases, and key features.
-
-## Background
-
-Grafana added support for _frontend plugins_ in version 3.0 so that the Grafana community could create custom panels and data sources. It was wildly successful and has made Grafana much more useful for our user community.
-
-However, one limitation of these plugins is that they run on the client side, in the browser. Therefore, they can't support use cases that require server-side features.
-
-Since Grafana v7.0, we have supported server-side plugins that remove this limitation. We use the term _backend plugin_ to denote that a plugin has a backend component. A backend plugin usually requires frontend components as well. For example, some backend data source plugins need query editor components on the frontend.
-
-## Use cases for implementing a backend plugin
-
-The following examples give some common use cases for backend plugins:
-
-- Enable [Grafana Alerting]({{< relref "../../../alerting/" >}}) for data sources.
-- Connect to SQL database servers and other non-HTTP services that normally can't be connected to from a browser.
-- Keep state between users, for example, by query caching for data sources.
-- Use custom authentication methods and/or authorization checks that aren't supported in Grafana.
-- Use a custom data source request proxy (refer to [Resources]({{< relref "#resources" >}}) for more information).
-
-## Grafana backend plugin system
-
-The Grafana backend plugin system is based on HashiCorp's [Go Plugin System over RPC](https://github.com/hashicorp/go-plugin). Our implementation of the Grafana server launches each backend plugin as a subprocess and communicates with it over [gRPC](https://grpc.io/).
-
-### Benefits for plugin development
-
-Grafana's approach has benefits for developers:
-
-- **Stability:** Plugins can't crash your Grafana process: a panic in a plugin doesn't panic the server.
-- **Ease of development:** Plugins can be written in any language that supports gRPC (for example, write a Go application and run `go build`).
-- **Security:** Plugins only have access to the interfaces and arguments given to them, not to the entire memory space of the process.
-
-### Capabilities of the backend plugin system
-
-Grafana's backend plugin system exposes several key capabilities, or building blocks, that your backend plugin can implement:
-
-- Query data
-- Resources
-- Health checks
-- Collect metrics
-- Streaming
-
-#### Query data
-
-The query data capability allows a backend plugin to handle data source queries that are submitted from a [dashboard]({{< relref "../../../dashboards/" >}}), [Explore]({{< relref "../../../explore/" >}}) or [Grafana Alerting]({{< relref "../../../alerting/" >}}). The response contains [data frames]({{< relref "../data-frames/" >}}), which are used to visualize metrics, logs, and traces.
-
-{{% admonition type="note" %}} Backend data source plugins are required to implement the query data capability.{{%
-/admonition %}}
-
-#### Resources
-
-The resources capability allows a backend plugin to handle custom HTTP requests sent to the Grafana HTTP API and respond with custom HTTP responses. Here, the request and response formats can vary. For example, you can use JSON, plain text, HTML, or static resources such as images and files, and so on.
-
-Compared to the query data capability, where the response contains data frames, the resources capability gives the plugin developer more flexibility for extending and opening up Grafana for new and interesting use cases.
-
-### Use cases
-
-Examples of use cases for implementing resources:
-
-- Implement a custom data source proxy to provide certain authentication, authorization, or other requirements that are not supported in Grafana's [built-in data proxy]({{< relref "../../http_api/data_source/#data-source-proxy-calls" >}}).
-- Return data or information in a format suitable for use within a data source query editor to provide auto-complete functionality.
-- Return static resources such as images or files.
-- Send a command to a device, such as a microcontroller or IoT device.
-- Request information from a device, such as a microcontroller or IoT device.
-- Extend Grafana's HTTP API with custom resources, methods and actions.
-- Use [chunked transfer encoding](https://en.wikipedia.org/wiki/Chunked_transfer_encoding) to return large data responses in chunks or to enable certain streaming capabilities.
-
-#### Health checks
-
-The health checks capability allows a backend plugin to return the status of the plugin. For data source backend plugins, the health check is automatically called when a user edits a data source and selects _Save & Test_ in the UI.
-
-A plugin's health check endpoint is exposed in the Grafana HTTP API and allows external systems to continuously poll the plugin's health to make sure that it's running and working as expected.
-
-#### Collect metrics
-
-A backend plugin can collect and return runtime, process, and custom metrics using the text-based Prometheus [exposition format](https://prometheus.io/docs/instrumenting/exposition_formats/). If you're using the [Grafana Plugin SDK for Go]({{< relref "grafana-plugin-sdk-for-go/" >}}) to implement your backend plugin, then the [Prometheus instrumentation library for Go applications](https://github.com/prometheus/client_golang) is built-in. This SDK gives you Go runtime metrics and process metrics out of the box. You can use the [Prometheus instrumentation library](https://github.com/prometheus/client_golang) to add custom metrics to instrument your backend plugin.
-
-The Grafana HTTP API offers an endpoint (`/api/plugins//metrics`) that allows you to configure a Prometheus instance to scrape the metrics.
-
-#### Streaming
-
-The streaming capability allows a backend plugin to handle data source queries that are streaming. For more information, refer to [Build a streaming data source plugin]({{}})
diff --git a/docs/sources/developers/plugins/backend/grafana-plugin-sdk-for-go.md b/docs/sources/developers/plugins/backend/grafana-plugin-sdk-for-go.md
deleted file mode 100644
index e26860ff2bd..00000000000
--- a/docs/sources/developers/plugins/backend/grafana-plugin-sdk-for-go.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-keywords:
- - grafana
- - plugins
- - backend
- - plugin
- - backend-plugins
- - sdk
- - documentation
-title: Grafana Plugin SDK for Go
----
-
-# Grafana plugin SDK for Go
-
-The [Grafana plugin SDK for Go](https://pkg.go.dev/mod/github.com/grafana/grafana-plugin-sdk-go?tab=overview) is a [Go](https://golang.org/) module that provides a set of [packages](https://pkg.go.dev/mod/github.com/grafana/grafana-plugin-sdk-go?tab=packages) that you can use to implement a backend plugin.
-
-The plugin SDK provides a high-level framework with APIs, utilities, and tooling. By using the SDK, you can avoid the need to learn the details of the [plugin protocol]({{< relref "plugin-protocol/" >}}) and RPC communication protocol, so you don't have to manage either one.
-
-## Versioning
-
-The Grafana plugin Go SDK is still in development. It is based on the [plugin protocol]({{< relref "plugin-protocol/" >}}), which is versioned separately and is considered stable. However, from time to time, we might introduce breaking changes in the SDK.
-
-When we update the plugin SDK, those plugins that use an older version of the SDK should still work with Grafana. However, these older plugins may be unable to use the new features and capabilities we introduce in updated SDK versions.
-
-## See also
-
-- [SDK source code](https://github.com/grafana/grafana-plugin-sdk-go)
-- [Go reference documentation](https://pkg.go.dev/github.com/grafana/grafana-plugin-sdk-go)
diff --git a/docs/sources/developers/plugins/backend/plugin-protocol.md b/docs/sources/developers/plugins/backend/plugin-protocol.md
deleted file mode 100644
index 822a9234892..00000000000
--- a/docs/sources/developers/plugins/backend/plugin-protocol.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-keywords:
- - grafana
- - plugins
- - backend
- - plugin
- - backend-plugins
- - documentation
-title: Plugin protocol
----
-
-# Plugin protocol
-
-The Grafana server uses a physical wire protocol to communicate with backend plugins. This protocol establishes a contract between Grafana and backend plugins to allow them to communicate with each other.
-
-## Developing with the plugin protocol
-
-{{% admonition type="caution" %}} We strongly recommend that backend plugin development not be implemented directly against the protocol. Instead, we prefer that you use the [Grafana Plugin SDK for Go]({{< relref "grafana-plugin-sdk-for-go/" >}}) that implements this protocol and provides higher-level APIs. {{%
-/admonition %}}
-
-If you choose to develop against the plugin protocol directly, you can do so using [Protocol Buffers](https://developers.google.com/protocol-buffers) (that is, protobufs) with [gRPC](https://grpc.io/).
-
-Grafana's plugin protocol protobufs are available in the [GitHub repository](https://github.com/grafana/grafana-plugin-sdk-go/blob/master/proto/backend.proto).
-
-{{% admonition type="note" %}}
-The plugin protocol lives in the [Grafana Plugin SDK for Go]({{< relref "grafana-plugin-sdk-for-go/" >}}) because Grafana itself uses parts of the SDK as a dependency.
-{{% /admonition %}}
-
-## Versioning
-
-From time to time, Grafana will offer additions of services, messages, and fields in the latest version of the plugin protocol. We don't expect these updates to introduce any breaking changes. However, if we must introduce breaking changes to the plugin protocol, we'll create a new major version of the plugin protocol.
-
-Grafana will release new major versions of the plugin protocol alongside new major Grafana releases. When this happens, we'll support both the old and the new plugin protocol for some time to make sure existing backend plugins continue to work.
-
-The plugin protocol attempts to follow Grafana's versioning. However, that doesn't mean we will automatically create a new major version of the plugin protocol when a new major release of Grafana is released.
-
-## Writing plugins without Go
-
-If you want to write a backend plugin in a language other than Go, then it's possible as long as the language supports gRPC. However, we recommend that you develop your plugin in Go for several reasons:
-
-- We offer an official plugin SDK.
-- The compiled output is a single binary.
-- Writing for multiple platforms is easy. Typically, no additional dependencies must be installed on the target platform.
-- Small footprint for binary size.
-- Small footprint for resource usage.
diff --git a/docs/sources/developers/plugins/build-a-logs-data-source-plugin.md b/docs/sources/developers/plugins/build-a-logs-data-source-plugin.md
deleted file mode 100644
index 027521dbad8..00000000000
--- a/docs/sources/developers/plugins/build-a-logs-data-source-plugin.md
+++ /dev/null
@@ -1,148 +0,0 @@
----
-title: Build a logs data source plugin
----
-
-# Build a logs data source plugin
-
-Grafana data source plugins support metrics, logs, and other data types. The steps to build a logs data source plugin are largely the same as for a metrics data source, but there are a few differences which we will explain in this guide.
-
-## Before you begin
-
-This guide assumes that you're already familiar with how to [Build a data source plugin](/tutorials/build-a-data-source-plugin/) for metrics. We recommend that you review this material before continuing.
-
-## Add logs support to your data source
-
-To add logs support to an existing data source, you need to:
-
-1. Enable logs support
-1. Construct the log data
-
-When these steps are done, then you can improve the user experience with one or more [optional features](#enhance-your-logs-data-source-plugin-with-optional-features).
-
-### Step 1: Enable logs support
-
-Tell Grafana that your data source plugin can return log data, by adding `"logs": true` to the [plugin.json]({{< relref "metadata/" >}}) file.
-
-```json
-{
- "logs": true
-}
-```
-
-### Step 2: Construct the log data
-
-As it does with metrics data, Grafana expects your plugin to return log data as a [data frame]({{< relref "data-frames/" >}}).
-
-To return log data, return a data frame with at least one time field and one text field from the data source's `query` method.
-
-**Example:**
-
-```ts
-const frame = new MutableDataFrame({
- refId: query.refId,
- fields: [
- { name: 'time', type: FieldType.time },
- { name: 'content', type: FieldType.string },
- ],
-});
-
-frame.add({ time: 1589189388597, content: 'user registered' });
-frame.add({ time: 1589189406480, content: 'user logged in' });
-```
-
-That's all you need to start returning log data from your data source. Go ahead and try it out in [Explore]({{< relref "../../explore/" >}}) or by adding a [Logs panel]({{< relref "../../panels-visualizations/visualizations/logs/" >}}).
-
-Congratulations, you just wrote your first logs data source plugin! Next, let's look at a couple of features that can further improve the experience for the user.
-
-## Enhance your logs data source plugin with optional features
-
-Add visualization type hints, labels, and other optional features to logs.
-
-### Add a preferred visualization type hint to the data frame
-
-To make sure Grafana recognizes data as logs and shows logs visualization automatically in Explore, set `meta.preferredVisualisationType` to `'logs'` in the returned data frame. See [Selecting preferred visualisation section]({{< relref "add-support-for-explore-queries/#selecting-preferred-visualisation" >}})
-
-**Example:**
-
-```ts
-const frame = new MutableDataFrame({
- refId: query.refId,
- meta: {
- preferredVisualisationType: 'logs',
- },
- fields: [
- { name: 'time', type: FieldType.time },
- { name: 'content', type: FieldType.string },
- ],
-});
-```
-
-### Add labels to your logs
-
-Many log systems let you query logs based on metadata, or _labels_, to help filter log lines.
-
-Add labels to a stream of logs by setting the `labels` property on the Field.
-
-**Example**:
-
-```ts
-const frame = new MutableDataFrame({
- refId: query.refId,
- fields: [
- { name: 'time', type: FieldType.time },
- { name: 'content', type: FieldType.string, labels: { filename: 'file.txt' } },
- ],
-});
-
-frame.add({ time: 1589189388597, content: 'user registered' });
-frame.add({ time: 1589189406480, content: 'user logged in' });
-```
-
-### Extract detected fields from your logs
-
-Add additional information about each log line by supplying more data frame fields.
-
-If a data frame has more than one text field, then Grafana assumes the first field in the data frame to be the actual log line. Grafana treats subsequent text fields as [detected fields]({{< relref "../../explore/#labels-and-detected-fields" >}}).
-
-Any number of custom fields can be added to your data frame; Grafana comes with two dedicated fields: `levels` and `id`.
-
-#### Levels
-
-To set the level for each log line, add a `level` field.
-
-**Example:**
-
-```ts
-const frame = new MutableDataFrame({
- refId: query.refId,
- fields: [
- { name: 'time', type: FieldType.time },
- { name: 'content', type: FieldType.string, labels: { filename: 'file.txt' } },
- { name: 'level', type: FieldType.string },
- ],
-});
-
-frame.add({ time: 1589189388597, content: 'user registered', level: 'info' });
-frame.add({ time: 1589189406480, content: 'unknown error', level: 'error' });
-```
-
-#### 'id' for assigning unique identifiers to log lines
-
-By default, Grafana offers basic support for deduplicating log lines. You can improve the support by adding an `id` field to explicitly assign identifiers to each log line.
-
-**Example:**
-
-```ts
-const frame = new MutableDataFrame({
- refId: query.refId,
- fields: [
- { name: 'time', type: FieldType.time },
- { name: 'content', type: FieldType.string, labels: { filename: 'file.txt' } },
- { name: 'level', type: FieldType.string },
- { name: 'id', type: FieldType.string },
- ],
-});
-
-frame.add({ time: 1589189388597, content: 'user registered', level: 'info', id: 'd3b07384d113edec49eaa6238ad5ff00' });
-frame.add({ time: 1589189406480, content: 'unknown error', level: 'error', id: 'c157a79031e1c40f85931829bc5fc552' });
-```
diff --git a/docs/sources/developers/plugins/build-a-streaming-data-source-plugin.md b/docs/sources/developers/plugins/build-a-streaming-data-source-plugin.md
deleted file mode 100644
index ecfe9aff478..00000000000
--- a/docs/sources/developers/plugins/build-a-streaming-data-source-plugin.md
+++ /dev/null
@@ -1,151 +0,0 @@
----
-title: Build a streaming data source plugin
----
-
-# Build a streaming data source plugin
-
-In Grafana, you can set your dashboards to automatically refresh at a certain interval, no matter what data source you use. Unfortunately, this means that your queries are requesting all the data to be sent again, regardless of whether the data has actually changed. Adding streaming to a plugin helps reduce queries so your dashboard is only updated when new data becomes available.
-
-## Before you begin
-
-This guide assumes that you're already familiar with how to [Build a data source plugin](/tutorials/build-a-data-source-plugin/).
-
-Grafana uses [RxJS](https://rxjs.dev/) to continuously send data from a data source to a panel visualization.
-
-> **Note:** To learn more about RxJs, refer to the [RxJS documentation](https://rxjs.dev/guide/overview).
-
-## Add streaming to your data source
-
-Enable streaming for your data source plugin to update your dashboard when new data becomes available.
-
-For example, a streaming data source plugin can connect to a websocket, or subscribe to a message bus, and update the visualization whenever a new message is available.
-
-### Step 1: Edit the `plugin.json` file
-
-Enable streaming for your data source in the `plugin.json` file.
-
-```json
-{
- "streaming": true
-}
-```
-
-### Step 2: Change the signature of the `query` method
-
-Modify the signature of the `query` method to return an `Observable` from the `rxjs` package. Make sure you remove the `async` keyword.
-
-```ts
-import { Observable } from 'rxjs';
-```
-
-```ts
-query(options: DataQueryRequest): Observable {
- // ...
-}
-```
-
-### Step 3: Create an `Observable` instance for each query
-
-Create an `Observable` instance for each query, and then combine them all using the `merge` function from the `rxjs` package.
-
-```ts
-import { Observable, merge } from 'rxjs';
-```
-
-```ts
-const observables = options.targets.map((target) => {
- return new Observable((subscriber) => {
- // ...
- });
-});
-
-return merge(...observables);
-```
-
-### Step 4: Create a `CircularDataFrame` instance
-
-In the `subscribe` function, create a `CircularDataFrame` instance.
-
-```ts
-import { CircularDataFrame } from '@grafana/data';
-```
-
-```ts
-const frame = new CircularDataFrame({
- append: 'tail',
- capacity: 1000,
-});
-
-frame.refId = query.refId;
-frame.addField({ name: 'time', type: FieldType.time });
-frame.addField({ name: 'value', type: FieldType.number });
-```
-
-Circular data frames have a limited capacity. When a circular data frame reaches its capacity, the oldest data point is removed.
-
-### Step 5: Send the updated data frame
-
-Use `subscriber.next()` to send the updated data frame whenever you receive new updates.
-
-```ts
-import { LoadingState } from '@grafana/data';
-```
-
-```ts
-const intervalId = setInterval(() => {
- frame.add({ time: Date.now(), value: Math.random() });
-
- subscriber.next({
- data: [frame],
- key: query.refId,
- state: LoadingState.Streaming,
- });
-}, 500);
-
-return () => {
- clearInterval(intervalId);
-};
-```
-
-> **Note:** In practice, you'd call `subscriber.next` as soon as you receive new data from a websocket or a message bus. In the example above, data is being received every 500 milliseconds.
-
-### Example code for final `query` method
-
-```ts
-query(options: DataQueryRequest): Observable {
- const streams = options.targets.map(target => {
- const query = defaults(target, defaultQuery);
-
- return new Observable(subscriber => {
- const frame = new CircularDataFrame({
- append: 'tail',
- capacity: 1000,
- });
-
- frame.refId = query.refId;
- frame.addField({ name: 'time', type: FieldType.time });
- frame.addField({ name: 'value', type: FieldType.number });
-
- const intervalId = setInterval(() => {
- frame.add({ time: Date.now(), value: Math.random() });
-
- subscriber.next({
- data: [frame],
- key: query.refId,
- state: LoadingState.Streaming,
- });
- }, 100);
-
- return () => {
- clearInterval(intervalId);
- };
- });
- });
-
- return merge(...streams);
-}
-```
-
-One limitation with this example is that the panel visualization is cleared every time you update the dashboard. If you have access to historical data, you can add it, or _backfill_ it, to the data frame before the first call to `subscriber.next()`.
-
-For another example of a streaming plugin, refer to the [streaming websocket example](https://github.com/grafana/grafana-plugin-examples/tree/main/examples/datasource-streaming-websocket) on GitHub.
diff --git a/docs/sources/developers/plugins/create-a-grafana-plugin/_index.md b/docs/sources/developers/plugins/create-a-grafana-plugin/_index.md
deleted file mode 100644
index 7fb41d0d4e6..00000000000
--- a/docs/sources/developers/plugins/create-a-grafana-plugin/_index.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-description: How-to topics for plugin development
-title: Create a plugin
----
-
-# Create a Grafana plugin
-
-This section contains how-to topics for developing Grafana plugins.
-
-- [Build a Grafana plugin](https://grafana.github.io/plugin-tools/docs/creating-a-plugin)
- - [Build a panel plugin](https://grafana.com/tutorials/build-a-panel-plugin/)
- - [Build a data source plugin](https://grafana.com/tutorials/build-a-data-source-plugin/)
- - [Build a data source backend plugin](https://grafana.com/tutorials/build-a-data-source-backend-plugin/)
- - [Build a logs data source plugin]({{< relref "../build-a-logs-data-source-plugin.md">}})
- - [Build a streaming data source plugin]({{< relref "../build-a-streaming-data-source-plugin.md">}})
-- Extend a Grafana plugin
- - [Add annotations]({{< relref "add-support-for-annotations.md">}})
- - [Add anonymous usage reporting]({{< relref "add-anonymous-usage-reporting.md">}})
- - [Add authentication for a data source plugin]({{< relref "add-authentication-for-data-source-plugins.md">}})
- - [Add Explore queries]({{< relref "add-support-for-explore-queries.md">}})
- - [Add query editor help]({{< relref "add-query-editor-help.md">}})
- - [Add variables]({{< relref "add-support-for-variables.md">}})
- - [Create panel option editors]({{< relref "custom-panel-option-editors.md">}})
-- [Sign a plugin]({{< relref "sign-a-plugin.md">}})
-- [Automate development with CI](https://grafana.github.io/plugin-tools/docs/ci)
-- [Create nested plugins](https://grafana.github.io/plugin-tools/docs/nested-plugins)
-- [Extend configurations](https://grafana.github.io/plugin-tools/docs/advanced-configuration)
diff --git a/docs/sources/developers/plugins/cross-plugin-linking.md b/docs/sources/developers/plugins/cross-plugin-linking.md
deleted file mode 100644
index 1772e2816e6..00000000000
--- a/docs/sources/developers/plugins/cross-plugin-linking.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-title: Work with cross-plugin links
-description: Learn how to add plugin links to a Grafana app plugin
----
-
-# Work with cross-plugin links
-
-With the Plugins extension API, app plugins can register extension points of their own to display other plugins links. This is called _cross-plugin linking_, and you can use it to create more immersive user experiences with installed plugins.
-
-## Available extension points within plugins
-
-An extension point is a location in another plugin's UI where your plugin can insert links. All extension point IDs within plugins should follow the naming convention `plugins//`.
-
-## How to create an extension point within a plugin
-
-Use the `getPluginExtensions` method in `@grafana/runtime` to create an extension point within your plugin. An extension point is a way to specify where in the plugin UI other plugins links are rendered.
-
-{{% admonition type="note" %}}
-Creating an extension point in a plugin creates a public interface for other plugins to interact with. Changes to the extension point ID or its context could break any plugin that attempts to register a link inside your plugin.
-{{% /admonition %}}
-
-The `getPluginExtensions` method takes an object consisting of the `extensionPointId`, which must begin `plugin/`, and any contextual information that you want to provide. The `getPluginExtensions` method returns a list of `extensionLinks` that your program can loop over:
-
-```typescript
-import { getPluginExtensions } from '@grafana/runtime';
-import { isPluginExtensionLink } from '@grafana/data';
-import { LinkButton } from '@grafana/ui';
-
-function AppExtensionPointExample() {
- const { extensions } = getPluginExtensions({
- extensionPointId: 'plugin/another-app-plugin/menu',
- context: {
- pluginId: 'another-app-plugin',
- },
- });
-
- if (extensions.length === 0) {
- return null;
- }
-
- return (
-
- );
-}
-```
-
-The preceding example shows a component that renders `` components for all link extensions that other plugins registered for the `plugin/another-app-plugin/menu` extension point ID. The context is passed as the second parameter to `getPluginExtensions`, which uses `Object.freeze` to make the context immutable before passing it to other plugins.
-
-## Insert links into another plugin
-
-Create links for other plugins in the same way you [extend the Grafana application UI]({{< relref "./extend-the-grafana-ui-with-links" >}}) with a link. Don't specify a `grafana/...` extension point. Instead, specify the plugin extension point `plugin//`.
-
-Given the preceding example, use a plugin link such as the following:
-
-```typescript
-new AppPlugin().configureExtensionLink({
- title: 'Go to basic app',
- description: 'Will navigate the user to the basic app',
- extensionPointId: 'plugin/another-app-plugin/menu',
- path: '/a/myorg-basic-app/one',
-});
-```
diff --git a/docs/sources/developers/plugins/custom-panel-option-editors.md b/docs/sources/developers/plugins/custom-panel-option-editors.md
deleted file mode 100644
index 344ced91328..00000000000
--- a/docs/sources/developers/plugins/custom-panel-option-editors.md
+++ /dev/null
@@ -1,119 +0,0 @@
----
-title: Build a custom panel option editor
----
-
-# Build a custom panel option editor
-
-The Grafana plugin platform comes with a range of editors that allow your users to customize a panel. The standard editors cover the most common types of options, such as text input and boolean switches. If you don't find the editor you're looking for, you can build your own.
-
-## Panel option editor basics
-
-The simplest editor is a React component that accepts two props:
-
-- **`value`**: the current value of the option
-- **`onChange`**: updates the option's value
-
-The editor in the example below lets the user toggle a boolean value by clicking a button:
-
-**SimpleEditor.tsx**
-
-```ts
-import React from 'react';
-import { Button } from '@grafana/ui';
-import { StandardEditorProps } from '@grafana/data';
-
-export const SimpleEditor: React.FC> = ({ value, onChange }) => {
- return ;
-};
-```
-
-To use a custom panel option editor, use the `addCustomEditor` on the `OptionsUIBuilder` object in your `module.ts` file and set the `editor` property to the name of your custom editor component.
-
-**module.ts**
-
-```ts
-export const plugin = new PanelPlugin(SimplePanel).setPanelOptions((builder) => {
- return builder.addCustomEditor({
- id: 'label',
- path: 'label',
- name: 'Label',
- editor: SimpleEditor,
- });
-});
-```
-
-## Add settings to your panel option editor
-
-You can use your custom editor to customize multiple possible settings. To add settings to your editor, set the second template variable of `StandardEditorProps` to an interface that contains the settings you want to configure. Access the editor settings through the `item` prop.
-
-Here's an example of an editor that populates a drop-down with a range of numbers. The `Settings` interface defines the range of the `from` and `to` properties.
-
-**SimpleEditor.tsx**
-
-```ts
-interface Settings {
- from: number;
- to: number;
-}
-
-export const SimpleEditor: React.FC> = ({ item, value, onChange }) => {
- const options: Array> = [];
-
- // Default values
- const from = item.settings?.from ?? 1;
- const to = item.settings?.to ?? 10;
-
- for (let i = from; i <= to; i++) {
- options.push({
- label: i.toString(),
- value: i,
- });
- }
-
- return