Metrics.tsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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
  85. .filter(m => m.service === selectedMetricDescriptor.service)
  86. .map(m => ({
  87. service: m.service,
  88. value: m.type,
  89. label: m.displayName,
  90. description: m.description,
  91. }));
  92. return metricsByService;
  93. }
  94. onServiceChange = service => {
  95. const { metricDescriptors } = this.state;
  96. const { templateSrv, metricType } = this.props;
  97. const metrics = metricDescriptors
  98. .filter(m => m.service === templateSrv.replace(service))
  99. .map(m => ({
  100. service: m.service,
  101. value: m.type,
  102. label: m.displayName,
  103. description: m.description,
  104. }));
  105. this.setState({ service, metrics });
  106. if (metrics.length > 0 && !metrics.some(m => m.value === templateSrv.replace(metricType))) {
  107. this.onMetricTypeChange(metrics[0].value);
  108. }
  109. };
  110. onMetricTypeChange = value => {
  111. const metricDescriptor = this.getSelectedMetricDescriptor(value);
  112. this.setState({ metricDescriptor });
  113. this.props.onChange({ ...metricDescriptor, type: value });
  114. };
  115. getServicesList(metricDescriptors: MetricDescriptor[]) {
  116. const services = metricDescriptors.map(m => ({
  117. value: m.service,
  118. label: _.startCase(m.serviceShortName),
  119. }));
  120. return services.length > 0 ? _.uniqBy(services, s => s.value) : [];
  121. }
  122. getTemplateVariablesGroup() {
  123. return {
  124. label: 'Template Variables',
  125. options: this.props.templateSrv.variables.map(v => ({
  126. label: `$${v.name}`,
  127. value: `$${v.name}`,
  128. })),
  129. };
  130. }
  131. render() {
  132. const { services, service, metrics } = this.state;
  133. const { metricType, templateSrv } = this.props;
  134. return (
  135. <>
  136. <div className="gf-form-inline">
  137. <div className="gf-form">
  138. <span className="gf-form-label width-9 query-keyword">Service</span>
  139. <MetricSelect
  140. onChange={this.onServiceChange}
  141. value={service}
  142. options={services}
  143. isSearchable={false}
  144. placeholder="Select Services"
  145. className="width-15"
  146. />
  147. </div>
  148. <div className="gf-form gf-form--grow">
  149. <div className="gf-form-label gf-form-label--grow" />
  150. </div>
  151. </div>
  152. <div className="gf-form-inline">
  153. <div className="gf-form">
  154. <span className="gf-form-label width-9 query-keyword">Metric</span>
  155. <MetricSelect
  156. onChange={this.onMetricTypeChange}
  157. value={metricType}
  158. variables={templateSrv.variables}
  159. options={[
  160. {
  161. label: 'Metrics',
  162. expanded: true,
  163. options: metrics,
  164. },
  165. ]}
  166. placeholder="Select Metric"
  167. className="width-15"
  168. />
  169. </div>
  170. <div className="gf-form gf-form--grow">
  171. <div className="gf-form-label gf-form-label--grow" />
  172. </div>
  173. </div>
  174. {this.props.children(this.state.metricDescriptor)}
  175. </>
  176. );
  177. }
  178. }