Hi everyone,
First of all, thank you so much for the hard work on Grafana, the platform is awesome.
I’m using Grafana 7.3.6 and I’m building a datasource plugin with a backend.
My plugin looks as follow:
export const plugin = new DataSourcePlugin<DataSource, MyDataQuery, MyOptions>(DataSource)
.setConfigEditor(ConfigEditor)
.setQueryEditor(QueryEditor)
.setVariableQueryEditor(VariablesEditor);
What I’m trying to achieve is to use the dashboard variables in the query editor.
This idea is to allow users to either use the dashboard variables or a query editor configuration as a parameter to query the data.
In the query editor, I added a switch “Use dashboard variables” so users decide whether they want to use the template variables or the configuration.
export type Props = QueryEditorProps<DataSource, MyDataQuery, MyOptions>;
export default class QueryEditor extends PureComponent<Props, State> {
async componentDidMount() {
// fetch the different values of the query parameter
// so users can select one in the query editor
const values = await this.props.datasource.fetchValues();
this.setState({ values });
}
render() {
const { values } = this.state;
let { value, useDashboardVar } = query;
if (useDashboardVar) {
value = this.props.datasource.getSelectedValue();
}
return (
<>
<div className="gf-form">
<InlineField label="Use dashboard variables">
<div className="gf-form-switch">
<Switch
value={!!useDashboardVar}
onChange={handleChange}
/>
</div>
</InlineField>
{!useDashboardVar && (
<InlineField label="A value">
<Select
value={value}
options={values}
placeholder="Select a value"
/>
</InlineField>
)}
</div>
{/* ... */}
</>
);
}
}
The frontend datasource class
export class DataSource extends DataSourceWithBackend<MyDataQuery, MyOptions> {
// retrieve the value selected at the dashboard level
getSelectedValue(): string {
const ds = getDataSourceSrv();
if ('templateSrv' in ds && Array.isArray((ds as DataSourceSrv).templateSrv?.variables)) {
const variable = ds.templateSrv.variables.find(({ name }) => name === 'var-name');
if (variable && typeof variable.current !== 'undefined') {
return variable.current.value;
}
}
return '';
}
async fetchValues(): Promise<string[]> {
// fetch the data from the datasource
}
// returns the values when users them as dashboard variables
async metricFindQuery({ queryType }: MyVariableQuery, options?: any): Promise<MetricFindValue[]> {
const values = await this.fetchValues();
return values.map((value) => ({ text: value }));
}
query(request: DataQueryRequest<MyDataQuery>): Observable<DataQueryResponse> {
const value = this.getSelectedValue();
const { targets } = request;
// if users have selected "useDashboardVar",
// we replace the myParam value with the template variable
// otherwise we send the query without modification
// it will use the value selected in the query editor
const data = targets.map(query => (query.useDashboardVar && value ? { ...query, myParam: value } : query));
return super.query({ ...request, targets: data });
}
//...
}
So this works but it feels kind of hacky and I was wondering whether there was a more straightforward solution. The query editor doesn’t seem to have any knowledge of the dashboard variables.
I tried to use applyTemplateVariables but I only get the “__interval” and “__interval_ms” properties in the ScopedVars objects.
Am I missing something?
Is there a better approach?