Commit 285ea759 by Ivana Huckova Committed by GitHub

Explore: Fix rendering of react query editors (#24593)

* Fix rendering of react query editors

* Refactor solution for improved readability

* Update

* Add test coverage

* Refactor
parent f29b70b4
......@@ -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 {
......
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(<QueryRow {...props} />);
return wrapper;
};
const ExploreMetricsQueryField = () => <div />;
const ExploreLogsQueryField = () => <div />;
const ExploreQueryField = () => <div />;
const QueryEditor = () => <div />;
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);
});
});
});
......@@ -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,16 +101,23 @@ export class QueryRow extends PureComponent<QueryRowProps, QueryRowState> {
this.setState({ textEditModeEnabled: !this.state.textEditModeEnabled });
};
updateLogsHighlights = debounce((value: DataQuery) => {
const { datasourceInstance } = this.props;
if (datasourceInstance.getHighlighterExpression) {
const { exploreId } = this.props;
const expressions = datasourceInstance.getHighlighterExpression(value);
this.props.highlightLogsExpressionAction({ exploreId, expressions });
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;
}
}, 500);
return QueryEditor;
};
render() {
renderQueryEditor = () => {
const {
datasourceInstance,
history,
......@@ -120,54 +127,64 @@ export class QueryRow extends PureComponent<QueryRowProps, QueryRowState> {
absoluteRange,
queryResponse,
mode,
latency,
exploreId,
} = this.props;
const queryErrors = queryResponse.error && queryResponse.error.refId === query.refId ? [queryResponse.error] : [];
const ReactQueryEditor = this.setReactQueryEditor();
if (ReactQueryEditor) {
return (
<ReactQueryEditor
datasource={datasourceInstance}
query={query}
history={history}
onRunQuery={this.onRunQuery}
onBlur={noopOnBlur}
onChange={this.onChange}
data={queryResponse}
absoluteRange={absoluteRange}
exploreMode={mode}
exploreId={exploreId}
/>
);
}
return (
<AngularQueryEditor
error={queryErrors}
datasource={datasourceInstance}
onQueryChange={this.onChange}
onExecuteQuery={this.onRunQuery}
initialQuery={query}
exploreEvents={exploreEvents}
range={range}
textEditModeEnabled={this.state.textEditModeEnabled}
/>
);
};
updateLogsHighlights = debounce((value: DataQuery) => {
const { datasourceInstance } = this.props;
if (datasourceInstance.getHighlighterExpression) {
const { exploreId } = this.props;
const expressions = datasourceInstance.getHighlighterExpression(value);
this.props.highlightLogsExpressionAction({ exploreId, expressions });
}
}, 500);
render() {
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 (
<>
<div className="query-row">
<div className="query-row-field flex-shrink-1">
{QueryField ? (
<QueryField
datasource={datasourceInstance}
query={query}
history={history}
onRunQuery={this.onRunQuery}
onBlur={noopOnBlur}
onChange={this.onChange}
data={queryResponse}
absoluteRange={absoluteRange}
exploreMode={mode}
exploreId={exploreId}
/>
) : (
<QueryEditor
error={queryErrors}
datasource={datasourceInstance}
onQueryChange={this.onChange}
onExecuteQuery={this.onRunQuery}
initialQuery={query}
exploreEvents={exploreEvents}
range={range}
textEditModeEnabled={this.state.textEditModeEnabled}
/>
)}
</div>
<div className="query-row-field flex-shrink-1">{this.renderQueryEditor()}</div>
<QueryRowActions
canToggleEditorModes={canToggleEditorModes}
isDisabled={query.hide}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment