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"
</InlineFormLabel> className={cx(
<input 'gf-form explore-input-margin',
type={'text'} css`
className="gf-form-input width-4" flex-wrap: nowrap;
placeholder={'auto'} `
onChange={onChangeFunc} )}
onKeyDown={onKeyDownFunc} aria-label="Query type field"
value={value} >
/> <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>
<input
type={'text'}
className="gf-form-input width-4"
placeholder={'auto'}
onChange={onStepChange}
onKeyDown={onKeyDownFunc}
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,69 +45,25 @@ 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} onRunQuery={onRunQuery}
onRunQuery={onRunQuery} onChange={onChange}
onChange={onChange} onBlur={() => {}}
onBlur={() => {}} history={history}
history={history} data={data}
data={data} ExtraFieldElement={
ExtraFieldElement={ <PromExploreExtraField
<PromExploreExtraField queryType={query.range && query.instant ? 'both' : query.instant ? 'instant' : 'range'}
label={'Step'} stepValue={query.interval || ''}
onChangeFunc={onStepChange} onQueryTypeChange={onQueryTypeChange}
onKeyDownFunc={onReturnKeyDown} onStepChange={onStepChange}
value={query.interval || ''} onKeyDownFunc={onReturnKeyDown}
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>
); );
}; };

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,43 +1,25 @@
// 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={ <Memo
<PromExploreExtraField onKeyDownFunc={[Function]}
hasTooltip={true} onQueryTypeChange={[Function]}
label="Step" onStepChange={[Function]}
onChangeFunc={[Function]} queryType="range"
onKeyDownFunc={[Function]} stepValue="1s"
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 {
data={ "request": Object {
Object { "app": "Grafana",
"request": Object { "dashboardId": 1,
"app": "Grafana", "interval": "1s",
"dashboardId": 1, "intervalMs": 1000,
"interval": "1s", "panelId": 1,
"intervalMs": 1000, "range": Object {
"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 {
"from": "2020-01-01T00:00:00.000Z", "from": "2020-01-01T00:00:00.000Z",
"raw": Object { "raw": Object {
"from": "2020-01-01T00:00:00.000Z", "from": "2020-01-01T00:00:00.000Z",
@ -45,24 +27,35 @@ exports[`PromExploreQueryEditor should render component 1`] = `
}, },
"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 {
"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 []} datasource={Object {}}
onBlur={[Function]} history={Array []}
onChange={[MockFunction]} onBlur={[Function]}
onRunQuery={[MockFunction]} onChange={[MockFunction]}
query={ onRunQuery={[MockFunction]}
Object { query={
"expr": "", Object {
"interval": "1s", "expr": "",
"refId": "A", "interval": "1s",
} "refId": "A",
} }
/> }
<PromExploreRadioButton />
onQueryTypeChange={[Function]}
selected="range"
/>
</Fragment>
`; `;