Metrics.tsx 5.5 KB

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