From 285ea7595d8a5056ca881ea979e039e9caaf7955 Mon Sep 17 00:00:00 2001
From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
Date: Wed, 13 May 2020 15:56:22 +0200
Subject: [PATCH] Explore: Fix rendering of react query editors (#24593)
* Fix rendering of react query editors
* Refactor solution for improved readability
* Update
* Add test coverage
* Refactor
---
packages/grafana-data/src/types/datasource.ts | 2 +
public/app/features/explore/QueryRow.test.tsx | 74 +++++++++++
public/app/features/explore/QueryRow.tsx | 117 ++++++++++--------
3 files changed, 143 insertions(+), 50 deletions(-)
create mode 100644 public/app/features/explore/QueryRow.test.tsx
diff --git a/packages/grafana-data/src/types/datasource.ts b/packages/grafana-data/src/types/datasource.ts
index ddc73f45568..704e38f5b15 100644
--- a/packages/grafana-data/src/types/datasource.ts
+++ b/packages/grafana-data/src/types/datasource.ts
@@ -305,12 +305,14 @@ export interface QueryEditorProps<
query: TQuery;
onRunQuery: () => void;
onChange: (value: TQuery) => void;
+ onBlur?: () => void;
/**
* Contains query response filtered by refId of QueryResultBase and possible query error
*/
data?: PanelData;
exploreMode?: ExploreMode;
exploreId?: any;
+ history?: HistoryItem[];
}
export enum DataSourceStatus {
diff --git a/public/app/features/explore/QueryRow.test.tsx b/public/app/features/explore/QueryRow.test.tsx
new file mode 100644
index 00000000000..422fc587094
--- /dev/null
+++ b/public/app/features/explore/QueryRow.test.tsx
@@ -0,0 +1,74 @@
+import React from 'react';
+import { QueryRow, QueryRowProps } from './QueryRow';
+import { shallow } from 'enzyme';
+import { ExploreId } from 'app/types/explore';
+import { Emitter } from 'app/core/utils/emitter';
+import { DataSourceApi, TimeRange, AbsoluteTimeRange, ExploreMode, PanelData } from '@grafana/data';
+
+const setup = (propOverrides?: object) => {
+ const props: QueryRowProps = {
+ exploreId: ExploreId.left,
+ index: 1,
+ exploreEvents: {} as Emitter,
+ changeQuery: jest.fn(),
+ datasourceInstance: {} as DataSourceApi,
+ highlightLogsExpressionAction: jest.fn() as any,
+ history: [],
+ query: {
+ refId: 'A',
+ },
+ modifyQueries: jest.fn(),
+ range: {} as TimeRange,
+ absoluteRange: {} as AbsoluteTimeRange,
+ removeQueryRowAction: jest.fn() as any,
+ runQueries: jest.fn(),
+ queryResponse: {} as PanelData,
+ mode: ExploreMode.Metrics,
+ latency: 1,
+ };
+
+ Object.assign(props, propOverrides);
+
+ const wrapper = shallow();
+ return wrapper;
+};
+
+const ExploreMetricsQueryField = () =>
;
+const ExploreLogsQueryField = () => ;
+const ExploreQueryField = () => ;
+const QueryEditor = () => ;
+
+describe('QueryRow', () => {
+ describe('if datasource has all query field components ', () => {
+ const allComponents = {
+ ExploreMetricsQueryField,
+ ExploreLogsQueryField,
+ ExploreQueryField,
+ QueryEditor,
+ };
+
+ it('it should render ExploreMetricsQueryField in metrics mode', () => {
+ const wrapper = setup({ mode: ExploreMode.Metrics, datasourceInstance: { components: allComponents } });
+ expect(wrapper.find(ExploreMetricsQueryField)).toHaveLength(1);
+ });
+ it('it should render ExploreLogsQueryField in logs mode', () => {
+ const wrapper = setup({ mode: ExploreMode.Logs, datasourceInstance: { components: allComponents } });
+ expect(wrapper.find(ExploreLogsQueryField)).toHaveLength(1);
+ });
+ it('it should render ExploreQueryField in tracing mode', () => {
+ const wrapper = setup({ mode: ExploreMode.Tracing, datasourceInstance: { components: allComponents } });
+ expect(wrapper.find(ExploreQueryField)).toHaveLength(1);
+ });
+ });
+
+ describe('if datasource does not have Explore query fields ', () => {
+ it('it should render QueryEditor if datasource has it', () => {
+ const wrapper = setup({ datasourceInstance: { components: { QueryEditor } } });
+ expect(wrapper.find(QueryEditor)).toHaveLength(1);
+ });
+ it('it should not render QueryEditor if datasource does not have it', () => {
+ const wrapper = setup({ datasourceInstance: { components: {} } });
+ expect(wrapper.find(QueryEditor)).toHaveLength(0);
+ });
+ });
+});
diff --git a/public/app/features/explore/QueryRow.tsx b/public/app/features/explore/QueryRow.tsx
index 94448b4cae7..30d4154fd15 100644
--- a/public/app/features/explore/QueryRow.tsx
+++ b/public/app/features/explore/QueryRow.tsx
@@ -6,7 +6,7 @@ import { hot } from 'react-hot-loader';
// @ts-ignore
import { connect } from 'react-redux';
// Components
-import QueryEditor from './QueryEditor';
+import AngularQueryEditor from './QueryEditor';
import { QueryRowActions } from './QueryRowActions';
// Actions
import { changeQuery, modifyQueries, runQueries } from './state/actions';
@@ -34,7 +34,7 @@ interface PropsFromParent {
exploreEvents: Emitter;
}
-interface QueryRowProps extends PropsFromParent {
+export interface QueryRowProps extends PropsFromParent {
changeQuery: typeof changeQuery;
className?: string;
exploreId: ExploreId;
@@ -101,6 +101,69 @@ export class QueryRow extends PureComponent {
this.setState({ textEditModeEnabled: !this.state.textEditModeEnabled });
};
+ setReactQueryEditor = () => {
+ const { mode, datasourceInstance } = this.props;
+ let QueryEditor;
+
+ if (mode === ExploreMode.Metrics && datasourceInstance.components?.ExploreMetricsQueryField) {
+ QueryEditor = datasourceInstance.components.ExploreMetricsQueryField;
+ } else if (mode === ExploreMode.Logs && datasourceInstance.components?.ExploreLogsQueryField) {
+ QueryEditor = datasourceInstance.components.ExploreLogsQueryField;
+ } else if (datasourceInstance.components?.ExploreQueryField) {
+ QueryEditor = datasourceInstance.components.ExploreQueryField;
+ } else {
+ QueryEditor = datasourceInstance.components?.QueryEditor;
+ }
+ return QueryEditor;
+ };
+
+ renderQueryEditor = () => {
+ const {
+ datasourceInstance,
+ history,
+ query,
+ exploreEvents,
+ range,
+ absoluteRange,
+ queryResponse,
+ mode,
+ exploreId,
+ } = this.props;
+
+ const queryErrors = queryResponse.error && queryResponse.error.refId === query.refId ? [queryResponse.error] : [];
+
+ const ReactQueryEditor = this.setReactQueryEditor();
+
+ if (ReactQueryEditor) {
+ return (
+
+ );
+ }
+ return (
+
+ );
+ };
+
updateLogsHighlights = debounce((value: DataQuery) => {
const { datasourceInstance } = this.props;
if (datasourceInstance.getHighlighterExpression) {
@@ -111,63 +174,17 @@ export class QueryRow extends PureComponent {
}, 500);
render() {
- const {
- datasourceInstance,
- history,
- query,
- exploreEvents,
- range,
- absoluteRange,
- queryResponse,
- mode,
- latency,
- exploreId,
- } = this.props;
+ const { datasourceInstance, query, queryResponse, mode, latency } = this.props;
const canToggleEditorModes =
mode === ExploreMode.Metrics && has(datasourceInstance, 'components.QueryCtrl.prototype.toggleEditorMode');
const isNotStarted = queryResponse.state === LoadingState.NotStarted;
const queryErrors = queryResponse.error && queryResponse.error.refId === query.refId ? [queryResponse.error] : [];
- let QueryField;
-
- if (mode === ExploreMode.Metrics && datasourceInstance.components?.ExploreMetricsQueryField) {
- QueryField = datasourceInstance.components.ExploreMetricsQueryField;
- } else if (mode === ExploreMode.Logs && datasourceInstance.components?.ExploreLogsQueryField) {
- QueryField = datasourceInstance.components.ExploreLogsQueryField;
- } else {
- QueryField = datasourceInstance.components?.ExploreQueryField;
- }
return (
<>
-
- {QueryField ? (
-
- ) : (
-
- )}
-
+
{this.renderQueryEditor()}