QueryEditor.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import React from 'react';
  2. import _ from 'lodash';
  3. import { Metrics } from './Metrics';
  4. import { Filter } from './Filter';
  5. import { Aggregations } from './Aggregations';
  6. import { Alignments } from './Alignments';
  7. import { AlignmentPeriods } from './AlignmentPeriods';
  8. import { AliasBy } from './AliasBy';
  9. import { Help } from './Help';
  10. import { Target } from '../types';
  11. import { getAlignmentPickerData } from '../functions';
  12. export interface Props {
  13. onQueryChange: (target: Target) => void;
  14. onExecuteQuery?: () => void;
  15. target: Target;
  16. events: any;
  17. datasource: any;
  18. uiSegmentSrv: any;
  19. }
  20. interface State extends Target {
  21. alignOptions: any[];
  22. lastQuery: string;
  23. lastQueryError: string;
  24. [key: string]: any;
  25. }
  26. const DefaultTarget: State = {
  27. defaultProject: 'loading project...',
  28. metricType: '',
  29. metricKind: '',
  30. valueType: '',
  31. refId: '',
  32. service: '',
  33. unit: '',
  34. crossSeriesReducer: 'REDUCE_MEAN',
  35. alignmentPeriod: 'stackdriver-auto',
  36. perSeriesAligner: 'ALIGN_MEAN',
  37. groupBys: [],
  38. filters: [],
  39. aliasBy: '',
  40. alignOptions: [],
  41. lastQuery: '',
  42. lastQueryError: '',
  43. };
  44. export class QueryEditor extends React.Component<Props, State> {
  45. state: State = DefaultTarget;
  46. componentDidMount() {
  47. const { events, target, datasource } = this.props;
  48. events.on('data-received', this.onDataReceived.bind(this));
  49. events.on('data-error', this.onDataError.bind(this));
  50. const { perSeriesAligner, alignOptions } = getAlignmentPickerData(target, datasource.templateSrv);
  51. this.setState({
  52. ...this.props.target,
  53. alignOptions,
  54. perSeriesAligner,
  55. });
  56. }
  57. onDataReceived(dataList) {
  58. const series = dataList.find(item => item.refId === this.props.target.refId);
  59. if (series) {
  60. this.setState({ lastQuery: decodeURIComponent(series.meta.rawQuery), lastQueryError: '' });
  61. }
  62. }
  63. onDataError(err) {
  64. let lastQuery;
  65. let lastQueryError;
  66. if (err.data && err.data.error) {
  67. lastQueryError = this.props.datasource.formatStackdriverError(err);
  68. } else if (err.data && err.data.results) {
  69. const queryRes = err.data.results[this.props.target.refId];
  70. lastQuery = decodeURIComponent(queryRes.meta.rawQuery);
  71. if (queryRes && queryRes.error) {
  72. try {
  73. lastQueryError = JSON.parse(queryRes.error).error.message;
  74. } catch {
  75. lastQueryError = queryRes.error;
  76. }
  77. }
  78. }
  79. this.setState({ lastQuery, lastQueryError });
  80. }
  81. handleMetricTypeChange({ valueType, metricKind, type, unit }) {
  82. const { datasource, onQueryChange, onExecuteQuery } = this.props;
  83. const { perSeriesAligner, alignOptions } = getAlignmentPickerData(
  84. { valueType, metricKind, perSeriesAligner: this.state.perSeriesAligner },
  85. datasource.templateSrv
  86. );
  87. this.setState(
  88. {
  89. alignOptions,
  90. perSeriesAligner,
  91. metricType: type,
  92. unit,
  93. valueType,
  94. metricKind,
  95. },
  96. () => {
  97. onQueryChange(this.state);
  98. onExecuteQuery();
  99. }
  100. );
  101. }
  102. handleChange(prop, value) {
  103. this.setState({ [prop]: value }, () => {
  104. this.props.onQueryChange(this.state);
  105. this.props.onExecuteQuery();
  106. });
  107. }
  108. render() {
  109. const {
  110. defaultProject,
  111. metricType,
  112. crossSeriesReducer,
  113. groupBys,
  114. perSeriesAligner,
  115. alignOptions,
  116. alignmentPeriod,
  117. aliasBy,
  118. lastQuery,
  119. lastQueryError,
  120. } = this.state;
  121. const { datasource, uiSegmentSrv } = this.props;
  122. return (
  123. <React.Fragment>
  124. <Metrics
  125. defaultProject={defaultProject}
  126. metricType={metricType}
  127. templateSrv={datasource.templateSrv}
  128. datasource={datasource}
  129. onChange={value => this.handleMetricTypeChange(value)}
  130. >
  131. {metric => (
  132. <React.Fragment>
  133. <Filter
  134. filtersChanged={value => this.handleChange('filters', value)}
  135. groupBysChanged={value => this.handleChange('groupBys', value)}
  136. target={this.state}
  137. uiSegmentSrv={uiSegmentSrv}
  138. templateSrv={datasource.templateSrv}
  139. datasource={datasource}
  140. metricType={metric ? metric.type : ''}
  141. />
  142. <Aggregations
  143. metricDescriptor={metric}
  144. templateSrv={datasource.templateSrv}
  145. crossSeriesReducer={crossSeriesReducer}
  146. groupBys={groupBys}
  147. onChange={value => this.handleChange('crossSeriesReducer', value)}
  148. >
  149. {displayAdvancedOptions =>
  150. displayAdvancedOptions && (
  151. <Alignments
  152. alignOptions={alignOptions}
  153. templateSrv={datasource.templateSrv}
  154. perSeriesAligner={perSeriesAligner}
  155. onChange={value => this.handleChange('perSeriesAligner', value)}
  156. />
  157. )
  158. }
  159. </Aggregations>
  160. <AliasBy value={aliasBy} onChange={value => this.handleChange('aliasBy', value)} />
  161. <AlignmentPeriods
  162. templateSrv={datasource.templateSrv}
  163. alignmentPeriod={alignmentPeriod}
  164. onChange={value => this.handleChange('alignmentPeriod', value)}
  165. />
  166. <Help datasource={datasource} rawQuery={lastQuery} lastQueryError={lastQueryError} />
  167. </React.Fragment>
  168. )}
  169. </Metrics>
  170. </React.Fragment>
  171. );
  172. }
  173. }