mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus: Add classic query option to variable query editor (#74060)
* add classic query to variable query editor * copy fixes * update test
This commit is contained in:
parent
0f552053e9
commit
951876b465
@ -31,13 +31,14 @@ You have the option to use several different variable types, but variables of th
|
|||||||
|
|
||||||
Select a Prometheus data source query type and enter the required inputs:
|
Select a Prometheus data source query type and enter the required inputs:
|
||||||
|
|
||||||
| Query Type | Input(\* required) | Description | Used API endpoints |
|
| Query Type | Input(\* required) | Description | Used API endpoints |
|
||||||
| -------------- | ------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------- |
|
| --------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
|
||||||
| `Label names` | `metric` | Returns a list of all label names matching the specified `metric` regex. | /api/v1/labels |
|
| `Label names` | `metric` | Returns a list of all label names matching the specified `metric` regex. | /api/v1/labels |
|
||||||
| `Label values` | `label`\*, `metric` | Returns a list of label values for the `label` in all metrics or the optional metric. | /api/v1/label/`label`/values or /api/v1/series |
|
| `Label values` | `label`\*, `metric` | Returns a list of label values for the `label` in all metrics or the optional metric. | /api/v1/label/`label`/values or /api/v1/series |
|
||||||
| `Metrics` | `metric` | Returns a list of metrics matching the specified `metric` regex. | /api/v1/label/\_\_name\_\_/values |
|
| `Metrics` | `metric` | Returns a list of metrics matching the specified `metric` regex. | /api/v1/label/\_\_name\_\_/values |
|
||||||
| `Query result` | `query` | Returns a list of Prometheus query result for the `query`. | /api/v1/query |
|
| `Query result` | `query` | Returns a list of Prometheus query result for the `query`. | /api/v1/query |
|
||||||
| `Series query` | `metric`, `label` or both | Returns a list of time series associated with the entered data. | /api/v1/series |
|
| `Series query` | `metric`, `label` or both | Returns a list of time series associated with the entered data. | /api/v1/series |
|
||||||
|
| `Classic query` | classic query string | Deprecated, classic version of variable query editor. Enter a string with the query type using a syntax like the following: `label_values(<metric>, <label>)` | all |
|
||||||
|
|
||||||
For details on _metric names_, _label names_, and _label values_, refer to the [Prometheus documentation](http://prometheus.io/docs/concepts/data_model/#metric-names-and-labels).
|
For details on _metric names_, _label names_, and _label values_, refer to the [Prometheus documentation](http://prometheus.io/docs/concepts/data_model/#metric-names-and-labels).
|
||||||
|
|
||||||
|
@ -149,6 +149,7 @@ describe('PromVariableQueryEditor', () => {
|
|||||||
await waitFor(() => expect(screen.getByText('Metrics')).toBeInTheDocument());
|
await waitFor(() => expect(screen.getByText('Metrics')).toBeInTheDocument());
|
||||||
await waitFor(() => expect(screen.getByText('Query result')).toBeInTheDocument());
|
await waitFor(() => expect(screen.getByText('Query result')).toBeInTheDocument());
|
||||||
await waitFor(() => expect(screen.getByText('Series query')).toBeInTheDocument());
|
await waitFor(() => expect(screen.getByText('Series query')).toBeInTheDocument());
|
||||||
|
await waitFor(() => expect(screen.getByText('Classic query')).toBeInTheDocument());
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Calls onChange for label_names(match) query', async () => {
|
test('Calls onChange for label_names(match) query', async () => {
|
||||||
@ -167,10 +168,11 @@ describe('PromVariableQueryEditor', () => {
|
|||||||
expect(onChange).toHaveBeenCalledWith({
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
query: 'label_names(that)',
|
query: 'label_names(that)',
|
||||||
refId,
|
refId,
|
||||||
|
qryType: 0,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Calls onChange for label_names, label_values, metrics, and query result queries', async () => {
|
test('Calls onChange for label_names, label_values, metrics, query result and and classic query.', async () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
|
|
||||||
props.query = {
|
props.query = {
|
||||||
@ -184,8 +186,9 @@ describe('PromVariableQueryEditor', () => {
|
|||||||
await selectOptionInTest(screen.getByLabelText('Query type'), 'Label values');
|
await selectOptionInTest(screen.getByLabelText('Query type'), 'Label values');
|
||||||
await selectOptionInTest(screen.getByLabelText('Query type'), 'Metrics');
|
await selectOptionInTest(screen.getByLabelText('Query type'), 'Metrics');
|
||||||
await selectOptionInTest(screen.getByLabelText('Query type'), 'Query result');
|
await selectOptionInTest(screen.getByLabelText('Query type'), 'Query result');
|
||||||
|
await selectOptionInTest(screen.getByLabelText('Query type'), 'Classic query');
|
||||||
|
|
||||||
expect(onChange).toHaveBeenCalledTimes(4);
|
expect(onChange).toHaveBeenCalledTimes(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Does not call onChange for series query', async () => {
|
test('Does not call onChange for series query', async () => {
|
||||||
@ -220,6 +223,7 @@ describe('PromVariableQueryEditor', () => {
|
|||||||
expect(onChange).toHaveBeenCalledWith({
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
query: 'metrics(a)',
|
query: 'metrics(a)',
|
||||||
refId,
|
refId,
|
||||||
|
qryType: 2,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -230,6 +234,7 @@ describe('PromVariableQueryEditor', () => {
|
|||||||
props.query = {
|
props.query = {
|
||||||
refId: 'test',
|
refId: 'test',
|
||||||
query: 'label_names()',
|
query: 'label_names()',
|
||||||
|
qryType: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
render(<PromVariableQueryEditor {...props} onChange={onChange} />);
|
render(<PromVariableQueryEditor {...props} onChange={onChange} />);
|
||||||
@ -243,6 +248,7 @@ describe('PromVariableQueryEditor', () => {
|
|||||||
expect(onChange).toHaveBeenCalledWith({
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
query: 'label_values(this)',
|
query: 'label_values(this)',
|
||||||
refId,
|
refId,
|
||||||
|
qryType: 1,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -270,6 +276,7 @@ describe('PromVariableQueryEditor', () => {
|
|||||||
expect(onChange).toHaveBeenCalledWith({
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
query: 'label_values(that,this)',
|
query: 'label_values(that,this)',
|
||||||
refId,
|
refId,
|
||||||
|
qryType: 1,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -292,6 +299,7 @@ describe('PromVariableQueryEditor', () => {
|
|||||||
expect(onChange).toHaveBeenCalledWith({
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
query: 'query_result(a)',
|
query: 'query_result(a)',
|
||||||
refId,
|
refId,
|
||||||
|
qryType: 3,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -313,6 +321,30 @@ describe('PromVariableQueryEditor', () => {
|
|||||||
expect(onChange).toHaveBeenCalledWith({
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
query: '{a: "example"}',
|
query: '{a: "example"}',
|
||||||
refId,
|
refId,
|
||||||
|
qryType: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Calls onChange for classic query onBlur', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
|
||||||
|
props.query = {
|
||||||
|
refId: 'test',
|
||||||
|
qryType: 5,
|
||||||
|
query: 'label_values(instance)',
|
||||||
|
};
|
||||||
|
|
||||||
|
render(<PromVariableQueryEditor {...props} onChange={onChange} />);
|
||||||
|
|
||||||
|
const labelSelect = screen.getByLabelText('Classic Query');
|
||||||
|
await userEvent.click(labelSelect);
|
||||||
|
const functionSelect = screen.getByLabelText('Query type').parentElement!;
|
||||||
|
await userEvent.click(functionSelect);
|
||||||
|
|
||||||
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
|
query: 'label_values(instance)',
|
||||||
|
refId,
|
||||||
|
qryType: 5,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -26,6 +26,7 @@ export const variableOptions = [
|
|||||||
{ label: 'Metrics', value: QueryType.MetricNames },
|
{ label: 'Metrics', value: QueryType.MetricNames },
|
||||||
{ label: 'Query result', value: QueryType.VarQueryResult },
|
{ label: 'Query result', value: QueryType.VarQueryResult },
|
||||||
{ label: 'Series query', value: QueryType.SeriesQuery },
|
{ label: 'Series query', value: QueryType.SeriesQuery },
|
||||||
|
{ label: 'Classic query', value: QueryType.ClassicQuery },
|
||||||
];
|
];
|
||||||
|
|
||||||
export type Props = QueryEditorProps<PrometheusDatasource, PromQuery, PromOptions, PromVariableQuery>;
|
export type Props = QueryEditorProps<PrometheusDatasource, PromQuery, PromOptions, PromVariableQuery>;
|
||||||
@ -49,6 +50,9 @@ export const PromVariableQueryEditor = ({ onChange, query, datasource }: Props)
|
|||||||
// seriesQuery is only a whole
|
// seriesQuery is only a whole
|
||||||
const [seriesQuery, setSeriesQuery] = useState('');
|
const [seriesQuery, setSeriesQuery] = useState('');
|
||||||
|
|
||||||
|
// the original variable query implementation
|
||||||
|
const [classicQuery, setClassicQuery] = useState('');
|
||||||
|
|
||||||
// list of label names for label_values(), /api/v1/labels, contains the same results as label_names() function
|
// list of label names for label_values(), /api/v1/labels, contains the same results as label_names() function
|
||||||
const [labelOptions, setLabelOptions] = useState<Array<SelectableValue<string>>>([]);
|
const [labelOptions, setLabelOptions] = useState<Array<SelectableValue<string>>>([]);
|
||||||
|
|
||||||
@ -59,17 +63,24 @@ export const PromVariableQueryEditor = ({ onChange, query, datasource }: Props)
|
|||||||
if (!query) {
|
if (!query) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 1. Changing from standard to custom variable editor changes the string attr from expr to query
|
|
||||||
// 2. jsonnet grafana as code passes a variable as a string
|
|
||||||
const variableQuery = variableMigration(query);
|
|
||||||
|
|
||||||
setLabelNamesMatch(variableQuery.match ?? '');
|
if (query.qryType === QueryType.ClassicQuery) {
|
||||||
setQryType(variableQuery.qryType);
|
setQryType(query.qryType);
|
||||||
setLabel(variableQuery.label ?? '');
|
setClassicQuery(query.query ?? '');
|
||||||
setMetric(variableQuery.metric ?? '');
|
} else {
|
||||||
setLabelFilters(variableQuery.labelFilters ?? []);
|
// 1. Changing from standard to custom variable editor changes the string attr from expr to query
|
||||||
setVarQuery(variableQuery.varQuery ?? '');
|
// 2. jsonnet grafana as code passes a variable as a string
|
||||||
setSeriesQuery(variableQuery.seriesQuery ?? '');
|
const variableQuery = variableMigration(query);
|
||||||
|
|
||||||
|
setLabelNamesMatch(variableQuery.match ?? '');
|
||||||
|
setQryType(variableQuery.qryType);
|
||||||
|
setLabel(variableQuery.label ?? '');
|
||||||
|
setMetric(variableQuery.metric ?? '');
|
||||||
|
setLabelFilters(variableQuery.labelFilters ?? []);
|
||||||
|
setVarQuery(variableQuery.varQuery ?? '');
|
||||||
|
setSeriesQuery(variableQuery.seriesQuery ?? '');
|
||||||
|
setClassicQuery(variableQuery.classicQuery ?? '');
|
||||||
|
}
|
||||||
}, [query]);
|
}, [query]);
|
||||||
|
|
||||||
// set the label names options for the label values var query
|
// set the label names options for the label values var query
|
||||||
@ -116,6 +127,7 @@ export const PromVariableQueryEditor = ({ onChange, query, datasource }: Props)
|
|||||||
match: labelNamesMatch,
|
match: labelNamesMatch,
|
||||||
varQuery,
|
varQuery,
|
||||||
seriesQuery,
|
seriesQuery,
|
||||||
|
classicQuery,
|
||||||
refId: 'PrometheusVariableQueryEditor-VariableQuery',
|
refId: 'PrometheusVariableQueryEditor-VariableQuery',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -128,6 +140,7 @@ export const PromVariableQueryEditor = ({ onChange, query, datasource }: Props)
|
|||||||
// setting query.query property allows for update of variable definition
|
// setting query.query property allows for update of variable definition
|
||||||
onChange({
|
onChange({
|
||||||
query: queryString,
|
query: queryString,
|
||||||
|
qryType: updatedVar.qryType,
|
||||||
refId,
|
refId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -200,6 +213,10 @@ export const PromVariableQueryEditor = ({ onChange, query, datasource }: Props)
|
|||||||
setSeriesQuery(e.currentTarget.value);
|
setSeriesQuery(e.currentTarget.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onClassicQueryChange = (e: FormEvent<HTMLInputElement>) => {
|
||||||
|
setClassicQuery(e.currentTarget.value);
|
||||||
|
};
|
||||||
|
|
||||||
const promVisualQuery = useCallback(() => {
|
const promVisualQuery = useCallback(() => {
|
||||||
return { metric: metric, labels: labelFilters, operations: [] };
|
return { metric: metric, labels: labelFilters, operations: [] };
|
||||||
}, [metric, labelFilters]);
|
}, [metric, labelFilters]);
|
||||||
@ -371,6 +388,35 @@ export const PromVariableQueryEditor = ({ onChange, query, datasource }: Props)
|
|||||||
</InlineField>
|
</InlineField>
|
||||||
</InlineFieldRow>
|
</InlineFieldRow>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{qryType === QueryType.ClassicQuery && (
|
||||||
|
<InlineFieldRow>
|
||||||
|
<InlineField
|
||||||
|
label="Classic Query"
|
||||||
|
labelWidth={20}
|
||||||
|
tooltip={
|
||||||
|
<div>
|
||||||
|
The original implemetation of the Prometheus variable query editor. Enter a string with the correct
|
||||||
|
query type and parameters as described in these docs. For example, label_values(label, metric).
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
aria-label="Classic Query"
|
||||||
|
placeholder="Classic Query"
|
||||||
|
value={classicQuery}
|
||||||
|
onChange={onClassicQueryChange}
|
||||||
|
onBlur={() => {
|
||||||
|
if (qryType === QueryType.ClassicQuery && classicQuery) {
|
||||||
|
onChangeWithVariableString({ qryType });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
width={100}
|
||||||
|
/>
|
||||||
|
</InlineField>
|
||||||
|
</InlineFieldRow>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -123,7 +123,9 @@ export function migrateVariableEditorBackToVariableSupport(QueryVariable: PromVa
|
|||||||
const varQuery = removeLineBreaks(QueryVariable.varQuery);
|
const varQuery = removeLineBreaks(QueryVariable.varQuery);
|
||||||
return `query_result(${varQuery})`;
|
return `query_result(${varQuery})`;
|
||||||
case QueryType.SeriesQuery:
|
case QueryType.SeriesQuery:
|
||||||
return '' + QueryVariable.seriesQuery;
|
return QueryVariable.seriesQuery ?? '';
|
||||||
|
case QueryType.ClassicQuery:
|
||||||
|
return QueryVariable.classicQuery ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
|
@ -183,6 +183,7 @@ export enum PromVariableQueryType {
|
|||||||
MetricNames,
|
MetricNames,
|
||||||
VarQueryResult,
|
VarQueryResult,
|
||||||
SeriesQuery,
|
SeriesQuery,
|
||||||
|
ClassicQuery,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PromVariableQuery extends DataQuery {
|
export interface PromVariableQuery extends DataQuery {
|
||||||
@ -195,6 +196,7 @@ export interface PromVariableQuery extends DataQuery {
|
|||||||
seriesQuery?: string;
|
seriesQuery?: string;
|
||||||
labelFilters?: QueryBuilderLabelFilter[];
|
labelFilters?: QueryBuilderLabelFilter[];
|
||||||
match?: string;
|
match?: string;
|
||||||
|
classicQuery?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StandardPromVariableQuery = {
|
export type StandardPromVariableQuery = {
|
||||||
|
Loading…
Reference in New Issue
Block a user