Metrics.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import React from 'react';
  2. import _ from 'lodash';
  3. import StackdriverDatasource from '../datasource';
  4. import appEvents from 'app/core/app_events';
  5. import { MetricDescriptor } from '../types';
  6. import { MetricSelect } from 'app/core/components/Select/MetricSelect';
  7. import { TemplateSrv } from 'app/features/templating/template_srv';
  8. export interface Props {
  9. onChange: (metricDescriptor: MetricDescriptor) => void;
  10. templateSrv: TemplateSrv;
  11. datasource: StackdriverDatasource;
  12. defaultProject: string;
  13. metricType: string;
  14. children?: (renderProps: any) => JSX.Element;
  15. }
  16. interface State {
  17. metricDescriptors: MetricDescriptor[];
  18. metrics: any[];
  19. services: any[];
  20. service: string;
  21. metric: string;
  22. metricDescriptor: MetricDescriptor;
  23. defaultProject: string;
  24. }
  25. export class Metrics extends React.Component<Props, State> {
  26. state: State = {
  27. metricDescriptors: [],
  28. metrics: [],
  29. services: [],
  30. service: '',
  31. metric: '',
  32. metricDescriptor: null,
  33. defaultProject: '',
  34. };
  35. constructor(props) {
  36. super(props);
  37. }
  38. componentDidMount() {
  39. this.setState({ defaultProject: this.props.defaultProject }, () => {
  40. this.getCurrentProject()
  41. .then(this.loadMetricDescriptors.bind(this))
  42. .then(this.initializeServiceAndMetrics.bind(this));
  43. });
  44. }
  45. async getCurrentProject() {
  46. return new Promise(async (resolve, reject) => {
  47. try {
  48. if (!this.state.defaultProject || this.state.defaultProject === 'loading project...') {
  49. const defaultProject = await this.props.datasource.getDefaultProject();
  50. this.setState({ defaultProject });
  51. }
  52. resolve(this.state.defaultProject);
  53. } catch (error) {
  54. appEvents.emit('ds-request-error', error);
  55. reject();
  56. }
  57. });
  58. }
  59. async loadMetricDescriptors() {
  60. if (this.state.defaultProject !== 'loading project...') {
  61. const metricDescriptors = await this.props.datasource.getMetricTypes(this.state.defaultProject);
  62. this.setState({ metricDescriptors });
  63. return metricDescriptors;
  64. } else {
  65. return [];
  66. }
  67. }
  68. async initializeServiceAndMetrics() {
  69. const { metricDescriptors } = this.state;
  70. const services = this.getServicesList(metricDescriptors);
  71. const metrics = this.getMetricsList(metricDescriptors);
  72. const service = metrics.length > 0 ? metrics[0].service : '';
  73. const metricDescriptor = this.getSelectedMetricDescriptor(this.props.metricType);
  74. this.setState({ metricDescriptors, services, metrics, service: service, metricDescriptor });
  75. }
  76. getSelectedMetricDescriptor(metricType) {
  77. return this.state.metricDescriptors.find(md => md.type === this.props.templateSrv.replace(metricType));
  78. }
  79. getMetricsList(metricDescriptors: MetricDescriptor[]) {
  80. const selectedMetricDescriptor = this.getSelectedMetricDescriptor(this.props.metricType);
  81. if (!selectedMetricDescriptor) {
  82. return [];
  83. }
  84. const metricsByService = metricDescriptors.filter(m => m.service === selectedMetricDescriptor.service).map(m => ({
  85. service: m.service,
  86. value: m.type,
  87. label: m.displayName,
  88. description: m.description,
  89. }));
  90. return metricsByService;
  91. }
  92. onServiceChange = service => {
  93. const { metricDescriptors } = this.state;
  94. const { templateSrv, metricType } = this.props;
  95. const metrics = metricDescriptors.filter(m => m.service === templateSrv.replace(service)).map(m => ({
  96. service: m.service,
  97. value: m.type,
  98. label: m.displayName,
  99. description: m.description,
  100. }));
  101. this.setState({ service, metrics });
  102. if (metrics.length > 0 && !metrics.some(m => m.value === templateSrv.replace(metricType))) {
  103. this.onMetricTypeChange(metrics[0].value);
  104. }
  105. };
  106. onMetricTypeChange = value => {
  107. const metricDescriptor = this.getSelectedMetricDescriptor(value);
  108. this.setState({ metricDescriptor });
  109. this.props.onChange({ ...metricDescriptor, type: value });
  110. };
  111. getServicesList(metricDescriptors: MetricDescriptor[]) {
  112. const services = metricDescriptors.map(m => ({
  113. value: m.service,
  114. label: _.startCase(m.serviceShortName),
  115. }));
  116. return services.length > 0 ? _.uniqBy(services, s => s.value) : [];
  117. }
  118. getTemplateVariablesGroup() {
  119. return {
  120. label: 'Template Variables',
  121. options: this.props.templateSrv.variables.map(v => ({
  122. label: `$${v.name}`,
  123. value: `$${v.name}`,
  124. })),
  125. };
  126. }
  127. render() {
  128. const { services, service, metrics } = this.state;
  129. const { metricType, templateSrv } = this.props;
  130. return (
  131. <>
  132. <div className="gf-form-inline">
  133. <div className="gf-form">
  134. <span className="gf-form-label width-9 query-keyword">Service</span>
  135. <MetricSelect
  136. onChange={this.onServiceChange}
  137. value={service}
  138. options={services}
  139. isSearchable={false}
  140. placeholder="Select Services"
  141. className="width-15"
  142. />
  143. </div>
  144. <div className="gf-form gf-form--grow">
  145. <div className="gf-form-label gf-form-label--grow" />
  146. </div>
  147. </div>
  148. <div className="gf-form-inline">
  149. <div className="gf-form">
  150. <span className="gf-form-label width-9 query-keyword">Metric</span>
  151. <MetricSelect
  152. onChange={this.onMetricTypeChange}
  153. value={metricType}
  154. variables={templateSrv.variables}
  155. options={[
  156. {
  157. label: 'Metrics',
  158. expanded: true,
  159. options: metrics,
  160. },
  161. ]}
  162. placeholder="Select Metric"
  163. className="width-15"
  164. />
  165. </div>
  166. <div className="gf-form gf-form--grow">
  167. <div className="gf-form-label gf-form-label--grow" />
  168. </div>
  169. </div>
  170. {this.props.children(this.state.metricDescriptor)}
  171. </>
  172. );
  173. }
  174. }