refactor: Replace react-bootstrap MenuItems with Antd Menu (#11554)

* Refactor SliceHeaderControls

* Refactor DisplayQueryButton

* Fix duplicate keys

* Refactor SliceAdder

* Move css from styles to Emotion

* Fix e2e test
This commit is contained in:
Kamil Gabryjelski 2020-11-05 22:30:03 +01:00 committed by GitHub
parent 091432ea8e
commit 1490f3074d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 289 additions and 270 deletions

View File

@ -81,8 +81,7 @@ describe('Dashboard top-level controls', () => {
.next()
.find('[data-test="dashboard-slice-refresh-tooltip"]')
.parent()
.parent()
.should('have.class', 'disabled');
.should('have.class', 'ant-menu-item-disabled');
cy.wait(`@postJson_${mapId}_force`);
cy.get('[data-test="refresh-dashboard-menu-item"]').should(

View File

@ -18,10 +18,10 @@
*/
import React from 'react';
import { mount } from 'enzyme';
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
import { Menu } from 'src/common/components';
import ModalTrigger from 'src/components/ModalTrigger';
import { DisplayQueryButton } from 'src/explore/components/DisplayQueryButton';
import { MenuItem } from 'react-bootstrap';
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
describe('DisplayQueryButton', () => {
const defaultProps = {
@ -51,6 +51,6 @@ describe('DisplayQueryButton', () => {
},
});
expect(wrapper.find(ModalTrigger)).toHaveLength(3);
expect(wrapper.find(MenuItem)).toHaveLength(5);
expect(wrapper.find(Menu.Item)).toHaveLength(5);
});
});

View File

@ -191,7 +191,7 @@ export function Menu({
</DropdownMenu.ItemGroup>,
]}
{(navbarRight.version_string || navbarRight.version_sha) && [
<DropdownMenu.Divider key="user-divider" />,
<DropdownMenu.Divider key="navbar-divider" />,
<DropdownMenu.ItemGroup
key="about-section"
title={t('About')}

View File

@ -18,7 +18,6 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { MenuItem } from 'react-bootstrap';
import Modal from 'src/common/components/Modal';
import Button from 'src/components/Button';
@ -31,7 +30,6 @@ const propTypes = {
beforeOpen: PropTypes.func,
onExit: PropTypes.func,
isButton: PropTypes.bool,
isMenuItem: PropTypes.bool,
className: PropTypes.string,
tooltip: PropTypes.string,
width: PropTypes.string,
@ -43,7 +41,6 @@ const defaultProps = {
beforeOpen: () => {},
onExit: () => {},
isButton: false,
isMenuItem: false,
className: '',
modalTitle: '',
};
@ -102,14 +99,6 @@ export default class ModalTrigger extends React.Component {
</>
);
}
if (this.props.isMenuItem) {
return (
<>
<MenuItem onClick={this.open}>{this.props.triggerNode}</MenuItem>
{this.renderModal()}
</>
);
}
/* eslint-disable jsx-a11y/interactive-supports-focus */
return (
<>

View File

@ -29,7 +29,6 @@ const propTypes = {
emailSubject: PropTypes.string,
emailContent: PropTypes.string,
addDangerToast: PropTypes.func.isRequired,
isMenuItem: PropTypes.bool,
title: PropTypes.string,
triggerNode: PropTypes.node.isRequired,
};
@ -65,7 +64,6 @@ class URLShortLinkModal extends React.Component {
return (
<ModalTrigger
ref={this.setModalRef}
isMenuItem={this.props.isMenuItem}
triggerNode={this.props.triggerNode}
beforeOpen={this.getCopyUrl}
modalTitle={this.props.title || t('Share Dashboard')}

View File

@ -19,11 +19,11 @@
/* eslint-env browser */
import React from 'react';
import PropTypes from 'prop-types';
import { DropdownButton, MenuItem } from 'react-bootstrap';
import { List } from 'react-virtualized';
import SearchInput, { createFilter } from 'react-search-input';
import { t } from '@superset-ui/core';
import { Select } from 'src/common/components';
import AddSliceCard from './AddSliceCard';
import AddSliceDragPreview from './dnd/AddSliceDragPreview';
import DragDroppable from './dnd/DragDroppable';
@ -52,12 +52,14 @@ const defaultProps = {
};
const KEYS_TO_FILTERS = ['slice_name', 'viz_type', 'datasource_name'];
const KEYS_TO_SORT = [
{ key: 'slice_name', label: 'Name' },
{ key: 'viz_type', label: 'Vis type' },
{ key: 'datasource_name', label: 'Dataset' },
{ key: 'changed_on', label: 'Recent' },
];
const KEYS_TO_SORT = {
slice_name: 'Name',
viz_type: 'Vis type',
datasource_name: 'Dataset',
changed_on: 'Recent',
};
const DEFAULT_SORT_KEY = 'changed_on';
const MARGIN_BOTTOM = 16;
const SIDEPANE_HEADER_HEIGHT = 30;
@ -84,7 +86,7 @@ class SliceAdder extends React.Component {
this.state = {
filteredSlices: [],
searchTerm: '',
sortBy: KEYS_TO_SORT.findIndex(item => item.key === 'changed_on'),
sortBy: DEFAULT_SORT_KEY,
selectedSliceIdsSet: new Set(props.selectedSliceIds),
};
this.rowRenderer = this.rowRenderer.bind(this);
@ -102,7 +104,7 @@ class SliceAdder extends React.Component {
if (nextProps.lastUpdated !== this.props.lastUpdated) {
nextState.filteredSlices = Object.values(nextProps.slices)
.filter(createFilter(this.state.searchTerm, KEYS_TO_FILTERS))
.sort(SliceAdder.sortByComparator(KEYS_TO_SORT[this.state.sortBy].key));
.sort(SliceAdder.sortByComparator(this.state.sortBy));
}
if (nextProps.selectedSliceIds !== this.props.selectedSliceIds) {
@ -123,7 +125,7 @@ class SliceAdder extends React.Component {
getFilteredSortedSlices(searchTerm, sortBy) {
return Object.values(this.props.slices)
.filter(createFilter(searchTerm, KEYS_TO_FILTERS))
.sort(SliceAdder.sortByComparator(KEYS_TO_SORT[sortBy].key));
.sort(SliceAdder.sortByComparator(sortBy));
}
handleKeyPress(ev) {
@ -216,17 +218,17 @@ class SliceAdder extends React.Component {
onKeyPress={this.handleKeyPress}
data-test="dashboard-charts-filter-search-input"
/>
<DropdownButton
title={`Sort by ${KEYS_TO_SORT[this.state.sortBy].label}`}
onSelect={this.handleSelect}
<Select
id="slice-adder-sortby"
defaultValue={DEFAULT_SORT_KEY}
onChange={this.handleSelect}
>
{KEYS_TO_SORT.map((item, index) => (
<MenuItem key={item.key} eventKey={index}>
Sort by {item.label}
</MenuItem>
{Object.entries(KEYS_TO_SORT).map(([key, label]) => (
<Select.Option key={key} value={key}>
Sort by {label}
</Select.Option>
))}
</DropdownButton>
</Select>
</div>
{this.props.isLoading && <Loading />}
{!this.props.isLoading && this.state.filteredSlices.length > 0 && (

View File

@ -19,8 +19,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import { Dropdown, MenuItem } from 'react-bootstrap';
import { t } from '@superset-ui/core';
import { DropdownButton } from 'react-bootstrap';
import { styled, t } from '@superset-ui/core';
import { Menu } from 'src/common/components';
import URLShortLinkModal from '../../components/URLShortLinkModal';
import downloadAsImage from '../../utils/downloadAsImage';
import getDashboardUrl from '../util/getDashboardUrl';
@ -58,41 +59,49 @@ const defaultProps = {
sliceCanEdit: false,
};
const MENU_KEYS = {
FORCE_REFRESH: 'force_refresh',
TOGGLE_CHART_DESCRIPTION: 'toggle_chart_description',
EXPLORE_CHART: 'explore_chart',
EXPORT_CSV: 'export_csv',
RESIZE_LABEL: 'resize_label',
SHARE_CHART: 'share_chart',
DOWNLOAD_AS_IMAGE: 'download_as_image',
};
const VerticalDotsContainer = styled.div`
padding: ${({ theme }) => theme.gridUnit / 4}px
${({ theme }) => theme.gridUnit * 1.5}px;
.dot {
display: block;
}
&:hover {
cursor: pointer;
}
`;
const VerticalDotsTrigger = () => (
<div className="vertical-dots-container">
<VerticalDotsContainer>
<span className="dot" />
<span className="dot" />
<span className="dot" />
</div>
</VerticalDotsContainer>
);
class SliceHeaderControls extends React.PureComponent {
constructor(props) {
super(props);
this.exportCSV = this.exportCSV.bind(this);
this.exploreChart = this.exploreChart.bind(this);
this.toggleControls = this.toggleControls.bind(this);
this.refreshChart = this.refreshChart.bind(this);
this.toggleExpandSlice = this.props.toggleExpandSlice.bind(
this,
this.props.slice.slice_id,
);
this.handleToggleFullSize = this.handleToggleFullSize.bind(this);
this.handleMenuClick = this.handleMenuClick.bind(this);
this.state = {
showControls: false,
};
}
exportCSV() {
this.props.exportCSV(this.props.slice.slice_id);
}
exploreChart() {
this.props.exploreChart(this.props.slice.slice_id);
}
refreshChart() {
if (this.props.updatedDttm) {
this.props.forceRefresh(
@ -108,8 +117,32 @@ class SliceHeaderControls extends React.PureComponent {
}));
}
handleToggleFullSize() {
this.props.handleToggleFullSize();
handleMenuClick({ key, domEvent }) {
switch (key) {
case MENU_KEYS.FORCE_REFRESH:
this.refreshChart();
break;
case MENU_KEYS.TOGGLE_CHART_DESCRIPTION:
this.props.toggleExpandSlice(this.props.slice.slice_id);
break;
case MENU_KEYS.EXPLORE_CHART:
this.props.exploreChart(this.props.slice.slice_id);
break;
case MENU_KEYS.EXPORT_CSV:
this.props.exportCSV(this.props.slice.slice_id);
break;
case MENU_KEYS.RESIZE_LABEL:
this.props.handleToggleFullSize();
break;
case MENU_KEYS.DOWNLOAD_AS_IMAGE:
downloadAsImage(
'.dashboard-component-chart-holder',
this.props.slice.slice_name,
)(domEvent);
break;
default:
break;
}
}
render() {
@ -129,21 +162,21 @@ class SliceHeaderControls extends React.PureComponent {
: (updatedWhen && t('Fetched %s', updatedWhen)) || '';
const resizeLabel = isFullSize ? t('Minimize') : t('Maximize');
return (
<Dropdown
<DropdownButton
id={`slice_${slice.slice_id}-controls`}
pullRight
noCaret
title={<VerticalDotsTrigger />}
style={{ padding: 0 }}
// react-bootstrap handles visibility, but call toggle to force a re-render
// and update the fetched/cached timestamps
onToggle={this.toggleControls}
>
<Dropdown.Toggle className="slice-header-controls-trigger" noCaret>
<VerticalDotsTrigger />
</Dropdown.Toggle>
<Dropdown.Menu>
<MenuItem
onClick={this.refreshChart}
<Menu onClick={this.handleMenuClick} selectable={false}>
<Menu.Item
key={MENU_KEYS.FORCE_REFRESH}
disabled={this.props.chartStatus === 'loading'}
style={{ height: 'auto', lineHeight: 'initial' }}
>
{t('Force refresh')}
<div
@ -152,50 +185,46 @@ class SliceHeaderControls extends React.PureComponent {
>
{refreshTooltip}
</div>
</MenuItem>
</Menu.Item>
<MenuItem divider />
<Menu.Divider />
{slice.description && (
<MenuItem onClick={this.toggleExpandSlice}>
<Menu.Item key={MENU_KEYS.TOGGLE_CHART_DESCRIPTION}>
{t('Toggle chart description')}
</MenuItem>
</Menu.Item>
)}
{this.props.supersetCanExplore && (
<MenuItem onClick={this.exploreChart}>
<Menu.Item key={MENU_KEYS.EXPLORE_CHART}>
{t('Explore chart')}
</MenuItem>
</Menu.Item>
)}
{this.props.supersetCanCSV && (
<MenuItem onClick={this.exportCSV}>{t('Export CSV')}</MenuItem>
<Menu.Item key={MENU_KEYS.EXPORT_CSV}>{t('Export CSV')}</Menu.Item>
)}
<MenuItem onClick={this.handleToggleFullSize}>{resizeLabel}</MenuItem>
<Menu.Item key={MENU_KEYS.RESIZE_LABEL}>{resizeLabel}</Menu.Item>
<URLShortLinkModal
url={getDashboardUrl(
window.location.pathname,
getActiveFilters(),
componentId,
)}
addDangerToast={addDangerToast}
isMenuItem
title={t('Share chart')}
triggerNode={<span>{t('Share chart')}</span>}
/>
<Menu.Item key={MENU_KEYS.SHARE_CHART}>
<URLShortLinkModal
url={getDashboardUrl(
window.location.pathname,
getActiveFilters(),
componentId,
)}
addDangerToast={addDangerToast}
title={t('Share chart')}
triggerNode={<span>{t('Share chart')}</span>}
/>
</Menu.Item>
<MenuItem
onClick={downloadAsImage(
'.dashboard-component-chart-holder',
slice.slice_name,
)}
>
<Menu.Item key={MENU_KEYS.DOWNLOAD_AS_IMAGE}>
{t('Download as image')}
</MenuItem>
</Dropdown.Menu>
</Dropdown>
</Menu.Item>
</Menu>
</DropdownButton>
);
}
}

View File

@ -112,14 +112,6 @@
}
}
.slice-header-controls-trigger {
padding: 2px 6px;
&:hover {
cursor: pointer;
}
}
.dot {
@dot-diameter: 4px;
@ -131,10 +123,6 @@
background-color: @gray;
display: inline-block;
.vertical-dots-container & {
display: block;
}
a[role='menuitem'] & {
width: 8px;
height: 8px;

View File

@ -138,16 +138,8 @@ body {
padding: 9px 0;
}
.dropdown-menu li a {
padding: 3px 16px;
color: @almost-black;
font-size: @font-size-m;
&:hover,
&:focus {
background: @menu-hover;
color: @almost-black;
}
.dropdown-menu li {
font-weight: @font-weight-normal;
}
}

View File

@ -26,16 +26,11 @@ import markdownSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/mar
import sqlSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql';
import jsonSyntax from 'react-syntax-highlighter/dist/cjs/languages/hljs/json';
import github from 'react-syntax-highlighter/dist/cjs/styles/hljs/github';
import {
DropdownButton,
MenuItem,
Row,
Col,
FormControl,
} from 'react-bootstrap';
import { DropdownButton, Row, Col, FormControl } from 'react-bootstrap';
import { Table } from 'reactable-arc';
import { t } from '@superset-ui/core';
import { Menu } from 'src/common/components';
import Button from 'src/components/Button';
import getClientErrorObject from '../../utils/getClientErrorObject';
import CopyToClipboard from '../../components/CopyToClipboard';
@ -65,6 +60,12 @@ const propTypes = {
slice: PropTypes.object,
};
const MENU_KEYS = {
EDIT_PROPERTIES: 'edit_properties',
RUN_IN_SQL_LAB: 'run_in_sql_lab',
DOWNLOAD_AS_IMAGE: 'download_as_image',
};
export class DisplayQueryButton extends React.PureComponent {
constructor(props) {
super(props);
@ -81,8 +82,8 @@ export class DisplayQueryButton extends React.PureComponent {
};
this.beforeOpen = this.beforeOpen.bind(this);
this.changeFilterText = this.changeFilterText.bind(this);
this.openPropertiesModal = this.openPropertiesModal.bind(this);
this.closePropertiesModal = this.closePropertiesModal.bind(this);
this.handleMenuClick = this.handleMenuClick.bind(this);
}
beforeOpen(resultType) {
@ -118,10 +119,6 @@ export class DisplayQueryButton extends React.PureComponent {
this.setState({ filterText: event.target.value });
}
redirectSQLLab() {
this.props.onOpenInEditor(this.props.latestQueryFormData);
}
openPropertiesModal() {
this.setState({ isPropertiesModalOpen: true });
}
@ -130,6 +127,35 @@ export class DisplayQueryButton extends React.PureComponent {
this.setState({ isPropertiesModalOpen: false });
}
handleMenuClick({ key, domEvent }) {
const {
chartHeight,
slice,
onOpenInEditor,
latestQueryFormData,
} = this.props;
switch (key) {
case MENU_KEYS.EDIT_PROPERTIES:
this.openPropertiesModal();
break;
case MENU_KEYS.RUN_IN_SQL_LAB:
onOpenInEditor(latestQueryFormData);
break;
case MENU_KEYS.DOWNLOAD_AS_IMAGE:
downloadAsImage(
'.chart-container',
// eslint-disable-next-line camelcase
slice?.slice_name ?? t('New chart'),
{
height: parseInt(chartHeight, 10),
},
)(domEvent);
break;
default:
break;
}
}
renderQueryModalBody() {
if (this.state.isLoading) {
return <Loading />;
@ -230,7 +256,7 @@ export class DisplayQueryButton extends React.PureComponent {
}
render() {
const { chartHeight, slice } = this.props;
const { slice } = this.props;
return (
<DropdownButton
noCaret
@ -245,62 +271,56 @@ export class DisplayQueryButton extends React.PureComponent {
pullRight
id="query"
>
{slice && (
<>
<MenuItem onClick={this.openPropertiesModal}>
<Menu onClick={this.handleMenuClick} selectable={false}>
{slice && [
<Menu.Item key={MENU_KEYS.EDIT_PROPERTIES}>
{t('Edit properties')}
</MenuItem>
</Menu.Item>,
<PropertiesModal
slice={slice}
show={this.state.isPropertiesModalOpen}
onHide={this.closePropertiesModal}
onSave={this.props.sliceUpdated}
/>,
]}
<Menu.Item>
<ModalTrigger
triggerNode={
<span data-test="view-query-menu-item">{t('View query')}</span>
}
modalTitle={t('View query')}
beforeOpen={() => this.beforeOpen('query')}
modalBody={this.renderQueryModalBody()}
responsive
/>
</>
)}
<ModalTrigger
isMenuItem
triggerNode={
<span data-test="view-query-menu-item">{t('View query')}</span>
}
modalTitle={t('View query')}
beforeOpen={() => this.beforeOpen('query')}
modalBody={this.renderQueryModalBody()}
responsive
/>
<ModalTrigger
isMenuItem
triggerNode={<span>{t('View results')}</span>}
modalTitle={t('View results')}
beforeOpen={() => this.beforeOpen('results')}
modalBody={this.renderResultsModalBody()}
responsive
/>
<ModalTrigger
isMenuItem
triggerNode={<span>{t('View samples')}</span>}
modalTitle={t('View samples')}
beforeOpen={() => this.beforeOpen('samples')}
modalBody={this.renderSamplesModalBody()}
responsive
/>
{this.state.sqlSupported && (
<MenuItem eventKey="3" onClick={this.redirectSQLLab.bind(this)}>
{t('Run in SQL Lab')}
</MenuItem>
)}
<MenuItem
onClick={downloadAsImage(
'.chart-container',
// eslint-disable-next-line camelcase
slice?.slice_name ?? t('New chart'),
{
height: parseInt(chartHeight, 10),
},
</Menu.Item>
<Menu.Item>
<ModalTrigger
triggerNode={<span>{t('View results')}</span>}
modalTitle={t('View results')}
beforeOpen={() => this.beforeOpen('results')}
modalBody={this.renderResultsModalBody()}
responsive
/>
</Menu.Item>
<Menu.Item>
<ModalTrigger
triggerNode={<span>{t('View samples')}</span>}
modalTitle={t('View samples')}
beforeOpen={() => this.beforeOpen('samples')}
modalBody={this.renderSamplesModalBody()}
responsive
/>
</Menu.Item>
{this.state.sqlSupported && (
<Menu.Item key={MENU_KEYS.RUN_IN_SQL_LAB}>
{t('Run in SQL Lab')}
</Menu.Item>
)}
>
{t('Download as image')}
</MenuItem>
<Menu.Item key={MENU_KEYS.DOWNLOAD_AS_IMAGE}>
{t('Download as image')}
</Menu.Item>
</Menu>
</DropdownButton>
);
}

View File

@ -88,8 +88,6 @@ const FREEFORM_TOOLTIP = t(
'`2 weeks from now` can be used.',
);
const DATE_FILTER_POPOVER_STYLE = { width: '250px' };
const propTypes = {
animation: PropTypes.bool,
name: PropTypes.string.isRequired,
@ -173,12 +171,34 @@ function getStateFromCustomRange(value) {
};
}
const Styles = styled.div`
const TimeFramesStyles = styled.div`
.radio {
margin: ${({ theme }) => theme.gridUnit}px 0;
}
`;
const PopoverContentStyles = styled.div`
width: ${({ theme }) => theme.gridUnit * 60}px;
.timeframes-container {
margin-left: ${({ theme }) => theme.gridUnit * 2}px;
}
.relative-timerange-container {
display: flex;
margin-top: ${({ theme }) => theme.gridUnit * 2}px;
}
.timerange-input {
width: ${({ theme }) => theme.gridUnit * 15}px;
margin: 0 ${({ theme }) => theme.gridUnit}px;
}
.datetime {
margin: ${({ theme }) => theme.gridUnit}px 0;
}
`;
class DateFilterControl extends React.Component {
constructor(props) {
super(props);
@ -399,7 +419,7 @@ class DateFilterControl extends React.Component {
const timeRange = buildTimeRangeString(nextState.since, nextState.until);
return (
<Styles key={timeFrame}>
<TimeFramesStyles key={timeFrame}>
<OverlayTrigger
key={timeFrame}
placement="right"
@ -419,14 +439,13 @@ class DateFilterControl extends React.Component {
</Radio>
</div>
</OverlayTrigger>
</Styles>
</TimeFramesStyles>
);
});
return (
<div
<PopoverContentStyles
id="filter-popover"
style={DATE_FILTER_POPOVER_STYLE}
ref={ref => {
this.popoverContainer = ref;
}}
@ -438,7 +457,7 @@ class DateFilterControl extends React.Component {
onSelect={this.changeTab}
>
<Tabs.TabPane key="1" tab="Defaults" forceRender>
<div style={{ marginLeft: '8px' }}>
<div className="timeframes-container">
<FormGroup>{timeFrames}</FormGroup>
</div>
</Tabs.TabPane>
@ -449,48 +468,37 @@ class DateFilterControl extends React.Component {
isSelected={this.state.type === TYPES.CUSTOM_RANGE}
onSelect={this.setTypeCustomRange}
>
<div
className="clearfix centered"
style={{ marginTop: '8px', display: 'flex' }}
>
<div className="input-inline">
<Select
value={this.state.rel}
onSelect={value => this.setCustomRange('rel', value)}
onFocus={this.setTypeCustomRange}
>
<Select.Option value={RELATIVE_TIME_OPTIONS.LAST}>
Last
</Select.Option>
<Select.Option value={RELATIVE_TIME_OPTIONS.NEXT}>
Next
</Select.Option>
</Select>
</div>
<div
style={{ width: '60px' }}
className="input-inline m-l-5 m-r-3"
<div className="relative-timerange-container clearfix centered">
<Select
value={this.state.rel}
onSelect={value => this.setCustomRange('rel', value)}
onFocus={this.setTypeCustomRange}
>
<Input
type="text"
onChange={event =>
this.setCustomRange('num', event.target.value)
}
onFocus={this.setTypeCustomRange}
onPressEnter={this.close}
value={this.state.num}
/>
</div>
<div className="input-inline">
<Select
value={this.state.grain}
onFocus={this.setTypeCustomRange}
onSelect={value => this.setCustomRange('grain', value)}
dropdownMatchSelectWidth={false}
>
{grainOptions}
</Select>
</div>
<Select.Option value={RELATIVE_TIME_OPTIONS.LAST}>
Last
</Select.Option>
<Select.Option value={RELATIVE_TIME_OPTIONS.NEXT}>
Next
</Select.Option>
</Select>
<Input
className="timerange-input"
type="text"
onChange={event =>
this.setCustomRange('num', event.target.value)
}
onFocus={this.setTypeCustomRange}
onPressEnter={this.close}
value={this.state.num}
/>
<Select
value={this.state.grain}
onFocus={this.setTypeCustomRange}
onSelect={value => this.setCustomRange('grain', value)}
dropdownMatchSelectWidth={false}
>
{grainOptions}
</Select>
</div>
</PopoverSection>
<PopoverSection
@ -505,48 +513,42 @@ class DateFilterControl extends React.Component {
}}
>
<InputGroup data-test="date-input-group">
<div style={{ margin: '5px 0' }}>
<Datetime
inputProps={{ 'data-test': 'date-from-input' }}
value={this.state.since}
defaultValue={this.state.since}
viewDate={this.state.since}
onChange={value =>
this.setCustomStartEnd('since', value)
}
isValidDate={this.isValidSince}
onClick={this.setTypeCustomStartEnd}
renderInput={props =>
this.renderInput(props, 'showSinceCalendar')
}
open={this.state.showSinceCalendar}
viewMode={this.state.sinceViewMode}
onViewModeChange={sinceViewMode =>
this.setState({ sinceViewMode })
}
/>
</div>
<div style={{ margin: '5px 0' }}>
<Datetime
inputProps={{ 'data-test': 'date-to-input' }}
value={this.state.until}
defaultValue={this.state.until}
viewDate={this.state.until}
onChange={value =>
this.setCustomStartEnd('until', value)
}
isValidDate={this.isValidUntil}
onClick={this.setTypeCustomStartEnd}
renderInput={props =>
this.renderInput(props, 'showUntilCalendar')
}
open={this.state.showUntilCalendar}
viewMode={this.state.untilViewMode}
onViewModeChange={untilViewMode =>
this.setState({ untilViewMode })
}
/>
</div>
<Datetime
className="datetime"
inputProps={{ 'data-test': 'date-from-input' }}
value={this.state.since}
defaultValue={this.state.since}
viewDate={this.state.since}
onChange={value => this.setCustomStartEnd('since', value)}
isValidDate={this.isValidSince}
onClick={this.setTypeCustomStartEnd}
renderInput={props =>
this.renderInput(props, 'showSinceCalendar')
}
open={this.state.showSinceCalendar}
viewMode={this.state.sinceViewMode}
onViewModeChange={sinceViewMode =>
this.setState({ sinceViewMode })
}
/>
<Datetime
className="datetime"
inputProps={{ 'data-test': 'date-to-input' }}
value={this.state.until}
defaultValue={this.state.until}
viewDate={this.state.until}
onChange={value => this.setCustomStartEnd('until', value)}
isValidDate={this.isValidUntil}
onClick={this.setTypeCustomStartEnd}
renderInput={props =>
this.renderInput(props, 'showUntilCalendar')
}
open={this.state.showUntilCalendar}
viewMode={this.state.untilViewMode}
onViewModeChange={untilViewMode =>
this.setState({ untilViewMode })
}
/>
</InputGroup>
</div>
</PopoverSection>
@ -564,7 +566,7 @@ class DateFilterControl extends React.Component {
Ok
</Button>
</div>
</div>
</PopoverContentStyles>
);
}