The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx

257 lines
8.3 KiB

import React, { FC, FormEvent, useEffect, useState } from 'react';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Input, Select, TextArea } from '@grafana/ui';
import { PrometheusDatasource } from '../datasource';
import {
migrateVariableEditorBackToVariableSupport,
migrateVariableQueryToEditor,
} from '../migrations/variableMigration';
import { PromOptions, PromQuery, PromVariableQuery, PromVariableQueryType as QueryType } from '../types';
export const variableOptions = [
{ label: 'Label names', value: QueryType.LabelNames },
{ label: 'Label values', value: QueryType.LabelValues },
{ label: 'Metrics', value: QueryType.MetricNames },
{ label: 'Query result', value: QueryType.VarQueryResult },
{ label: 'Series query', value: QueryType.SeriesQuery },
];
export type Props = QueryEditorProps<PrometheusDatasource, PromQuery, PromOptions, PromVariableQuery>;
const refId = 'PrometheusVariableQueryEditor-VariableQuery';
export const PromVariableQueryEditor: FC<Props> = ({ onChange, query, datasource }) => {
// to select the query type, i.e. label_names, label_values, etc.
const [qryType, setQryType] = useState<number | undefined>(undefined);
// list of variables for each function
const [label, setLabel] = useState('');
// metric is used for both label_values() and metric()
// label_values() metric requires a whole/complete metric
// metric() is expected to be a part of a metric string
const [metric, setMetric] = useState('');
// varQuery is a whole query, can include math/rates/etc
const [varQuery, setVarQuery] = useState('');
// seriesQuery is only a whole
const [seriesQuery, setSeriesQuery] = useState('');
// 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>>>([]);
useEffect(() => {
if (!query) {
return;
}
// Changing from standard to custom variable editor changes the string attr from expr to query
const variableQuery = query.query ? migrateVariableQueryToEditor(query.query) : query;
setQryType(variableQuery.qryType);
setLabel(variableQuery.label ?? '');
setMetric(variableQuery.metric ?? '');
setVarQuery(variableQuery.varQuery ?? '');
setSeriesQuery(variableQuery.seriesQuery ?? '');
// set the migrated label in the label options
if (variableQuery.label) {
setLabelOptions([{ label: variableQuery.label, value: variableQuery.label }]);
}
}, [query]);
// set the label names options for the label values var query
useEffect(() => {
if (qryType !== QueryType.LabelValues) {
return;
}
datasource.getLabelNames().then((labelNames: Array<{ text: string }>) => {
setLabelOptions(labelNames.map(({ text }) => ({ label: text, value: text })));
});
}, [datasource, qryType]);
const onChangeWithVariableString = (qryType: QueryType) => {
const queryVar = {
qryType: qryType,
label,
metric,
varQuery,
seriesQuery,
refId: 'PrometheusVariableQueryEditor-VariableQuery',
};
const queryString = migrateVariableEditorBackToVariableSupport(queryVar);
onChange({
query: queryString,
refId,
});
};
const onQueryTypeChange = (newType: SelectableValue<QueryType>) => {
setQryType(newType.value);
if (newType.value === QueryType.LabelNames) {
onChangeWithVariableString(newType.value);
}
};
const onLabelChange = (newLabel: SelectableValue<string>) => {
setLabel(newLabel.value ?? '');
};
const onMetricChange = (e: FormEvent<HTMLInputElement>) => {
setMetric(e.currentTarget.value);
};
const onVarQueryChange = (e: FormEvent<HTMLTextAreaElement>) => {
setVarQuery(e.currentTarget.value);
};
const onSeriesQueryChange = (e: FormEvent<HTMLInputElement>) => {
setSeriesQuery(e.currentTarget.value);
};
const handleBlur = () => {
if (qryType === QueryType.LabelNames) {
onChangeWithVariableString(qryType);
} else if (qryType === QueryType.LabelValues && label) {
onChangeWithVariableString(qryType);
} else if (qryType === QueryType.MetricNames && metric) {
onChangeWithVariableString(qryType);
} else if (qryType === QueryType.VarQueryResult && varQuery) {
onChangeWithVariableString(qryType);
} else if (qryType === QueryType.SeriesQuery && seriesQuery) {
onChangeWithVariableString(qryType);
}
};
return (
<InlineFieldRow>
<InlineField
label="Query Type"
labelWidth={20}
tooltip={
<div>The Prometheus data source plugin provides the following query types for template variables.</div>
}
>
<Select
placeholder="Select query type"
aria-label="Query type"
onChange={onQueryTypeChange}
onBlur={handleBlur}
value={qryType}
options={variableOptions}
width={25}
/>
</InlineField>
{qryType === QueryType.LabelValues && (
<>
<InlineField
label="Label"
labelWidth={20}
required
tooltip={
<div>
Returns a list of label values for the label name in all metrics unless the metric is specified.
</div>
}
>
<Select
aria-label="label-select"
onChange={onLabelChange}
onBlur={handleBlur}
value={label}
options={labelOptions}
width={25}
allowCustomValue
/>
</InlineField>
<InlineField
label="Metric"
labelWidth={20}
tooltip={<div>Optional: returns a list of label values for the label name in the specified metric.</div>}
>
<Input
type="text"
aria-label="Metric selector"
placeholder="Optional metric selector"
value={metric}
onChange={onMetricChange}
onBlur={handleBlur}
width={25}
/>
</InlineField>
</>
)}
{qryType === QueryType.MetricNames && (
<>
<InlineField
label="Metric Regex"
labelWidth={20}
tooltip={<div>Returns a list of metrics matching the specified metric regex.</div>}
>
<Input
type="text"
aria-label="Metric selector"
placeholder="Metric Regex"
value={metric}
onChange={onMetricChange}
onBlur={handleBlur}
width={25}
/>
</InlineField>
</>
)}
{qryType === QueryType.VarQueryResult && (
<>
<InlineField
label="Query"
labelWidth={20}
tooltip={
<div>
Returns a list of Prometheus query results for the query. This can include Prometheus functions, i.e.
sum(go_goroutines).
</div>
}
>
<TextArea
type="text"
aria-label="Prometheus Query"
placeholder="Prometheus Query"
value={varQuery}
onChange={onVarQueryChange}
onBlur={handleBlur}
cols={100}
/>
</InlineField>
</>
)}
{qryType === QueryType.SeriesQuery && (
<>
<InlineField
label="Series Query"
labelWidth={20}
tooltip={
<div>
Enter enter a metric with labels, only a metric or only labels, i.e.
go_goroutines&#123;instance=&quot;localhost:9090&quot;&#125;, go_goroutines, or
&#123;instance=&quot;localhost:9090&quot;&#125;. Returns a list of time series associated with the
entered data.
</div>
}
>
<Input
type="text"
aria-label="Series Query"
placeholder="Series Query"
value={seriesQuery}
onChange={onSeriesQueryChange}
onBlur={handleBlur}
width={100}
/>
</InlineField>
</>
)}
</InlineFieldRow>
);
};