InfluxDB: Introduce custom variable support (#87903)

* Introduce custom variable support

* Remove comment lines

* betterer
This commit is contained in:
ismail simsek 2024-05-21 13:46:41 +02:00 committed by GitHub
parent a2aea70100
commit 9bdfb6ee13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 109 additions and 70 deletions

View File

@ -5555,12 +5555,6 @@ exports[`no gf-form usage`] = {
"public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/TagsSection.tsx:5381": [
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
],
"public/app/plugins/datasource/influxdb/components/editor/variable/VariableQueryEditor.tsx:5381": [
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
],
"public/app/plugins/datasource/loki/components/LokiQueryField.tsx:5381": [
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],

View File

@ -20,7 +20,7 @@ export const QueryEditor = ({ query, onChange, onRunQuery, datasource }: Props)
case InfluxVersion.Flux:
return (
<div className="gf-form-query-content">
<FluxQueryEditor query={query} onChange={onChange} onRunQuery={onRunQuery} datasource={datasource} />
<FluxQueryEditor query={query} onChange={onChange} datasource={datasource} />
</div>
);
case InfluxVersion.SQL:

View File

@ -20,7 +20,6 @@ import { InfluxQuery } from '../../../../types';
interface Props extends Themeable2 {
onChange: (query: InfluxQuery) => void;
onRunQuery: () => void;
query: InfluxQuery;
// `datasource` is not used internally, but this component is used at some places
// directly, where the `datasource` prop has to exist. later, when the whole
@ -98,7 +97,6 @@ v1.tagValues(
class UnthemedFluxQueryEditor extends PureComponent<Props> {
onFluxQueryChange = (query: string) => {
this.props.onChange({ ...this.props.query, query });
this.props.onRunQuery();
};
onSampleChange = (val: SelectableValue<string>) => {
@ -109,7 +107,6 @@ class UnthemedFluxQueryEditor extends PureComponent<Props> {
// Angular HACK: Since the target does not actually change!
this.forceUpdate();
this.props.onRunQuery();
};
getSuggestions = (): CodeEditorSuggestionItem[] => {

View File

@ -1,68 +1,75 @@
import React, { PureComponent } from 'react';
import React from 'react';
import { Field, FieldSet, InlineFormLabel, TextArea } from '@grafana/ui';
import { QueryEditorProps } from '@grafana/data';
import { Field, FieldSet, InlineFieldRow, TextArea } from '@grafana/ui';
import { InlineField } from '@grafana/ui/';
import InfluxDatasource from '../../../datasource';
import { InfluxVersion } from '../../../types';
import { InfluxOptions, InfluxQuery, InfluxVariableQuery, InfluxVersion } from '../../../types';
import { FluxQueryEditor } from '../query/flux/FluxQueryEditor';
interface Props {
query: string; // before flux, it was always a string
onChange: (query?: string) => void;
datasource: InfluxDatasource;
}
export type Props = QueryEditorProps<InfluxDatasource, InfluxQuery, InfluxOptions, InfluxVariableQuery>;
export default class VariableQueryEditor extends PureComponent<Props> {
onRefresh = () => {
// noop
const refId = 'InfluxVariableQueryEditor-VariableQuery';
const useVariableQuery = (query: InfluxVariableQuery | string): InfluxVariableQuery => {
// in legacy variable support query can be only a string
// in new variable support query can be an object and hold more information
// to be able to support old version we check the query here
if (typeof query === 'string') {
return {
refId,
query,
};
} else {
return {
refId,
query: query.query ?? '',
};
}
};
export const InfluxVariableEditor = ({ onChange, datasource, query }: Props) => {
const varQuery = useVariableQuery(query);
const onChangeHandler = (q: InfluxQuery) => {
onChange({ refId, query: q.query || '' });
};
render() {
let { query, datasource, onChange } = this.props;
const onBlurHandler = (e: React.FocusEvent<HTMLTextAreaElement>) => {
onChange({ refId, query: e.currentTarget.value });
};
switch (datasource.version) {
case InfluxVersion.Flux:
return (
<FluxQueryEditor
datasource={datasource}
query={{
refId: 'A',
query,
}}
onRunQuery={this.onRefresh}
onChange={(v) => onChange(v.query)}
/>
);
case InfluxVersion.SQL:
return (
<FieldSet>
<Field htmlFor="influx-sql-variable-query">
<TextArea
id="influx-sql-variable-query"
defaultValue={query || ''}
placeholder="metric name or tags query"
rows={1}
onBlur={(e) => onChange(e.currentTarget.value)}
/>
</Field>
</FieldSet>
);
case InfluxVersion.InfluxQL:
default:
return (
<div className="gf-form-inline">
<InlineFormLabel width={10}>Query</InlineFormLabel>
<div className="gf-form-inline gf-form--grow">
<TextArea
defaultValue={query || ''}
placeholder="metric name or tags query"
rows={1}
className="gf-form-input"
onBlur={(e) => onChange(e.currentTarget.value)}
/>
</div>
</div>
);
}
switch (datasource.version) {
case InfluxVersion.Flux:
return <FluxQueryEditor datasource={datasource} query={varQuery} onChange={onChangeHandler} />;
case InfluxVersion.SQL:
return (
<FieldSet>
<Field htmlFor="influx-sql-variable-query">
<TextArea
id="influx-sql-variable-query"
defaultValue={varQuery.query || ''}
placeholder="metric name or tags query"
rows={1}
onBlur={onBlurHandler}
/>
</Field>
</FieldSet>
);
case InfluxVersion.InfluxQL:
default:
return (
<InlineFieldRow>
<InlineField label="Query" labelWidth={20} required grow aria-labelledby="label-select">
<TextArea
defaultValue={varQuery.query || ''}
placeholder="metric name or tags query"
rows={1}
onBlur={onBlurHandler}
/>
</InlineField>
</InlineFieldRow>
);
}
}
};

View File

@ -49,6 +49,7 @@ import { prepareAnnotation } from './migrations';
import { buildRawQuery, removeRegexWrapper } from './queryUtils';
import ResponseParser from './response_parser';
import { DEFAULT_POLICY, InfluxOptions, InfluxQuery, InfluxQueryTag, InfluxVersion } from './types';
import { InfluxVariableSupport } from './variables';
export default class InfluxDatasource extends DataSourceWithBackend<InfluxQuery, InfluxOptions> {
type: string;
@ -89,6 +90,7 @@ export default class InfluxDatasource extends DataSourceWithBackend<InfluxQuery,
this.responseParser = new ResponseParser();
this.version = settingsData.version ?? InfluxVersion.InfluxQL;
this.isProxyAccess = instanceSettings.access === 'proxy';
this.variables = new InfluxVariableSupport(this, this.templateSrv);
if (this.version === InfluxVersion.Flux) {
// When flux, use an annotation processor rather than the `annotationQuery` lifecycle

View File

@ -3,11 +3,9 @@ import { DataSourcePlugin } from '@grafana/data';
import ConfigEditor from './components/editor/config/ConfigEditor';
import { QueryEditor } from './components/editor/query/QueryEditor';
import { InfluxStartPage } from './components/editor/query/influxql/InfluxStartPage';
import VariableQueryEditor from './components/editor/variable/VariableQueryEditor';
import InfluxDatasource from './datasource';
export const plugin = new DataSourcePlugin(InfluxDatasource)
.setConfigEditor(ConfigEditor)
.setQueryEditor(QueryEditor)
.setVariableQueryEditor(VariableQueryEditor)
.setQueryEditorHelp(InfluxStartPage);

View File

@ -60,6 +60,10 @@ export interface InfluxQueryTag {
export type ResultFormat = 'time_series' | 'table' | 'logs';
export interface InfluxVariableQuery extends DataQuery {
query: string;
}
export interface InfluxQuery extends DataQuery {
policy?: string;
measurement?: string;

View File

@ -0,0 +1,37 @@
import { from, Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { CustomVariableSupport, DataQueryRequest, DataQueryResponse } from '@grafana/data';
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
import { InfluxVariableEditor } from './components/editor/variable/VariableQueryEditor';
import InfluxDatasource from './datasource';
import { InfluxVariableQuery } from './types';
export class InfluxVariableSupport extends CustomVariableSupport<InfluxDatasource> {
editor = InfluxVariableEditor;
constructor(
private readonly datasource: InfluxDatasource,
private readonly templateSrv: TemplateSrv = getTemplateSrv()
) {
super();
}
query(request: DataQueryRequest<InfluxVariableQuery>): Observable<DataQueryResponse> {
let query: string | undefined;
if (typeof request.targets[0] === 'string') {
query = request.targets[0];
} else {
query = request.targets[0].query;
}
if (!query) {
return of({ data: [] });
}
const interpolated = this.templateSrv.replace(query, request.scopedVars, this.datasource.interpolateQueryExpr);
const metricFindStream = from(this.datasource.metricFindQuery(interpolated, request.range));
return metricFindStream.pipe(map((results) => ({ data: results })));
}
}