Metrics.tsx 5.7 KB

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