Skip to content

Commit cb21883

Browse files
refactor: Move ops and querying to DataSource
1 parent e665410 commit cb21883

4 files changed

Lines changed: 82 additions & 68 deletions

File tree

src/components/QueryEditor.tsx

Lines changed: 13 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import React, { ChangeEvent, ReactNode } from 'react';
22
import { AsyncSelect, Button, Form, Icon, InlineField, Input, VerticalGroup } from '@grafana/ui';
3-
import { DataFrame, DataQueryRequest, Field, getDefaultTimeRange, QueryEditorProps, SelectableValue, Vector } from '@grafana/data';
4-
import { DataSource } from '../datasource';
5-
import { DEFAULT_QUERY, HaystackDataSourceOptions, HaystackQuery } from '../types';
3+
import { QueryEditorProps } from '@grafana/data';
4+
import { DataSource, queryTypes } from '../datasource';
5+
import { DEFAULT_QUERY, HaystackDataSourceOptions, HaystackQuery, QueryType } from '../types';
66

77
type Props = QueryEditorProps<DataSource, HaystackQuery, HaystackDataSourceOptions>;
88

9-
export function QueryEditor({ datasource, query, onChange, onRunQuery, range, app }: Props) {
10-
const onTypeChange = (event: SelectableValue<string>) => {
11-
onChange({ ...query, type: event.value ?? queryTypeDefault.value! });
9+
export function QueryEditor({ datasource, query, onChange, onRunQuery }: Props) {
10+
const onTypeChange = (event: QueryType | null) => {
11+
onChange({ ...query, type: event?.value ?? queryTypeDefault.value! });
1212
};
1313
const onEvalChange = (event: ChangeEvent<HTMLInputElement>) => {
1414
onChange({ ...query, type: 'eval', eval: event.target.value });
@@ -20,83 +20,31 @@ export function QueryEditor({ datasource, query, onChange, onRunQuery, range, ap
2020
onChange({ ...query, type: 'read', read: event.target.value });
2121
};
2222

23-
interface QueryType extends SelectableValue<string> {
24-
apiRequirements: string[];
25-
}
26-
27-
const queryTypes: QueryType[] = [
28-
{ label: 'Read', value: "read", apiRequirements: ["read"], description: 'Read the records matched by a filter' },
29-
{ label: 'HisRead', value: "hisRead", apiRequirements: ["hisRead"], description: 'Read the history of a point' },
30-
{ label: 'Eval', value: "eval", apiRequirements: ["eval"], description: 'Evaluate an Axon expression' },
31-
];
3223
const queryTypeDefault = queryTypes[0];
33-
function queryTypeFromLabel(label: string) {
34-
return queryTypes.find((queryType) => queryType.value === label);
24+
function queryTypeFromValue(value: string): QueryType | null {
25+
return queryTypes.find((queryType) => queryType.value === value) ?? null;
3526
}
3627

3728
const SelectComponent = () => {
3829
return (
3930
<InlineField label="Type">
4031
<AsyncSelect
41-
loadOptions={loadOps}
32+
loadOptions={() => {return datasource.loadOps(query.refId);}}
4233
defaultOptions
43-
value={queryTypeFromLabel(query.type)}
34+
value={queryTypeFromValue(query.type)}
4435
width={30}
4536
onChange={(queryType) => {
46-
onTypeChange(queryType);
37+
// QueryType comes back as a SelectableValue, so we just convert it to the QueryType
38+
onTypeChange(queryTypeFromValue(queryType.value ?? ""));
4739
}}
4840
/>
4941
</InlineField>
5042
);
5143
};
5244

53-
// Queries the available ops from the datasource on only returns the ones that are supported.
54-
const loadOps = () => {
55-
let opsRequest: DataQueryRequest<HaystackQuery> = {
56-
requestId: 'ops',
57-
dashboardId: 0,
58-
interval: '0',
59-
intervalMs: 0,
60-
panelId: 0,
61-
range: range ?? getDefaultTimeRange(),
62-
scopedVars: {},
63-
targets: [{ type: 'ops' , eval: "", read: "", hisRead: "", refId: query.refId}],
64-
timezone: 'UTC',
65-
app: 'ops',
66-
startTime: 0,
67-
}
68-
return datasource.query(opsRequest).toPromise().then((result) => {
69-
if(result?.state === 'Error') {
70-
return [];
71-
}
72-
let frame = result?.data?.find((frame: DataFrame) => {
73-
return frame.refId === query.refId
74-
})
75-
let opSymbols = frame?.fields?.find((field: Field<any, Vector<string>>) => {
76-
return field.name === 'def'
77-
}).values ?? [];
78-
let ops: string[] = opSymbols.map((opSymbol: string) => {
79-
if (opSymbol.startsWith('^op:')) {
80-
return opSymbol.substring(4);
81-
} else {
82-
return opSymbol;
83-
}
84-
});
85-
86-
return queryTypes.filter((queryType) => {
87-
return queryType.apiRequirements.every((apiRequirement) => {
88-
return ops.find((op) => {
89-
return op === apiRequirement
90-
}) !== undefined;
91-
});
92-
});
93-
});
94-
}
95-
9645
function renderQuery(): ReactNode {
9746
let width = 100;
98-
let queryType = queryTypeFromLabel(query.type);
99-
switch (queryType?.value) {
47+
switch (query.type) {
10048
case "eval":
10149
return (
10250
<InlineField>

src/components/VariableQueryEditor.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ export const VariableQueryEditor: React.FC<VariableQueryProps> = ({ onChange, qu
2323
<>
2424
<div className="gf-form">
2525
<span className="gf-form-label width-10">Eval</span>
26-
<input name="eval" className="gf-form-input" onBlur={saveQuery} onChange={handleChange} value={state.eval} />
26+
<input
27+
name="eval"
28+
className="gf-form-input"
29+
onBlur={saveQuery}
30+
onChange={handleChange}
31+
value={state.eval}
32+
/>
2733
</div>
2834
<div className="gf-form">
2935
<span className="gf-form-label width-10">Column</span>

src/datasource.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,72 @@ import {
66
DataFrame,
77
Field,
88
MetricFindValue,
9+
Vector,
10+
getDefaultTimeRange,
911
} from '@grafana/data';
1012
import { DataSourceWithBackend, getTemplateSrv } from '@grafana/runtime';
1113

12-
import { HaystackQuery, HaystackDataSourceOptions, DEFAULT_QUERY, HaystackVariableQuery } from './types';
14+
import { HaystackQuery, HaystackDataSourceOptions, DEFAULT_QUERY, HaystackVariableQuery, QueryType } from './types';
15+
16+
export const queryTypes: QueryType[] = [
17+
{ label: 'Read', value: 'read', apiRequirements: ['read'], description: 'Read the records matched by a filter' },
18+
{ label: 'HisRead', value: 'hisRead', apiRequirements: ['hisRead'], description: 'Read the history of a point' },
19+
{ label: 'Eval', value: 'eval', apiRequirements: ['eval'], description: 'Evaluate an Axon expression' },
20+
];
1321

1422
export class DataSource extends DataSourceWithBackend<HaystackQuery, HaystackDataSourceOptions> {
1523
constructor(instanceSettings: DataSourceInstanceSettings<HaystackDataSourceOptions>) {
1624
super(instanceSettings);
1725
}
1826

27+
// Queries the available ops from the datasource and returns the queryTypes that are supported.
28+
loadOps(refId: string): Promise<QueryType[]> {
29+
let opsRequest: DataQueryRequest<HaystackQuery> = {
30+
requestId: 'ops',
31+
dashboardId: 0,
32+
interval: '0',
33+
intervalMs: 0,
34+
panelId: 0,
35+
range: getDefaultTimeRange(),
36+
scopedVars: {},
37+
targets: [{ type: 'ops', eval: '', read: '', hisRead: '', refId: refId }],
38+
timezone: 'UTC',
39+
app: 'ops',
40+
startTime: 0,
41+
};
42+
return this.query(opsRequest)
43+
.toPromise()
44+
.then((result) => {
45+
if (result?.state === 'Error') {
46+
return [];
47+
}
48+
let frame = result?.data?.find((frame: DataFrame) => {
49+
return frame.refId === refId;
50+
});
51+
let opSymbols =
52+
frame?.fields?.find((field: Field<any, Vector<string>>) => {
53+
return field.name === 'def';
54+
}).values ?? [];
55+
let ops: string[] = opSymbols.map((opSymbol: string) => {
56+
if (opSymbol.startsWith('^op:')) {
57+
return opSymbol.substring(4);
58+
} else {
59+
return opSymbol;
60+
}
61+
});
62+
63+
return queryTypes.filter((queryType) => {
64+
return queryType.apiRequirements.every((apiRequirement) => {
65+
return (
66+
ops.find((op) => {
67+
return op === apiRequirement;
68+
}) !== undefined
69+
);
70+
});
71+
});
72+
});
73+
}
74+
1975
applyTemplateVariables(query: HaystackQuery, scopedVars: ScopedVars): Record<string, any> {
2076
return {
2177
...query,

src/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DataQuery, DataSourceJsonData } from '@grafana/data';
1+
import { DataQuery, DataSourceJsonData, SelectableValue } from '@grafana/data';
22

33
export interface HaystackQuery extends DataQuery {
44
type: string; // Defines the type of query that should be executed
@@ -7,6 +7,10 @@ export interface HaystackQuery extends DataQuery {
77
read: string;
88
}
99

10+
export interface QueryType extends SelectableValue<string> {
11+
apiRequirements: string[];
12+
}
13+
1014
export interface HaystackVariableQuery {
1115
column: string;
1216
eval: string;

0 commit comments

Comments
 (0)