Skip to content

Commit 78a3d17

Browse files
chore: Switches to CustomVariableSupport
1 parent 5bafe21 commit 78a3d17

File tree

3 files changed

+98
-74
lines changed

3 files changed

+98
-74
lines changed

src/components/VariableQueryEditor.tsx

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
import React, { PureComponent } from 'react';
2-
import { HaystackVariableQuery } from '../types';
2+
import { HaystackDataSourceOptions, HaystackQuery, HaystackVariableQuery } from '../types';
33
import { HaystackQueryTypeSelector } from './HaystackQueryTypeSelector';
44
import { HaystackQueryInput } from './HaystackQueryInput';
55
import { InlineField, Input } from '@grafana/ui';
6+
import { DataSource } from 'datasource';
7+
import { QueryEditorProps } from '@grafana/data';
68

7-
interface VariableQueryProps {
8-
query: HaystackVariableQuery;
9-
onChange: (query: HaystackVariableQuery, definition: string) => void;
10-
}
9+
type VariableQueryProps = QueryEditorProps<DataSource, HaystackQuery, HaystackDataSourceOptions, HaystackVariableQuery>;
1110

1211
interface VariableState {
1312
query: HaystackVariableQuery;
1413
refId?: string;
1514
}
1615

17-
const refId = "variable";
16+
export const VARIABLE_REF_ID = "variable";
1817

