QueriesTab.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Libraries
  2. import React, { PureComponent } from 'react';
  3. import _ from 'lodash';
  4. // Components
  5. import { EditorTabBody, EditorToolbarView } from './EditorTabBody';
  6. import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
  7. import { QueryInspector } from './QueryInspector';
  8. import { QueryOptions } from './QueryOptions';
  9. import { PanelOptionsGroup } from '@grafana/ui';
  10. import { QueryEditorRow } from './QueryEditorRow';
  11. // Services
  12. import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
  13. import { BackendSrv, getBackendSrv } from 'app/core/services/backend_srv';
  14. import config from 'app/core/config';
  15. // Types
  16. import { PanelModel } from '../panel_model';
  17. import { DashboardModel } from '../dashboard_model';
  18. import { DataQuery, DataSourceSelectItem } from 'app/types';
  19. import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp';
  20. interface Props {
  21. panel: PanelModel;
  22. dashboard: DashboardModel;
  23. }
  24. interface State {
  25. currentDS: DataSourceSelectItem;
  26. helpContent: JSX.Element;
  27. isLoadingHelp: boolean;
  28. isPickerOpen: boolean;
  29. isAddingMixed: boolean;
  30. }
  31. export class QueriesTab extends PureComponent<Props, State> {
  32. datasources: DataSourceSelectItem[] = getDatasourceSrv().getMetricSources();
  33. backendSrv: BackendSrv = getBackendSrv();
  34. state: State = {
  35. isLoadingHelp: false,
  36. currentDS: this.findCurrentDataSource(),
  37. helpContent: null,
  38. isPickerOpen: false,
  39. isAddingMixed: false,
  40. };
  41. findCurrentDataSource(): DataSourceSelectItem {
  42. const { panel } = this.props;
  43. return this.datasources.find(datasource => datasource.value === panel.datasource) || this.datasources[0];
  44. }
  45. onChangeDataSource = datasource => {
  46. const { panel } = this.props;
  47. const { currentDS } = this.state;
  48. // switching to mixed
  49. if (datasource.meta.mixed) {
  50. panel.targets.forEach(target => {
  51. target.datasource = panel.datasource;
  52. if (!target.datasource) {
  53. target.datasource = config.defaultDatasource;
  54. }
  55. });
  56. } else if (currentDS) {
  57. // if switching from mixed
  58. if (currentDS.meta.mixed) {
  59. for (const target of panel.targets) {
  60. delete target.datasource;
  61. }
  62. } else if (currentDS.meta.id !== datasource.meta.id) {
  63. // we are changing data source type, clear queries
  64. panel.targets = [{ refId: 'A' }];
  65. }
  66. }
  67. panel.datasource = datasource.value;
  68. panel.refresh();
  69. this.setState({
  70. currentDS: datasource,
  71. });
  72. };
  73. renderQueryInspector = () => {
  74. const { panel } = this.props;
  75. return <QueryInspector panel={panel} />;
  76. };
  77. renderHelp = () => {
  78. return <PluginHelp plugin={this.state.currentDS.meta} type="query_help" />;
  79. };
  80. onAddQuery = (query?: Partial<DataQuery>) => {
  81. this.props.panel.addQuery(query);
  82. this.forceUpdate();
  83. };
  84. onAddQueryClick = () => {
  85. if (this.state.currentDS.meta.mixed) {
  86. this.setState({ isAddingMixed: true });
  87. return;
  88. }
  89. this.props.panel.addQuery();
  90. this.forceUpdate();
  91. };
  92. onRemoveQuery = (query: DataQuery) => {
  93. const { panel } = this.props;
  94. const index = _.indexOf(panel.targets, query);
  95. panel.targets.splice(index, 1);
  96. panel.refresh();
  97. this.forceUpdate();
  98. };
  99. onMoveQuery = (query: DataQuery, direction: number) => {
  100. const { panel } = this.props;
  101. const index = _.indexOf(panel.targets, query);
  102. _.move(panel.targets, index, index + direction);
  103. this.forceUpdate();
  104. };
  105. renderToolbar = () => {
  106. const { currentDS } = this.state;
  107. return <DataSourcePicker datasources={this.datasources} onChange={this.onChangeDataSource} current={currentDS} />;
  108. };
  109. renderMixedPicker = () => {
  110. return (
  111. <DataSourcePicker
  112. datasources={this.datasources}
  113. onChange={this.onAddMixedQuery}
  114. current={null}
  115. autoFocus={true}
  116. onBlur={this.onMixedPickerBlur}
  117. />
  118. );
  119. };
  120. onAddMixedQuery = datasource => {
  121. this.onAddQuery({ datasource: datasource.name });
  122. this.setState({ isAddingMixed: false });
  123. };
  124. onMixedPickerBlur = () => {
  125. this.setState({ isAddingMixed: false });
  126. };
  127. render() {
  128. const { panel } = this.props;
  129. const { currentDS, isAddingMixed } = this.state;
  130. const queryInspector: EditorToolbarView = {
  131. title: 'Query Inspector',
  132. render: this.renderQueryInspector,
  133. };
  134. const dsHelp: EditorToolbarView = {
  135. heading: 'Help',
  136. icon: 'fa fa-question',
  137. render: this.renderHelp,
  138. };
  139. return (
  140. <EditorTabBody heading="Queries" renderToolbar={this.renderToolbar} toolbarItems={[queryInspector, dsHelp]}>
  141. <>
  142. <div className="query-editor-rows">
  143. {panel.targets.map((query, index) => (
  144. <QueryEditorRow
  145. datasourceName={query.datasource || panel.datasource}
  146. key={query.refId}
  147. panel={panel}
  148. query={query}
  149. onRemoveQuery={this.onRemoveQuery}
  150. onAddQuery={this.onAddQuery}
  151. onMoveQuery={this.onMoveQuery}
  152. />
  153. ))}
  154. </div>
  155. <div>
  156. <div className="gf-form-query">
  157. <div className="gf-form gf-form-query-letter-cell">
  158. <label className="gf-form-label">
  159. <span className="gf-form-query-letter-cell-carret muted">
  160. <i className="fa fa-caret-down" />
  161. </span>{' '}
  162. <span className="gf-form-query-letter-cell-letter">{panel.getNextQueryLetter()}</span>
  163. </label>
  164. </div>
  165. <div className="gf-form">
  166. {!isAddingMixed && (
  167. <button className="btn btn-secondary gf-form-btn" onClick={this.onAddQueryClick}>
  168. Add Query
  169. </button>
  170. )}
  171. {isAddingMixed && this.renderMixedPicker()}
  172. </div>
  173. </div>
  174. </div>
  175. <PanelOptionsGroup>
  176. <QueryOptions panel={panel} datasource={currentDS} />
  177. </PanelOptionsGroup>
  178. </>
  179. </EditorTabBody>
  180. );
  181. }
  182. }