//VariableQueryEditor.tsx
import React, { ChangeEvent } from 'react';
import { VerticalGroup, InlineField, InlineFieldRow, Input, Checkbox, TextArea, Button } from '@grafana/ui';
import { QueryEditorProps } from '@grafana/data';
import { DataSource } from '../datasource';
import { MyDataSourceOptions, MyQuery } from '../types';
type Props = QueryEditorProps<DataSource, MyQuery, MyDataSourceOptions>;
export function VariableQueryEditor({ query, onChange, onRunQuery }: Props) {
const onVariableFieldChange = (event: ChangeEvent<HTMLInputElement>) => {
onChange({ ...query, variableField: event.target.value });
};
const onQueryTextChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
onChange({ ...query, queryText: event.target.value });
};
const onIsVariableChange = (event: ChangeEvent<HTMLInputElement>) => {
onChange({ ...query, isVariable: event.target.checked });
};
const { variableField, queryText, isVariable } = query;
return (
<div className="gf-form">
<VerticalGroup spacing="sm">
<InlineFieldRow>
<InlineField label="Is Variable">
<Checkbox onChange={onIsVariableChange} value={isVariable || false} />
</InlineField>
</InlineFieldRow>
{isVariable && (
<InlineFieldRow>
<InlineField label="Variable Field">
<Input
onChange={onVariableFieldChange}
value={variableField || ''}
placeholder="Field name for variable options"
autoComplete="off"
/>
</InlineField>
</InlineFieldRow>
)}
<InlineFieldRow style={{ width: '100%' }}>
<InlineField grow style={{ width: '100%' }}>
<TextArea
onChange={onQueryTextChange}
value={queryText || ''}
placeholder="Enter a query…"
rows={8}
/>
</InlineField>
</InlineFieldRow>
<InlineFieldRow>
<Button variant="secondary" onClick={onRunQuery}>
Run Query
</Button>
</InlineFieldRow>
</VerticalGroup>
</div>
);
}
//module.ts
import { DataSourcePlugin } from '@grafana/data';
import { DataSource } from './datasource';
import { ConfigEditor } from './components/ConfigEditor';
import { QueryEditor } from './components/QueryEditor';
import { VariableQueryEditor } from './components/VariableQueryEditor';
import { MyQuery, MyDataSourceOptions } from './types';
export const plugin = new DataSourcePlugin<DataSource, MyQuery, MyDataSourceOptions>(DataSource)
.setConfigEditor(ConfigEditor)
.setQueryEditor(QueryEditor)
.setVariableQueryEditor(VariableQueryEditor as any);
//datasource.go
func (d *Datasource) MetricFindQuery(ctx context.Context, query backend.DataQuery) backend.DataResponse {
var queryData queryModel
if err := json.Unmarshal(query.JSON, &queryData); err != nil {
return newErrorResponse(backend.StatusBadRequest, fmt.Errorf("invalid query JSON: %v", err))
}
collection := d.getCollection(queryData.Database, queryData.Collection)
if collection == nil {
return newErrorResponse(backend.StatusBadRequest, fmt.Errorf("invalid collection"))
}
pipeline := mongo.Pipeline{
bson.D{
{Key: "$group", Value: bson.D{
{Key: "_id", Value: "$" + queryData.VariableField},
}},
},
}
cursor, err := collection.Aggregate(ctx, pipeline)
if err != nil {
log.DefaultLogger.Error("Error executing aggregation:", err)
return newErrorResponse(backend.StatusBadRequest, err)
}
defer cursor.Close(ctx)
var results []string
for cursor.Next(ctx) {
var result struct {
ID string `bson:"_id"`
}
if err := cursor.Decode(&result); err != nil {
log.DefaultLogger.Error("Decode error:", err)
continue
}
results = append(results, result.ID)
}
return createVariableResponse(results)
}