1import React from 'react';
2import { LegacyForms } from '@grafana/ui';
3import { TemplateSrv } from '@grafana/runtime';
4import { SelectableValue, toOption } from '@grafana/data';
5
6import CloudMonitoringDatasource from '../datasource';
7import { AnnotationsHelp, LabelFilter, Metrics, Project, QueryEditorRow } from './';
8import { AnnotationTarget, EditorMode, MetricDescriptor, MetricKind } from '../types';
9
10const { Input } = LegacyForms;
11
12export interface Props {
13  onQueryChange: (target: AnnotationTarget) => void;
14  target: AnnotationTarget;
15  datasource: CloudMonitoringDatasource;
16  templateSrv: TemplateSrv;
17}
18
19interface State extends AnnotationTarget {
20  variableOptionGroup: SelectableValue<string>;
21  variableOptions: Array<SelectableValue<string>>;
22  labels: any;
23  [key: string]: any;
24}
25
26const DefaultTarget: State = {
27  editorMode: EditorMode.Visual,
28  projectName: '',
29  projects: [],
30  metricType: '',
31  filters: [],
32  metricKind: MetricKind.GAUGE,
33  valueType: '',
34  refId: 'annotationQuery',
35  title: '',
36  text: '',
37  labels: {},
38  variableOptionGroup: {},
39  variableOptions: [],
40};
41
42export class AnnotationQueryEditor extends React.Component<Props, State> {
43  state: State = DefaultTarget;
44
45  async UNSAFE_componentWillMount() {
46    // Unfortunately, migrations like this need to go UNSAFE_componentWillMount. As soon as there's
47    // migration hook for this module.ts, we can do the migrations there instead.
48    const { target, datasource } = this.props;
49    if (!target.projectName) {
50      target.projectName = datasource.getDefaultProject();
51    }
52
53    const variableOptionGroup = {
54      label: 'Template Variables',
55      options: datasource.getVariables().map(toOption),
56    };
57
58    const projects = await datasource.getProjects();
59    this.setState({
60      variableOptionGroup,
61      variableOptions: variableOptionGroup.options,
62      ...target,
63      projects,
64    });
65
66    datasource
67      .getLabels(target.metricType, target.projectName, target.refId)
68      .then((labels) => this.setState({ labels }));
69  }
70
71  onMetricTypeChange = ({ valueType, metricKind, type, unit }: MetricDescriptor) => {
72    const { onQueryChange, datasource } = this.props;
73    this.setState(
74      {
75        metricType: type,
76        unit,
77        valueType,
78        metricKind,
79      },
80      () => {
81        onQueryChange(this.state);
82      }
83    );
84    datasource.getLabels(type, this.state.refId, this.state.projectName).then((labels) => this.setState({ labels }));
85  };
86
87  onChange(prop: string, value: string | string[]) {
88    this.setState({ [prop]: value }, () => {
89      this.props.onQueryChange(this.state);
90    });
91  }
92
93  render() {
94    const { metricType, projectName, filters, title, text, variableOptionGroup, labels, variableOptions } = this.state;
95    const { datasource } = this.props;
96
97    return (
98      <>
99        <Project
100          templateVariableOptions={variableOptions}
101          datasource={datasource}
102          projectName={projectName || datasource.getDefaultProject()}
103          onChange={(value) => this.onChange('projectName', value)}
104        />
105        <Metrics
106          projectName={projectName}
107          metricType={metricType}
108          templateSrv={datasource.templateSrv}
109          datasource={datasource}
110          templateVariableOptions={variableOptions}
111          onChange={(metric) => this.onMetricTypeChange(metric)}
112        >
113          {(metric) => (
114            <>
115              <LabelFilter
116                labels={labels}
117                filters={filters}
118                onChange={(value) => this.onChange('filters', value)}
119                variableOptionGroup={variableOptionGroup}
120              />
121            </>
122          )}
123        </Metrics>
124
125        <QueryEditorRow label="Title">
126          <Input
127            type="text"
128            className="gf-form-input width-20"
129            value={title}
130            onChange={(e) => this.onChange('title', e.target.value)}
131          />
132        </QueryEditorRow>
133        <QueryEditorRow label="Text">
134          <Input
135            type="text"
136            className="gf-form-input width-20"
137            value={text}
138            onChange={(e) => this.onChange('text', e.target.value)}
139          />
140        </QueryEditorRow>
141
142        <AnnotationsHelp />
143      </>
144    );
145  }
146}
147