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