QueriesTab.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. scrollTop: number;
  31. }
  32. export class QueriesTab extends PureComponent<Props, State> {
  33. datasources: DataSourceSelectItem[] = getDatasourceSrv().getMetricSources();
  34. backendSrv: BackendSrv = getBackendSrv();
  35. state: State = {
  36. isLoadingHelp: false,
  37. currentDS: this.findCurrentDataSource(),
  38. helpContent: null,
  39. isPickerOpen: false,
  40. isAddingMixed: false,
  41. scrollTop: 0,
  42. };
  43. findCurrentDataSource(): DataSourceSelectItem {
  44. const { panel } = this.props;
  45. return this.datasources.find(datasource => datasource.value === panel.datasource) || this.datasources[0];
  46. }
  47. onChangeDataSource = datasource => {
  48. const { panel } = this.props;
  49. const { currentDS } = this.state;
  50. // switching to mixed
  51. if (datasource.meta.mixed) {
  52. panel.targets.forEach(target => {
  53. target.datasource = panel.datasource;
  54. if (!target.datasource) {
  55. target.datasource = config.defaultDatasource;
  56. }
  57. });
  58. } else if (currentDS) {
  59. // if switching from mixed
  60. if (currentDS.meta.mixed) {
  61. for (const target of panel.targets) {
  62. delete target.datasource;
  63. }
  64. } else if (currentDS.meta.id !== datasource.meta.id) {
  65. // we are changing data source type, clear queries
  66. panel.targets = [{ refId: 'A' }];
  67. }
  68. }
  69. panel.datasource = datasource.value;
  70. panel.refresh();
  71. this.setState({
  72. currentDS: datasource,
  73. });
  74. };
  75. renderQueryInspector = () => {
  76. const { panel } = this.props;
  77. return <QueryInspector panel={panel} />;
  78. };
  79. renderHelp = () => {
  80. return <PluginHelp plugin={this.state.currentDS.meta} type="query_help" />;
  81. };
  82. onAddQuery = (query?: Partial<DataQuery>) => {
  83. this.props.panel.addQuery(query);
  84. this.forceUpdate();
  85. };
  86. onAddQueryClick = () => {
  87. if (this.state.currentDS.meta.mixed) {
  88. this.setState({ isAddingMixed: true });
  89. return;
  90. }
  91. this.props.panel.addQuery();
  92. this.setState({ scrollTop: this.state.scrollTop + 100000 });
  93. };
  94. onRemoveQuery = (query: DataQuery) => {
  95. const { panel } = this.props;
  96. const index = _.indexOf(panel.targets, query);
  97. panel.targets.splice(index, 1);
  98. panel.refresh();
  99. this.forceUpdate();
  100. };
  101. onMoveQuery = (query: DataQuery, direction: number) => {
  102. const { panel } = this.props;
  103. const index = _.indexOf(panel.targets, query);
  104. _.move(panel.targets, index, index + direction);
  105. this.forceUpdate();
  106. };
  107. renderToolbar = () => {
  108. const { currentDS, isAddingMixed } = this.state;
  109. return (
  110. <>
  111. <DataSourcePicker datasources={this.datasources} onChange={this.onChangeDataSource} current={currentDS} />
  112. <div className="m-l-2">
  113. {!isAddingMixed && (
  114. <button className="btn navbar-button navbar-button--primary" onClick={this.onAddQueryClick}>
  115. Add Query
  116. </button>
  117. )}
  118. {isAddingMixed && this.renderMixedPicker()}
  119. </div>
  120. </>
  121. );
  122. };
  123. renderMixedPicker = () => {
  124. return (
  125. <DataSourcePicker
  126. datasources={this.datasources}
  127. onChange={this.onAddMixedQuery}
  128. current={null}
  129. autoFocus={true}
  130. onBlur={this.onMixedPickerBlur}
  131. />
  132. );
  133. };
  134. onAddMixedQuery = datasource => {
  135. this.onAddQuery({ datasource: datasource.name });
  136. this.setState({ isAddingMixed: false, scrollTop: this.state.scrollTop + 10000 });
  137. };
  138. onMixedPickerBlur = () => {
  139. this.setState({ isAddingMixed: false });
  140. };
  141. setScrollTop = (event: React.MouseEvent<HTMLElement>) => {
  142. const target = event.target as HTMLElement;
  143. this.setState({ scrollTop: target.scrollTop });
  144. };
  145. render() {
  146. const { panel } = this.props;
  147. const { currentDS, scrollTop } = this.state;
  148. const queryInspector: EditorToolbarView = {
  149. title: 'Query Inspector',
  150. render: this.renderQueryInspector,
  151. };
  152. const dsHelp: EditorToolbarView = {
  153. heading: 'Help',
  154. icon: 'fa fa-question',
  155. render: this.renderHelp,
  156. };
  157. return (
  158. <EditorTabBody
  159. heading="Data Source"
  160. renderToolbar={this.renderToolbar}
  161. toolbarItems={[queryInspector, dsHelp]}
  162. setScrollTop={this.setScrollTop}
  163. scrollTop={scrollTop}
  164. >
  165. <>
  166. <div className="query-editor-rows">
  167. {panel.targets.map((query, index) => (
  168. <QueryEditorRow
  169. datasourceName={query.datasource || panel.datasource}
  170. key={query.refId}
  171. panel={panel}
  172. query={query}
  173. onRemoveQuery={this.onRemoveQuery}
  174. onAddQuery={this.onAddQuery}
  175. onMoveQuery={this.onMoveQuery}
  176. inMixedMode={currentDS.meta.mixed}
  177. />
  178. ))}
  179. </div>
  180. <PanelOptionsGroup>
  181. <QueryOptions panel={panel} datasource={currentDS} />
  182. </PanelOptionsGroup>
  183. </>
  184. </EditorTabBody>
  185. );
  186. }
  187. }