Skip to content

Commit b4887c9

Browse files
feature: Adjust variable page to accept non eval ops
1 parent cb21883 commit b4887c9

File tree

6 files changed

+185
-115
lines changed

6 files changed

+185
-115
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { Icon, InlineField, Input } from '@grafana/ui';
2+
import React, { ChangeEvent } from 'react';
3+
import { DEFAULT_QUERY, HaystackQuery } from 'types';
4+
5+
export interface HaystackQueryInputProps {
6+
query: HaystackQuery;
7+
onChange: (query: string) => void;
8+
}
9+
10+
export function HaystackQueryInput({ query, onChange }: HaystackQueryInputProps) {
11+
const onQueryChange = (event: ChangeEvent<HTMLInputElement>) => {
12+
onChange(event.target.value);
13+
};
14+
15+
let width = 100;
16+
switch (query.type) {
17+
case "eval":
18+
return (
19+
<InlineField>
20+
<Input
21+
width={width}
22+
prefix={<Icon name="angle-right" />}
23+
onChange={onQueryChange}
24+
value={query.eval}
25+
placeholder={DEFAULT_QUERY.eval}
26+
/>
27+
</InlineField>
28+
);
29+
case "hisRead":
30+
return (
31+
<InlineField>
32+
<Input
33+
width={width}
34+
prefix={'@'}
35+
onChange={onQueryChange}
36+
value={query.hisRead}
37+
placeholder={DEFAULT_QUERY.hisRead}
38+
/>
39+
</InlineField>
40+
);
41+
case "read":
42+
return (
43+
<InlineField>
44+
<Input
45+
width={width}
46+
prefix={<Icon name="filter" />}
47+
onChange={onQueryChange}
48+
value={query.read}
49+
placeholder={DEFAULT_QUERY.read}
50+
/>
51+
</InlineField>
52+
);
53+
}
54+
return <p>Select a query type</p>;
55+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { AsyncSelect, InlineField } from '@grafana/ui';
2+
import React, { } from 'react';
3+
import { QueryType } from 'types';
4+
import { DataSource, queryTypes } from '../datasource';
5+
6+
export interface HaystackQueryTypeSelectorProps {
7+
datasource: DataSource | null;
8+
type: string;
9+
refId: string;
10+
onChange: (type: string) => void;
11+
}
12+
13+
export function HaystackQueryTypeSelector({ datasource, type, refId, onChange }: HaystackQueryTypeSelectorProps) {
14+
const onTypeChange = (event: QueryType | null) => {
15+
onChange(event?.value ?? queryTypeDefault.value!);
16+
};
17+
18+
const queryTypeDefault = queryTypes[0];
19+
function queryTypeFromValue(value: string): QueryType | null {
20+
return queryTypes.find((queryType) => queryType.value === value) ?? null;
21+
}
22+
23+
return (
24+
<InlineField label="Type">
25+
<AsyncSelect
26+
loadOptions={() => {return datasource?.loadOps(refId) ?? new Promise<QueryType[]>((resolve) => { resolve(queryTypes);})}}
27+
defaultOptions
28+
value={queryTypeFromValue(type)}
29+
width={30}
30+
onChange={(queryType) => {
31+
// QueryType comes back as a SelectableValue, so we just convert it to the QueryType
32+
onTypeChange(queryTypeFromValue(queryType.value ?? ""));
33+
}}
34+
/>
35+
</InlineField>
36+
);
37+
}

src/components/QueryEditor.tsx

Lines changed: 26 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,26 @@
1-
import React, { ChangeEvent, ReactNode } from 'react';
2-
import { AsyncSelect, Button, Form, Icon, InlineField, Input, VerticalGroup } from '@grafana/ui';
1+
import React, { } from 'react';
2+
import { Button, Form, VerticalGroup } from '@grafana/ui';
33
import { QueryEditorProps } from '@grafana/data';
4-
import { DataSource, queryTypes } from '../datasource';
5-
import { DEFAULT_QUERY, HaystackDataSourceOptions, HaystackQuery, QueryType } from '../types';
4+
import { DataSource } from '../datasource';
5+
import { HaystackDataSourceOptions, HaystackQuery } from '../types';
6+
import { HaystackQueryTypeSelector } from './HaystackQueryTypeSelector';
7+
import { HaystackQueryInput } from './HaystackQueryInput';
68

79
type Props = QueryEditorProps<DataSource, HaystackQuery, HaystackDataSourceOptions>;
810

911
export function QueryEditor({ datasource, query, onChange, onRunQuery }: Props) {
10-
const onTypeChange = (event: QueryType | null) => {
11-
onChange({ ...query, type: event?.value ?? queryTypeDefault.value! });
12+
const onTypeChange = (newType: string) => {
13+
onChange({ ...query, type: newType });
1214
};
13-
const onEvalChange = (event: ChangeEvent<HTMLInputElement>) => {
14-
onChange({ ...query, type: 'eval', eval: event.target.value });
15-
};
16-
const onHisReadChange = (event: ChangeEvent<HTMLInputElement>) => {
17-
onChange({ ...query, type: 'hisRead', hisRead: event.target.value });
18-
};
19-
const onReadChange = (event: ChangeEvent<HTMLInputElement>) => {
20-
onChange({ ...query, type: 'read', read: event.target.value });
21-
};
22-
23-
const queryTypeDefault = queryTypes[0];
24-
function queryTypeFromValue(value: string): QueryType | null {
25-
return queryTypes.find((queryType) => queryType.value === value) ?? null;
26-
}
27-
28-
const SelectComponent = () => {
29-
return (
30-
<InlineField label="Type">
31-
<AsyncSelect
32-
loadOptions={() => {return datasource.loadOps(query.refId);}}
33-
defaultOptions
34-
value={queryTypeFromValue(query.type)}
35-
width={30}
36-
onChange={(queryType) => {
37-
// QueryType comes back as a SelectableValue, so we just convert it to the QueryType
38-
onTypeChange(queryTypeFromValue(queryType.value ?? ""));
39-
}}
40-
/>
41-
</InlineField>
42-
);
43-
};
44-
45-
function renderQuery(): ReactNode {
46-
let width = 100;
47-
switch (query.type) {
48-
case "eval":
49-
return (
50-
<InlineField>
51-
<Input
52-
width={width}
53-
prefix={<Icon name="angle-right" />}
54-
onChange={onEvalChange}
55-
value={query.eval}
56-
placeholder={DEFAULT_QUERY.eval}
57-
/>
58-
</InlineField>
59-
);
60-
case "hisRead":
61-
return (
62-
<InlineField>
63-
<Input
64-
width={width}
65-
prefix={'@'}
66-
onChange={onHisReadChange}
67-
value={query.hisRead}
68-
placeholder={DEFAULT_QUERY.hisRead}
69-
/>
70-
</InlineField>
71-
);
72-
case "read":
73-
return (
74-
<InlineField>
75-
<Input
76-
width={width}
77-
prefix={<Icon name="filter" />}
78-
onChange={onReadChange}
79-
value={query.read}
80-
placeholder={DEFAULT_QUERY.read}
81-
/>
82-
</InlineField>
83-
);
15+
const onQueryChange = (newQuery: string) => {
16+
if (query.type === "hisRead") {
17+
onChange({ ...query, hisRead: newQuery });
18+
} else if (query.type === "eval") {
19+
onChange({ ...query, eval: newQuery });
20+
} else if (query.type === "read") {
21+
onChange({ ...query, read: newQuery });
8422
}
85-
return <p>Select a query type</p>;
86-
}
23+
};
8724

8825
function onSubmit(newQuery: Partial<HaystackQuery>) {
8926
query = { ...query, ...newQuery };
@@ -97,8 +34,16 @@ export function QueryEditor({ datasource, query, onChange, onRunQuery }: Props)
9734
{({ register, errors }) => {
9835
return (
9936
<VerticalGroup>
100-
<SelectComponent />
101-
{renderQuery()}
37+
<HaystackQueryTypeSelector
38+
datasource={datasource}
39+
type={query.type}
40+
refId={query.refId}
41+
onChange={onTypeChange}
42+
/>
43+
<HaystackQueryInput
44+
query={query}
45+
onChange={onQueryChange}
46+
/>
10247
<Button type="submit" >Run</Button>
10348
</VerticalGroup>
10449
);
Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,85 @@
11
import React, { useState } from 'react';
2-
import { HaystackVariableQuery } from '../types';
2+
import { HaystackQuery, HaystackVariableQuery } from '../types';
3+
import { HaystackQueryTypeSelector } from './HaystackQueryTypeSelector';
4+
import { HaystackQueryInput } from './HaystackQueryInput';
35

46
interface VariableQueryProps {
57
query: HaystackVariableQuery;
68
onChange: (query: HaystackVariableQuery, definition: string) => void;
79
}
810

9-
export const VariableQueryEditor: React.FC<VariableQueryProps> = ({ onChange, query }) => {
10-
const [state, setState] = useState(query);
11+
const blankQuery: Partial<HaystackQuery> = {
12+
refId: "variable",
13+
type: '',
14+
eval: '',
15+
hisRead: '',
16+
read: '',
17+
};
18+
19+
export const VariableQueryEditor: React.FC<VariableQueryProps> = ({ onChange, query: variableQuery }) => {
20+
const [state, setState] = useState(variableQuery);
1121

1222
const saveQuery = () => {
13-
onChange(state, `Eval: ${state.eval} Column: ${state.column}`);
23+
let query = state.query ?? blankQuery
24+
let type = query.type;
25+
let queryCmd = "";
26+
if (query.type === "hisRead") {
27+
queryCmd = query.hisRead
28+
} else if (query.type === "eval") {
29+
queryCmd = query.eval
30+
} else if (query.type === "read") {
31+
queryCmd = query.read
32+
}
33+
let column = "none";
34+
if (state.column !== undefined && state.column !== '') {
35+
column = `'${state.column}'`;
36+
}
37+
onChange(state, `Type: '${type}' Query: '${queryCmd}' Column: ${column}`);
38+
};
39+
40+
const onTypeChange = (newType: string) => {
41+
let query = {...state.query ?? blankQuery};
42+
query.type = newType;
43+
setState({ ...state, query: query});
44+
};
45+
46+
const onQueryChange = (newQuery: string) => {
47+
let query = {...state.query ?? blankQuery};
48+
if (state.query.type === "hisRead") {
49+
query.hisRead = newQuery
50+
} else if (state.query.type === "eval") {
51+
query.eval = newQuery
52+
} else if (state.query.type === "read") {
53+
query.read = newQuery
54+
}
55+
setState({ ...state, query: query});
1456
};
1557

16-
const handleChange = (event: React.FormEvent<HTMLInputElement>) =>
17-
setState({
18-
...state,
19-
[event.currentTarget.name]: event.currentTarget.value,
20-
});
58+
const onColumnChange = (event: React.FormEvent<HTMLInputElement>) => {
59+
setState({...state, column: event.currentTarget.value,});
60+
};
2161

2262
return (
23-
<>
24-
<div className="gf-form">
25-
<span className="gf-form-label width-10">Eval</span>
26-
<input
27-
name="eval"
28-
className="gf-form-input"
29-
onBlur={saveQuery}
30-
onChange={handleChange}
31-
value={state.eval}
32-
/>
33-
</div>
63+
<div onBlur={saveQuery}>
64+
<HaystackQueryTypeSelector
65+
datasource={null}
66+
type={state.query?.type ?? blankQuery.type}
67+
refId={state.query?.refId ?? blankQuery.refId}
68+
onChange={onTypeChange}
69+
/>
70+
<HaystackQueryInput
71+
query={state.query ?? blankQuery}
72+
onChange={onQueryChange}
73+
/>
3474
<div className="gf-form">
3575
<span className="gf-form-label width-10">Column</span>
3676
<input
3777
name="column"
3878
className="gf-form-input"
39-
onBlur={saveQuery}
40-
onChange={handleChange}
79+
onChange={onColumnChange}
4180
value={state.column}
4281
/>
4382
</div>
44-
</>
83+
</div>
4584
);
4685
};

src/datasource.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,8 @@ export class DataSource extends DataSourceWithBackend<HaystackQuery, HaystackDat
8282
}
8383

8484
// This is called when the user is selecting a variable value
85-
async metricFindQuery(query: HaystackVariableQuery, options?: any) {
86-
let request: HaystackQuery = {
87-
refId: 'VariableQuery',
88-
type: 'eval',
89-
eval: query.eval,
90-
hisRead: '',
91-
read: '',
92-
};
85+
async metricFindQuery(variableQuery: HaystackVariableQuery, options?: any) {
86+
let request: HaystackQuery = variableQuery.query;
9387
let response = await this.query({ targets: [request] } as DataQueryRequest<HaystackQuery>).toPromise();
9488

9589
if (response === undefined || response.data === undefined) {
@@ -98,9 +92,9 @@ export class DataSource extends DataSourceWithBackend<HaystackQuery, HaystackDat
9892

9993
return response.data.reduce((acc: MetricFindValue[], frame: DataFrame) => {
10094
let field = frame.fields[0];
101-
if (query.column !== undefined && query.column !== '') {
95+
if (variableQuery.column !== undefined && variableQuery.column !== '') {
10296
// If a column was input, match the column name
103-
field = frame.fields.find((field: Field) => field.name === query.column) ?? field;
97+
field = frame.fields.find((field: Field) => field.name === variableQuery.column) ?? field;
10498
}
10599

106100
let fieldVals = field.values.toArray().map((value) => {

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export interface QueryType extends SelectableValue<string> {
1212
}
1313

1414
export interface HaystackVariableQuery {
15+
query: HaystackQuery;
1516
column: string;
16-
eval: string;
1717
}
1818

1919
export const DEFAULT_QUERY: Partial<HaystackQuery> = {

0 commit comments

Comments
 (0)