1+++ 2title = "Add support for variables in plugins" 3+++ 4 5# Add support for variables in plugins 6 7Variables are placeholders for values, and can be used to create things like templated queries and dashboard or panel links. For more information on variables, refer to [Templates and variables]({{< relref "../../variables/_index.md" >}}). 8 9This guide explains how to leverage template variables in your panel plugins and data source plugins. 10 11We'll see how you can turn a string like this: 12 13```sql 14SELECT * FROM services WHERE id = "$service" 15``` 16 17into 18 19```sql 20SELECT * FROM services WHERE id = "auth-api" 21``` 22 23Grafana provides a couple of helper functions to interpolate variables in a string template. Let's see how you can use them in your plugin. 24 25## Interpolate variables in panel plugins 26 27For panels, the `replaceVariables` function is available in the PanelProps. 28 29Add `replaceVariables` to the argument list, and pass it a user-defined template string. 30 31```ts 32export const SimplePanel: React.FC<Props> = ({ options, data, width, height, replaceVariables }) => { 33 const query = replaceVariables('Now displaying $service'); 34 35 return <div>{query}</div>; 36}; 37``` 38 39## Interpolate variables in data source plugins 40 41For data sources, you need to use the getTemplateSrv, which returns an instance of TemplateSrv. 42 431. Import `getTemplateSrv` from the `runtime` package. 44 45 ```ts 46 import { getTemplateSrv } from '@grafana/runtime'; 47 ``` 48 491. In your `query` method, call the `replace` method with a user-defined template string. 50 51 ```ts 52 async query(options: DataQueryRequest<MyQuery>): Promise<DataQueryResponse> { 53 const query = getTemplateSrv().replace('SELECT * FROM services WHERE id = "$service"', options.scopedVars); 54 55 const data = makeDbQuery(query); 56 57 return { data }; 58 } 59 ``` 60 61## Format multi-value variables 62 63When a user selects multiple values for variable, the value of the interpolated variable depends on the [variable format](https://grafana.com/docs/grafana/next/variables/advanced-variable-format-options/). 64 65A data source can define the default format option when no format is specified by adding a third argument to the interpolation function. 66 67Let's change the SQL query to use CSV format by default: 68 69```ts 70getTemplateSrv().replace('SELECT * FROM services WHERE id IN ($service)', options.scopedVars, 'csv'); 71``` 72 73Now, when users write `$service`, the query looks like this: 74 75```sql 76SELECT * FROM services WHERE id IN (admin,auth,billing) 77``` 78 79For more information on the available variable formats, refer to [Advanced variable format options]({{< relref "../../variables/advanced-variable-format-options.md" >}}). 80 81## Set a variable from your plugin 82 83Not only can you read the value of a variable, you can also update the variable from your plugin. Use LocationSrv.update() 84 85The following example shows how to update a variable called `service`. 86 87- `query` contains the query parameters you want to update. Query parameters controlling variables are prefixed with `var-`. 88- `partial: true` makes the update only affect the query parameters listed in `query`, and leaves the other query parameters unchanged. 89- `replace: true` tells Grafana to update the current URL state, rather than creating a new history entry. 90 91```ts 92import { getLocationSrv } from '@grafana/runtime'; 93``` 94 95```ts 96getLocationSrv().update({ 97 query: { 98 'var-service': 'billing', 99 }, 100 partial: true, 101 replace: true, 102}); 103``` 104 105> **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. 106 107## Add support for query variables to your data source 108 109[Query variables]({{< relref "../../variables/variable-types/add-query-variable.md" >}}) 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. 110 111Let's start by defining a query model for the variable query. 112 113```ts 114export interface MyVariableQuery { 115 namespace: string; 116 rawQuery: string; 117} 118``` 119 120For a data source to support query variables, you must override the `metricFindQuery` in your `DataSourceApi` class. `metricFindQuery` returns an array of `MetricFindValue` which has a single property, `text`: 121 122```ts 123async metricFindQuery(query: MyVariableQuery, options?: any) { 124 // Retrieve DataQueryResponse based on query. 125 const response = await this.fetchMetricNames(query.namespace, query.rawQuery); 126 127 // Convert query results to a MetricFindValue[] 128 const values = response.data.map(frame => ({ text: frame.name })); 129 130 return values; 131} 132``` 133 134> **Note:** By default, Grafana provides a default query model and editor for simple text queries. If that's all you need, then you can leave the query type as `string`. 135> 136> ```ts 137> async metricFindQuery(query: string, options?: any) 138> ``` 139 140Let's create a custom query editor to allow the user to edit the query model. 141 1421. Create a `VariableQueryEditor` component. 143 144 ```ts 145 import React, { useState } from 'react'; 146 import { MyVariableQuery } from './types'; 147 148 interface VariableQueryProps { 149 query: MyVariableQuery; 150 onChange: (query: MyVariableQuery, definition: string) => void; 151 } 152 153 export const VariableQueryEditor: React.FC<VariableQueryProps> = ({ onChange, query }) => { 154 const [state, setState] = useState(query); 155 156 const saveQuery = () => { 157 onChange(state, `${state.query} (${state.namespace})`); 158 }; 159 160 const handleChange = (event: React.FormEvent<HTMLInputElement>) => 161 setState({ 162 ...state, 163 [event.currentTarget.name]: event.currentTarget.value, 164 }); 165 166 return ( 167 <> 168 <div className="gf-form"> 169 <span className="gf-form-label width-10">Namespace</span> 170 <input 171 name="namespace" 172 className="gf-form-input" 173 onBlur={saveQuery} 174 onChange={handleChange} 175 value={state.namespace} 176 /> 177 </div> 178 <div className="gf-form"> 179 <span className="gf-form-label width-10">Query</span> 180 <input 181 name="rawQuery" 182 className="gf-form-input" 183 onBlur={saveQuery} 184 onChange={handleChange} 185 value={state.rawQuery} 186 /> 187 </div> 188 </> 189 ); 190 }; 191 ``` 192 193 Grafana saves the query model whenever one of the text fields loses focus (`onBlur`) and then previews the values returned by `metricFindQuery`. 194 195 The second argument to `onChange` allows you to set a text representation of the query which will appear next to the name of the variable in the variables list. 196 1971. Finally, configure your plugin to use the query editor. 198 199 ```ts 200 import { VariableQueryEditor } from './VariableQueryEditor'; 201 202 export const plugin = new DataSourcePlugin<DataSource, MyQuery, MyDataSourceOptions>(DataSource) 203 .setQueryEditor(QueryEditor) 204 .setVariableQueryEditor(VariableQueryEditor); 205 ``` 206 207That's it! You can now try out the plugin by adding a [query variable]({{< relref "../../variables/variable-types/add-query-variable.md" >}}) to your dashboard. 208