1import React, { useState, useEffect, useCallback } from 'react';
2import { SelectableValue } from '@grafana/data';
3import { Project, VisualMetricQueryEditor, AliasBy } from '.';
4import {
5  MetricQuery,
6  MetricDescriptor,
7  EditorMode,
8  MetricKind,
9  PreprocessorType,
10  AlignmentTypes,
11  CustomMetaData,
12  ValueTypes,
13  SLOQuery,
14} from '../types';
15import { getAlignmentPickerData } from '../functions';
16import CloudMonitoringDatasource from '../datasource';
17import { MQLQueryEditor } from './MQLQueryEditor';
18
19export interface Props {
20  refId: string;
21  customMetaData: CustomMetaData;
22  variableOptionGroup: SelectableValue<string>;
23  onChange: (query: MetricQuery) => void;
24  onRunQuery: () => void;
25  query: MetricQuery;
26  datasource: CloudMonitoringDatasource;
27}
28
29interface State {
30  labels: any;
31  [key: string]: any;
32}
33
34export const defaultState: State = {
35  labels: {},
36};
37
38export const defaultQuery: (dataSource: CloudMonitoringDatasource) => MetricQuery = (dataSource) => ({
39  editorMode: EditorMode.Visual,
40  projectName: dataSource.getDefaultProject(),
41  metricType: '',
42  metricKind: MetricKind.GAUGE,
43  valueType: '',
44  crossSeriesReducer: 'REDUCE_MEAN',
45  alignmentPeriod: 'cloud-monitoring-auto',
46  perSeriesAligner: AlignmentTypes.ALIGN_MEAN,
47  groupBys: [],
48  filters: [],
49  aliasBy: '',
50  query: '',
51  preprocessor: PreprocessorType.None,
52});
53
54function Editor({
55  refId,
56  query,
57  datasource,
58  onChange: onQueryChange,
59  onRunQuery,
60  customMetaData,
61  variableOptionGroup,
62}: React.PropsWithChildren<Props>) {
63  const [state, setState] = useState<State>(defaultState);
64  const { projectName, metricType, groupBys, editorMode, crossSeriesReducer } = query;
65
66  useEffect(() => {
67    if (projectName && metricType) {
68      datasource
69        .getLabels(metricType, refId, projectName)
70        .then((labels) => setState((prevState) => ({ ...prevState, labels })));
71    }
72  }, [datasource, groupBys, metricType, projectName, refId, crossSeriesReducer]);
73
74  const onChange = useCallback(
75    (metricQuery: MetricQuery | SLOQuery) => {
76      onQueryChange({ ...query, ...metricQuery });
77      onRunQuery();
78    },
79    [onQueryChange, onRunQuery, query]
80  );
81
82  const onMetricTypeChange = useCallback(
83    ({ valueType, metricKind, type }: MetricDescriptor) => {
84      const preprocessor =
85        metricKind === MetricKind.GAUGE || valueType === ValueTypes.DISTRIBUTION
86          ? PreprocessorType.None
87          : PreprocessorType.Rate;
88      const { perSeriesAligner } = getAlignmentPickerData(valueType, metricKind, state.perSeriesAligner, preprocessor);
89      onChange({
90        ...query,
91        perSeriesAligner,
92        metricType: type,
93        valueType,
94        metricKind,
95        preprocessor,
96      });
97    },
98    [onChange, query, state]
99  );
100
101  return (
102    <>
103      <Project
104        templateVariableOptions={variableOptionGroup.options}
105        projectName={projectName}
106        datasource={datasource}
107        onChange={(projectName) => {
108          onChange({ ...query, projectName });
109        }}
110      />
111
112      {editorMode === EditorMode.Visual && (
113        <VisualMetricQueryEditor
114          labels={state.labels}
115          variableOptionGroup={variableOptionGroup}
116          customMetaData={customMetaData}
117          onMetricTypeChange={onMetricTypeChange}
118          onChange={onChange}
119          datasource={datasource}
120          query={query}
121        />
122      )}
123
124      {editorMode === EditorMode.MQL && (
125        <MQLQueryEditor
126          onChange={(q: string) => onQueryChange({ ...query, query: q })}
127          onRunQuery={onRunQuery}
128          query={query.query}
129        ></MQLQueryEditor>
130      )}
131
132      <AliasBy
133        value={query.aliasBy}
134        onChange={(aliasBy) => {
135          onChange({ ...query, aliasBy });
136        }}
137      />
138    </>
139  );
140}
141
142export const MetricQueryEditor = React.memo(Editor);
143