mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* add support for code editor and builder * refactor cloudwatch migration * Add tooltip to editor field (#56) * add tooltip * add old tooltips * Bug bash feedback fixes (#58) * make ASC the default option * update sql preview whenever sql changes * don't allow queries without aggregation * set default value for aggregation * use new input field * cleanup * pr feedback * prevent unnecessary rerenders * use frame error instead of main error * remove not used snapshot * Use dimension filter in schema picker (#63) * use dimension key filter in group by and schema labels * add dimension filter also to code editor * add tests * fix build error * fix strict error * remove debug code * fix annotation editor (#64) * fix annotation editor * fix broken test * revert annotation backend change * PR feedback (#67) * pr feedback * removed dimension filter from group by * add spacing between common fields and rest * do not generate deep link for metric queries (#70) * update docs (#69) Co-authored-by: Erik Sundell <erik.sundell87@gmail.com> * fix lint problem caused by merge conflict Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
188 lines
5.9 KiB
TypeScript
188 lines
5.9 KiB
TypeScript
import React, { PureComponent, ChangeEvent } from 'react';
|
|
|
|
import { QueryEditorProps } from '@grafana/data';
|
|
import { Input } from '@grafana/ui';
|
|
import {
|
|
CloudWatchQuery,
|
|
CloudWatchMetricsQuery,
|
|
CloudWatchJsonData,
|
|
MetricQueryType,
|
|
MetricEditorMode,
|
|
} from '../types';
|
|
import { CloudWatchDatasource } from '../datasource';
|
|
import { Alias, MetricStatEditor, MathExpressionQueryField, SQLBuilderEditor, SQLCodeEditor } from './';
|
|
|
|
import EditorRow from './ui/EditorRow';
|
|
import EditorField from './ui/EditorField';
|
|
import { Space } from './ui/Space';
|
|
import QueryHeader from './QueryHeader';
|
|
import { isMetricsQuery } from '../guards';
|
|
|
|
export type Props = QueryEditorProps<CloudWatchDatasource, CloudWatchQuery, CloudWatchJsonData>;
|
|
|
|
interface State {
|
|
sqlCodeEditorIsDirty: boolean;
|
|
}
|
|
|
|
export const normalizeQuery = ({
|
|
namespace,
|
|
metricName,
|
|
expression,
|
|
dimensions,
|
|
region,
|
|
id,
|
|
alias,
|
|
statistic,
|
|
period,
|
|
sqlExpression,
|
|
metricQueryType,
|
|
metricEditorMode,
|
|
...rest
|
|
}: CloudWatchMetricsQuery): CloudWatchMetricsQuery => {
|
|
const normalizedQuery = {
|
|
queryMode: 'Metrics' as const,
|
|
namespace: namespace ?? '',
|
|
metricName: metricName ?? '',
|
|
expression: expression ?? '',
|
|
dimensions: dimensions ?? {},
|
|
region: region ?? 'default',
|
|
id: id ?? '',
|
|
alias: alias ?? '',
|
|
statistic: statistic ?? 'Average',
|
|
period: period ?? '',
|
|
metricQueryType: metricQueryType ?? MetricQueryType.Search,
|
|
metricEditorMode: metricEditorMode ?? MetricEditorMode.Builder,
|
|
sqlExpression: sqlExpression ?? '',
|
|
...rest,
|
|
};
|
|
return !rest.hasOwnProperty('matchExact') ? { ...normalizedQuery, matchExact: true } : normalizedQuery;
|
|
};
|
|
|
|
export class MetricsQueryEditor extends PureComponent<Props, State> {
|
|
state = {
|
|
sqlCodeEditorIsDirty: false,
|
|
};
|
|
|
|
componentDidMount = () => {
|
|
const metricsQuery = this.props.query as CloudWatchMetricsQuery;
|
|
const query = normalizeQuery(metricsQuery);
|
|
this.props.onChange(query);
|
|
};
|
|
|
|
onChange = (query: CloudWatchQuery) => {
|
|
const { onChange, onRunQuery } = this.props;
|
|
onChange(query);
|
|
onRunQuery();
|
|
};
|
|
|
|
render() {
|
|
const { onRunQuery, datasource } = this.props;
|
|
const metricsQuery = this.props.query as CloudWatchMetricsQuery;
|
|
const query = normalizeQuery(metricsQuery);
|
|
|
|
return (
|
|
<>
|
|
<QueryHeader
|
|
query={query}
|
|
onRunQuery={onRunQuery}
|
|
datasource={datasource}
|
|
onChange={(newQuery) => {
|
|
if (isMetricsQuery(newQuery) && newQuery.metricEditorMode !== query.metricEditorMode) {
|
|
this.setState({ sqlCodeEditorIsDirty: false });
|
|
}
|
|
this.onChange(newQuery);
|
|
}}
|
|
sqlCodeEditorIsDirty={this.state.sqlCodeEditorIsDirty}
|
|
/>
|
|
<Space v={0.5} />
|
|
|
|
{query.metricQueryType === MetricQueryType.Search && (
|
|
<>
|
|
{query.metricEditorMode === MetricEditorMode.Builder && (
|
|
<MetricStatEditor {...{ ...this.props, query }}></MetricStatEditor>
|
|
)}
|
|
{query.metricEditorMode === MetricEditorMode.Code && (
|
|
<MathExpressionQueryField
|
|
onRunQuery={onRunQuery}
|
|
expression={query.expression ?? ''}
|
|
onChange={(expression) => this.props.onChange({ ...query, expression })}
|
|
></MathExpressionQueryField>
|
|
)}
|
|
</>
|
|
)}
|
|
{query.metricQueryType === MetricQueryType.Query && (
|
|
<>
|
|
{query.metricEditorMode === MetricEditorMode.Code && (
|
|
<SQLCodeEditor
|
|
region={query.region}
|
|
sql={query.sqlExpression ?? ''}
|
|
onChange={(sqlExpression) => {
|
|
if (!this.state.sqlCodeEditorIsDirty) {
|
|
this.setState({ sqlCodeEditorIsDirty: true });
|
|
}
|
|
this.props.onChange({ ...metricsQuery, sqlExpression });
|
|
}}
|
|
onRunQuery={onRunQuery}
|
|
datasource={datasource}
|
|
/>
|
|
)}
|
|
|
|
{query.metricEditorMode === MetricEditorMode.Builder && (
|
|
<>
|
|
<SQLBuilderEditor
|
|
query={query}
|
|
onChange={this.props.onChange}
|
|
onRunQuery={onRunQuery}
|
|
datasource={datasource}
|
|
></SQLBuilderEditor>
|
|
</>
|
|
)}
|
|
</>
|
|
)}
|
|
<Space v={0.5} />
|
|
<EditorRow>
|
|
<EditorField
|
|
label="ID"
|
|
width={26}
|
|
optional
|
|
tooltip="ID can be used to reference other queries in math expressions. The ID can include numbers, letters, and underscore, and must start with a lowercase letter."
|
|
>
|
|
<Input
|
|
onBlur={onRunQuery}
|
|
onChange={(event: ChangeEvent<HTMLInputElement>) =>
|
|
this.onChange({ ...metricsQuery, id: event.target.value })
|
|
}
|
|
type="text"
|
|
invalid={!!query.id && !/^$|^[a-z][a-zA-Z0-9_]*$/.test(query.id)}
|
|
value={query.id}
|
|
/>
|
|
</EditorField>
|
|
|
|
<EditorField label="Period" width={26} tooltip="Minimum interval between points in seconds.">
|
|
<Input
|
|
value={query.period || ''}
|
|
placeholder="auto"
|
|
onBlur={onRunQuery}
|
|
onChange={(event: ChangeEvent<HTMLInputElement>) =>
|
|
this.onChange({ ...metricsQuery, period: event.target.value })
|
|
}
|
|
/>
|
|
</EditorField>
|
|
|
|
<EditorField
|
|
label="Alias"
|
|
width={26}
|
|
optional
|
|
tooltip="Change time series legend name using this field. See documentation for replacement variable formats."
|
|
>
|
|
<Alias
|
|
value={metricsQuery.alias ?? ''}
|
|
onChange={(value: string) => this.onChange({ ...metricsQuery, alias: value })}
|
|
/>
|
|
</EditorField>
|
|
</EditorRow>
|
|
</>
|
|
);
|
|
}
|
|
}
|