diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ed3f45e420..b1e96e789a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Convert the other of the services to TypeScript ([#1392](https://github.com/elastic/eui/pull/1392)) - Changed single selection to select existing option in the list ([#1391](https://github.com/elastic/eui/pull/1391)) +- Added `showUpdateButton` prop to `EuiSuperDatePicker` ([#1399](https://github.com/elastic/eui/pull/1399)) ## [`6.0.1`](https://github.com/elastic/eui/tree/v6.0.1) @@ -22,7 +23,6 @@ - Only style anchor tags in `EuiText` that have no class attribute ([#1373](https://github.com/elastic/eui/pull/1373)) - Fixed some EUI services' TS definitions ([#1380](https://github.com/elastic/eui/pull/1380)) -- `EuiColorPicker` align color picker popup with color selector when page is scrolled ([#1397](https://github.com/elastic/eui/pull/1397)) **Breaking changes** diff --git a/src-docs/src/views/date_picker/date_picker_example.js b/src-docs/src/views/date_picker/date_picker_example.js index b326f755eaa..59d6e087a31 100644 --- a/src-docs/src/views/date_picker/date_picker_example.js +++ b/src-docs/src/views/date_picker/date_picker_example.js @@ -281,6 +281,23 @@ export const DatePickerExample = { in either datemath format (e.g.: now, now-15m, now-15m/m) or as absolute date in the format YYYY-MM-DDTHH:mm:ss.sssZ

+

+ onTimeChange will be immediately invoked when{' '} + start and end change from interactions with{' '} + Quick select, Commonly used, or Recently used date ranges{' '} + since these interactions set both start and end in a single event. +

+

+ onTimeChange will not be invoked when + start and end change from interactions with{' '} + Absolute, Relative, and Now tabs.{' '} + onTimeChange will be invoked when the user clicks the Update button. + This gives users the ability to set both start and end{' '} + before triggering onTimeChange. + Set showUpdateButton to false{' '} + to immediately invoke onTimeChange{' '} + for all start and end changes. +

), demo: , diff --git a/src-docs/src/views/date_picker/super_date_picker.js b/src-docs/src/views/date_picker/super_date_picker.js index 47c0347522a..3c9154d47de 100644 --- a/src-docs/src/views/date_picker/super_date_picker.js +++ b/src-docs/src/views/date_picker/super_date_picker.js @@ -1,8 +1,12 @@ -import React, { Component } from 'react'; +import React, { Component, Fragment } from 'react'; import { EuiSuperDatePicker, + EuiSwitch, + EuiSpacer, + EuiFormRow, + EuiFieldText, } from '../../../../src/components'; export default class extends Component { @@ -10,6 +14,9 @@ export default class extends Component { state = { recentlyUsedRanges: [], isLoading: false, + showUpdateButton: true, + start: 'now-30m', + end: 'now', } onTimeChange = ({ start, end }) => { @@ -47,18 +54,51 @@ export default class extends Component { }); } + toggleShowApplyButton = () => { + this.setState(prevState => ({ + showUpdateButton: !prevState.showUpdateButton, + })); + } + render() { return ( - + + + + + + + + + + + + + ); } } diff --git a/src/components/date_picker/super_date_picker/index.js b/src/components/date_picker/super_date_picker/index.js index 183a5d85800..35eb266d870 100644 --- a/src/components/date_picker/super_date_picker/index.js +++ b/src/components/date_picker/super_date_picker/index.js @@ -1,5 +1,3 @@ -import { - WrappedEuiSuperDatePicker, +export { + EuiSuperDatePicker, } from './super_date_picker'; - -export { WrappedEuiSuperDatePicker as EuiSuperDatePicker }; diff --git a/src/components/date_picker/super_date_picker/super_date_picker.js b/src/components/date_picker/super_date_picker/super_date_picker.js index 641eb0d8bce..4fc67449caf 100644 --- a/src/components/date_picker/super_date_picker/super_date_picker.js +++ b/src/components/date_picker/super_date_picker/super_date_picker.js @@ -15,79 +15,89 @@ import { EuiButton } from '../../button'; import { EuiFlexGroup, EuiFlexItem } from '../../flex'; import { EuiToolTip } from '../../tool_tip'; -// EuiSuperDatePicker has state that needs to be reset when start or end change. -// Instead of using getDerivedStateFromProps, this wrapper adds a key to the component. -// When a key changes, React will create a new component instance rather than update the current one -// https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key -export function WrappedEuiSuperDatePicker(props) { - return ( - - ); -} +export class EuiSuperDatePicker extends Component { -WrappedEuiSuperDatePicker.propTypes = { - isLoading: PropTypes.bool, - /** - * String as either datemath (e.g.: now, now-15m, now-15m/m) or - * absolute date in the format 'YYYY-MM-DDTHH:mm:ss.sssZ' - */ - start: PropTypes.string, - /** - * String as either datemath (e.g.: now, now-15m, now-15m/m) or - * absolute date in the format 'YYYY-MM-DDTHH:mm:ss.sssZ' - */ - end: PropTypes.string, - /** - * Callback for when the time changes. Called with { start, end } - */ - onTimeChange: PropTypes.func.isRequired, - isPaused: PropTypes.bool, - /** - * Refresh interval in milliseconds - */ - refreshInterval: PropTypes.number, - /** - * Callback for when the refresh interval changes. Called with { isPaused, refreshInterval } - * Supply onRefreshChange to show refresh interval inputs in quick select popover - */ - onRefreshChange: PropTypes.func, - - /** - * 'start' and 'end' must be string as either datemath (e.g.: now, now-15m, now-15m/m) or - * absolute date in the format 'YYYY-MM-DDTHH:mm:ss.sssZ' - */ - commonlyUsedRanges: PropTypes.arrayOf(commonlyUsedRangeShape), - dateFormat: PropTypes.string, - /** - * 'start' and 'end' must be string as either datemath (e.g.: now, now-15m, now-15m/m) or - * absolute date in the format 'YYYY-MM-DDTHH:mm:ss.sssZ' - */ - recentlyUsedRanges: PropTypes.arrayOf(recentlyUsedRangeShape), -}; - -WrappedEuiSuperDatePicker.defaultProps = { - start: 'now-15m', - end: 'now', - isPaused: true, - refreshInterval: 0, - commonlyUsedRanges: [ - { start: 'now/d', end: 'now/d', label: 'Today' }, - { start: 'now-1d/d', end: 'now-1d/d', label: 'Yesterday' }, - { start: 'now/w', end: 'now/w', label: 'This week' }, - { start: 'now/w', end: 'now', label: 'Week to date' }, - { start: 'now/M', end: 'now/M', label: 'This month' }, - { start: 'now/M', end: 'now', label: 'Month to date' }, - { start: 'now/y', end: 'now/y', label: 'This year' }, - { start: 'now/y', end: 'now', label: 'Year to date' }, - ], - dateFormat: 'MMM D, YYYY @ HH:mm:ss.SSS', - recentlyUsedRanges: [], -}; + static propTypes = { + isLoading: PropTypes.bool, + /** + * String as either datemath (e.g.: now, now-15m, now-15m/m) or + * absolute date in the format 'YYYY-MM-DDTHH:mm:ss.sssZ' + */ + start: PropTypes.string, + /** + * String as either datemath (e.g.: now, now-15m, now-15m/m) or + * absolute date in the format 'YYYY-MM-DDTHH:mm:ss.sssZ' + */ + end: PropTypes.string, + /** + * Callback for when the time changes. Called with { start, end } + */ + onTimeChange: PropTypes.func.isRequired, + isPaused: PropTypes.bool, + /** + * Refresh interval in milliseconds + */ + refreshInterval: PropTypes.number, + /** + * Callback for when the refresh interval changes. Called with { isPaused, refreshInterval } + * Supply onRefreshChange to show refresh interval inputs in quick select popover + */ + onRefreshChange: PropTypes.func, + + /** + * 'start' and 'end' must be string as either datemath (e.g.: now, now-15m, now-15m/m) or + * absolute date in the format 'YYYY-MM-DDTHH:mm:ss.sssZ' + */ + commonlyUsedRanges: PropTypes.arrayOf(commonlyUsedRangeShape), + dateFormat: PropTypes.string, + /** + * 'start' and 'end' must be string as either datemath (e.g.: now, now-15m, now-15m/m) or + * absolute date in the format 'YYYY-MM-DDTHH:mm:ss.sssZ' + */ + recentlyUsedRanges: PropTypes.arrayOf(recentlyUsedRangeShape), + /** + * Set showUpdateButton to false to immediately invoke onTimeChange for all start and end changes. + */ + showUpdateButton: PropTypes.bool, + } -export class EuiSuperDatePicker extends Component { + static defaultProps = { + start: 'now-15m', + end: 'now', + isPaused: true, + refreshInterval: 0, + commonlyUsedRanges: [ + { start: 'now/d', end: 'now/d', label: 'Today' }, + { start: 'now-1d/d', end: 'now-1d/d', label: 'Yesterday' }, + { start: 'now/w', end: 'now/w', label: 'This week' }, + { start: 'now/w', end: 'now', label: 'Week to date' }, + { start: 'now/M', end: 'now/M', label: 'This month' }, + { start: 'now/M', end: 'now', label: 'Month to date' }, + { start: 'now/y', end: 'now/y', label: 'This year' }, + { start: 'now/y', end: 'now', label: 'Year to date' }, + ], + dateFormat: 'MMM D, YYYY @ HH:mm:ss.SSS', + recentlyUsedRanges: [], + showUpdateButton: true, + } + + static getDerivedStateFromProps(nextProps, prevState) { + if (nextProps.start !== prevState.prevProps.start + || nextProps.end !== prevState.prevProps.end) { + return { + prevProps: { + start: nextProps.start, + end: nextProps.end, + }, + start: nextProps.start, + end: nextProps.end, + isInvalid: false, + hasChanged: false, + }; + } + + return null; + } constructor(props) { super(props); @@ -99,6 +109,10 @@ export class EuiSuperDatePicker extends Component { } = this.props; this.state = { + prevProps: { + start: props.start, + end: props.end, + }, start, end, isInvalid: false, @@ -118,13 +132,13 @@ export class EuiSuperDatePicker extends Component { setTootipRef = node => (this.tooltip = node); showTooltip = () => { - if (!this._isMounted) { + if (!this._isMounted || !this.tooltip) { return; } this.tooltip.showToolTip(); } hideTooltip = () => { - if (!this._isMounted) { + if (!this._isMounted || !this.tooltip) { return; } this.tooltip.hideToolTip(); @@ -149,6 +163,11 @@ export class EuiSuperDatePicker extends Component { }); if (!isInvalid) { + if (!this.props.showUpdateButton) { + this.props.onTimeChange({ start, end }); + return; + } + this.showTooltip(); this.tooltipTimeout = setTimeout(() => { this.hideTooltip(); @@ -169,6 +188,9 @@ export class EuiSuperDatePicker extends Component { } applyQuickTime = ({ start, end }) => { + this.setState({ + showPrettyDuration: showPrettyDuration(start, end, this.props.commonlyUsedRanges), + }); this.props.onTimeChange({ start, end }); } @@ -236,6 +258,10 @@ export class EuiSuperDatePicker extends Component { } renderUpdateButton = () => { + if (!this.props.showUpdateButton) { + return; + } + let buttonText = 'Refresh'; if (this.state.hasChanged || this.props.isLoading) { buttonText = this.props.isLoading ? 'Updating' : 'Update'; @@ -305,7 +331,3 @@ export class EuiSuperDatePicker extends Component { ); } } - -EuiSuperDatePicker.propTypes = WrappedEuiSuperDatePicker.propTypes; -EuiSuperDatePicker.defaultProps = WrappedEuiSuperDatePicker.defaultProps; -