diff --git a/changelogs/upcoming/7516.md b/changelogs/upcoming/7516.md
new file mode 100644
index 00000000000..f05e82de4e9
--- /dev/null
+++ b/changelogs/upcoming/7516.md
@@ -0,0 +1,2 @@
+- Updated `EuiSuperDatePicker` with a new `refreshMinInterval` prop, which accepts a minimum number in milliseconds
+- Updated `EuiAutoRefresh` and `EuiRefreshInterval` with a new `minInterval` prop, which accepts a minimum number in milliseconds
diff --git a/src/components/date_picker/auto_refresh/auto_refresh.test.tsx b/src/components/date_picker/auto_refresh/auto_refresh.test.tsx
index 9edbcc3f546..fe6a4ff158f 100644
--- a/src/components/date_picker/auto_refresh/auto_refresh.test.tsx
+++ b/src/components/date_picker/auto_refresh/auto_refresh.test.tsx
@@ -42,6 +42,49 @@ describe('EuiAutoRefresh', () => {
expect(container.firstChild).toMatchSnapshot();
});
+ test('minInterval renders an invalid warning on the number input', () => {
+ const onRefreshChange = jest.fn();
+ const { getByRole, getByTestSubject } = render(
+
+ );
+ const getNumberInput = () =>
+ getByTestSubject('superDatePickerRefreshIntervalInput');
+ const getUnitSelect = () =>
+ getByTestSubject('superDatePickerRefreshIntervalUnitsSelect');
+
+ fireEvent.click(getByRole('button'));
+ expect(getNumberInput()).toBeInvalid();
+
+ fireEvent.change(getUnitSelect(), { target: { value: 'm' } });
+ expect(onRefreshChange).toHaveBeenLastCalledWith({
+ refreshInterval: 60000,
+ intervalUnits: 'm',
+ isPaused: false,
+ });
+ expect(getNumberInput()).toBeValid();
+
+ fireEvent.change(getUnitSelect(), { target: { value: 's' } });
+ expect(onRefreshChange).toHaveBeenLastCalledWith({
+ refreshInterval: 3000, // Should pass back the minimum instead of the current 1000 value
+ intervalUnits: 's',
+ isPaused: false,
+ });
+ expect(getNumberInput()).toBeInvalid();
+
+ fireEvent.change(getNumberInput(), { target: { value: 5 } });
+ expect(onRefreshChange).toHaveBeenLastCalledWith({
+ refreshInterval: 5000,
+ intervalUnits: 's',
+ isPaused: false,
+ });
+ expect(getNumberInput()).toBeValid();
+ });
+
test('intervalUnits forces rendering in the provided units', () => {
const { getByLabelText, getByRole, getByTestSubject } = render(
= ({
isDisabled,
isPaused = true,
refreshInterval = 1000,
+ minInterval = 0,
readOnly = true,
...rest
}) => {
@@ -90,6 +91,7 @@ export const EuiAutoRefresh: FunctionComponent = ({
onRefreshChange={onRefreshChange}
isPaused={isPaused}
refreshInterval={refreshInterval}
+ minInterval={minInterval}
intervalUnits={intervalUnits}
/>
@@ -115,6 +117,7 @@ export const EuiAutoRefreshButton: FunctionComponent<
isDisabled,
isPaused = true,
refreshInterval = 1000,
+ minInterval = 0,
shortHand = false,
size = 's',
color = 'text',
@@ -168,6 +171,7 @@ export const EuiAutoRefreshButton: FunctionComponent<
onRefreshChange={onRefreshChange}
isPaused={isPaused}
refreshInterval={refreshInterval}
+ minInterval={minInterval}
intervalUnits={intervalUnits}
/>
diff --git a/src/components/date_picker/auto_refresh/refresh_interval.tsx b/src/components/date_picker/auto_refresh/refresh_interval.tsx
index 5c86a7ef997..9de28b0775e 100644
--- a/src/components/date_picker/auto_refresh/refresh_interval.tsx
+++ b/src/components/date_picker/auto_refresh/refresh_interval.tsx
@@ -30,10 +30,10 @@ const MILLISECONDS_IN_SECOND = 1000;
const MILLISECONDS_IN_MINUTE = MILLISECONDS_IN_SECOND * 60;
const MILLISECONDS_IN_HOUR = MILLISECONDS_IN_MINUTE * 60;
-function fromMilliseconds(
+const fromMilliseconds = (
milliseconds: Milliseconds,
unit?: RefreshUnitsOptions
-): EuiRefreshIntervalState {
+): EuiRefreshIntervalState => {
const round = (value: number) => parseFloat(value.toFixed(2));
if (unit === 'h' || (!unit && milliseconds > MILLISECONDS_IN_HOUR)) {
return {
@@ -53,9 +53,9 @@ function fromMilliseconds(
units: 's',
value: round(milliseconds / MILLISECONDS_IN_SECOND),
};
-}
+};
-function toMilliseconds(units: RefreshUnitsOptions, value: Milliseconds) {
+const toMilliseconds = (units: RefreshUnitsOptions, value: Milliseconds) => {
switch (units) {
case 'h':
return Math.round(value * MILLISECONDS_IN_HOUR);
@@ -65,7 +65,16 @@ function toMilliseconds(units: RefreshUnitsOptions, value: Milliseconds) {
default:
return Math.round(value * MILLISECONDS_IN_SECOND);
}
-}
+};
+
+const getMinInterval = (
+ minInterval?: Milliseconds,
+ unit?: RefreshUnitsOptions
+): number => {
+ if (!minInterval) return 0;
+ const { value } = fromMilliseconds(minInterval, unit);
+ return Math.floor(value || 0);
+};
export type EuiRefreshIntervalProps = {
/**
@@ -77,9 +86,9 @@ export type EuiRefreshIntervalProps = {
*/
refreshInterval?: Milliseconds;
/**
- * Passes back the updated state of `isPaused` `refreshInterval`, and `intervalUnits`.
+ * Allows specifying a minimum interval in milliseconds
*/
- onRefreshChange: ApplyRefreshInterval;
+ minInterval?: Milliseconds;
/**
* By default, refresh interval units will be rounded up to next largest unit of time
* (for example, 90 seconds will become 2m).
@@ -87,11 +96,16 @@ export type EuiRefreshIntervalProps = {
* If you do not want this behavior, you can manually control the rendered unit via this prop.
*/
intervalUnits?: RefreshUnitsOptions;
+ /**
+ * Passes back the updated state of `isPaused`, `refreshInterval`, and `intervalUnits`.
+ */
+ onRefreshChange: ApplyRefreshInterval;
};
interface EuiRefreshIntervalState {
value: number | '';
units: RefreshUnitsOptions;
+ min?: Milliseconds;
}
export class EuiRefreshInterval extends Component<
@@ -101,12 +115,16 @@ export class EuiRefreshInterval extends Component<
static defaultProps = {
isPaused: true,
refreshInterval: 1000,
+ minInterval: 0,
};
- state: EuiRefreshIntervalState = fromMilliseconds(
- this.props.refreshInterval || 0,
- this.props.intervalUnits
- );
+ state: EuiRefreshIntervalState = {
+ ...fromMilliseconds(
+ this.props.refreshInterval || 0,
+ this.props.intervalUnits
+ ),
+ min: getMinInterval(this.props.minInterval, this.props.intervalUnits),
+ };
generateId = htmlIdGenerator();
legendId = this.generateId();
@@ -123,9 +141,11 @@ export class EuiRefreshInterval extends Component<
};
onUnitsChange: ChangeEventHandler = (event) => {
+ const units = event.target.value as RefreshUnitsOptions;
this.setState(
{
- units: event.target.value as RefreshUnitsOptions,
+ units,
+ min: getMinInterval(this.props.minInterval, units),
},
this.applyRefreshInterval
);
@@ -151,7 +171,7 @@ export class EuiRefreshInterval extends Component<
};
applyRefreshInterval = () => {
- const { onRefreshChange, isPaused } = this.props;
+ const { onRefreshChange, isPaused, minInterval } = this.props;
const { units, value } = this.state;
if (value === '') {
return;
@@ -160,7 +180,10 @@ export class EuiRefreshInterval extends Component<
return;
}
- const refreshInterval = toMilliseconds(units, value);
+ const refreshInterval = Math.max(
+ toMilliseconds(units, value),
+ minInterval || 0
+ );
onRefreshChange({
refreshInterval,
@@ -221,7 +244,7 @@ export class EuiRefreshInterval extends Component<
render() {
const { isPaused } = this.props;
- const { value, units } = this.state;
+ const { value, units, min } = this.state;
return (
@@ -255,6 +278,7 @@ export class EuiRefreshInterval extends Component<
compressed
fullWidth
value={value}
+ min={min}
onChange={this.onValueChange}
onKeyDown={this.handleKeyDown}
isInvalid={!isPaused && (value === '' || value <= 0)}
diff --git a/src/components/date_picker/super_date_picker/quick_select_popover/__snapshots__/quick_select_popover.test.tsx.snap b/src/components/date_picker/super_date_picker/quick_select_popover/__snapshots__/quick_select_popover.test.tsx.snap
index c1be9589f98..54dbcc3c5cb 100644
--- a/src/components/date_picker/super_date_picker/quick_select_popover/__snapshots__/quick_select_popover.test.tsx.snap
+++ b/src/components/date_picker/super_date_picker/quick_select_popover/__snapshots__/quick_select_popover.test.tsx.snap
@@ -350,6 +350,7 @@ exports[`EuiQuickSelectPanels customQuickSelectPanels should render custom panel
class="euiFieldNumber euiFieldNumber--fullWidth euiFieldNumber--compressed"
data-test-subj="superDatePickerRefreshIntervalInput"
disabled=""
+ min="0"
step="any"
type="number"
value="0"
diff --git a/src/components/date_picker/super_date_picker/super_date_picker.tsx b/src/components/date_picker/super_date_picker/super_date_picker.tsx
index ab94d756605..d7db318dd59 100644
--- a/src/components/date_picker/super_date_picker/super_date_picker.tsx
+++ b/src/components/date_picker/super_date_picker/super_date_picker.tsx
@@ -148,6 +148,11 @@ export type EuiSuperDatePickerProps = CommonProps & {
* @default 1000
*/
refreshInterval?: Milliseconds;
+ /**
+ * Minimum refresh interval in milliseconds
+ * @default 0
+ */
+ refreshMinInterval?: Milliseconds;
/**
* By default, refresh interval units will be rounded up to next largest unit of time
* (for example, 90 seconds will become 2m).
@@ -497,6 +502,7 @@ export class EuiSuperDatePickerInternal extends Component<
timeOptions,
dateFormat,
refreshInterval,
+ refreshMinInterval,
refreshIntervalUnits,
isPaused,
isDisabled,
@@ -511,6 +517,7 @@ export class EuiSuperDatePickerInternal extends Component<
const autoRefreshAppend: EuiFormControlLayoutProps['append'] = !isPaused ? (