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>
This commit is contained in:
Ivana Huckova
2020-09-28 21:25:16 +02:00
committed by GitHub
parent e82e3f27a5
commit d7e192a8fe
6 changed files with 155 additions and 187 deletions

View File

@ -1,28 +1,35 @@
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { render, screen } from '@testing-library/react';
import { PromExploreExtraField, PromExploreExtraFieldProps } from './PromExploreExtraField'; import { PromExploreExtraFieldProps, PromExploreExtraField } from './PromExploreExtraField';
const setup = (propOverrides?: PromExploreExtraFieldProps) => { const setup = (propOverrides?: PromExploreExtraFieldProps) => {
const label = 'Prometheus Explore Extra Field'; const queryType = 'range';
const value = '123'; const stepValue = '1';
const onChangeFunc = jest.fn(); const onStepChange = jest.fn();
const onQueryTypeChange = jest.fn();
const onKeyDownFunc = jest.fn(); const onKeyDownFunc = jest.fn();
const props: any = { const props: any = {
label, queryType,
value, stepValue,
onChangeFunc, onStepChange,
onQueryTypeChange,
onKeyDownFunc, onKeyDownFunc,
}; };
Object.assign(props, propOverrides); Object.assign(props, propOverrides);
return shallow(<PromExploreExtraField {...props} />); return render(<PromExploreExtraField {...props} />);
}; };
describe('PrometheusExploreExtraField', () => { describe('PromExploreExtraField', () => {
it('should render component', () => { it('should render step field', () => {
const wrapper = setup(); setup();
expect(wrapper).toMatchSnapshot(); expect(screen.getByTestId('stepField')).toBeInTheDocument();
});
it('should render query type field', () => {
setup();
expect(screen.getByTestId('queryTypeField')).toBeInTheDocument();
}); });
}); });

View File

@ -1,38 +1,72 @@
// Libraries // Libraries
import React, { memo } from 'react'; import React, { memo } from 'react';
import { css, cx } from 'emotion';
// Types // Types
import { InlineFormLabel } from '@grafana/ui'; import { InlineFormLabel, RadioButtonGroup } from '@grafana/ui';
export interface PromExploreExtraFieldProps { export interface PromExploreExtraFieldProps {
label: string; queryType: string;
onChangeFunc: (e: React.SyntheticEvent<HTMLInputElement>) => void; stepValue: string;
onStepChange: (e: React.SyntheticEvent<HTMLInputElement>) => void;
onKeyDownFunc: (e: React.KeyboardEvent<HTMLInputElement>) => void; onKeyDownFunc: (e: React.KeyboardEvent<HTMLInputElement>) => void;
value: string; onQueryTypeChange: (value: string) => void;
hasTooltip?: boolean;
tooltipContent?: string;
} }
export function PromExploreExtraField(props: PromExploreExtraFieldProps) { export const PromExploreExtraField: React.FC<PromExploreExtraFieldProps> = memo(
const { label, onChangeFunc, onKeyDownFunc, value, hasTooltip, tooltipContent } = props; ({ queryType, stepValue, onStepChange, onQueryTypeChange, onKeyDownFunc }) => {
const rangeOptions = [
{ value: 'range', label: 'Range' },
{ value: 'instant', label: 'Instant' },
{ value: 'both', label: 'Both' },
];
return ( return (
<div className="gf-form-inline" aria-label="Prometheus extra field"> <div aria-label="Prometheus extra field" className="gf-form-inline">
<div className="gf-form"> {/*QueryTypeField */}
<InlineFormLabel width={5} tooltip={hasTooltip ? tooltipContent : undefined}> <div
{label} 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>
<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> </InlineFormLabel>
<input <input
type={'text'} type={'text'}
className="gf-form-input width-4" className="gf-form-input width-4"
placeholder={'auto'} placeholder={'auto'}
onChange={onChangeFunc} onChange={onStepChange}
onKeyDown={onKeyDownFunc} onKeyDown={onKeyDownFunc}
value={value} value={stepValue}
/> />
</div> </div>
</div> </div>
); );
} }
);
export default memo(PromExploreExtraField);

View File

@ -1,9 +1,7 @@
import React, { memo, FC } from 'react'; import React, { memo, FC } from 'react';
import { css } from 'emotion';
// Types // Types
import { ExploreQueryFieldProps } from '@grafana/data'; import { ExploreQueryFieldProps } from '@grafana/data';
import { RadioButtonGroup } from '@grafana/ui';
import { PrometheusDatasource } from '../datasource'; import { PrometheusDatasource } from '../datasource';
import { PromQuery, PromOptions } from '../types'; 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) { function onQueryTypeChange(value: string) {
const { query, onChange } = props; const { query, onChange } = props;
let nextQuery; let nextQuery;
@ -41,14 +45,7 @@ export const PromExploreQueryEditor: FC<Props> = (props: Props) => {
onChange(nextQuery); onChange(nextQuery);
} }
function onReturnKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') {
onRunQuery();
}
}
return ( return (
<>
<PromQueryField <PromQueryField
datasource={datasource} datasource={datasource}
query={query} query={query}
@ -59,51 +56,14 @@ export const PromExploreQueryEditor: FC<Props> = (props: Props) => {
data={data} data={data}
ExtraFieldElement={ ExtraFieldElement={
<PromExploreExtraField <PromExploreExtraField
label={'Step'} queryType={query.range && query.instant ? 'both' : query.instant ? 'instant' : 'range'}
onChangeFunc={onStepChange} stepValue={query.interval || ''}
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} onQueryTypeChange={onQueryTypeChange}
onStepChange={onStepChange}
onKeyDownFunc={onReturnKeyDown}
/>
}
/> />
</>
);
};
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>
); );
}; };

View File

@ -331,7 +331,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
{chooserText} {chooserText}
</ButtonCascader> </ButtonCascader>
</div> </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 <QueryField
additionalPlugins={this.plugins} additionalPlugins={this.plugins}
cleanText={cleanText} cleanText={cleanText}
@ -346,8 +346,8 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
syntaxLoaded={syntaxLoaded} syntaxLoaded={syntaxLoaded}
/> />
</div> </div>
{ExtraFieldElement}
</div> </div>
{ExtraFieldElement}
{hint ? ( {hint ? (
<div className="query-row-break"> <div className="query-row-break">
<div className="prom-query-field-info text-warning"> <div className="prom-query-field-info text-warning">

View File

@ -1,26 +0,0 @@
// 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>
`;

View File

@ -1,16 +1,14 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PromExploreQueryEditor should render component 1`] = ` exports[`PromExploreQueryEditor should render component 1`] = `
<Fragment>
<PromQueryField <PromQueryField
ExtraFieldElement={ ExtraFieldElement={
<PromExploreExtraField <Memo
hasTooltip={true}
label="Step"
onChangeFunc={[Function]}
onKeyDownFunc={[Function]} onKeyDownFunc={[Function]}
tooltipContent="Time units can be used here, for example: 5s, 1m, 3h, 1d, 1y (Default if no unit is specified: s)" onQueryTypeChange={[Function]}
value="1s" onStepChange={[Function]}
queryType="range"
stepValue="1s"
/> />
} }
data={ data={
@ -60,9 +58,4 @@ exports[`PromExploreQueryEditor should render component 1`] = `
} }
} }
/> />
<PromExploreRadioButton
onQueryTypeChange={[Function]}
selected="range"
/>
</Fragment>
`; `;