1918
export class VariableQueryEditor extends PureComponent<VariableQueryProps, VariableState> {
2019
constructor(props: VariableQueryProps) {
@@ -28,29 +27,31 @@ export class VariableQueryEditor extends PureComponent<VariableQueryProps, Varia
2827

2928
saveQuery() {
3029
// refId must match but doesn't get set originally so set should set it on every change
31-
this.setState({ ...this.state, refId: refId});
30+
this.setState({ ...this.state, refId: VARIABLE_REF_ID});
3231

33-
let type = this.state.query.type;
34-
let queryCmd = "";
35-
if (this.state.query.type === "eval") {
36-
queryCmd = this.state.query.eval
37-
} else if (this.state.query.type === "hisRead") {
38-
queryCmd = this.state.query.hisRead
39-
} else if (this.state.query.type === "hisReadFilter") {
40-
queryCmd = this.state.query.hisReadFilter
41-
} else if (this.state.query.type === "read") {
42-
queryCmd = this.state.query.read
43-
}
44-
let column = "none";
45-
if (this.state.query.column !== undefined && this.state.query.column !== '') {
46-
column = `'${this.state.query.column}'`;
47-
}
48-
let displayColumn = "none";
49-
if (this.state.query.displayColumn !== undefined && this.state.query.displayColumn !== '') {
50-
displayColumn = `'${this.state.query.displayColumn}'`;
51-
}
52-
let displayString = `${type}: '${queryCmd}', Column: ${column}, Display: ${displayColumn}`
53-
this.props.onChange(this.state.query, displayString);
32+
// Returning a display string in `onChange` no longer seems to be used by Grafana?
33+
34+
// let type = this.state.query.type;
35+
// let queryCmd = "";
36+
// if (this.state.query.type === "eval") {
37+
// queryCmd = this.state.query.eval
38+
// } else if (this.state.query.type === "hisRead") {
39+
// queryCmd = this.state.query.hisRead
40+
// } else if (this.state.query.type === "hisReadFilter") {
41+
// queryCmd = this.state.query.hisReadFilter
42+
// } else if (this.state.query.type === "read") {
43+
// queryCmd = this.state.query.read
44+
// }
45+
// let column = "none";
46+
// if (this.state.query.column !== undefined && this.state.query.column !== '') {
47+
// column = `'${this.state.query.column}'`;
48+
// }
49+
// let displayColumn = "none";
50+
// if (this.state.query.displayColumn !== undefined && this.state.query.displayColumn !== '') {
51+
// displayColumn = `'${this.state.query.displayColumn}'`;
52+
// }
53+
// let displayString = `${type}: '${queryCmd}', Column: ${column}, Display: ${displayColumn}`
54+
this.props.onChange(this.state.query);
5455
};
5556

5657
onTypeChange(newType: string) {
@@ -83,7 +84,7 @@ export class VariableQueryEditor extends PureComponent<VariableQueryProps, Varia
8384
<HaystackQueryTypeSelector
8485
datasource={null}
8586
type={this.state.query.type}
86-
refId={this.state.query.refId ?? refId}
87+
refId={this.state.query.refId ?? VARIABLE_REF_ID}
8788
onChange={(e) => this.onTypeChange(e)}
8889
/>
8990
<HaystackQueryInput

src/datasource.ts

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@ import {
77
MetricFindValue,
88
getDefaultTimeRange,
99
FieldType,
10+
CustomVariableSupport,
11+
DataQueryResponse,
12+
QueryEditorProps,
1013
} from '@grafana/data';
1114
import { DataSourceWithBackend, getTemplateSrv } from '@grafana/runtime';
1215

1316
import { HaystackQuery, OpsQuery, HaystackDataSourceOptions, HaystackVariableQuery, QueryType } from './types';
14-
import { firstValueFrom } from 'rxjs';
17+
import { firstValueFrom, map, Observable } from 'rxjs';
1518
import { isRef, parseRef } from 'haystack';
19+
import { ComponentType } from 'react';
20+
import { VARIABLE_REF_ID, VariableQueryEditor } from 'components/VariableQueryEditor';
1621

1722
export const queryTypes: QueryType[] = [
1823
{ label: 'Eval', value: 'eval', apiRequirements: ['eval'], description: 'Evaluate an Axon expression' },
@@ -29,6 +34,9 @@ export const queryTypes: QueryType[] = [
2934
export class DataSource extends DataSourceWithBackend<HaystackQuery, HaystackDataSourceOptions> {
3035
constructor(instanceSettings: DataSourceInstanceSettings<HaystackDataSourceOptions>) {
3136
super(instanceSettings);
37+
this.variables = new HaystackVariableSupport((request) => {
38+
return this.query(request)
39+
});
3240
}
3341

3442
// Queries the available ops from the datasource and returns the queryTypes that are supported.
@@ -89,48 +97,6 @@ export class DataSource extends DataSourceWithBackend<HaystackQuery, HaystackDat
8997
};
9098
}
9199

92-
// This is called when the user is selecting a variable value
93-
async metricFindQuery(variableQuery: HaystackVariableQuery, options?: any) {
94-
let request: HaystackQuery = variableQuery;
95-
let observable = this.query({ targets: [request] } as DataQueryRequest<HaystackQuery>);
96-
let response = await firstValueFrom(observable);
97-
98-
if (response === undefined || response.data === undefined) {
99-
return [];
100-
}
101-
102-
return response.data.reduce((acc: MetricFindValue[], frame: DataFrame) => {
103-
// Default to the first field
104-
let column = frame.fields[0];
105-
if (variableQuery.column !== undefined && variableQuery.column !== '') {
106-
// If a column was input, match the column name
107-
column = frame.fields.find((field: Field) => field.name === variableQuery.column) ?? column;
108-
} else if (frame.fields.some((field: Field) => field.name === 'id')) {
109-
// If there is an id column, use that
110-
column = frame.fields.find((field: Field) => field.name === 'id') ?? column;
111-
}
112-
113-
// Default to the selected column
114-
let displayColumn = column;
115-
if (variableQuery.displayColumn !== undefined && variableQuery.displayColumn !== '') {
116-
// If a column was input, match the column name
117-
displayColumn =
118-
frame.fields.find((field: Field) => field.name === variableQuery.displayColumn) ?? displayColumn;
119-
}
120-
121-
let variableValues = column.values.map((value, index) => {
122-
let variableValue = variableValueFromCell(value, column.type);
123-
124-
let displayValue = displayColumn.values[index];
125-
let variableText = variableTextFromCell(displayValue, displayColumn.type);
126-
127-
return { text: variableText, value: variableValue };
128-
});
129-
130-
return acc.concat(variableValues);
131-
}, []);
132-
}
133-
134100
// Returns a DataQueryRequest that gets the available ops from the datasource
135101
// This applies a bunch of defaults because it's not a time series query
136102
private opsRequest(refId: string): DataQueryRequest<HaystackQuery> {
@@ -150,6 +116,65 @@ export class DataSource extends DataSourceWithBackend<HaystackQuery, HaystackDat
150116
}
151117
}
152118

119+
export class HaystackVariableSupport extends CustomVariableSupport<DataSource, HaystackVariableQuery, HaystackQuery, HaystackDataSourceOptions> {
120+
editor: ComponentType<QueryEditorProps<DataSource, HaystackQuery, HaystackDataSourceOptions, HaystackVariableQuery>>;
121+
122+
// Requests data from the backend. This allows this class to reuse the DataSource.query method to get data.
123+
onQuery: (request: DataQueryRequest<HaystackVariableQuery>) => Observable<DataQueryResponse>;
124+
125+
constructor(onQuery: (request: DataQueryRequest<HaystackVariableQuery>) => Observable<DataQueryResponse>) {
126+
super();
127+
this.editor = VariableQueryEditor;
128+
this.onQuery = onQuery;
129+
}
130+
131+
query(request: DataQueryRequest<HaystackVariableQuery>): Observable<DataQueryResponse> {
132+
let variableQuery = request.targets[0];
133+
variableQuery.refId = VARIABLE_REF_ID;
134+
let observable = this.onQuery(request);
135+
return observable.pipe(
136+
map((response) => {
137+
if (response === undefined || response.errors !== undefined || response.data === undefined) {
138+
return response
139+
}
140+
141+
let variableValues = response.data.reduce((acc: MetricFindValue[], frame: DataFrame) => {
142+
// Default to the first field
143+
let column = frame.fields[0];
144+
if (variableQuery.column !== undefined && variableQuery.column !== '') {
145+
// If a column was input, match the column name
146+
column = frame.fields.find((field: Field) => field.name === variableQuery.column) ?? column;
147+
} else if (frame.fields.some((field: Field) => field.name === 'id')) {
148+
// If there is an id column, use that
149+
column = frame.fields.find((field: Field) => field.name === 'id') ?? column;
150+
}
151+
152+
// Default to the selected column
153+
let displayColumn = column;
154+
if (variableQuery.displayColumn !== undefined && variableQuery.displayColumn !== '') {
155+
// If a column was input, match the column name
156+
displayColumn = frame.fields.find((field: Field) => {
157+
return field.name === variableQuery.displayColumn
158+
}) ?? displayColumn;
159+
}
160+
161+
let variableValues = column.values.map((value, index) => {
162+
let variableValue = variableValueFromCell(value, column.type);
163+
164+
let displayValue = displayColumn.values[index];
165+
let variableText = variableTextFromCell(displayValue, displayColumn.type);
166+
167+
return { text: variableText, value: variableValue };
168+
});
169+
return acc.concat(variableValues);
170+
}, []);
171+
return { ...response, data: variableValues };
172+
})
173+
);
174+
}
175+
}
176+
177+
153178
function variableValueFromCell(value: string, columnType: FieldType): string {
154179
switch (columnType) {
155180
case FieldType.string:

src/module.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ import { DataSourcePlugin } from '@grafana/data';
22
import { DataSource } from './datasource';
33
import { ConfigEditor } from './components/ConfigEditor';
44
import { QueryEditor } from './components/QueryEditor';
5-
import { VariableQueryEditor } from './components/VariableQueryEditor';
65
import { HaystackQuery, HaystackDataSourceOptions } from './types';
76

87
export const plugin = new DataSourcePlugin<DataSource, HaystackQuery, HaystackDataSourceOptions>(DataSource)
98
.setConfigEditor(ConfigEditor)
109
.setQueryEditor(QueryEditor)
11-
.setVariableQueryEditor(VariableQueryEditor);

0 commit comments

Comments
 (0)