Metrics.tsx 5.8 KB

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