QueriesTab.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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 '../state/PanelModel';
  17. import { DashboardModel } from '../state/DashboardModel';
  18. import { DataQuery, DataSourceSelectItem } from '@grafana/ui/src/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.setState({ scrollTop: this.state.scrollTop + 100000 });
  85. };
  86. onAddQueryClick = () => {
  87. if (this.state.currentDS.meta.mixed) {
  88. this.setState({ isAddingMixed: true });
  89. return;
  90. }
  91. this.onAddQuery();
  92. };
  93. onRemoveQuery = (query: DataQuery) => {
  94. const { panel } = this.props;
  95. const index = _.indexOf(panel.targets, query);
  96. panel.targets.splice(index, 1);
  97. panel.refresh();
  98. this.forceUpdate();
  99. };
  100. onMoveQuery = (query: DataQuery, direction: number) => {
  101. const { panel } = this.props;
  102. const index = _.indexOf(panel.targets, query);
  103. _.move(panel.targets, index, index + direction);
  104. this.forceUpdate();
  105. };
  106. renderToolbar = () => {
  107. const { currentDS, isAddingMixed } = this.state;
  108. return (
  109. <>
  110. <DataSourcePicker datasources={this.datasources} onChange={this.onChangeDataSource} current={currentDS} />
  111. <div className="flex-grow-1" />
  112. {!isAddingMixed && (
  113. <button className="btn navbar-button" onClick={this.onAddQueryClick}>
  114. Add Query
  115. </button>
  116. )}
  117. {isAddingMixed && this.renderMixedPicker()}
  118. </>
  119. );
  120. };
  121. renderMixedPicker = () => {
  122. return (
  123. <DataSourcePicker
  124. datasources={this.datasources}
  125. onChange={this.onAddMixedQuery}
  126. current={null}
  127. autoFocus={true}
  128. onBlur={this.onMixedPickerBlur}
  129. />
  130. );
  131. };
  132. onAddMixedQuery = datasource => {
  133. this.onAddQuery({ datasource: datasource.name });
  134. this.setState({ isAddingMixed: false, scrollTop: this.state.scrollTop + 10000 });
  135. };
  136. onMixedPickerBlur = () => {
  137. this.setState({ isAddingMixed: false });
  138. };
  139. onQueryChange = (query: DataQuery, index) => {
  140. this.props.panel.changeQuery(query, index);
  141. this.forceUpdate();
  142. };
  143. setScrollTop = (event: React.MouseEvent<HTMLElement>) => {
  144. const target = event.target as HTMLElement;
  145. this.setState({ scrollTop: target.scrollTop });
  146. };
  147. render() {
  148. const { panel, dashboard } = this.props;
  149. const { currentDS, scrollTop } = this.state;
  150. const queryInspector: EditorToolbarView = {
  151. title: 'Query Inspector',
  152. render: this.renderQueryInspector,
  153. };
  154. const dsHelp: EditorToolbarView = {
  155. heading: 'Help',
  156. icon: 'fa fa-question',
  157. render: this.renderHelp,
  158. };
  159. return (
  160. <EditorTabBody
  161. heading="Queries to"
  162. renderToolbar={this.renderToolbar}
  163. toolbarItems={[queryInspector, dsHelp]}
  164. setScrollTop={this.setScrollTop}
  165. scrollTop={scrollTop}
  166. >
  167. <>
  168. <div className="query-editor-rows">
  169. {panel.targets.map((query, index) => (
  170. <QueryEditorRow
  171. dataSourceValue={query.datasource || panel.datasource}
  172. key={query.refId}
  173. panel={panel}
  174. dashboard={dashboard}
  175. query={query}
  176. onChange={query => this.onQueryChange(query, index)}
  177. onRemoveQuery={this.onRemoveQuery}
  178. onAddQuery={this.onAddQuery}
  179. onMoveQuery={this.onMoveQuery}
  180. inMixedMode={currentDS.meta.mixed}
  181. />
  182. ))}
  183. </div>
  184. <PanelOptionsGroup>
  185. <QueryOptions panel={panel} datasource={currentDS} />
  186. </PanelOptionsGroup>
  187. </>
  188. </EditorTabBody>
  189. );
  190. }
  191. }