From 8fed495be6448d6a4e4a61994ae4fc9f1a86ef6c Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Mon, 27 Oct 2025 15:44:36 +0100 Subject: [PATCH 01/30] Render toolbar UI --- .../super_date_picker/super_date_picker.tsx | 36 ++++++ .../super_date_picker/time_window_toolbar.tsx | 108 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx index 46d20c15cf8..244f6d0eba0 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx @@ -39,6 +39,7 @@ import { import { TimeOptions, RenderI18nTimeOptions } from './time_options'; import { PrettyDuration, showPrettyDuration } from './pretty_duration'; +import { TimeWindowToolbar } from './time_window_toolbar'; import { AsyncInterval } from './async_interval'; import { @@ -69,6 +70,11 @@ export interface OnRefreshProps extends DurationRange { refreshInterval: number; } +export interface TimeWindowToolbarConfig { + zoomOut?: boolean; + timeShift?: boolean; +} + export type EuiSuperDatePickerProps = CommonProps & { commonlyUsedRanges?: DurationRange[]; customQuickSelectPanels?: QuickSelectPanel[]; @@ -202,6 +208,12 @@ export type EuiSuperDatePickerProps = CommonProps & { */ showUpdateButton?: boolean | 'iconOnly'; + /** + * Set to true to display a toolbar next to the top-level control + * with buttons for zooming out and time shifting. + */ + showTimeWindowToolbar?: boolean | TimeWindowToolbarConfig; + /** * Hides the actual input reducing to just the quick select button. */ @@ -725,6 +737,29 @@ export class EuiSuperDatePickerInternal extends Component< } }; + renderTimeShiftToolbar = () => { + if (!this.props.showTimeWindowToolbar) { + return null; + } + const { + start, + end, + // showTimeWindowToolbar: config, // will use later on + compressed, + isDisabled, + } = this.props; + + return ( + + ); + }; + renderUpdateButton = () => { const { isLoading, @@ -805,6 +840,7 @@ export class EuiSuperDatePickerInternal extends Component< ) : ( <> {this.renderDatePickerRange()} + {this.renderTimeShiftToolbar()} {this.renderUpdateButton()} )} diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx new file mode 100644 index 00000000000..edff9c2a6c2 --- /dev/null +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +// import dateMath from '@elastic/datemath'; +// import moment from 'moment'; + +import { ShortDate, ApplyTime } from '../types'; +import { useEuiMemoizedStyles, useGeneratedHtmlId } from '../../../services'; + +import { EuiButtonGroupButton } from '../../button/button_group/button_group_button'; +import { euiButtonGroupButtonsStyles } from '../../button/button_group/button_group.styles'; + +interface TimeWindowToolbarProps { + applyTime: ApplyTime; + start: ShortDate; + end: ShortDate; + compressed?: boolean; + isDisabled?: boolean; +} + +/** + * Toolbar for managing the time window with controls for moving the time window + * forwards and backwards, and zooming out. + * + * We're using EuiButtonGroupButton wrapped in role=toolbar, + * whenever we have something like EuiToolbar, this might get refactored. + * + * @todo + * - [ ] translate labels, etc. + * - [ ] is `aria-pressed` being rendered causing any trouble? + * - [ ] use `euiButtonGroup__buttons` class? + * - [ ] check if hiding tooltips when isDisabled is the right thing to do + */ +export const TimeWindowToolbar: React.FC = ({ + // applyTime, + // start, + // end, + compressed, + isDisabled, +}) => { + const buttonColor = 'text'; + const buttonSize = compressed ? 'compressed' : 'm'; + const styles = useEuiMemoizedStyles(euiButtonGroupButtonsStyles); + const cssStyles = [styles.euiButtonGroup__buttons, styles[buttonSize]]; + + // Previous + const previousId = useGeneratedHtmlId({ prefix: 'previous' }); + const previousLabel = 'Previous'; // TODO translate + const previousTooltipContent = 'Previous ...'; // TODO translate + + // Zoom out + const zoomOutId = useGeneratedHtmlId({ prefix: 'zoom_out' }); + const zoomOutLabel = 'Zoom out'; // TODO translate + + // Next + const nextId = useGeneratedHtmlId({ prefix: 'next' }); + const nextLabel = 'Next'; // TODO translate + const nextTooltipContent = 'Next ...'; // TODO translate + + const handleClickForNow = () => {}; + + return ( +
+ + + +
+ ); +}; From c83ed61081c6085c1fb8d6267728b9ed94285e63 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Mon, 27 Oct 2025 17:30:32 +0100 Subject: [PATCH 02/30] Implement time window logic - step forward and backward - zoom out --- .../super_date_picker/time_window_toolbar.tsx | 96 ++++++++++++++++--- 1 file changed, 81 insertions(+), 15 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx index edff9c2a6c2..99c2074c977 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx @@ -7,14 +7,15 @@ */ import React from 'react'; -// import dateMath from '@elastic/datemath'; -// import moment from 'moment'; +import dateMath from '@elastic/datemath'; +import moment, { Moment } from 'moment'; import { ShortDate, ApplyTime } from '../types'; -import { useEuiMemoizedStyles, useGeneratedHtmlId } from '../../../services'; +import { usePrettyInterval } from './pretty_interval'; import { EuiButtonGroupButton } from '../../button/button_group/button_group_button'; import { euiButtonGroupButtonsStyles } from '../../button/button_group/button_group.styles'; +import { useEuiMemoizedStyles, useGeneratedHtmlId } from '../../../services'; interface TimeWindowToolbarProps { applyTime: ApplyTime; @@ -24,6 +25,10 @@ interface TimeWindowToolbarProps { isDisabled?: boolean; } +// How much time is added to the interval (or window) +// e.g. 60 minutes * 0.3 -> 18 minutes will be added (9 on each end) +const ZOOM_FACTOR = 0.3; + /** * Toolbar for managing the time window with controls for moving the time window * forwards and backwards, and zooming out. @@ -38,21 +43,26 @@ interface TimeWindowToolbarProps { * - [ ] check if hiding tooltips when isDisabled is the right thing to do */ export const TimeWindowToolbar: React.FC = ({ - // applyTime, - // start, - // end, + applyTime, + start, + end, compressed, isDisabled, }) => { const buttonColor = 'text'; const buttonSize = compressed ? 'compressed' : 'm'; const styles = useEuiMemoizedStyles(euiButtonGroupButtonsStyles); - const cssStyles = [styles.euiButtonGroup__buttons, styles[buttonSize]]; + + const { prettyInterval, stepForward, stepBackward, zoomOut } = useTimeWindow( + start, + end, + applyTime + ); // Previous const previousId = useGeneratedHtmlId({ prefix: 'previous' }); const previousLabel = 'Previous'; // TODO translate - const previousTooltipContent = 'Previous ...'; // TODO translate + const previousTooltipContent = `Previous ~${prettyInterval}`; // TODO translate // Zoom out const zoomOutId = useGeneratedHtmlId({ prefix: 'zoom_out' }); @@ -61,15 +71,17 @@ export const TimeWindowToolbar: React.FC = ({ // Next const nextId = useGeneratedHtmlId({ prefix: 'next' }); const nextLabel = 'Next'; // TODO translate - const nextTooltipContent = 'Next ...'; // TODO translate - - const handleClickForNow = () => {}; + const nextTooltipContent = `Next ~${prettyInterval}`; // TODO translate return ( -
+
= ({ /> = ({ /> = ({
); }; + +/** + * + * Partly adapted from date_picker/super_date_picker/quick_select_popover/quick_select.tsx + * + * @todo check variable names, most of them are terrible + */ +export function useTimeWindow( + start: ShortDate, + end: ShortDate, + apply: ApplyTime +) { + const min = dateMath.parse(start) as Moment; + const max = dateMath.parse(end, { roundUp: true }) as Moment; + const diff = max.diff(min); + // terrible name, I meant what's added on the edges + // e.g. 25% substracted to the start, 25% added to the end + const edgeDiff = diff * (ZOOM_FACTOR / 2); + + const prettyInterval = usePrettyInterval(false, diff, { + shortHand: true, + }); + // const prettyZoomInterval = usePrettyInterval(false, diff + edgeDiff * 2, { + // shortHand: true, + // }); + + return { + prettyInterval, + stepForward, + stepBackward, + zoomOut, + }; + + function stepForward() { + apply({ + start: moment(max).toISOString(), + end: moment(max).add(diff, 'ms').toISOString(), + }); + } + + function stepBackward() { + apply({ + start: moment(min).subtract(diff, 'ms').toISOString(), + end: moment(min).toISOString(), + }); + } + + function zoomOut() { + apply({ + start: moment(min).subtract(edgeDiff, 'ms').toISOString(), + end: moment(max).add(edgeDiff, 'ms').toISOString(), + }); + } +} From 357e577d2490869add4164b5ce59700b18761a9e Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Mon, 27 Oct 2025 17:35:05 +0100 Subject: [PATCH 03/30] Correct method name --- .../date_picker/super_date_picker/super_date_picker.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx index 244f6d0eba0..968e24c20ba 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx @@ -72,7 +72,7 @@ export interface OnRefreshProps extends DurationRange { export interface TimeWindowToolbarConfig { zoomOut?: boolean; - timeShift?: boolean; + windowShift?: boolean; // TODO revise name } export type EuiSuperDatePickerProps = CommonProps & { @@ -737,7 +737,7 @@ export class EuiSuperDatePickerInternal extends Component< } }; - renderTimeShiftToolbar = () => { + renderTimeWindowToolbar = () => { if (!this.props.showTimeWindowToolbar) { return null; } @@ -840,7 +840,7 @@ export class EuiSuperDatePickerInternal extends Component< ) : ( <> {this.renderDatePickerRange()} - {this.renderTimeShiftToolbar()} + {this.renderTimeWindowToolbar()} {this.renderUpdateButton()} )} From 4e742f888ffd89ae69124eb2d72c775b7f9eb5c1 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Tue, 28 Oct 2025 12:13:14 +0100 Subject: [PATCH 04/30] [TimeWindowToolbar] Make which buttons to show configurable --- .../super_date_picker/super_date_picker.tsx | 16 +-- .../super_date_picker/time_window_toolbar.tsx | 98 +++++++++++-------- 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx index 968e24c20ba..e329ee60651 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx @@ -71,8 +71,10 @@ export interface OnRefreshProps extends DurationRange { } export interface TimeWindowToolbarConfig { + /** Show button for zooming out */ zoomOut?: boolean; - windowShift?: boolean; // TODO revise name + /** Show buttons for navigating between time windows */ + navigationArrows?: boolean; } export type EuiSuperDatePickerProps = CommonProps & { @@ -741,13 +743,10 @@ export class EuiSuperDatePickerInternal extends Component< if (!this.props.showTimeWindowToolbar) { return null; } - const { - start, - end, - // showTimeWindowToolbar: config, // will use later on - compressed, - isDisabled, - } = this.props; + const { start, end, showTimeWindowToolbar, compressed, isDisabled } = + this.props; + const config = + typeof showTimeWindowToolbar === 'boolean' ? {} : showTimeWindowToolbar; return ( ); }; diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx index 99c2074c977..fdf5ae915a2 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx @@ -23,6 +23,10 @@ interface TimeWindowToolbarProps { end: ShortDate; compressed?: boolean; isDisabled?: boolean; + /** @default true */ + zoomOut?: boolean; + /** @default true */ + navigationArrows?: boolean; } // How much time is added to the interval (or window) @@ -48,16 +52,20 @@ export const TimeWindowToolbar: React.FC = ({ end, compressed, isDisabled, + zoomOut = true, + navigationArrows = true, }) => { const buttonColor = 'text'; const buttonSize = compressed ? 'compressed' : 'm'; const styles = useEuiMemoizedStyles(euiButtonGroupButtonsStyles); - const { prettyInterval, stepForward, stepBackward, zoomOut } = useTimeWindow( - start, - end, - applyTime - ); + // TODO rename handlers? + const { + prettyInterval, + stepForward, + stepBackward, + zoomOut: zoom, + } = useTimeWindow(start, end, applyTime); // Previous const previousId = useGeneratedHtmlId({ prefix: 'previous' }); @@ -73,48 +81,56 @@ export const TimeWindowToolbar: React.FC = ({ const nextLabel = 'Next'; // TODO translate const nextTooltipContent = `Next ~${prettyInterval}`; // TODO translate + if (!zoomOut && !navigationArrows) return null; + return (
- - - + {navigationArrows && ( + + )} + {zoomOut && ( + + )} + {navigationArrows && ( + + )}
); }; From 9e06fcee20ea7afda2b183052e974990b315b9a1 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Tue, 28 Oct 2025 12:37:13 +0100 Subject: [PATCH 05/30] [TimeWindowToolbar] Add tilde prefix for _inexact_ ranges only also make zoom factor an option in the hook --- .../super_date_picker/time_window_toolbar.tsx | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx index fdf5ae915a2..0791bdb7675 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx @@ -70,7 +70,7 @@ export const TimeWindowToolbar: React.FC = ({ // Previous const previousId = useGeneratedHtmlId({ prefix: 'previous' }); const previousLabel = 'Previous'; // TODO translate - const previousTooltipContent = `Previous ~${prettyInterval}`; // TODO translate + const previousTooltipContent = `Previous ${prettyInterval}`; // TODO translate // Zoom out const zoomOutId = useGeneratedHtmlId({ prefix: 'zoom_out' }); @@ -79,7 +79,7 @@ export const TimeWindowToolbar: React.FC = ({ // Next const nextId = useGeneratedHtmlId({ prefix: 'next' }); const nextLabel = 'Next'; // TODO translate - const nextTooltipContent = `Next ~${prettyInterval}`; // TODO translate + const nextTooltipContent = `Next ${prettyInterval}`; // TODO translate if (!zoomOut && !navigationArrows) return null; @@ -144,21 +144,23 @@ export const TimeWindowToolbar: React.FC = ({ export function useTimeWindow( start: ShortDate, end: ShortDate, - apply: ApplyTime + apply: ApplyTime, + options?: { zoomFactor?: number } ) { const min = dateMath.parse(start) as Moment; const max = dateMath.parse(end, { roundUp: true }) as Moment; const diff = max.diff(min); + const zoomFactor = options?.zoomFactor ?? ZOOM_FACTOR; // terrible name, I meant what's added on the edges // e.g. 25% substracted to the start, 25% added to the end - const edgeDiff = diff * (ZOOM_FACTOR / 2); + const edgeDiff = diff * (zoomFactor / 2); - const prettyInterval = usePrettyInterval(false, diff, { + let prettyInterval = usePrettyInterval(false, diff, { shortHand: true, }); - // const prettyZoomInterval = usePrettyInterval(false, diff + edgeDiff * 2, { - // shortHand: true, - // }); + if (!isExactMinuteRange(diff)) { + prettyInterval = `~${prettyInterval}`; + } return { prettyInterval, @@ -188,3 +190,8 @@ export function useTimeWindow( }); } } + +function isExactMinuteRange(diffMs: number) { + // 60 * 1000 = ms per minute + return diffMs % (60 * 1000) === 0; +} From 596fc0181bd5e1f54f7cdf47eb82515ad25b4995 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Tue, 28 Oct 2025 12:47:45 +0100 Subject: [PATCH 06/30] [TimeWindowToolbar] Rename variables for readability --- .../super_date_picker/time_window_toolbar.tsx | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx index 0791bdb7675..dad348145f0 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx @@ -59,18 +59,17 @@ export const TimeWindowToolbar: React.FC = ({ const buttonSize = compressed ? 'compressed' : 'm'; const styles = useEuiMemoizedStyles(euiButtonGroupButtonsStyles); - // TODO rename handlers? const { - prettyInterval, + displayInterval, stepForward, stepBackward, - zoomOut: zoom, + expandWindow, } = useTimeWindow(start, end, applyTime); // Previous const previousId = useGeneratedHtmlId({ prefix: 'previous' }); const previousLabel = 'Previous'; // TODO translate - const previousTooltipContent = `Previous ${prettyInterval}`; // TODO translate + const previousTooltipContent = `Previous ${displayInterval}`; // TODO translate // Zoom out const zoomOutId = useGeneratedHtmlId({ prefix: 'zoom_out' }); @@ -79,7 +78,7 @@ export const TimeWindowToolbar: React.FC = ({ // Next const nextId = useGeneratedHtmlId({ prefix: 'next' }); const nextLabel = 'Next'; // TODO translate - const nextTooltipContent = `Next ${prettyInterval}`; // TODO translate + const nextTooltipContent = `Next ${displayInterval}`; // TODO translate if (!zoomOut && !navigationArrows) return null; @@ -106,7 +105,7 @@ export const TimeWindowToolbar: React.FC = ({ {zoomOut && ( = ({ }; /** - * * Partly adapted from date_picker/super_date_picker/quick_select_popover/quick_select.tsx - * - * @todo check variable names, most of them are terrible */ export function useTimeWindow( start: ShortDate, @@ -149,44 +145,43 @@ export function useTimeWindow( ) { const min = dateMath.parse(start) as Moment; const max = dateMath.parse(end, { roundUp: true }) as Moment; - const diff = max.diff(min); + const windowDuration = max.diff(min); const zoomFactor = options?.zoomFactor ?? ZOOM_FACTOR; - // terrible name, I meant what's added on the edges - // e.g. 25% substracted to the start, 25% added to the end - const edgeDiff = diff * (zoomFactor / 2); + // Gets added to each end, that's why it's split in half + const zoomAddition = windowDuration * (zoomFactor / 2); - let prettyInterval = usePrettyInterval(false, diff, { + let displayInterval = usePrettyInterval(false, windowDuration, { shortHand: true, }); - if (!isExactMinuteRange(diff)) { - prettyInterval = `~${prettyInterval}`; + if (!isExactMinuteRange(windowDuration)) { + displayInterval = `~${displayInterval}`; } return { - prettyInterval, + displayInterval, stepForward, stepBackward, - zoomOut, + expandWindow, }; function stepForward() { apply({ start: moment(max).toISOString(), - end: moment(max).add(diff, 'ms').toISOString(), + end: moment(max).add(windowDuration, 'ms').toISOString(), }); } function stepBackward() { apply({ - start: moment(min).subtract(diff, 'ms').toISOString(), + start: moment(min).subtract(windowDuration, 'ms').toISOString(), end: moment(min).toISOString(), }); } - function zoomOut() { + function expandWindow() { apply({ - start: moment(min).subtract(edgeDiff, 'ms').toISOString(), - end: moment(max).add(edgeDiff, 'ms').toISOString(), + start: moment(min).subtract(zoomAddition, 'ms').toISOString(), + end: moment(max).add(zoomAddition, 'ms').toISOString(), }); } } From 9c0cc3d30496e552eea28574f8205347bb9f7fff Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Tue, 28 Oct 2025 17:57:34 +0100 Subject: [PATCH 07/30] [TimeWindowToolbar] Fix displayInterval, consistent tilde, start adding tests --- .../time_window_toolbar.test.tsx | 63 +++++++++++++++++++ .../super_date_picker/time_window_toolbar.tsx | 14 ++--- 2 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.test.tsx diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.test.tsx new file mode 100644 index 00000000000..6b09ca11c31 --- /dev/null +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.test.tsx @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// import React from 'react'; +// import moment from 'moment'; +// renderHookAct +import { renderHook } from '../../../test/rtl'; + +import { useTimeWindow } from './time_window_toolbar'; + +describe('TimeWindowToolbar: useTimeWindow hook', () => { + describe('displayInterval', () => { + it('handles relative times', () => { + const applyTime = jest.fn(); + const start = 'now-15m'; + const end = 'now'; + + const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); + + expect(result.current.displayInterval).toBe('15 m'); + }); + + it('handles absolute times', () => { + const applyTime = jest.fn(); + const start = '2025-10-29T16:00:00.000Z'; + const end = '2025-10-29T16:15:00.000Z'; + + const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); + + expect(result.current.displayInterval).toBe('15 m'); + }); + + it('adds a tilde for approximate ranges', () => { + const applyTime = jest.fn(); + const start = '2025-10-27T16:00:01.000Z'; + const end = '2025-10-29T16:12:00.000Z'; + + const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); + + expect(result.current.displayInterval).toBe('~2 d'); + }); + }); + + describe('stepForward callback', () => { + it.todo('moves time window forward'); + }); + + describe('stepBackward callback', () => { + it.todo('moves time window backward'); + }); + + // TODO import ZOOM_FACTOR const + describe('expandWindow callback', () => { + it.todo('expands time window on both ends of the range'); + + it.todo('handles different zoom factor option'); + }); +}); diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx index dad348145f0..6363d9e4782 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx @@ -59,12 +59,8 @@ export const TimeWindowToolbar: React.FC = ({ const buttonSize = compressed ? 'compressed' : 'm'; const styles = useEuiMemoizedStyles(euiButtonGroupButtonsStyles); - const { - displayInterval, - stepForward, - stepBackward, - expandWindow, - } = useTimeWindow(start, end, applyTime); + const { displayInterval, stepForward, stepBackward, expandWindow } = + useTimeWindow(start, end, applyTime); // Previous const previousId = useGeneratedHtmlId({ prefix: 'previous' }); @@ -153,7 +149,7 @@ export function useTimeWindow( let displayInterval = usePrettyInterval(false, windowDuration, { shortHand: true, }); - if (!isExactMinuteRange(windowDuration)) { + if (!isRelativeToNow(start, end) && !isExactMinuteRange(windowDuration)) { displayInterval = `~${displayInterval}`; } @@ -186,6 +182,10 @@ export function useTimeWindow( } } +function isRelativeToNow(start: ShortDate, end: ShortDate) { + return String(end).includes('now') || String(start).includes('now'); +} + function isExactMinuteRange(diffMs: number) { // 60 * 1000 = ms per minute return diffMs % (60 * 1000) === 0; From 095dcb66ff071885c72723a311b27ac0b9390cef Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Thu, 30 Oct 2025 10:38:07 +0100 Subject: [PATCH 08/30] [TimeWindowButtons] Rename TimeWindowToolbar - add zoomFactor as prop - move TimeWindowButtonsConfig into same file --- .../super_date_picker/super_date_picker.tsx | 26 +++---- ....test.tsx => time_window_buttons.test.tsx} | 2 +- ...ow_toolbar.tsx => time_window_buttons.tsx} | 73 ++++++++++++------- 3 files changed, 60 insertions(+), 41 deletions(-) rename packages/eui/src/components/date_picker/super_date_picker/{time_window_toolbar.test.tsx => time_window_buttons.test.tsx} (97%) rename packages/eui/src/components/date_picker/super_date_picker/{time_window_toolbar.tsx => time_window_buttons.tsx} (78%) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx index e329ee60651..2c1f744679b 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx @@ -39,7 +39,10 @@ import { import { TimeOptions, RenderI18nTimeOptions } from './time_options'; import { PrettyDuration, showPrettyDuration } from './pretty_duration'; -import { TimeWindowToolbar } from './time_window_toolbar'; +import { + TimeWindowButtons, + type TimeWindowButtonsConfig, +} from './time_window_buttons'; import { AsyncInterval } from './async_interval'; import { @@ -70,13 +73,6 @@ export interface OnRefreshProps extends DurationRange { refreshInterval: number; } -export interface TimeWindowToolbarConfig { - /** Show button for zooming out */ - zoomOut?: boolean; - /** Show buttons for navigating between time windows */ - navigationArrows?: boolean; -} - export type EuiSuperDatePickerProps = CommonProps & { commonlyUsedRanges?: DurationRange[]; customQuickSelectPanels?: QuickSelectPanel[]; @@ -214,7 +210,7 @@ export type EuiSuperDatePickerProps = CommonProps & { * Set to true to display a toolbar next to the top-level control * with buttons for zooming out and time shifting. */ - showTimeWindowToolbar?: boolean | TimeWindowToolbarConfig; + showTimeWindowButtons?: boolean | TimeWindowButtonsConfig; /** * Hides the actual input reducing to just the quick select button. @@ -739,17 +735,17 @@ export class EuiSuperDatePickerInternal extends Component< } }; - renderTimeWindowToolbar = () => { - if (!this.props.showTimeWindowToolbar) { + renderTimeWindowButtons = () => { + if (!this.props.showTimeWindowButtons) { return null; } - const { start, end, showTimeWindowToolbar, compressed, isDisabled } = + const { start, end, showTimeWindowButtons, compressed, isDisabled } = this.props; const config = - typeof showTimeWindowToolbar === 'boolean' ? {} : showTimeWindowToolbar; + typeof showTimeWindowButtons === 'boolean' ? {} : showTimeWindowButtons; return ( - {this.renderDatePickerRange()} - {this.renderTimeWindowToolbar()} + {this.renderTimeWindowButtons()} {this.renderUpdateButton()} )} diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx similarity index 97% rename from packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.test.tsx rename to packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx index 6b09ca11c31..30b9dcf801e 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx @@ -11,7 +11,7 @@ // renderHookAct import { renderHook } from '../../../test/rtl'; -import { useTimeWindow } from './time_window_toolbar'; +import { useTimeWindow } from './time_window_buttons'; describe('TimeWindowToolbar: useTimeWindow hook', () => { describe('displayInterval', () => { diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx similarity index 78% rename from packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx rename to packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index 6363d9e4782..44c763213a8 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_toolbar.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -17,50 +17,61 @@ import { EuiButtonGroupButton } from '../../button/button_group/button_group_but import { euiButtonGroupButtonsStyles } from '../../button/button_group/button_group.styles'; import { useEuiMemoizedStyles, useGeneratedHtmlId } from '../../../services'; -interface TimeWindowToolbarProps { +const ZOOM_FACTOR_DEFAULT = 0.42; // no special reason for this number + +export interface TimeWindowButtonsConfig { + /** + * Show button for zooming out + * @default true + */ + zoomOut?: boolean; + /** + * Show buttons for shifting the time window forward and backward + * @default true + */ + shiftArrows?: boolean; + /** + * How much the time window is increased when zooming. + * Can be a number (0.25) or a string representing a percentage (25%) + * @default 0.42 + * */ + zoomFactor?: number | string; +} + +export type TimeWindowButtonsProps = TimeWindowButtonsConfig & { applyTime: ApplyTime; start: ShortDate; end: ShortDate; compressed?: boolean; isDisabled?: boolean; - /** @default true */ - zoomOut?: boolean; - /** @default true */ - navigationArrows?: boolean; -} - -// How much time is added to the interval (or window) -// e.g. 60 minutes * 0.3 -> 18 minutes will be added (9 on each end) -const ZOOM_FACTOR = 0.3; +}; /** - * Toolbar for managing the time window with controls for moving the time window + * Toolbar for managing the time window with controls for shifting the time window * forwards and backwards, and zooming out. * - * We're using EuiButtonGroupButton wrapped in role=toolbar, - * whenever we have something like EuiToolbar, this might get refactored. - * * @todo * - [ ] translate labels, etc. * - [ ] is `aria-pressed` being rendered causing any trouble? * - [ ] use `euiButtonGroup__buttons` class? * - [ ] check if hiding tooltips when isDisabled is the right thing to do */ -export const TimeWindowToolbar: React.FC = ({ +export const TimeWindowButtons: React.FC = ({ applyTime, start, end, compressed, isDisabled, zoomOut = true, - navigationArrows = true, + shiftArrows = true, + zoomFactor = ZOOM_FACTOR_DEFAULT, }) => { const buttonColor = 'text'; const buttonSize = compressed ? 'compressed' : 'm'; const styles = useEuiMemoizedStyles(euiButtonGroupButtonsStyles); const { displayInterval, stepForward, stepBackward, expandWindow } = - useTimeWindow(start, end, applyTime); + useTimeWindow(start, end, applyTime, { zoomFactor }); // Previous const previousId = useGeneratedHtmlId({ prefix: 'previous' }); @@ -76,15 +87,14 @@ export const TimeWindowToolbar: React.FC = ({ const nextLabel = 'Next'; // TODO translate const nextTooltipContent = `Next ${displayInterval}`; // TODO translate - if (!zoomOut && !navigationArrows) return null; + if (!zoomOut && !shiftArrows) return null; return (
- {navigationArrows && ( + {shiftArrows && ( = ({ isDisabled={isDisabled} /> )} - {navigationArrows && ( + {shiftArrows && ( Date: Thu, 30 Oct 2025 10:41:45 +0100 Subject: [PATCH 09/30] [TimeWindowButtons] Zoom factor default to 0.5 --- .../date_picker/super_date_picker/time_window_buttons.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index 44c763213a8..85537e2acad 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -17,7 +17,7 @@ import { EuiButtonGroupButton } from '../../button/button_group/button_group_but import { euiButtonGroupButtonsStyles } from '../../button/button_group/button_group.styles'; import { useEuiMemoizedStyles, useGeneratedHtmlId } from '../../../services'; -const ZOOM_FACTOR_DEFAULT = 0.42; // no special reason for this number +const ZOOM_FACTOR_DEFAULT = 0.5; export interface TimeWindowButtonsConfig { /** @@ -33,7 +33,7 @@ export interface TimeWindowButtonsConfig { /** * How much the time window is increased when zooming. * Can be a number (0.25) or a string representing a percentage (25%) - * @default 0.42 + * @default 0.5 * */ zoomFactor?: number | string; } From f605001b8252fbf4acab039fdb5c3862aa538c0d Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Thu, 30 Oct 2025 11:14:39 +0100 Subject: [PATCH 10/30] [TimeWindowButtons] Display full units instead of short hand in tooltips --- .../date_picker/super_date_picker/time_window_buttons.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index 85537e2acad..b9fde548044 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -156,9 +156,7 @@ export function useTimeWindow( // Gets added to each end, that's why it's split in half const zoomAddition = windowDuration * (zoomFactor / 2); - let displayInterval = usePrettyInterval(false, windowDuration, { - shortHand: true, - }); + let displayInterval = usePrettyInterval(false, windowDuration); if (!isRelativeToNow(start, end) && !isExactMinuteRange(windowDuration)) { displayInterval = `~${displayInterval}`; } From 9595438985e7e5207282100df0f3c26a215b1aa1 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Thu, 30 Oct 2025 11:15:16 +0100 Subject: [PATCH 11/30] [TimeWindowButtons] Add unit tests for useTimeWindow hook --- .../time_window_buttons.test.tsx | 90 ++++++++++++++++--- .../super_date_picker/time_window_buttons.tsx | 2 +- 2 files changed, 78 insertions(+), 14 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx index 30b9dcf801e..7dd40d06c96 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx @@ -6,12 +6,10 @@ * Side Public License, v 1. */ -// import React from 'react'; -// import moment from 'moment'; -// renderHookAct -import { renderHook } from '../../../test/rtl'; +import moment from 'moment'; +import { renderHook, renderHookAct } from '../../../test/rtl'; -import { useTimeWindow } from './time_window_buttons'; +import { useTimeWindow, ZOOM_FACTOR_DEFAULT } from './time_window_buttons'; describe('TimeWindowToolbar: useTimeWindow hook', () => { describe('displayInterval', () => { @@ -22,7 +20,7 @@ describe('TimeWindowToolbar: useTimeWindow hook', () => { const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); - expect(result.current.displayInterval).toBe('15 m'); + expect(result.current.displayInterval).toBe('15 minutes'); }); it('handles absolute times', () => { @@ -32,7 +30,7 @@ describe('TimeWindowToolbar: useTimeWindow hook', () => { const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); - expect(result.current.displayInterval).toBe('15 m'); + expect(result.current.displayInterval).toBe('15 minutes'); }); it('adds a tilde for approximate ranges', () => { @@ -42,22 +40,88 @@ describe('TimeWindowToolbar: useTimeWindow hook', () => { const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); - expect(result.current.displayInterval).toBe('~2 d'); + expect(result.current.displayInterval).toBe('~2 days'); }); }); describe('stepForward callback', () => { - it.todo('moves time window forward'); + it('shifts time window forward', () => { + const applyTime = jest.fn(); + const start = '2025-10-30T10:00:00.000Z'; + const end = '2025-10-30T11:00:00.000Z'; + + const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); + + renderHookAct(() => { + result.current.stepForward(); + }) + + expect(applyTime).toHaveBeenCalledWith({ + start: '2025-10-30T11:00:00.000Z', + end: '2025-10-30T12:00:00.000Z', + }); + }); }); describe('stepBackward callback', () => { - it.todo('moves time window backward'); + it('shifts time window backward', () => { + const applyTime = jest.fn(); + const start = '2025-10-30T10:00:00.000Z'; + const end = '2025-10-30T11:00:00.000Z'; + + const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); + + renderHookAct(() => { + result.current.stepBackward(); + }) + + expect(applyTime).toHaveBeenCalledWith({ + start: '2025-10-30T09:00:00.000Z', + end: '2025-10-30T10:00:00.000Z', + }); + }); }); - // TODO import ZOOM_FACTOR const describe('expandWindow callback', () => { - it.todo('expands time window on both ends of the range'); + it('expands time window on both ends of the range', () => { + const applyTime = jest.fn(); + const start = '2025-10-30T10:00:00.000Z'; + const end = '2025-10-30T11:00:00.000Z'; - it.todo('handles different zoom factor option'); + const shiftedStart = moment(start).subtract(ZOOM_FACTOR_DEFAULT / 2, 'hours'); + const shiftedEnd = moment(end).add(ZOOM_FACTOR_DEFAULT / 2, 'hours'); + + const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); + + renderHookAct(() => { + result.current.expandWindow(); + }) + + expect(applyTime).toHaveBeenCalledWith({ + start: shiftedStart.toISOString(), + end: shiftedEnd.toISOString(), + }); + }); + + it('handles different zoom factor option', () => { + const customZoomFactor = 0.42; + const applyTime = jest.fn(); + const start = '2025-10-30T10:00:00.000Z'; + const end = '2025-10-30T11:00:00.000Z'; + + const shiftedStart = moment(start).subtract(customZoomFactor / 2, 'hours'); + const shiftedEnd = moment(end).add(customZoomFactor / 2, 'hours'); + + const { result } = renderHook(() => useTimeWindow(start, end, applyTime, { zoomFactor: customZoomFactor })); + + renderHookAct(() => { + result.current.expandWindow(); + }) + + expect(applyTime).toHaveBeenCalledWith({ + start: shiftedStart.toISOString(), + end: shiftedEnd.toISOString(), + }); + }); }); }); diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index b9fde548044..c48680a02d1 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -17,7 +17,7 @@ import { EuiButtonGroupButton } from '../../button/button_group/button_group_but import { euiButtonGroupButtonsStyles } from '../../button/button_group/button_group.styles'; import { useEuiMemoizedStyles, useGeneratedHtmlId } from '../../../services'; -const ZOOM_FACTOR_DEFAULT = 0.5; +export const ZOOM_FACTOR_DEFAULT = 0.5; export interface TimeWindowButtonsConfig { /** From 87df23bafa7f8738066c9ed980277b17d693a54c Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Thu, 30 Oct 2025 13:04:15 +0100 Subject: [PATCH 12/30] [TimeWindowButtons] Test integration in EuiSuperDatePicker --- .../super_date_picker.test.tsx | 92 ++++++++++++++++++- .../super_date_picker/time_window_buttons.tsx | 22 +++-- 2 files changed, 104 insertions(+), 10 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx index 17f0e1e2485..87287e6ee12 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx @@ -8,7 +8,7 @@ import React, { useState } from 'react'; import moment from 'moment'; -import { fireEvent, act } from '@testing-library/react'; +import { fireEvent, act, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { render, waitForEuiPopoverOpen, screen } from '../../../test/rtl'; @@ -640,4 +640,94 @@ describe('EuiSuperDatePicker', () => { expect(prevEnd).toBe('2025-01-01T10:00:00.000Z'); }); }); + + describe('Time window buttons', () => { + it('renders only when showTimeWindowButtons prop is passed', () => { + const start = '2025-10-30T12:00:00.000Z'; + const end = '2025-10-30T13:00:00.000Z'; + + const { queryByTestSubject, rerender } = render( + {}} + showTimeWindowButtons + /> + ); + + expect(queryByTestSubject('timeWindowButtons')).toBeInTheDocument(); + + rerender( + {}} + /> + ) + + expect(queryByTestSubject('timeWindowButtons')).not.toBeInTheDocument(); + }); + + it('updates time when shifting', async () => { + const start = '2025-10-30T12:00:00.000Z'; + const end = '2025-10-30T13:00:00.000Z'; + let lastTimeChange: { start: string; end: string } = { start, end }; + + const { queryByTestSubject } = render( + { + lastTimeChange = { start, end }; + }} + showUpdateButton={false} + showTimeWindowButtons={true} + /> + ); + + act(() => { + userEvent.click(queryByTestSubject('timeWindowButtonsPrevious')!); + }) + + await waitFor(() => { + const initialTimeStart = new Date(start).getTime(); + const updatedTimeStart = new Date(lastTimeChange.start).getTime(); + const initialTimeEnd = new Date(end).getTime(); + const updatedTimeEnd = new Date(lastTimeChange.end).getTime(); + expect(initialTimeStart).toBeGreaterThan(updatedTimeStart); + expect(initialTimeEnd).toBeGreaterThan(updatedTimeEnd); + }); + }); + + it('updates time when zooming out', async () => { + const start = '2025-10-30T12:00:00.000Z'; + const end = '2025-10-31T12:00:00.000Z'; + let lastTimeChange: { start: string; end: string } = { start, end }; + + const { queryByTestSubject } = render( + { + lastTimeChange = { start, end }; + }} + showUpdateButton={false} + showTimeWindowButtons={true} + /> + ); + + act(() => { + userEvent.click(queryByTestSubject('timeWindowButtonsZoomOut')!); + }) + + await waitFor(() => { + const initialTimeStart = new Date(start).getTime(); + const updatedTimeStart = new Date(lastTimeChange.start).getTime(); + const initialTimeEnd = new Date(end).getTime(); + const updatedTimeEnd = new Date(lastTimeChange.end).getTime(); + expect(initialTimeStart).toBeGreaterThan(updatedTimeStart); + expect(initialTimeEnd).toBeLessThan(updatedTimeEnd); + }); + }); + }); }); diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index c48680a02d1..4ca8e4f33e2 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -93,47 +93,51 @@ export const TimeWindowButtons: React.FC = ({
{shiftArrows && ( )} {zoomOut && ( )} {shiftArrows && ( )}
From 46bbc7c08b3f549859a48dcfa3de199027702601 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Thu, 30 Oct 2025 13:31:50 +0100 Subject: [PATCH 13/30] [TimeWindowButtons] Translate labels and tooltips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and lint… --- .../super_date_picker.test.tsx | 16 +++---- .../time_window_buttons.test.tsx | 22 ++++++---- .../super_date_picker/time_window_buttons.tsx | 42 ++++++++++++------- 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx index 87287e6ee12..1ea82aa4902 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx @@ -658,12 +658,8 @@ describe('EuiSuperDatePicker', () => { expect(queryByTestSubject('timeWindowButtons')).toBeInTheDocument(); rerender( - {}} - /> - ) + {}} /> + ); expect(queryByTestSubject('timeWindowButtons')).not.toBeInTheDocument(); }); @@ -687,8 +683,8 @@ describe('EuiSuperDatePicker', () => { act(() => { userEvent.click(queryByTestSubject('timeWindowButtonsPrevious')!); - }) - + }); + await waitFor(() => { const initialTimeStart = new Date(start).getTime(); const updatedTimeStart = new Date(lastTimeChange.start).getTime(); @@ -718,8 +714,8 @@ describe('EuiSuperDatePicker', () => { act(() => { userEvent.click(queryByTestSubject('timeWindowButtonsZoomOut')!); - }) - + }); + await waitFor(() => { const initialTimeStart = new Date(start).getTime(); const updatedTimeStart = new Date(lastTimeChange.start).getTime(); diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx index 7dd40d06c96..21adf535f61 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx @@ -54,7 +54,7 @@ describe('TimeWindowToolbar: useTimeWindow hook', () => { renderHookAct(() => { result.current.stepForward(); - }) + }); expect(applyTime).toHaveBeenCalledWith({ start: '2025-10-30T11:00:00.000Z', @@ -73,7 +73,7 @@ describe('TimeWindowToolbar: useTimeWindow hook', () => { renderHookAct(() => { result.current.stepBackward(); - }) + }); expect(applyTime).toHaveBeenCalledWith({ start: '2025-10-30T09:00:00.000Z', @@ -88,14 +88,17 @@ describe('TimeWindowToolbar: useTimeWindow hook', () => { const start = '2025-10-30T10:00:00.000Z'; const end = '2025-10-30T11:00:00.000Z'; - const shiftedStart = moment(start).subtract(ZOOM_FACTOR_DEFAULT / 2, 'hours'); + const shiftedStart = moment(start).subtract( + ZOOM_FACTOR_DEFAULT / 2, + 'hours' + ); const shiftedEnd = moment(end).add(ZOOM_FACTOR_DEFAULT / 2, 'hours'); const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); renderHookAct(() => { result.current.expandWindow(); - }) + }); expect(applyTime).toHaveBeenCalledWith({ start: shiftedStart.toISOString(), @@ -109,14 +112,19 @@ describe('TimeWindowToolbar: useTimeWindow hook', () => { const start = '2025-10-30T10:00:00.000Z'; const end = '2025-10-30T11:00:00.000Z'; - const shiftedStart = moment(start).subtract(customZoomFactor / 2, 'hours'); + const shiftedStart = moment(start).subtract( + customZoomFactor / 2, + 'hours' + ); const shiftedEnd = moment(end).add(customZoomFactor / 2, 'hours'); - const { result } = renderHook(() => useTimeWindow(start, end, applyTime, { zoomFactor: customZoomFactor })); + const { result } = renderHook(() => + useTimeWindow(start, end, applyTime, { zoomFactor: customZoomFactor }) + ); renderHookAct(() => { result.current.expandWindow(); - }) + }); expect(applyTime).toHaveBeenCalledWith({ start: shiftedStart.toISOString(), diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index 4ca8e4f33e2..e0ebcb18c9e 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -16,6 +16,7 @@ import { usePrettyInterval } from './pretty_interval'; import { EuiButtonGroupButton } from '../../button/button_group/button_group_button'; import { euiButtonGroupButtonsStyles } from '../../button/button_group/button_group.styles'; import { useEuiMemoizedStyles, useGeneratedHtmlId } from '../../../services'; +import { useEuiI18n } from '../../i18n'; export const ZOOM_FACTOR_DEFAULT = 0.5; @@ -47,13 +48,11 @@ export type TimeWindowButtonsProps = TimeWindowButtonsConfig & { }; /** - * Toolbar for managing the time window with controls for shifting the time window + * Button group with time window controls for shifting the time window * forwards and backwards, and zooming out. * * @todo - * - [ ] translate labels, etc. * - [ ] is `aria-pressed` being rendered causing any trouble? - * - [ ] use `euiButtonGroup__buttons` class? * - [ ] check if hiding tooltips when isDisabled is the right thing to do */ export const TimeWindowButtons: React.FC = ({ @@ -73,25 +72,36 @@ export const TimeWindowButtons: React.FC = ({ const { displayInterval, stepForward, stepBackward, expandWindow } = useTimeWindow(start, end, applyTime, { zoomFactor }); - // Previous const previousId = useGeneratedHtmlId({ prefix: 'previous' }); - const previousLabel = 'Previous'; // TODO translate - const previousTooltipContent = `Previous ${displayInterval}`; // TODO translate + const previousLabel = useEuiI18n( + 'euiTimeWindowButtons.previousLabel', + 'Previous' + ); + const previousTooltipContent = useEuiI18n( + 'euiTimeWindowButtons.previousDescription', + 'Previous {displayInterval}', + { displayInterval } + ); - // Zoom out const zoomOutId = useGeneratedHtmlId({ prefix: 'zoom_out' }); - const zoomOutLabel = 'Zoom out'; // TODO translate + const zoomOutLabel = useEuiI18n( + 'euiTimeWindowButtons.zoomOutLabel', + 'Zoom out' + ); - // Next const nextId = useGeneratedHtmlId({ prefix: 'next' }); - const nextLabel = 'Next'; // TODO translate - const nextTooltipContent = `Next ${displayInterval}`; // TODO translate + const nextLabel = useEuiI18n('euiTimeWindowButtons.nextLabel', 'Next'); + const nextTooltipContent = useEuiI18n( + 'euiTimeWindowButtons.nextDescription', + 'Next {displayInterval}', + { displayInterval } + ); if (!zoomOut && !shiftArrows) return null; return (
@@ -156,7 +166,9 @@ export function useTimeWindow( const min = dateMath.parse(start) as Moment; const max = dateMath.parse(end, { roundUp: true }) as Moment; const windowDuration = max.diff(min); - const zoomFactor = getPercentageMultiplier(options?.zoomFactor ?? ZOOM_FACTOR_DEFAULT); + const zoomFactor = getPercentageMultiplier( + options?.zoomFactor ?? ZOOM_FACTOR_DEFAULT + ); // Gets added to each end, that's why it's split in half const zoomAddition = windowDuration * (zoomFactor / 2); @@ -197,9 +209,7 @@ export function useTimeWindow( /** * Get a number out of either 0.2 or "20%" */ -function getPercentageMultiplier( - value: number | string -) { +function getPercentageMultiplier(value: number | string) { if (typeof value === 'number') return value; return parseInt(String(value).replace('%', '').trim()) / 100; } From 7c70b8230a61a533a9433f5f0bebbd039d7dd8e0 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Thu, 30 Oct 2025 13:44:47 +0100 Subject: [PATCH 14/30] [TimeWindowButtons] Test disabled state --- .../super_date_picker.test.tsx | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx index 1ea82aa4902..1af9ea9e6ea 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx @@ -725,5 +725,41 @@ describe('EuiSuperDatePicker', () => { expect(initialTimeEnd).toBeLessThan(updatedTimeEnd); }); }); + + it('is disabled when date/time range is invalid', async () => { + // reversed range (invalid) + const start = '2025-10-30T14:00:00.000Z'; + const end = '2025-10-31T14:00:00.000Z'; + + const { rerender, queryByTestSubject } = render( + {}} + showTimeWindowButtons={true} + /> + ); + + expect(queryByTestSubject('timeWindowButtonsPrevious')!).toBeDisabled(); + expect(queryByTestSubject('timeWindowButtonsZoomOut')!).toBeDisabled(); + expect(queryByTestSubject('timeWindowButtonsNext')!).toBeDisabled(); + + rerender( + {}} + showTimeWindowButtons={true} + /> + ); + + expect( + queryByTestSubject('timeWindowButtonsPrevious')! + ).not.toBeDisabled(); + expect( + queryByTestSubject('timeWindowButtonsZoomOut')! + ).not.toBeDisabled(); + expect(queryByTestSubject('timeWindowButtonsNext')!).not.toBeDisabled(); + }); }); }); From 034a66b63642684a21c84b01625e40c2e1686027 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Thu, 30 Oct 2025 14:50:56 +0100 Subject: [PATCH 15/30] Remove leftovers of previous toolbar naming --- .../date_picker/super_date_picker/super_date_picker.tsx | 4 ++-- .../super_date_picker/time_window_buttons.test.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx index 2c1f744679b..8ccdcad0c25 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx @@ -207,8 +207,8 @@ export type EuiSuperDatePickerProps = CommonProps & { showUpdateButton?: boolean | 'iconOnly'; /** - * Set to true to display a toolbar next to the top-level control - * with buttons for zooming out and time shifting. + * Set to true to display buttons for time shifting and zooming out, + * next to the top-level control. */ showTimeWindowButtons?: boolean | TimeWindowButtonsConfig; diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx index 21adf535f61..95b288a66e3 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx @@ -11,7 +11,7 @@ import { renderHook, renderHookAct } from '../../../test/rtl'; import { useTimeWindow, ZOOM_FACTOR_DEFAULT } from './time_window_buttons'; -describe('TimeWindowToolbar: useTimeWindow hook', () => { +describe('TimeWindowButtons: useTimeWindow hook', () => { describe('displayInterval', () => { it('handles relative times', () => { const applyTime = jest.fn(); From 89ce75e2c284cdb73c6ba848fc3419d9b237a40f Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Thu, 30 Oct 2025 15:18:40 +0100 Subject: [PATCH 16/30] [Docs][EuiSuperDatePicker] Add Time window buttons section --- .../forms/date-and-time/super-date-picker.mdx | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/packages/website/docs/components/forms/date-and-time/super-date-picker.mdx b/packages/website/docs/components/forms/date-and-time/super-date-picker.mdx index 5f84da6fb90..63a708e4c57 100644 --- a/packages/website/docs/components/forms/date-and-time/super-date-picker.mdx +++ b/packages/website/docs/components/forms/date-and-time/super-date-picker.mdx @@ -569,6 +569,59 @@ export default () => { }; ``` +```mdx-code-block +import { ZOOM_FACTOR_DEFAULT } from '@elastic/eui/es/components/date_picker/super_date_picker/time_window_buttons'; +``` + +## Time window buttons + +A button group with buttons to modify the time window (or range) can be shown next to the main control. To show it, pass the `showTimeWindowButtons` prop to the `EuiSuperDatePicker` component. It allows to zoom out the window, or shift it both forwards or backwards. + +Zooming out will expand the window by {ZOOM_FACTOR_DEFAULT * 100}% by default. This is configurable via the `showTimeWindowButtons` prop, by passing a config object with a `zoomFactor` property e.g. `showTimeWindowButtons={{ zoomFactor: 0.42 }}`. + +```tsx interactive +import React, { useState } from 'react'; +import { + EuiSuperDatePicker, + EuiSuperDatePickerProps, + OnTimeChangeProps, +} from '@elastic/eui'; + +export default () => { + const { euiTheme } = useEuiTheme(); + + const [showButtons, setShowButtons] = useState(true); + const [start, setStart] = useState('now-45m'); + const [end, setEnd] = useState('now'); + + const onTimeChange = ({ start, end }: OnTimeChangeProps) => { + setStart(start); + setEnd(end); + }; + + return ( + <> + + setShowButtons(e.target.checked)} + label="Show time window buttons" + /> + + + + + ); +}; +``` + ## Elastic pattern with KQL The following is a demo pattern of how to layout the **EuiSuperDatePicker** alongside Elastic's KQL search bar using [EuiSearchBar](../search-and-filter/search-bar.mdx) and shrinking to fit when the search bar is in focus. From d52cddb1fba0be0b7867b6d171c35bf7e01582e5 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Thu, 30 Oct 2025 15:25:24 +0100 Subject: [PATCH 17/30] [EuiSuperDatePicker] Add TimeWindowButtons story --- .../super_date_picker/super_date_picker.stories.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.stories.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.stories.tsx index 4168682c27f..d70ffe34b5c 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.stories.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.stories.tsx @@ -190,6 +190,14 @@ export const QuickSelectOnly: Story = { }, }; +export const TimeWindowButtons: Story = { + args: { + showTimeWindowButtons: true, + showUpdateButton: false, + }, + render: (args) => , +}; + /** * VRT only */ From 2481264465b8c97b014fbb0d3743e6d3c9e24f43 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Fri, 31 Oct 2025 09:33:45 +0100 Subject: [PATCH 18/30] [Docs] Polish example snippet --- .../forms/date-and-time/super-date-picker.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/website/docs/components/forms/date-and-time/super-date-picker.mdx b/packages/website/docs/components/forms/date-and-time/super-date-picker.mdx index 63a708e4c57..5323c51e36b 100644 --- a/packages/website/docs/components/forms/date-and-time/super-date-picker.mdx +++ b/packages/website/docs/components/forms/date-and-time/super-date-picker.mdx @@ -583,16 +583,16 @@ Zooming out will expand the window by {ZOOM_FACTOR_DEFAULT * 100}% by default. T import React, { useState } from 'react'; import { EuiSuperDatePicker, - EuiSuperDatePickerProps, + EuiFlexGroup, + EuiSwitch, + EuiSpacer, OnTimeChangeProps, -} from '@elastic/eui'; +} from "@elastic/eui"; export default () => { - const { euiTheme } = useEuiTheme(); - const [showButtons, setShowButtons] = useState(true); - const [start, setStart] = useState('now-45m'); - const [end, setEnd] = useState('now'); + const [start, setStart] = useState("now-15m"); + const [end, setEnd] = useState("now"); const onTimeChange = ({ start, end }: OnTimeChangeProps) => { setStart(start); @@ -615,7 +615,7 @@ export default () => { onTimeChange={onTimeChange} showTimeWindowButtons={showButtons} showUpdateButton={false} - width={'auto'} + width={"full"} /> ); From 68a1f472b83c7604ce63b2a0e63ebc44b3b8db1d Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Fri, 31 Oct 2025 09:48:17 +0100 Subject: [PATCH 19/30] [TimeWindowButtons] Improve screen-reader output the aria-pressed attribute on buttons needs to be removed, in a different PR --- .../date_picker/super_date_picker/time_window_buttons.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index e0ebcb18c9e..fef7dc23487 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -50,10 +50,6 @@ export type TimeWindowButtonsProps = TimeWindowButtonsConfig & { /** * Button group with time window controls for shifting the time window * forwards and backwards, and zooming out. - * - * @todo - * - [ ] is `aria-pressed` being rendered causing any trouble? - * - [ ] check if hiding tooltips when isDisabled is the right thing to do */ export const TimeWindowButtons: React.FC = ({ applyTime, @@ -110,6 +106,7 @@ export const TimeWindowButtons: React.FC = ({ id={previousId} data-test-subj="timeWindowButtonsPrevious" label={previousLabel} + title='' toolTipContent={!isDisabled && previousTooltipContent} color={buttonColor} size={buttonSize} @@ -125,7 +122,9 @@ export const TimeWindowButtons: React.FC = ({ id={zoomOutId} data-test-subj="timeWindowButtonsZoomOut" label={zoomOutLabel} + title='' toolTipContent={!isDisabled && zoomOutLabel} + toolTipProps={{ disableScreenReaderOutput: true }} color={buttonColor} size={buttonSize} iconType="magnifyWithMinus" @@ -140,6 +139,7 @@ export const TimeWindowButtons: React.FC = ({ id={nextId} data-test-subj="timeWindowButtonsNext" label={nextLabel} + title='' toolTipContent={!isDisabled && nextTooltipContent} color={buttonColor} size={buttonSize} From cb338c75aba24f823f534a14326b2d0c3859fd52 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Fri, 31 Oct 2025 10:15:38 +0100 Subject: [PATCH 20/30] [TimeWindowButtons] Fix compressed styles --- .../date_picker/super_date_picker/time_window_buttons.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index fef7dc23487..10986b479f2 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -62,7 +62,8 @@ export const TimeWindowButtons: React.FC = ({ zoomFactor = ZOOM_FACTOR_DEFAULT, }) => { const buttonColor = 'text'; - const buttonSize = compressed ? 'compressed' : 'm'; + const buttonSize = compressed ? 's' : 'm'; + const iconSize = compressed ? 's' : 'm'; const styles = useEuiMemoizedStyles(euiButtonGroupButtonsStyles); const { displayInterval, stepForward, stepBackward, expandWindow } = @@ -111,6 +112,7 @@ export const TimeWindowButtons: React.FC = ({ color={buttonColor} size={buttonSize} iconType="arrowLeft" + iconSize={iconSize} isIconOnly isSelected={false} isDisabled={isDisabled} @@ -128,6 +130,7 @@ export const TimeWindowButtons: React.FC = ({ color={buttonColor} size={buttonSize} iconType="magnifyWithMinus" + iconSize={iconSize} isIconOnly isSelected={false} isDisabled={isDisabled} @@ -144,6 +147,7 @@ export const TimeWindowButtons: React.FC = ({ color={buttonColor} size={buttonSize} iconType="arrowRight" + iconSize={iconSize} isIconOnly isSelected={false} isDisabled={isDisabled} From c7a15596f7dcab74b285306340934f33943f7d97 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Fri, 31 Oct 2025 10:51:10 +0100 Subject: [PATCH 21/30] Update VRT might need another update if EuiButtonGroupButton gets updated too --- ...r_EuiSuperDatePicker_Quick_Select_Only.png | Bin 18968 -> 18959 bytes ...EuiSuperDatePicker_Time_Window_Buttons.png | Bin 0 -> 4299 bytes ...r_EuiSuperDatePicker_Quick_Select_Only.png | Bin 34426 -> 34430 bytes ...EuiSuperDatePicker_Time_Window_Buttons.png | Bin 0 -> 8028 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Time_Window_Buttons.png create mode 100644 packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Time_Window_Buttons.png diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Quick_Select_Only.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Quick_Select_Only.png index d2984d4a0be825c43ff16f229167d11f39e4174d..c8987f6687ed1790cdf9bfe060d73a436fb9bc5b 100644 GIT binary patch literal 18959 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 literal 18968 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 diff --git a/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Time_Window_Buttons.png b/packages/eui/.loki/reference/chrome_desktop_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Time_Window_Buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..05ef003b1d3aac730f781b131eb0e3d1a8ca7a75 GIT binary patch literal 4299 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Ⓢ_vGlkBmzj{wszgj@z-S0v}5 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 diff --git a/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Time_Window_Buttons.png b/packages/eui/.loki/reference/chrome_mobile_Forms_EuiSuperDatePicker_EuiSuperDatePicker_Time_Window_Buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..94bac6e6ed145015c927341e1fde8bf77b303e3b GIT binary patch literal 8028 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 literal 0 HcmV?d00001 From ce59f27acd2d3ff8c50289203821ac7b538fa828 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Fri, 31 Oct 2025 10:53:29 +0100 Subject: [PATCH 22/30] Changelog --- packages/eui/changelogs/upcoming/9151.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 packages/eui/changelogs/upcoming/9151.md diff --git a/packages/eui/changelogs/upcoming/9151.md b/packages/eui/changelogs/upcoming/9151.md new file mode 100644 index 00000000000..548300f184c --- /dev/null +++ b/packages/eui/changelogs/upcoming/9151.md @@ -0,0 +1,2 @@ +- Updated `EuiSuperDatePicker` with new time window buttons for time shifting and zoom out, opt-in via `showTimeWindowButtons` boolean prop. + From da66b3c13b263017c6c31a16aa85560263c43c75 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Fri, 31 Oct 2025 11:46:03 +0100 Subject: [PATCH 23/30] Lint, argh --- .../date_picker/super_date_picker/time_window_buttons.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index 10986b479f2..7b3b7d37bf5 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -107,7 +107,7 @@ export const TimeWindowButtons: React.FC = ({ id={previousId} data-test-subj="timeWindowButtonsPrevious" label={previousLabel} - title='' + title="" toolTipContent={!isDisabled && previousTooltipContent} color={buttonColor} size={buttonSize} @@ -124,7 +124,7 @@ export const TimeWindowButtons: React.FC = ({ id={zoomOutId} data-test-subj="timeWindowButtonsZoomOut" label={zoomOutLabel} - title='' + title="" toolTipContent={!isDisabled && zoomOutLabel} toolTipProps={{ disableScreenReaderOutput: true }} color={buttonColor} @@ -142,7 +142,7 @@ export const TimeWindowButtons: React.FC = ({ id={nextId} data-test-subj="timeWindowButtonsNext" label={nextLabel} - title='' + title="" toolTipContent={!isDisabled && nextTooltipContent} color={buttonColor} size={buttonSize} From 5de76819b77bf2715354ed9828b264881b10750b Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Tue, 4 Nov 2025 12:56:15 +0100 Subject: [PATCH 24/30] [EuiSuperDatePicker][Tests] Remove unnecessary bangs --- .../super_date_picker.test.tsx | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx index 1af9ea9e6ea..40381fcbf47 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx @@ -669,7 +669,7 @@ describe('EuiSuperDatePicker', () => { const end = '2025-10-30T13:00:00.000Z'; let lastTimeChange: { start: string; end: string } = { start, end }; - const { queryByTestSubject } = render( + const { getByTestSubject } = render( { ); act(() => { - userEvent.click(queryByTestSubject('timeWindowButtonsPrevious')!); + userEvent.click(getByTestSubject('timeWindowButtonsPrevious')); }); await waitFor(() => { @@ -700,7 +700,7 @@ describe('EuiSuperDatePicker', () => { const end = '2025-10-31T12:00:00.000Z'; let lastTimeChange: { start: string; end: string } = { start, end }; - const { queryByTestSubject } = render( + const { getByTestSubject } = render( { ); act(() => { - userEvent.click(queryByTestSubject('timeWindowButtonsZoomOut')!); + userEvent.click(getByTestSubject('timeWindowButtonsZoomOut')); }); await waitFor(() => { @@ -731,7 +731,7 @@ describe('EuiSuperDatePicker', () => { const start = '2025-10-30T14:00:00.000Z'; const end = '2025-10-31T14:00:00.000Z'; - const { rerender, queryByTestSubject } = render( + const { rerender, getByTestSubject } = render( { /> ); - expect(queryByTestSubject('timeWindowButtonsPrevious')!).toBeDisabled(); - expect(queryByTestSubject('timeWindowButtonsZoomOut')!).toBeDisabled(); - expect(queryByTestSubject('timeWindowButtonsNext')!).toBeDisabled(); + expect(getByTestSubject('timeWindowButtonsPrevious')).toBeDisabled(); + expect(getByTestSubject('timeWindowButtonsZoomOut')).toBeDisabled(); + expect(getByTestSubject('timeWindowButtonsNext')).toBeDisabled(); rerender( { /> ); - expect( - queryByTestSubject('timeWindowButtonsPrevious')! - ).not.toBeDisabled(); - expect( - queryByTestSubject('timeWindowButtonsZoomOut')! - ).not.toBeDisabled(); - expect(queryByTestSubject('timeWindowButtonsNext')!).not.toBeDisabled(); + expect(getByTestSubject('timeWindowButtonsPrevious')).not.toBeDisabled(); + expect(getByTestSubject('timeWindowButtonsZoomOut')).not.toBeDisabled(); + expect(getByTestSubject('timeWindowButtonsNext')).not.toBeDisabled(); }); }); }); From 6c50c8b9ba581591895ace1d36e280820671477a Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Tue, 4 Nov 2025 13:01:58 +0100 Subject: [PATCH 25/30] [TimeWindowButtons] Rename config props to be more explicit --- .../super_date_picker/time_window_buttons.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index 7b3b7d37bf5..5d3b1480fee 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -25,12 +25,12 @@ export interface TimeWindowButtonsConfig { * Show button for zooming out * @default true */ - zoomOut?: boolean; + showZoomOut?: boolean; /** * Show buttons for shifting the time window forward and backward * @default true */ - shiftArrows?: boolean; + showShiftArrows?: boolean; /** * How much the time window is increased when zooming. * Can be a number (0.25) or a string representing a percentage (25%) @@ -57,8 +57,8 @@ export const TimeWindowButtons: React.FC = ({ end, compressed, isDisabled, - zoomOut = true, - shiftArrows = true, + showZoomOut = true, + showShiftArrows = true, zoomFactor = ZOOM_FACTOR_DEFAULT, }) => { const buttonColor = 'text'; @@ -94,7 +94,7 @@ export const TimeWindowButtons: React.FC = ({ { displayInterval } ); - if (!zoomOut && !shiftArrows) return null; + if (!showZoomOut && !showShiftArrows) return null; return (
= ({ css={[styles.euiButtonGroup__buttons, styles[buttonSize]]} data-test-subj="timeWindowButtons" > - {shiftArrows && ( + {showShiftArrows && ( = ({ onClick={stepBackward} /> )} - {zoomOut && ( + {showZoomOut && ( = ({ onClick={expandWindow} /> )} - {shiftArrows && ( + {showShiftArrows && ( Date: Tue, 4 Nov 2025 13:04:00 +0100 Subject: [PATCH 26/30] [TimeWindowButtons] Do not show when isAutoRefreshOnly is true --- .../date_picker/super_date_picker/super_date_picker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx index 8ccdcad0c25..68e130e31d2 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.tsx @@ -736,7 +736,7 @@ export class EuiSuperDatePickerInternal extends Component< }; renderTimeWindowButtons = () => { - if (!this.props.showTimeWindowButtons) { + if (!this.props.showTimeWindowButtons || this.props.isAutoRefreshOnly) { return null; } const { start, end, showTimeWindowButtons, compressed, isDisabled } = From a5e2e0d082844446784a208318626dfcf0605f0b Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Tue, 4 Nov 2025 13:15:55 +0100 Subject: [PATCH 27/30] [EuiSuperDatePicker] Move isRelativeToNow util to shared utils file --- .../super_date_picker/pretty_duration.tsx | 12 +----------- .../super_date_picker/relative_utils.ts | 16 +++++++++++++++- .../super_date_picker/time_window_buttons.tsx | 5 +---- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/pretty_duration.tsx b/packages/eui/src/components/date_picker/super_date_picker/pretty_duration.tsx index 3f6f36d2ef0..494ac1ceb6f 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/pretty_duration.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/pretty_duration.tsx @@ -11,7 +11,7 @@ import dateMath from '@elastic/datemath'; import moment, { LocaleSpecifier, RelativeTimeKey } from 'moment'; // eslint-disable-line import/named import { useEuiI18n } from '../../i18n'; import { getDateMode, DATE_MODES } from './date_modes'; -import { parseRelativeParts } from './relative_utils'; +import { parseRelativeParts, isRelativeToNow } from './relative_utils'; import { useI18nTimeOptions } from './time_options'; import { DurationRange, @@ -315,16 +315,6 @@ const hasRangeMatch = ( return ranges.find(({ start, end }) => timeFrom === start && timeTo === end); }; -const isRelativeToNow = (timeFrom: ShortDate, timeTo: ShortDate): boolean => { - const fromDateMode = getDateMode(timeFrom); - const toDateMode = getDateMode(timeTo); - const isLast = - fromDateMode === DATE_MODES.RELATIVE && toDateMode === DATE_MODES.NOW; - const isNext = - fromDateMode === DATE_MODES.NOW && toDateMode === DATE_MODES.RELATIVE; - return isLast || isNext; -}; - export const showPrettyDuration = ( timeFrom: ShortDate, timeTo: ShortDate, diff --git a/packages/eui/src/components/date_picker/super_date_picker/relative_utils.ts b/packages/eui/src/components/date_picker/super_date_picker/relative_utils.ts index 9ad0b211f6c..43bd15ef60e 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/relative_utils.ts +++ b/packages/eui/src/components/date_picker/super_date_picker/relative_utils.ts @@ -11,7 +11,8 @@ import moment from 'moment'; import { get } from '../../../services/objects'; import { isString } from '../../../services/predicate'; -import { TimeUnitId, RelativeParts } from '../types'; +import { TimeUnitId, RelativeParts, ShortDate } from '../types'; +import { getDateMode, DATE_MODES } from './date_modes'; const ROUND_DELIMETER = '/'; @@ -80,3 +81,16 @@ export const toRelativeStringFromParts = (relativeParts: RelativeParts) => { return `now${operator}${count}${unit}${round}`; }; + +export const isRelativeToNow = ( + timeFrom: ShortDate, + timeTo: ShortDate +): boolean => { + const fromDateMode = getDateMode(timeFrom); + const toDateMode = getDateMode(timeTo); + const isLast = + fromDateMode === DATE_MODES.RELATIVE && toDateMode === DATE_MODES.NOW; + const isNext = + fromDateMode === DATE_MODES.NOW && toDateMode === DATE_MODES.RELATIVE; + return isLast || isNext; +}; diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index 5d3b1480fee..3d09711760e 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -12,6 +12,7 @@ import moment, { Moment } from 'moment'; import { ShortDate, ApplyTime } from '../types'; import { usePrettyInterval } from './pretty_interval'; +import { isRelativeToNow } from './relative_utils'; import { EuiButtonGroupButton } from '../../button/button_group/button_group_button'; import { euiButtonGroupButtonsStyles } from '../../button/button_group/button_group.styles'; @@ -225,7 +226,3 @@ function isExactMinuteRange(diffMs: number) { // 60 * 1000 = ms per minute return diffMs % (60 * 1000) === 0; } - -function isRelativeToNow(start: ShortDate, end: ShortDate) { - return String(end).includes('now') || String(start).includes('now'); -} From 8b65549d570b82a72f82915c33ee2b271d9c9ff4 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Tue, 4 Nov 2025 16:05:14 +0100 Subject: [PATCH 28/30] [TimeWindowButtons] Improve date/time parsing, more gracefully handle invalid states --- .../time_window_buttons.test.tsx.snap | 87 +++++++++++++++++++ .../time_window_buttons.test.tsx | 81 ++++++++++++++++- .../super_date_picker/time_window_buttons.tsx | 63 ++++++++++---- 3 files changed, 212 insertions(+), 19 deletions(-) create mode 100644 packages/eui/src/components/date_picker/super_date_picker/__snapshots__/time_window_buttons.test.tsx.snap diff --git a/packages/eui/src/components/date_picker/super_date_picker/__snapshots__/time_window_buttons.test.tsx.snap b/packages/eui/src/components/date_picker/super_date_picker/__snapshots__/time_window_buttons.test.tsx.snap new file mode 100644 index 00000000000..470d1f49ae9 --- /dev/null +++ b/packages/eui/src/components/date_picker/super_date_picker/__snapshots__/time_window_buttons.test.tsx.snap @@ -0,0 +1,87 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TimeWindowButtons renders 1`] = ` +
+ + + + + + + + + +
+`; diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx index 95b288a66e3..0be19f9c9e4 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.test.tsx @@ -5,11 +5,23 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import React from 'react'; import moment from 'moment'; -import { renderHook, renderHookAct } from '../../../test/rtl'; - -import { useTimeWindow, ZOOM_FACTOR_DEFAULT } from './time_window_buttons'; +import { act, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { + render, + renderHook, + renderHookAct, + waitForEuiToolTipVisible, +} from '../../../test/rtl'; + +import { + TimeWindowButtons, + useTimeWindow, + ZOOM_FACTOR_DEFAULT, +} from './time_window_buttons'; describe('TimeWindowButtons: useTimeWindow hook', () => { describe('displayInterval', () => { @@ -33,6 +45,29 @@ describe('TimeWindowButtons: useTimeWindow hook', () => { expect(result.current.displayInterval).toBe('15 minutes'); }); + it('handles invalid time (undefined)', () => { + const applyTime = jest.fn(); + const start = undefined; + const end = '2025-10-29T16:15:00.000Z'; + + // @ts-expect-error - intentionally testing with undefined start value + const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); + + expect(result.current.displayInterval).toBe(''); + expect(result.current.isInvalid).toBeTruthy(); + }); + + it('handles invalid time', () => { + const applyTime = jest.fn(); + const start = '2025-10-29T16:00:00.000Z'; + const end = 'not a date'; + + const { result } = renderHook(() => useTimeWindow(start, end, applyTime)); + + expect(result.current.displayInterval).toBe(''); + expect(result.current.isInvalid).toBeTruthy(); + }); + it('adds a tilde for approximate ranges', () => { const applyTime = jest.fn(); const start = '2025-10-27T16:00:01.000Z'; @@ -133,3 +168,41 @@ describe('TimeWindowButtons: useTimeWindow hook', () => { }); }); }); + +describe('TimeWindowButtons', () => { + it('renders', () => { + const start = 'now-15m'; + const end = 'now'; + + const { container } = render( + {}} /> + ); + + expect(container.firstChild).toMatchSnapshot(); + }); + + // This will not happen at all, because any invalid time range will toggle the buttons disabled, + // but we provide it in case requirements change + it('handles invalid times gracefully', async () => { + const apply = jest.fn(); + const start = 'not a date'; + const end = 'now'; + + const { getByTestSubject, getByRole } = render( + + ); + + act(() => { + userEvent.click(getByTestSubject('timeWindowButtonsPrevious')); + userEvent.click(getByTestSubject('timeWindowButtonsZoomOut')); + userEvent.click(getByTestSubject('timeWindowButtonsNext')); + }); + + expect(apply).not.toHaveBeenCalled(); + + fireEvent.mouseEnter(getByTestSubject('timeWindowButtonsZoomOut')); + await waitForEuiToolTipVisible(); + + expect(getByRole('tooltip')).toHaveTextContent(/Cannot/); + }); +}); diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index 3d09711760e..398755e2cc5 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -8,7 +8,7 @@ import React from 'react'; import dateMath from '@elastic/datemath'; -import moment, { Moment } from 'moment'; +import moment from 'moment'; import { ShortDate, ApplyTime } from '../types'; import { usePrettyInterval } from './pretty_interval'; @@ -67,8 +67,22 @@ export const TimeWindowButtons: React.FC = ({ const iconSize = compressed ? 's' : 'm'; const styles = useEuiMemoizedStyles(euiButtonGroupButtonsStyles); - const { displayInterval, stepForward, stepBackward, expandWindow } = - useTimeWindow(start, end, applyTime, { zoomFactor }); + const { + displayInterval, + isInvalid, + stepForward, + stepBackward, + expandWindow, + } = useTimeWindow(start, end, applyTime, { zoomFactor }); + + const invalidShiftDescription = useEuiI18n( + 'euiTimeWindowButtons.invalidShiftLabel', + 'Cannot shift invalid time window' + ); + const invalidZoomOutDescription = useEuiI18n( + 'euiTimeWindowButtons.invalidZoomOutLabel', + 'Cannot zoom out invalid time window' + ); const previousId = useGeneratedHtmlId({ prefix: 'previous' }); const previousLabel = useEuiI18n( @@ -86,6 +100,9 @@ export const TimeWindowButtons: React.FC = ({ 'euiTimeWindowButtons.zoomOutLabel', 'Zoom out' ); + const zoomOutTooltipContent = isInvalid + ? invalidZoomOutDescription + : zoomOutLabel; const nextId = useGeneratedHtmlId({ prefix: 'next' }); const nextLabel = useEuiI18n('euiTimeWindowButtons.nextLabel', 'Next'); @@ -109,7 +126,10 @@ export const TimeWindowButtons: React.FC = ({ data-test-subj="timeWindowButtonsPrevious" label={previousLabel} title="" - toolTipContent={!isDisabled && previousTooltipContent} + toolTipContent={ + !isDisabled && + (isInvalid ? invalidShiftDescription : previousTooltipContent) + } color={buttonColor} size={buttonSize} iconType="arrowLeft" @@ -126,8 +146,10 @@ export const TimeWindowButtons: React.FC = ({ data-test-subj="timeWindowButtonsZoomOut" label={zoomOutLabel} title="" - toolTipContent={!isDisabled && zoomOutLabel} - toolTipProps={{ disableScreenReaderOutput: true }} + toolTipContent={!isDisabled && zoomOutTooltipContent} + toolTipProps={{ + disableScreenReaderOutput: zoomOutLabel === zoomOutTooltipContent, + }} color={buttonColor} size={buttonSize} iconType="magnifyWithMinus" @@ -144,7 +166,10 @@ export const TimeWindowButtons: React.FC = ({ data-test-subj="timeWindowButtonsNext" label={nextLabel} title="" - toolTipContent={!isDisabled && nextTooltipContent} + toolTipContent={ + !isDisabled && + (isInvalid ? invalidShiftDescription : nextTooltipContent) + } color={buttonColor} size={buttonSize} iconType="arrowRight" @@ -168,28 +193,34 @@ export function useTimeWindow( apply: ApplyTime, options?: { zoomFactor?: TimeWindowButtonsConfig['zoomFactor'] } ) { - const min = dateMath.parse(start) as Moment; - const max = dateMath.parse(end, { roundUp: true }) as Moment; - const windowDuration = max.diff(min); + const min = dateMath.parse(start); + const max = dateMath.parse(end, { roundUp: true }); + const isInvalid = !min || !min.isValid() || !max || !max.isValid(); + const windowDuration = isInvalid ? 1 : max.diff(min); const zoomFactor = getPercentageMultiplier( options?.zoomFactor ?? ZOOM_FACTOR_DEFAULT ); - // Gets added to each end, that's why it's split in half - const zoomAddition = windowDuration * (zoomFactor / 2); - - let displayInterval = usePrettyInterval(false, windowDuration); - if (!isRelativeToNow(start, end) && !isExactMinuteRange(windowDuration)) { + const zoomAddition = windowDuration * (zoomFactor / 2); // Gets added to each end, that's why it's split in half + const prettyInterval = usePrettyInterval(false, windowDuration); + let displayInterval = isInvalid ? '' : prettyInterval; + if ( + !isInvalid && + !isRelativeToNow(start, end) && + !isExactMinuteRange(windowDuration) + ) { displayInterval = `~${displayInterval}`; } return { displayInterval, + isInvalid, stepForward, stepBackward, expandWindow, }; function stepForward() { + if (isInvalid) return; apply({ start: moment(max).toISOString(), end: moment(max).add(windowDuration, 'ms').toISOString(), @@ -197,6 +228,7 @@ export function useTimeWindow( } function stepBackward() { + if (isInvalid) return; apply({ start: moment(min).subtract(windowDuration, 'ms').toISOString(), end: moment(min).toISOString(), @@ -204,6 +236,7 @@ export function useTimeWindow( } function expandWindow() { + if (isInvalid) return; apply({ start: moment(min).subtract(zoomAddition, 'ms').toISOString(), end: moment(max).add(zoomAddition, 'ms').toISOString(), From cd48c7a3e2d3c8ce9b388200c3dafaaac86a083a Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Tue, 4 Nov 2025 17:10:32 +0100 Subject: [PATCH 29/30] [TimeWindowButtons] Improve util that provides final zoom factor value --- .../super_date_picker/time_window_buttons.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx index 398755e2cc5..38e0a2e68ba 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/time_window_buttons.tsx @@ -34,7 +34,7 @@ export interface TimeWindowButtonsConfig { showShiftArrows?: boolean; /** * How much the time window is increased when zooming. - * Can be a number (0.25) or a string representing a percentage (25%) + * A number between 0 and 1 e.g. 0.25, or a string representing a percentage e.g. 25% * @default 0.5 * */ zoomFactor?: number | string; @@ -248,8 +248,15 @@ export function useTimeWindow( * Get a number out of either 0.2 or "20%" */ function getPercentageMultiplier(value: number | string) { - if (typeof value === 'number') return value; - return parseInt(String(value).replace('%', '').trim()) / 100; + const result = + typeof value === 'number' + ? value + : parseFloat(String(value).replace('%', '').trim()); + if (isNaN(result)) + throw new TypeError( + 'Please provide a valid number or percentage string e.g. "25%"' + ); + return result > 1 ? result / 100 : result; } /** From 286650c5bba92f3e5b8c2444499ab47ac0d39e42 Mon Sep 17 00:00:00 2001 From: Arturo Castillo Delgado Date: Wed, 5 Nov 2025 09:44:54 +0100 Subject: [PATCH 30/30] [EuiSuperDatePicker] Test actual time shifted or zoomed out --- .../super_date_picker/super_date_picker.test.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx index 40381fcbf47..dc72e4e0443 100644 --- a/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx +++ b/packages/eui/src/components/date_picker/super_date_picker/super_date_picker.test.tsx @@ -19,6 +19,7 @@ import { EuiSuperDatePicker, EuiSuperDatePickerProps, } from './super_date_picker'; +import { ZOOM_FACTOR_DEFAULT } from './time_window_buttons'; const noop = () => {}; @@ -667,6 +668,8 @@ describe('EuiSuperDatePicker', () => { it('updates time when shifting', async () => { const start = '2025-10-30T12:00:00.000Z'; const end = '2025-10-30T13:00:00.000Z'; + const stepBackwardStart = '2025-10-30T11:00:00.000Z'; + const stepBackwardEnd = '2025-10-30T12:00:00.000Z'; let lastTimeChange: { start: string; end: string } = { start, end }; const { getByTestSubject } = render( @@ -686,12 +689,20 @@ describe('EuiSuperDatePicker', () => { }); await waitFor(() => { + expect(lastTimeChange.end).toEqual(stepBackwardEnd); + expect(lastTimeChange.start).toEqual(stepBackwardStart); + const initialTimeStart = new Date(start).getTime(); const updatedTimeStart = new Date(lastTimeChange.start).getTime(); const initialTimeEnd = new Date(end).getTime(); const updatedTimeEnd = new Date(lastTimeChange.end).getTime(); + expect(initialTimeStart).toBeGreaterThan(updatedTimeStart); expect(initialTimeEnd).toBeGreaterThan(updatedTimeEnd); + // Also check the diff is the same + expect(initialTimeEnd - initialTimeStart).toEqual( + updatedTimeEnd - updatedTimeStart + ); }); }); @@ -723,6 +734,10 @@ describe('EuiSuperDatePicker', () => { const updatedTimeEnd = new Date(lastTimeChange.end).getTime(); expect(initialTimeStart).toBeGreaterThan(updatedTimeStart); expect(initialTimeEnd).toBeLessThan(updatedTimeEnd); + // Check the diff expanded by zoom factor + expect( + (initialTimeEnd - initialTimeStart) * (1 + ZOOM_FACTOR_DEFAULT) + ).toEqual(updatedTimeEnd - updatedTimeStart); }); });