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