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()}