Metrics.tsx 5.8 KB

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