Commit d7e192a8 by Ivana Huckova Committed by GitHub

Prometheus/Explore: Update position of fields in editor (#27816)

* Update position of buttons

* Refactor, add tests

* Pass onKeydown func

* Update public/app/plugins/datasource/prometheus/components/PromQueryField.tsx

Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>

Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
parent e82e3f27
import React from 'react';
import { shallow } from 'enzyme';
import { PromExploreExtraField, PromExploreExtraFieldProps } from './PromExploreExtraField';
import { render, screen } from '@testing-library/react';
import { PromExploreExtraFieldProps, PromExploreExtraField } from './PromExploreExtraField';
const setup = (propOverrides?: PromExploreExtraFieldProps) => {
const label = 'Prometheus Explore Extra Field';
const value = '123';
const onChangeFunc = jest.fn();
const queryType = 'range';
const stepValue = '1';
const onStepChange = jest.fn();
const onQueryTypeChange = jest.fn();
const onKeyDownFunc = jest.fn();
const props: any = {
label,
value,
onChangeFunc,
queryType,
stepValue,
onStepChange,
onQueryTypeChange,
onKeyDownFunc,
};
Object.assign(props, propOverrides);
return shallow(<PromExploreExtraField {...props} />);
return render(<PromExploreExtraField {...props} />);
};
describe('PrometheusExploreExtraField', () => {
it('should render component', () => {
const wrapper = setup();
expect(wrapper).toMatchSnapshot();
describe('PromExploreExtraField', () => {
it('should render step field', () => {
setup();
expect(screen.getByTestId('stepField')).toBeInTheDocument();
});
it('should render query type field', () => {
setup();
expect(screen.getByTestId('queryTypeField')).toBeInTheDocument();
});
});
// Libraries
import React, { memo } from 'react';
import { css, cx } from 'emotion';
// Types
import { InlineFormLabel } from '@grafana/ui';
import { InlineFormLabel, RadioButtonGroup } from '@grafana/ui';
export interface PromExploreExtraFieldProps {
label: string;
onChangeFunc: (e: React.SyntheticEvent<HTMLInputElement>) => void;
queryType: string;
stepValue: string;
onStepChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;
onKeyDownFunc: (e: React.KeyboardEvent<HTMLInputElement>) => void;
value: string;
hasTooltip?: boolean;
tooltipContent?: string;
onQueryTypeChange: (value: string) => void;
}
export function PromExploreExtraField(props: PromExploreExtraFieldProps) {
const { label, onChangeFunc, onKeyDownFunc, value, hasTooltip, tooltipContent } = props;
export const PromExploreExtraField: React.FC<PromExploreExtraFieldProps> = memo(
({ queryType, stepValue, onStepChange, onQueryTypeChange, onKeyDownFunc }) => {
const rangeOptions = [
{ value: 'range', label: 'Range' },
{ value: 'instant', label: 'Instant' },
{ value: 'both', label: 'Both' },
];
return (
<div className="gf-form-inline" aria-label="Prometheus extra field">
<div className="gf-form">
<InlineFormLabel width={5} tooltip={hasTooltip ? tooltipContent : undefined}>
{label}
</InlineFormLabel>
<input
type={'text'}
className="gf-form-input width-4"
placeholder={'auto'}
onChange={onChangeFunc}
onKeyDown={onKeyDownFunc}
value={value}
/>
</div>
</div>
);
}
return (
<div aria-label="Prometheus extra field" className="gf-form-inline">
{/*QueryTypeField */}
<div
data-testid="queryTypeField"
className={cx(
'gf-form explore-input-margin',
css`
flex-wrap: nowrap;
`
)}
aria-label="Query type field"
>
<InlineFormLabel width={5}>Query type</InlineFormLabel>
export default memo(PromExploreExtraField);
<RadioButtonGroup options={rangeOptions} value={queryType} onChange={onQueryTypeChange} />
</div>
{/*Step field*/}
<div
data-testid="stepField"
className={cx(
'gf-form',
css`
flex-wrap: nowrap;
`
)}
aria-label="Step field"
>
<InlineFormLabel
width={5}
tooltip={
'Time units can be used here, for example: 5s, 1m, 3h, 1d, 1y (Default if no unit is specified: s)'
}
>
Step
</InlineFormLabel>
<input
type={'text'}
className="gf-form-input width-4"
placeholder={'auto'}
onChange={onStepChange}
onKeyDown={onKeyDownFunc}
value={stepValue}
/>
</div>
</div>
);
}
);
import React, { memo, FC } from 'react';
import { css } from 'emotion';
// Types
import { ExploreQueryFieldProps } from '@grafana/data';
import { RadioButtonGroup } from '@grafana/ui';
import { PrometheusDatasource } from '../datasource';
import { PromQuery, PromOptions } from '../types';
......@@ -28,6 +26,12 @@ export const PromExploreQueryEditor: FC<Props> = (props: Props) => {
}
}
function onReturnKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter' && (e.shiftKey || e.ctrlKey)) {
onRunQuery();
}
}
function onQueryTypeChange(value: string) {
const { query, onChange } = props;
let nextQuery;
......@@ -41,69 +45,25 @@ export const PromExploreQueryEditor: FC<Props> = (props: Props) => {
onChange(nextQuery);
}
function onReturnKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') {
onRunQuery();
}
}
return (
<>
<PromQueryField
datasource={datasource}
query={query}
onRunQuery={onRunQuery}
onChange={onChange}
onBlur={() => {}}
history={history}
data={data}
ExtraFieldElement={
<PromExploreExtraField
label={'Step'}
onChangeFunc={onStepChange}
onKeyDownFunc={onReturnKeyDown}
value={query.interval || ''}
hasTooltip={true}
tooltipContent={
'Time units can be used here, for example: 5s, 1m, 3h, 1d, 1y (Default if no unit is specified: s)'
}
/>
}
/>
<PromExploreRadioButton
selected={query.range && query.instant ? 'both' : query.instant ? 'instant' : 'range'}
onQueryTypeChange={onQueryTypeChange}
/>
</>
);
};
type PromExploreRadioButtonProps = {
selected: string;
onQueryTypeChange: (value: string) => void;
};
const PromExploreRadioButton: React.FunctionComponent<PromExploreRadioButtonProps> = ({
selected,
onQueryTypeChange,
}) => {
const rangeOptions = [
{ value: 'range', label: 'Range' },
{ value: 'instant', label: 'Instant' },
{ value: 'both', label: 'Both' },
];
return (
<div
className={css`
display: flex;
`}
>
<button className={`gf-form-label gf-form-label--btn width-5`}>
<span className="btn-title">Query type</span>
</button>
<RadioButtonGroup options={rangeOptions} value={selected} onChange={onQueryTypeChange} />
</div>
<PromQueryField
datasource={datasource}
query={query}
onRunQuery={onRunQuery}
onChange={onChange}
onBlur={() => {}}
history={history}
data={data}
ExtraFieldElement={
<PromExploreExtraField
queryType={query.range && query.instant ? 'both' : query.instant ? 'instant' : 'range'}
stepValue={query.interval || ''}
onQueryTypeChange={onQueryTypeChange}
onStepChange={onStepChange}
onKeyDownFunc={onReturnKeyDown}
/>
}
/>
);
};
......
......@@ -331,7 +331,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
{chooserText}
</ButtonCascader>
</div>
<div className={'gf-form gf-form--grow flex-shrink-1 min-width-15 explore-input-margin'}>
<div className="gf-form gf-form--grow flex-shrink-1 min-width-15">
<QueryField
additionalPlugins={this.plugins}
cleanText={cleanText}
......@@ -346,8 +346,8 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
syntaxLoaded={syntaxLoaded}
/>
</div>
{ExtraFieldElement}
</div>
{ExtraFieldElement}
{hint ? (
<div className="query-row-break">
<div className="prom-query-field-info text-warning">
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PrometheusExploreExtraField should render component 1`] = `
<div
aria-label="Prometheus extra field"
className="gf-form-inline"
>
<div
className="gf-form"
>
<Component
width={5}
>
Prometheus Explore Extra Field
</Component>
<input
className="gf-form-input width-4"
onChange={[MockFunction]}
onKeyDown={[MockFunction]}
placeholder="auto"
type="text"
value="123"
/>
</div>
</div>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PromExploreQueryEditor should render component 1`] = `
<Fragment>
<PromQueryField
ExtraFieldElement={
<PromExploreExtraField
hasTooltip={true}
label="Step"
onChangeFunc={[Function]}
onKeyDownFunc={[Function]}
tooltipContent="Time units can be used here, for example: 5s, 1m, 3h, 1d, 1y (Default if no unit is specified: s)"
value="1s"
/>
}
data={
Object {
"request": Object {
"app": "Grafana",
"dashboardId": 1,
"interval": "1s",
"intervalMs": 1000,
"panelId": 1,
"range": Object {
"from": "2020-01-01T00:00:00.000Z",
"raw": Object {
"from": "2020-01-01T00:00:00.000Z",
"to": "2020-01-02T00:00:00.000Z",
},
"to": "2020-01-02T00:00:00.000Z",
},
"requestId": "1",
"scopedVars": Object {},
"startTime": 0,
"targets": Array [],
"timezone": "GMT",
},
"series": Array [],
"state": "NotStarted",
"timeRange": Object {
<PromQueryField
ExtraFieldElement={
<Memo
onKeyDownFunc={[Function]}
onQueryTypeChange={[Function]}
onStepChange={[Function]}
queryType="range"
stepValue="1s"
/>
}
data={
Object {
"request": Object {
"app": "Grafana",
"dashboardId": 1,
"interval": "1s",
"intervalMs": 1000,
"panelId": 1,
"range": Object {
"from": "2020-01-01T00:00:00.000Z",
"raw": Object {
"from": "2020-01-01T00:00:00.000Z",
......@@ -45,24 +27,35 @@ exports[`PromExploreQueryEditor should render component 1`] = `
},
"to": "2020-01-02T00:00:00.000Z",
},
}
"requestId": "1",
"scopedVars": Object {},
"startTime": 0,
"targets": Array [],
"timezone": "GMT",
},
"series": Array [],
"state": "NotStarted",
"timeRange": Object {
"from": "2020-01-01T00:00:00.000Z",
"raw": Object {
"from": "2020-01-01T00:00:00.000Z",
"to": "2020-01-02T00:00:00.000Z",
},
"to": "2020-01-02T00:00:00.000Z",
},
}
datasource={Object {}}
history={Array []}
onBlur={[Function]}
onChange={[MockFunction]}
onRunQuery={[MockFunction]}
query={
Object {
"expr": "",
"interval": "1s",
"refId": "A",
}
}
datasource={Object {}}
history={Array []}
onBlur={[Function]}
onChange={[MockFunction]}
onRunQuery={[MockFunction]}
query={
Object {
"expr": "",
"interval": "1s",
"refId": "A",
}
/>
<PromExploreRadioButton
onQueryTypeChange={[Function]}
selected="range"
/>
</Fragment>
}
/>
`;
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