[Canvas] Converting time filter (and children) component to typescript and adding to storybook (#40443)
* Converting time filter (and children) component to typescript and adding to storybook
This commit is contained in:
parent
8571d56839
commit
8be17fe616
|
@ -5,10 +5,16 @@
|
|||
*/
|
||||
|
||||
import path from 'path';
|
||||
import moment from 'moment';
|
||||
import 'moment-timezone';
|
||||
|
||||
import initStoryshots, { multiSnapshotWithOptions } from '@storybook/addon-storyshots';
|
||||
import styleSheetSerializer from 'jest-styled-components/src/styleSheetSerializer';
|
||||
import { addSerializer } from 'jest-specific-snapshot';
|
||||
|
||||
// Set our default timezone to UTC for tests so we can generate predictable snapshots
|
||||
moment.tz.setDefault('UTC');
|
||||
|
||||
// Mock EUI generated ids to be consistently predictable for snapshots.
|
||||
jest.mock(`@elastic/eui/lib/components/form/form_row/make_id`, () => () => `generated-id`);
|
||||
|
||||
|
@ -25,6 +31,24 @@ jest.mock('../canvas_plugin_src/renderers/shape/shapes', () => ({
|
|||
},
|
||||
}));
|
||||
|
||||
// Mock datetime parsing so we can get stable results for tests (even while using the `now` format)
|
||||
jest.mock('@elastic/datemath', () => {
|
||||
return {
|
||||
parse: (d, opts) => {
|
||||
const dateMath = jest.requireActual('@elastic/datemath');
|
||||
return dateMath.parse(d, {...opts, forceNow: new Date(Date.UTC(2019, 5, 1))}); // June 1 2019
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Mock react-datepicker dep used by eui to avoid rendering the entire large component
|
||||
jest.mock('@elastic/eui/packages/react-datepicker', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
default: 'ReactDatePicker',
|
||||
}
|
||||
});
|
||||
|
||||
addSerializer(styleSheetSerializer);
|
||||
|
||||
// Initialize Storyshots and build the Jest Snapshots
|
||||
|
|
|
@ -0,0 +1,335 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar default 1`] = `
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
inline={true}
|
||||
onChange={[Function]}
|
||||
selected={null}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar invalid date 1`] = `
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="Invalid date"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
inline={true}
|
||||
onChange={[Function]}
|
||||
selected={null}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar with max date 1`] = `
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
inline={true}
|
||||
maxDate={"2019-07-04T00:00:00.000Z"}
|
||||
onChange={[Function]}
|
||||
selected={null}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar with min date 1`] = `
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
inline={true}
|
||||
minDate={"2019-07-04T00:00:00.000Z"}
|
||||
onChange={[Function]}
|
||||
selected={null}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar with start and end date 1`] = `
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
endDate={"2019-07-04T00:00:00.000Z"}
|
||||
inline={true}
|
||||
onChange={[Function]}
|
||||
selected={null}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
startDate={"2019-06-27T00:00:00.000Z"}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar with value 1`] = `
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="2019-06-27 00:00:00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
inline={true}
|
||||
onChange={[Function]}
|
||||
selected={"2019-06-27T00:00:00.000Z"}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { DatetimeCalendar } from '..';
|
||||
|
||||
const startDate = moment.utc('2019-06-27');
|
||||
const endDate = moment.utc('2019-07-04');
|
||||
|
||||
storiesOf('renderers/TimeFilter/components/DatetimeCalendar', module)
|
||||
.add('default', () => (
|
||||
<DatetimeCalendar onSelect={action('onSelect')} onValueChange={action('onValueChange')} />
|
||||
))
|
||||
.add('with value', () => (
|
||||
<DatetimeCalendar
|
||||
value={startDate}
|
||||
onSelect={action('onSelect')}
|
||||
onValueChange={action('onValueChange')}
|
||||
/>
|
||||
))
|
||||
.add('with start and end date', () => (
|
||||
<DatetimeCalendar
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
onSelect={action('onSelect')}
|
||||
onValueChange={action('onValueChange')}
|
||||
/>
|
||||
))
|
||||
.add('with min date', () => (
|
||||
<DatetimeCalendar
|
||||
onSelect={action('onSelect')}
|
||||
onValueChange={action('onValueChange')}
|
||||
minDate={endDate}
|
||||
/>
|
||||
))
|
||||
.add('with max date', () => (
|
||||
<DatetimeCalendar
|
||||
onSelect={action('onSelect')}
|
||||
onValueChange={action('onValueChange')}
|
||||
maxDate={endDate}
|
||||
/>
|
||||
))
|
||||
.add('invalid date', () => (
|
||||
<DatetimeCalendar
|
||||
value={moment('foo')}
|
||||
onSelect={action('onSelect')}
|
||||
onValueChange={action('onValueChange')}
|
||||
/>
|
||||
));
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import { EuiDatePicker } from '@elastic/eui';
|
||||
import { DatetimeInput } from '../datetime_input';
|
||||
|
||||
export const DatetimeCalendar = ({
|
||||
value,
|
||||
onValueChange,
|
||||
onSelect,
|
||||
startDate,
|
||||
endDate,
|
||||
minDate,
|
||||
maxDate,
|
||||
}) => (
|
||||
<div className="canvasDateTimeCal">
|
||||
<DatetimeInput moment={dateMath.parse(value)} setMoment={onValueChange} />
|
||||
<EuiDatePicker
|
||||
inline
|
||||
showTimeSelect
|
||||
shadow={false}
|
||||
selected={dateMath.parse(value)}
|
||||
onChange={onSelect}
|
||||
shouldCloseOnSelect={false}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
minDate={minDate}
|
||||
maxDate={maxDate}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
DatetimeCalendar.propTypes = {
|
||||
value: PropTypes.object,
|
||||
onSelect: PropTypes.func,
|
||||
onValueChange: PropTypes.func, // Called with a moment
|
||||
startDate: PropTypes.object, // a moment
|
||||
endDate: PropTypes.object, // a moment
|
||||
minDate: PropTypes.object, // a moment
|
||||
maxDate: PropTypes.object, // a moment
|
||||
};
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Moment } from 'moment';
|
||||
import { momentObj } from 'react-moment-proptypes';
|
||||
import { EuiDatePicker } from '@elastic/eui';
|
||||
import { DatetimeInput } from '../datetime_input';
|
||||
|
||||
export interface Props {
|
||||
/** Selected date (Moment date object) */
|
||||
value?: Moment;
|
||||
/** Function invoked when a date is selected from the datepicker */
|
||||
onSelect: (date: Moment | null) => void;
|
||||
/** Function invoked when the date text input changes */
|
||||
onValueChange: (moment: Moment) => void; // Called with a moment
|
||||
/** Start date of selected date range (Moment date object) */
|
||||
startDate?: Moment;
|
||||
/** End date of selected date range (Moment date object) */
|
||||
endDate?: Moment;
|
||||
/** Earliest selectable date (Moment date object) */
|
||||
minDate?: Moment;
|
||||
/** Latest selectable date (Moment date object) */
|
||||
maxDate?: Moment;
|
||||
}
|
||||
|
||||
export const DatetimeCalendar: FunctionComponent<Props> = ({
|
||||
value,
|
||||
onValueChange,
|
||||
onSelect,
|
||||
startDate,
|
||||
endDate,
|
||||
minDate,
|
||||
maxDate,
|
||||
}) => (
|
||||
<div className="canvasDateTimeCal">
|
||||
<DatetimeInput moment={value} setMoment={onValueChange} />
|
||||
<EuiDatePicker
|
||||
inline
|
||||
showTimeSelect
|
||||
shadow={false}
|
||||
selected={value && value.isValid() ? value : null}
|
||||
onChange={onSelect}
|
||||
shouldCloseOnSelect={false}
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
minDate={minDate}
|
||||
maxDate={maxDate}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
DatetimeCalendar.propTypes = {
|
||||
value: PropTypes.oneOfType([momentObj, PropTypes.object]), // Handle both valid and invalid moment objects
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
onValueChange: PropTypes.func.isRequired, // Called with a moment
|
||||
startDate: momentObj,
|
||||
endDate: momentObj,
|
||||
minDate: momentObj,
|
||||
maxDate: momentObj,
|
||||
};
|
|
@ -4,12 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const timeUnits = {
|
||||
s: 'second',
|
||||
m: 'minute',
|
||||
h: 'hour',
|
||||
d: 'day',
|
||||
w: 'week',
|
||||
M: 'month',
|
||||
y: 'year',
|
||||
};
|
||||
export { DatetimeCalendar } from './datetime_calendar';
|
|
@ -0,0 +1,67 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeInput default 1`] = `
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeInput invalid date 1`] = `
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="Invalid date"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeInput with date 1`] = `
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="2018-02-20 19:26:52"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { DatetimeInput } from '..';
|
||||
|
||||
storiesOf('renderers/TimeFilter/components/DatetimeInput', module)
|
||||
.add('default', () => <DatetimeInput setMoment={action('setMoment')} />)
|
||||
.add('with date', () => (
|
||||
<DatetimeInput moment={moment.utc('2018-02-20 19:26:52')} setMoment={action('setMoment')} />
|
||||
))
|
||||
.add('invalid date', () => (
|
||||
<DatetimeInput moment={moment('foo')} setMoment={action('setMoment')} />
|
||||
));
|
|
@ -4,13 +4,32 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { FunctionComponent, ChangeEvent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { EuiFieldText } from '@elastic/eui';
|
||||
import moment from 'moment';
|
||||
import moment, { Moment } from 'moment';
|
||||
|
||||
export const DatetimeInput = ({ strValue, setStrValue, setMoment, valid, setValid }) => {
|
||||
function check(e) {
|
||||
export interface Props {
|
||||
/** Selected string value of input */
|
||||
strValue: string;
|
||||
/** Function invoked with string when input is changed */
|
||||
setStrValue: (value: string) => void;
|
||||
/** Function invoked with moment when input is changed with valid datetime */
|
||||
setMoment: (value: Moment) => void;
|
||||
/** Boolean denotes whether current input value is valid date */
|
||||
valid: boolean;
|
||||
/** Function invoked with value validity when input is changed */
|
||||
setValid: (valid: boolean) => void;
|
||||
}
|
||||
|
||||
export const DatetimeInput: FunctionComponent<Props> = ({
|
||||
strValue,
|
||||
setStrValue,
|
||||
setMoment,
|
||||
valid,
|
||||
setValid,
|
||||
}) => {
|
||||
function check(e: ChangeEvent<HTMLInputElement>) {
|
||||
const parsed = moment(e.target.value, 'YYYY-MM-DD HH:mm:ss', true);
|
||||
if (parsed.isValid()) {
|
||||
setMoment(parsed);
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { compose, withState, lifecycle } from 'recompose';
|
||||
import { DatetimeInput as Component } from './datetime_input';
|
||||
|
||||
export const DatetimeInput = compose(
|
||||
withState('valid', 'setValid', () => true),
|
||||
withState('strValue', 'setStrValue', ({ moment }) => moment.format('YYYY-MM-DD HH:mm:ss')),
|
||||
lifecycle({
|
||||
componentWillReceiveProps({ moment, setStrValue, setValid }) {
|
||||
if (this.props.moment.isSame(moment)) {
|
||||
return;
|
||||
}
|
||||
setStrValue(moment.format('YYYY-MM-DD HH:mm:ss'));
|
||||
setValid(true);
|
||||
},
|
||||
})
|
||||
)(Component);
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Moment } from 'moment';
|
||||
import { compose, withState, lifecycle } from 'recompose';
|
||||
import { DatetimeInput as Component, Props as ComponentProps } from './datetime_input';
|
||||
|
||||
export interface Props {
|
||||
/** Input value (Moment date object) */
|
||||
moment?: Moment;
|
||||
/** Function to invoke when the input changes */
|
||||
setMoment: (m: Moment) => void;
|
||||
}
|
||||
|
||||
export const DatetimeInput = compose<ComponentProps, Props>(
|
||||
withState('valid', 'setValid', () => true),
|
||||
withState('strValue', 'setStrValue', ({ moment }) =>
|
||||
moment ? moment.format('YYYY-MM-DD HH:mm:ss') : ''
|
||||
),
|
||||
lifecycle<Props & ComponentProps, {}>({
|
||||
// TODO: Refactor to no longer use componentWillReceiveProps since it is being deprecated
|
||||
componentWillReceiveProps({ moment, setStrValue, setValid }) {
|
||||
if (!moment) return;
|
||||
|
||||
if (this.props.moment && this.props.moment.isSame(moment)) {
|
||||
return;
|
||||
}
|
||||
setStrValue(moment.format('YYYY-MM-DD HH:mm:ss'));
|
||||
setValid(true);
|
||||
},
|
||||
})
|
||||
)(Component);
|
|
@ -0,0 +1,219 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeQuickList with children 1`] = `
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"display": "grid",
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 24 hours
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButton euiButton--primary euiButton--small euiButton--fill"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButton__content"
|
||||
>
|
||||
<span
|
||||
className="euiButton__text"
|
||||
>
|
||||
Last 7 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 2 weeks
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 30 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 90 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 1 year
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Apply
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeQuickList with start and end dates 1`] = `
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"display": "grid",
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 24 hours
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButton euiButton--primary euiButton--small euiButton--fill"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButton__content"
|
||||
>
|
||||
<span
|
||||
className="euiButton__text"
|
||||
>
|
||||
Last 7 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 2 weeks
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 30 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 90 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 1 year
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiButtonEmpty } from '@elastic/eui';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { DatetimeQuickList } from '..';
|
||||
|
||||
storiesOf('renderers/TimeFilter/components/DatetimeQuickList', module)
|
||||
.add('with start and end dates', () => (
|
||||
<DatetimeQuickList from="now-7d" to="now" onSelect={action('onSelect')} />
|
||||
))
|
||||
.add('with children', () => (
|
||||
<DatetimeQuickList from="now-7d" to="now" onSelect={action('onSelect')}>
|
||||
<EuiButtonEmpty>Apply</EuiButtonEmpty>
|
||||
</DatetimeQuickList>
|
||||
));
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { EuiButton, EuiButtonEmpty } from '@elastic/eui';
|
||||
import 'react-datetime/css/react-datetime.css';
|
||||
|
||||
export const DatetimeQuickList = ({ from, to, ranges, onSelect, children }) => (
|
||||
<div style={{ display: 'grid', alignItems: 'center' }}>
|
||||
{ranges.map((range, i) =>
|
||||
from === range.from && to === range.to ? (
|
||||
<EuiButton size="s" fill key={i} onClick={() => onSelect(range.from, range.to)}>
|
||||
{range.display}
|
||||
</EuiButton>
|
||||
) : (
|
||||
<EuiButtonEmpty size="s" key={i} onClick={() => onSelect(range.from, range.to)}>
|
||||
{range.display}
|
||||
</EuiButtonEmpty>
|
||||
)
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
DatetimeQuickList.propTypes = {
|
||||
from: PropTypes.string,
|
||||
to: PropTypes.string,
|
||||
ranges: PropTypes.array,
|
||||
onSelect: PropTypes.func,
|
||||
children: PropTypes.node,
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { ReactNode, FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { EuiButton, EuiButtonEmpty } from '@elastic/eui';
|
||||
import 'react-datetime/css/react-datetime.css';
|
||||
|
||||
interface Props {
|
||||
/** Initial start date string */
|
||||
from: string;
|
||||
/** Initial end date string */
|
||||
to: string;
|
||||
|
||||
/** Function invoked when a date range is clicked */
|
||||
onSelect: (from: string, to: string) => void;
|
||||
|
||||
/** Nodes to display under the date range buttons */
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
const quickRanges = [
|
||||
{ from: 'now-24h', to: 'now', display: 'Last 24 hours' },
|
||||
{ from: 'now-7d', to: 'now', display: 'Last 7 days' },
|
||||
{ from: 'now-14d', to: 'now', display: 'Last 2 weeks' },
|
||||
{ from: 'now-30d', to: 'now', display: 'Last 30 days' },
|
||||
{ from: 'now-90d', to: 'now', display: 'Last 90 days' },
|
||||
{ from: 'now-1y', to: 'now', display: 'Last 1 year' },
|
||||
];
|
||||
|
||||
export const DatetimeQuickList: FunctionComponent<Props> = ({ from, to, onSelect, children }) => (
|
||||
<div style={{ display: 'grid', alignItems: 'center' }}>
|
||||
{quickRanges.map((range, i) =>
|
||||
from === range.from && to === range.to ? (
|
||||
<EuiButton size="s" fill key={i} onClick={() => onSelect(range.from, range.to)}>
|
||||
{range.display}
|
||||
</EuiButton>
|
||||
) : (
|
||||
<EuiButtonEmpty size="s" key={i} onClick={() => onSelect(range.from, range.to)}>
|
||||
{range.display}
|
||||
</EuiButtonEmpty>
|
||||
)
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
DatetimeQuickList.propTypes = {
|
||||
from: PropTypes.string.isRequired,
|
||||
to: PropTypes.string.isRequired,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
children: PropTypes.node,
|
||||
};
|
|
@ -4,7 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { compose } from 'recompose';
|
||||
import { TimePickerMini as Component } from './time_picker_mini';
|
||||
|
||||
export const TimePickerMini = compose()(Component);
|
||||
export { DatetimeQuickList } from './datetime_quick_list';
|
|
@ -0,0 +1,122 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/DatetimeRangeAbsolute default 1`] = `
|
||||
<div
|
||||
className="canvasDateTimeRangeAbsolute"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="2019-06-21 00:00:00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
endDate={"2019-07-05T00:00:00.000Z"}
|
||||
inline={true}
|
||||
maxDate={"2019-07-05T00:00:00.000Z"}
|
||||
onChange={[Function]}
|
||||
selected={"2019-06-21T00:00:00.000Z"}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
startDate={"2019-06-21T00:00:00.000Z"}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="2019-07-05 00:00:00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
endDate={"2019-07-05T00:00:00.000Z"}
|
||||
inline={true}
|
||||
minDate={"2019-06-21T00:00:00.000Z"}
|
||||
onChange={[Function]}
|
||||
selected={"2019-07-05T00:00:00.000Z"}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
startDate={"2019-06-21T00:00:00.000Z"}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { DatetimeRangeAbsolute } from '..';
|
||||
|
||||
const startDate = moment.utc('2019-06-21');
|
||||
const endDate = moment.utc('2019-07-05');
|
||||
|
||||
storiesOf('renderers/TimeFilter/components/DatetimeRangeAbsolute', module).add('default', () => (
|
||||
<DatetimeRangeAbsolute from={startDate} to={endDate} onSelect={action('onSelect')} />
|
||||
));
|
|
@ -4,12 +4,23 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import moment from 'moment';
|
||||
import { Moment } from 'moment';
|
||||
import { momentObj } from 'react-moment-proptypes';
|
||||
import { DatetimeCalendar } from '../datetime_calendar';
|
||||
|
||||
export const DatetimeRangeAbsolute = ({ from, to, onSelect }) => (
|
||||
interface Props {
|
||||
/** Optional initial start date moment */
|
||||
from?: Moment;
|
||||
/** Optional initial end date moment */
|
||||
to?: Moment;
|
||||
|
||||
/** Function invoked when a date is selected from the datetime calendar */
|
||||
onSelect: (from?: Moment, to?: Moment) => void;
|
||||
}
|
||||
|
||||
export const DatetimeRangeAbsolute: FunctionComponent<Props> = ({ from, to, onSelect }) => (
|
||||
<div className="canvasDateTimeRangeAbsolute">
|
||||
<div>
|
||||
<DatetimeCalendar
|
||||
|
@ -19,8 +30,12 @@ export const DatetimeRangeAbsolute = ({ from, to, onSelect }) => (
|
|||
maxDate={to}
|
||||
onValueChange={val => onSelect(val, to)}
|
||||
onSelect={val => {
|
||||
if (!val || !from) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sets the time to start of day if only the date was selected
|
||||
if (moment(from).format('hh:mm:ss a') === val.format('hh:mm:ss a')) {
|
||||
if (from.format('hh:mm:ss a') === val.format('hh:mm:ss a')) {
|
||||
onSelect(val.startOf('day'), to);
|
||||
} else {
|
||||
onSelect(val, to);
|
||||
|
@ -36,9 +51,13 @@ export const DatetimeRangeAbsolute = ({ from, to, onSelect }) => (
|
|||
minDate={from}
|
||||
onValueChange={val => onSelect(from, val)}
|
||||
onSelect={val => {
|
||||
if (!val || !to) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set the time to end of day if only the date was selected
|
||||
if (moment(to).format('hh:mm:ss a') === val.format('hh:mm:ss a')) {
|
||||
onSelect(from, moment(val).endOf('day'));
|
||||
if (to.format('hh:mm:ss a') === val.format('hh:mm:ss a')) {
|
||||
onSelect(from, val.endOf('day'));
|
||||
} else {
|
||||
onSelect(from, val);
|
||||
}
|
||||
|
@ -49,7 +68,7 @@ export const DatetimeRangeAbsolute = ({ from, to, onSelect }) => (
|
|||
);
|
||||
|
||||
DatetimeRangeAbsolute.propTypes = {
|
||||
from: PropTypes.object, // a moment
|
||||
to: PropTypes.object, // a moment
|
||||
onSelect: PropTypes.func,
|
||||
from: momentObj,
|
||||
to: momentObj,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { compose } from 'recompose';
|
||||
import { DatetimeRangeAbsolute as Component } from './datetime_range_absolute';
|
||||
|
||||
export const DatetimeRangeAbsolute = compose()(Component);
|
|
@ -4,7 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { compose } from 'recompose';
|
||||
import { DatetimeCalendar as Component } from './datetime_calendar';
|
||||
|
||||
export const DatetimeCalendar = compose()(Component);
|
||||
export { DatetimeRangeAbsolute } from './datetime_range_absolute';
|
|
@ -0,0 +1,13 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/PrettyDuration with absolute dates 1`] = `
|
||||
<span>
|
||||
~ 6 months ago to ~ 5 months ago
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/PrettyDuration with relative dates 1`] = `
|
||||
<span>
|
||||
Last 7 days
|
||||
</span>
|
||||
`;
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { PrettyDuration } from '..';
|
||||
|
||||
storiesOf('renderers/TimeFilter/components/PrettyDuration', module)
|
||||
.add('with relative dates', () => <PrettyDuration from="now-7d" to="now" />)
|
||||
.add('with absolute dates', () => <PrettyDuration from="01/01/2019" to="02/01/2019" />);
|
|
@ -5,16 +5,16 @@
|
|||
*/
|
||||
|
||||
import dateMath from '@elastic/datemath';
|
||||
import moment from 'moment';
|
||||
import { quickRanges } from './quick_ranges';
|
||||
import { timeUnits } from './time_units';
|
||||
import moment, { Moment } from 'moment';
|
||||
import { quickRanges, QuickRange } from './quick_ranges';
|
||||
import { timeUnits, TimeUnit } from '../../../../../../common/lib/time_units';
|
||||
|
||||
const lookupByRange = {};
|
||||
quickRanges.forEach(function(frame) {
|
||||
lookupByRange[frame.from + ' to ' + frame.to] = frame;
|
||||
const lookupByRange: { [key: string]: QuickRange } = {};
|
||||
quickRanges.forEach(frame => {
|
||||
lookupByRange[`${frame.from} to ${frame.to}`] = frame;
|
||||
});
|
||||
|
||||
function formatTime(time, roundUp = false) {
|
||||
function formatTime(time: string | Moment, roundUp = false) {
|
||||
if (moment.isMoment(time)) {
|
||||
return time.format('lll');
|
||||
} else {
|
||||
|
@ -27,24 +27,24 @@ function formatTime(time, roundUp = false) {
|
|||
}
|
||||
}
|
||||
|
||||
function cantLookup(from, to) {
|
||||
function cantLookup(from: string, to: string) {
|
||||
return `${formatTime(from)} to ${formatTime(to)}`;
|
||||
}
|
||||
|
||||
export function formatDuration(from, to) {
|
||||
let text;
|
||||
export function formatDuration(from: string, to: string) {
|
||||
// If both parts are date math, try to look up a reasonable string
|
||||
if (from && to && !moment.isMoment(from) && !moment.isMoment(to)) {
|
||||
const tryLookup = lookupByRange[from.toString() + ' to ' + to.toString()];
|
||||
const tryLookup = lookupByRange[`${from.toString()} to ${to.toString()}`];
|
||||
if (tryLookup) {
|
||||
return tryLookup.display;
|
||||
} else {
|
||||
const fromParts = from.toString().split('-');
|
||||
if (to.toString() === 'now' && fromParts[0] === 'now' && fromParts[1]) {
|
||||
const rounded = fromParts[1].split('/');
|
||||
text = 'Last ' + rounded[0];
|
||||
let text = `Last ${rounded[0]}`;
|
||||
if (rounded[1]) {
|
||||
text = text + ' rounded to the ' + timeUnits[rounded[1]];
|
||||
const unit = rounded[1] as TimeUnit;
|
||||
text = `${text} rounded to the ${timeUnits[unit]}`;
|
||||
}
|
||||
|
||||
return text;
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const quickRanges = [
|
||||
{ from: 'now/d', to: 'now/d', display: 'Today', section: 0 },
|
||||
{ from: 'now/w', to: 'now/w', display: 'This week', section: 0 },
|
||||
{ from: 'now/M', to: 'now/M', display: 'This month', section: 0 },
|
||||
{ from: 'now/y', to: 'now/y', display: 'This year', section: 0 },
|
||||
{ from: 'now/d', to: 'now', display: 'The day so far', section: 0 },
|
||||
{ from: 'now/w', to: 'now', display: 'Week to date', section: 0 },
|
||||
{ from: 'now/M', to: 'now', display: 'Month to date', section: 0 },
|
||||
{ from: 'now/y', to: 'now', display: 'Year to date', section: 0 },
|
||||
|
||||
{ from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday', section: 1 },
|
||||
{ from: 'now-2d/d', to: 'now-2d/d', display: 'Day before yesterday', section: 1 },
|
||||
{ from: 'now-7d/d', to: 'now-7d/d', display: 'This day last week', section: 1 },
|
||||
{ from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week', section: 1 },
|
||||
{ from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month', section: 1 },
|
||||
{ from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year', section: 1 },
|
||||
|
||||
{ from: 'now-15m', to: 'now', display: 'Last 15 minutes', section: 2 },
|
||||
{ from: 'now-30m', to: 'now', display: 'Last 30 minutes', section: 2 },
|
||||
{ from: 'now-1h', to: 'now', display: 'Last 1 hour', section: 2 },
|
||||
{ from: 'now-4h', to: 'now', display: 'Last 4 hours', section: 2 },
|
||||
{ from: 'now-12h', to: 'now', display: 'Last 12 hours', section: 2 },
|
||||
{ from: 'now-24h', to: 'now', display: 'Last 24 hours', section: 2 },
|
||||
{ from: 'now-7d', to: 'now', display: 'Last 7 days', section: 2 },
|
||||
|
||||
{ from: 'now-30d', to: 'now', display: 'Last 30 days', section: 3 },
|
||||
{ from: 'now-60d', to: 'now', display: 'Last 60 days', section: 3 },
|
||||
{ from: 'now-90d', to: 'now', display: 'Last 90 days', section: 3 },
|
||||
{ from: 'now-6M', to: 'now', display: 'Last 6 months', section: 3 },
|
||||
{ from: 'now-1y', to: 'now', display: 'Last 1 year', section: 3 },
|
||||
{ from: 'now-2y', to: 'now', display: 'Last 2 years', section: 3 },
|
||||
{ from: 'now-5y', to: 'now', display: 'Last 5 years', section: 3 },
|
||||
];
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export interface QuickRange {
|
||||
/** Start date string of range */
|
||||
from: string;
|
||||
/** Start date string of range */
|
||||
to: string;
|
||||
/** Display name describing date range */
|
||||
display: string;
|
||||
}
|
||||
|
||||
export const quickRanges: QuickRange[] = [
|
||||
{ from: 'now/d', to: 'now/d', display: 'Today' },
|
||||
{ from: 'now/w', to: 'now/w', display: 'This week' },
|
||||
{ from: 'now/M', to: 'now/M', display: 'This month' },
|
||||
{ from: 'now/y', to: 'now/y', display: 'This year' },
|
||||
{ from: 'now/d', to: 'now', display: 'The day so far' },
|
||||
{ from: 'now/w', to: 'now', display: 'Week to date' },
|
||||
{ from: 'now/M', to: 'now', display: 'Month to date' },
|
||||
{ from: 'now/y', to: 'now', display: 'Year to date' },
|
||||
|
||||
{ from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday' },
|
||||
{ from: 'now-2d/d', to: 'now-2d/d', display: 'Day before yesterday' },
|
||||
{ from: 'now-7d/d', to: 'now-7d/d', display: 'This day last week' },
|
||||
{ from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week' },
|
||||
{ from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month' },
|
||||
{ from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year' },
|
||||
|
||||
{ from: 'now-15m', to: 'now', display: 'Last 15 minutes' },
|
||||
{ from: 'now-30m', to: 'now', display: 'Last 30 minutes' },
|
||||
{ from: 'now-1h', to: 'now', display: 'Last 1 hour' },
|
||||
{ from: 'now-4h', to: 'now', display: 'Last 4 hours' },
|
||||
{ from: 'now-12h', to: 'now', display: 'Last 12 hours' },
|
||||
{ from: 'now-24h', to: 'now', display: 'Last 24 hours' },
|
||||
{ from: 'now-7d', to: 'now', display: 'Last 7 days' },
|
||||
|
||||
{ from: 'now-30d', to: 'now', display: 'Last 30 days' },
|
||||
{ from: 'now-60d', to: 'now', display: 'Last 60 days' },
|
||||
{ from: 'now-90d', to: 'now', display: 'Last 90 days' },
|
||||
{ from: 'now-6M', to: 'now', display: 'Last 6 months' },
|
||||
{ from: 'now-1y', to: 'now', display: 'Last 1 year' },
|
||||
{ from: 'now-2y', to: 'now', display: 'Last 2 years' },
|
||||
{ from: 'now-5y', to: 'now', display: 'Last 5 years' },
|
||||
];
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { PropTypes } from 'prop-types';
|
||||
import { formatDuration } from './lib/format_duration';
|
||||
|
||||
export const PrettyDuration = ({ from, to }) => <span>{formatDuration(from, to)}</span>;
|
||||
|
||||
PrettyDuration.propTypes = {
|
||||
from: PropTypes.any.isRequired,
|
||||
to: PropTypes.any.isRequired,
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { formatDuration } from './lib/format_duration';
|
||||
|
||||
interface Props {
|
||||
/** Initial start date string */
|
||||
from: string;
|
||||
/** Initial end date string */
|
||||
to: string;
|
||||
}
|
||||
|
||||
export const PrettyDuration: FunctionComponent<Props> = ({ from, to }) => (
|
||||
<span>{formatDuration(from, to)}</span>
|
||||
);
|
||||
|
||||
PrettyDuration.propTypes = {
|
||||
from: PropTypes.string.isRequired,
|
||||
to: PropTypes.string.isRequired,
|
||||
};
|
|
@ -0,0 +1,267 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter compact mode 1`] = `
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownCenter canvasTimePickerPopover"
|
||||
container={null}
|
||||
id="timefilter-popover-trigger-click"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiPopover__anchor canvasTimePickerPopover__anchor"
|
||||
>
|
||||
<button
|
||||
className="canvasTimePickerPopover__button"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<span>
|
||||
Last 7 days
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter default 1`] = `
|
||||
<div
|
||||
className="canvasTimePicker"
|
||||
>
|
||||
<div
|
||||
className="canvasDateTimeRangeAbsolute"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="2018-06-01 00:00:00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
endDate={"2019-05-25T00:00:00.000Z"}
|
||||
inline={true}
|
||||
maxDate={"2019-05-25T00:00:00.000Z"}
|
||||
onChange={[Function]}
|
||||
selected={"2018-06-01T00:00:00.000Z"}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
startDate={"2018-06-01T00:00:00.000Z"}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="2019-05-25 00:00:00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
endDate={"2019-05-25T00:00:00.000Z"}
|
||||
inline={true}
|
||||
minDate={"2018-06-01T00:00:00.000Z"}
|
||||
onChange={[Function]}
|
||||
selected={"2019-05-25T00:00:00.000Z"}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
startDate={"2018-06-01T00:00:00.000Z"}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"display": "grid",
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 24 hours
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 7 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 2 weeks
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 30 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 90 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 1 year
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButton euiButton--primary euiButton--small canvasTimePicker__apply euiButton--fill"
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButton__content"
|
||||
>
|
||||
<span
|
||||
className="euiButton__text"
|
||||
>
|
||||
Apply
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { TimeFilter } from '..';
|
||||
|
||||
storiesOf('renderers/TimeFilter', module)
|
||||
.add('default', () => (
|
||||
<TimeFilter
|
||||
filter="timefilter from=now-1y to=now-7d column=@timestamp"
|
||||
commit={action('commit')}
|
||||
/>
|
||||
))
|
||||
.add('compact mode', () => (
|
||||
<TimeFilter
|
||||
filter="timefilter from=now-7d to=now column=@timestamp"
|
||||
compact
|
||||
commit={action('commit')}
|
||||
/>
|
||||
));
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { get } from 'lodash';
|
||||
import { fromExpression } from '@kbn/interpreter/common';
|
||||
import { TimePicker } from '../time_picker';
|
||||
import { TimePickerMini } from '../time_picker_mini';
|
||||
|
||||
function getFilterMeta(filter) {
|
||||
const ast = fromExpression(filter);
|
||||
const column = get(ast, 'chain[0].arguments.column[0]');
|
||||
const from = get(ast, 'chain[0].arguments.from[0]');
|
||||
const to = get(ast, 'chain[0].arguments.to[0]');
|
||||
return { column, from, to };
|
||||
}
|
||||
|
||||
export const TimeFilter = ({ filter, commit, compact }) => {
|
||||
const setFilter = column => (from, to) => {
|
||||
commit(`timefilter from="${from}" to=${to} column=${column}`);
|
||||
};
|
||||
|
||||
const { column, from, to } = getFilterMeta(filter);
|
||||
|
||||
if (compact) {
|
||||
return <TimePickerMini from={from} to={to} onSelect={setFilter(column)} />;
|
||||
} else {
|
||||
return <TimePicker from={from} to={to} onSelect={setFilter(column)} />;
|
||||
}
|
||||
};
|
||||
|
||||
TimeFilter.propTypes = {
|
||||
filter: PropTypes.string,
|
||||
commit: PropTypes.func, // Canvas filter
|
||||
compact: PropTypes.bool,
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { get } from 'lodash';
|
||||
import { fromExpression } from '@kbn/interpreter/common';
|
||||
import { TimePicker } from '../time_picker';
|
||||
import { TimePickerPopover } from '../time_picker_popover';
|
||||
|
||||
export interface FilterMeta {
|
||||
/** Name of datetime column to be filtered */
|
||||
column: string;
|
||||
/** Start date string of filtered date range */
|
||||
from: string;
|
||||
/** End date string of filtered date range */
|
||||
to: string;
|
||||
}
|
||||
|
||||
function getFilterMeta(filter: string): FilterMeta {
|
||||
const ast = fromExpression(filter);
|
||||
const column = get<string>(ast, 'chain[0].arguments.column[0]');
|
||||
const from = get<string>(ast, 'chain[0].arguments.from[0]');
|
||||
const to = get<string>(ast, 'chain[0].arguments.to[0]');
|
||||
return { column, from, to };
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
/** Initial value of the filter */
|
||||
filter: string;
|
||||
/** Function invoked when the filter changes */
|
||||
commit: (filter: string) => void;
|
||||
/** Determines if compact or full-sized time picker is displayed */
|
||||
compact?: boolean;
|
||||
}
|
||||
|
||||
export const TimeFilter = ({ filter, commit, compact }: Props) => {
|
||||
const setFilter = (column: string) => (from: string, to: string) => {
|
||||
commit(`timefilter from="${from}" to=${to} column=${column}`);
|
||||
};
|
||||
|
||||
const { column, from, to } = getFilterMeta(filter);
|
||||
|
||||
if (compact) {
|
||||
return <TimePickerPopover from={from} to={to} onSelect={setFilter(column)} />;
|
||||
} else {
|
||||
return <TimePicker from={from} to={to} onSelect={setFilter(column)} />;
|
||||
}
|
||||
};
|
||||
|
||||
TimeFilter.propTypes = {
|
||||
filter: PropTypes.string.isRequired,
|
||||
commit: PropTypes.func.isRequired, // Canvas filter
|
||||
compact: PropTypes.bool,
|
||||
};
|
|
@ -0,0 +1,241 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/TimePicker default 1`] = `
|
||||
<div
|
||||
className="canvasTimePicker"
|
||||
>
|
||||
<div
|
||||
className="canvasDateTimeRangeAbsolute"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="2018-04-04 00:00:00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
endDate={"2019-04-04T00:00:00.000Z"}
|
||||
inline={true}
|
||||
maxDate={"2019-04-04T00:00:00.000Z"}
|
||||
onChange={[Function]}
|
||||
selected={"2018-04-04T00:00:00.000Z"}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
startDate={"2018-04-04T00:00:00.000Z"}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className="canvasDateTimeCal"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout euiFormControlLayout--compressed"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<input
|
||||
className="euiFieldText euiFieldText--compressed"
|
||||
onChange={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value="2019-04-04 00:00:00"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
<span
|
||||
className="euiDatePicker euiDatePicker--inline"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout"
|
||||
>
|
||||
<div
|
||||
className="euiFormControlLayout__childrenWrapper"
|
||||
>
|
||||
<ReactDatePicker
|
||||
accessibleMode={true}
|
||||
adjustDateOnChange={true}
|
||||
className="euiDatePicker euiFieldText"
|
||||
dateFormat="MM/DD/YYYY hh:mm A"
|
||||
endDate={"2019-04-04T00:00:00.000Z"}
|
||||
inline={true}
|
||||
minDate={"2018-04-04T00:00:00.000Z"}
|
||||
onChange={[Function]}
|
||||
selected={"2019-04-04T00:00:00.000Z"}
|
||||
shouldCloseOnSelect={false}
|
||||
showMonthDropdown={true}
|
||||
showTimeSelect={true}
|
||||
showYearDropdown={true}
|
||||
startDate={"2018-04-04T00:00:00.000Z"}
|
||||
timeFormat="hh:mm A"
|
||||
yearDropdownItemNumber={7}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"display": "grid",
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 24 hours
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 7 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 2 weeks
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 30 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 90 days
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButtonEmpty euiButtonEmpty--primary euiButtonEmpty--small"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__content"
|
||||
>
|
||||
<span
|
||||
className="euiButtonEmpty__text"
|
||||
>
|
||||
Last 1 year
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="euiButton euiButton--primary euiButton--small canvasTimePicker__apply euiButton--fill"
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
className="euiButton__content"
|
||||
>
|
||||
<span
|
||||
className="euiButton__text"
|
||||
>
|
||||
Apply
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { TimePicker } from '..';
|
||||
|
||||
const startDate = moment.utc('2018-04-04').toISOString();
|
||||
const endDate = moment.utc('2019-04-04').toISOString();
|
||||
|
||||
storiesOf('renderers/TimeFilter/components/TimePicker', module).add('default', () => (
|
||||
<TimePicker from={startDate} to={endDate} onSelect={action('onSelect')} />
|
||||
));
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { compose, withState, lifecycle } from 'recompose';
|
||||
import { TimePicker as Component } from './time_picker';
|
||||
|
||||
export const TimePicker = compose(
|
||||
withState('range', 'setRange', ({ from, to }) => ({ from, to })),
|
||||
withState('dirty', 'setDirty', false),
|
||||
lifecycle({
|
||||
componentWillReceiveProps({ from, to }) {
|
||||
if (from !== this.props.from || to !== this.props.to) {
|
||||
this.props.setRange({ from, to });
|
||||
this.props.setDirty(false);
|
||||
}
|
||||
},
|
||||
})
|
||||
)(Component);
|
|
@ -4,7 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { compose } from 'recompose';
|
||||
import { DatetimeQuickList as Component } from './datetime_quick_list';
|
||||
|
||||
export const DatetimeQuickList = compose()(Component);
|
||||
export { TimePicker } from './time_picker';
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import moment from 'moment';
|
||||
import { DatetimeRangeAbsolute } from '../datetime_range_absolute';
|
||||
import { DatetimeQuickList } from '../datetime_quick_list';
|
||||
|
||||
export const quickRanges = [
|
||||
{ from: 'now/d', to: 'now', display: 'Today' },
|
||||
{ from: 'now-24h', to: 'now', display: 'Last 24 hours' },
|
||||
{ from: 'now-7d', to: 'now', display: 'Last 7 days' },
|
||||
{ from: 'now-14d', to: 'now', display: 'Last 2 weeks' },
|
||||
{ from: 'now-30d', to: 'now', display: 'Last 30 days' },
|
||||
{ from: 'now-90d', to: 'now', display: 'Last 90 days' },
|
||||
{ from: 'now-1y', to: 'now', display: 'Last 1 year' },
|
||||
];
|
||||
|
||||
export const TimePicker = ({ range, setRange, dirty, setDirty, onSelect }) => {
|
||||
const { from, to } = range;
|
||||
|
||||
function absoluteSelect(from, to) {
|
||||
setDirty(true);
|
||||
setRange({ from: moment(from).toISOString(), to: moment(to).toISOString() });
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="canvasTimePicker">
|
||||
<DatetimeRangeAbsolute
|
||||
from={dateMath.parse(from)}
|
||||
to={dateMath.parse(to)}
|
||||
onSelect={absoluteSelect}
|
||||
/>
|
||||
<DatetimeQuickList from={range.from} to={range.to} ranges={quickRanges} onSelect={onSelect}>
|
||||
<EuiButton
|
||||
fill
|
||||
size="s"
|
||||
disabled={!dirty}
|
||||
className="canvasTimePicker__apply"
|
||||
onClick={() => {
|
||||
setDirty(false);
|
||||
onSelect(range.from, range.to);
|
||||
}}
|
||||
>
|
||||
Apply
|
||||
</EuiButton>
|
||||
</DatetimeQuickList>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
TimePicker.propTypes = {
|
||||
range: PropTypes.object,
|
||||
setRange: PropTypes.func,
|
||||
dirty: PropTypes.bool,
|
||||
setDirty: PropTypes.func,
|
||||
onSelect: PropTypes.func,
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import dateMath from '@elastic/datemath';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import moment from 'moment';
|
||||
import { DatetimeQuickList } from '../datetime_quick_list';
|
||||
import { DatetimeRangeAbsolute } from '../datetime_range_absolute';
|
||||
|
||||
export interface Props {
|
||||
/** Start date string */
|
||||
from: string;
|
||||
/** End date string */
|
||||
to: string;
|
||||
/** Function invoked when date range is changed */
|
||||
onSelect: (from: string, to: string) => void;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
range: {
|
||||
/** Start date string of selected date range */
|
||||
from: string;
|
||||
/** End date string of selected date range */
|
||||
to: string;
|
||||
};
|
||||
/** Boolean denoting whether selected date range has been applied */
|
||||
isDirty: boolean;
|
||||
}
|
||||
|
||||
export class TimePicker extends Component<Props, State> {
|
||||
static propTypes = {
|
||||
from: PropTypes.string.isRequired,
|
||||
to: PropTypes.string.isRequired,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
range: { from: this.props.from, to: this.props.to },
|
||||
isDirty: false,
|
||||
};
|
||||
|
||||
// TODO: Refactor to no longer use componentWillReceiveProps since it is being deprecated
|
||||
componentWillReceiveProps({ from, to }: Props) {
|
||||
if (from !== this.props.from || to !== this.props.to) {
|
||||
this.setState({
|
||||
range: { from, to },
|
||||
isDirty: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_absoluteSelect = (from?: moment.Moment, to?: moment.Moment) => {
|
||||
if (from && to) {
|
||||
this.setState({
|
||||
range: { from: moment(from).toISOString(), to: moment(to).toISOString() },
|
||||
isDirty: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { onSelect } = this.props;
|
||||
const { range, isDirty } = this.state;
|
||||
const { from, to } = range;
|
||||
|
||||
return (
|
||||
<div className="canvasTimePicker">
|
||||
<DatetimeRangeAbsolute
|
||||
from={dateMath.parse(from)}
|
||||
to={dateMath.parse(to)}
|
||||
onSelect={this._absoluteSelect}
|
||||
/>
|
||||
<DatetimeQuickList from={from} to={to} onSelect={onSelect}>
|
||||
<EuiButton
|
||||
fill
|
||||
size="s"
|
||||
disabled={!isDirty}
|
||||
className="canvasTimePicker__apply"
|
||||
onClick={() => {
|
||||
this.setState({ isDirty: false });
|
||||
onSelect(from, to);
|
||||
}}
|
||||
>
|
||||
Apply
|
||||
</EuiButton>
|
||||
</DatetimeQuickList>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Popover } from '../../../../../public/components/popover';
|
||||
import { PrettyDuration } from '../pretty_duration';
|
||||
import { TimePicker } from '../time_picker';
|
||||
|
||||
export const TimePickerMini = ({ from, to, onSelect }) => {
|
||||
const button = handleClick => (
|
||||
<button className="canvasTimePickerMini__button" onClick={handleClick}>
|
||||
<PrettyDuration from={from} to={to} />
|
||||
</button>
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
id="timefilter-popover-trigger-click"
|
||||
className="canvasTimePickerMini"
|
||||
anchorClassName="canvasTimePickerMini__anchor"
|
||||
button={button}
|
||||
>
|
||||
{() => <TimePicker from={from} to={to} onSelect={onSelect} />}
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
TimePickerMini.propTypes = {
|
||||
from: PropTypes.string,
|
||||
to: PropTypes.string,
|
||||
onSelect: PropTypes.func,
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots renderers/TimeFilter/components/TimePickerPopover default 1`] = `
|
||||
<div
|
||||
className="euiPopover euiPopover--anchorDownCenter canvasTimePickerPopover"
|
||||
container={null}
|
||||
id="timefilter-popover-trigger-click"
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onMouseUp={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
>
|
||||
<div
|
||||
className="euiPopover__anchor canvasTimePickerPopover__anchor"
|
||||
>
|
||||
<button
|
||||
className="canvasTimePickerPopover__button"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<span>
|
||||
~ 2 months ago to ~ a month ago
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { TimePickerPopover } from '..';
|
||||
|
||||
const startDate = moment.utc('2019-05-04').toISOString();
|
||||
const endDate = moment.utc('2019-06-04').toISOString();
|
||||
|
||||
storiesOf('renderers/TimeFilter/components/TimePickerPopover', module).add('default', () => (
|
||||
<TimePickerPopover from={startDate} to={endDate} onSelect={action('onSelect')} />
|
||||
));
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { TimePickerPopover } from './time_picker_popover';
|
|
@ -1,7 +1,7 @@
|
|||
.canvasTimePickerMini {
|
||||
.canvasTimePickerPopover {
|
||||
width: 100%;
|
||||
|
||||
.canvasTimePickerMini__button {
|
||||
.canvasTimePickerPopover__button {
|
||||
width: 100%;
|
||||
padding: $euiSizeXS;
|
||||
border: $euiBorderThin;
|
||||
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.canvasTimePickerMini__anchor {
|
||||
.canvasTimePickerPopover__anchor {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { FunctionComponent, MouseEvent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
// @ts-ignore untyped local
|
||||
import { Popover } from '../../../../../public/components/popover';
|
||||
import { PrettyDuration } from '../pretty_duration';
|
||||
import { TimePicker } from '../time_picker';
|
||||
|
||||
export interface Props {
|
||||
/** Start date string */
|
||||
from: string;
|
||||
/** End date string */
|
||||
to: string;
|
||||
/** Function invoked when date range is changed */
|
||||
onSelect: (from: string, to: string) => void;
|
||||
}
|
||||
|
||||
export const TimePickerPopover: FunctionComponent<Props> = ({ from, to, onSelect }) => {
|
||||
const button = (handleClick: (event: MouseEvent<HTMLButtonElement>) => void) => (
|
||||
<button className="canvasTimePickerPopover__button" onClick={handleClick}>
|
||||
<PrettyDuration from={from} to={to} />
|
||||
</button>
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
id="timefilter-popover-trigger-click"
|
||||
className="canvasTimePickerPopover"
|
||||
anchorClassName="canvasTimePickerPopover__anchor"
|
||||
button={button}
|
||||
>
|
||||
{() => <TimePicker from={from} to={to} onSelect={onSelect} />}
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
TimePickerPopover.propTypes = {
|
||||
from: PropTypes.string.isRequired,
|
||||
to: PropTypes.string.isRequired,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
};
|
|
@ -289,7 +289,7 @@
|
|||
"angle": 0,
|
||||
"parent": null
|
||||
},
|
||||
"expression": "timefilterControl compact=true column=\"@timestamp\"\n| render css=\".canvasTimePickerMini__button {\n border: none !important;\n}\"",
|
||||
"expression": "timefilterControl compact=true column=\"@timestamp\"\n| render css=\".canvasTimePickerPopover__button {\n border: none !important;\n}\"",
|
||||
"filter": "timefilter from=\"now-14d\" to=now column=@timestamp"
|
||||
},
|
||||
{
|
||||
|
|
25
x-pack/legacy/plugins/canvas/common/lib/time_units.ts
Normal file
25
x-pack/legacy/plugins/canvas/common/lib/time_units.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export enum TimeUnit {
|
||||
SECONDS = 's',
|
||||
MINUTES = 'm',
|
||||
HOURS = 'h',
|
||||
DAYS = 'd',
|
||||
WEEKS = 'w',
|
||||
MONTHS = 'M',
|
||||
YEARS = 'y',
|
||||
}
|
||||
|
||||
export const timeUnits: Record<TimeUnit, string> = {
|
||||
[TimeUnit.SECONDS]: 'second',
|
||||
[TimeUnit.MINUTES]: 'minute',
|
||||
[TimeUnit.HOURS]: 'hour',
|
||||
[TimeUnit.DAYS]: 'day',
|
||||
[TimeUnit.WEEKS]: 'week',
|
||||
[TimeUnit.MONTHS]: 'month',
|
||||
[TimeUnit.YEARS]: 'year',
|
||||
};
|
|
@ -67,5 +67,5 @@
|
|||
@import '../../canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.scss';
|
||||
@import '../../canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.scss';
|
||||
@import '../../canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.scss';
|
||||
@import '../../canvas_plugin_src/renderers/time_filter/components/time_picker_mini/time_picker_mini.scss';
|
||||
@import '../../canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.scss';
|
||||
@import '../../canvas_plugin_src/uis/arguments/image_upload/image_upload.scss';
|
||||
|
|
7
x-pack/legacy/plugins/canvas/types/react_moment_prototypes.d.ts
vendored
Normal file
7
x-pack/legacy/plugins/canvas/types/react_moment_prototypes.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
declare module 'react-moment-proptypes';
|
|
@ -306,6 +306,7 @@
|
|||
"react-fast-compare": "^2.0.4",
|
||||
"react-markdown": "^3.4.1",
|
||||
"react-markdown-renderer": "^1.4.0",
|
||||
"react-moment-proptypes": "^1.6.0",
|
||||
"react-portal": "^3.2.0",
|
||||
"react-redux": "^5.0.7",
|
||||
"react-redux-request": "^1.5.6",
|
||||
|
|
|
@ -19639,7 +19639,7 @@ moment@2.22.2, moment@>=2.14.0:
|
|||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66"
|
||||
integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=
|
||||
|
||||
moment@2.24.0:
|
||||
moment@2.24.0, moment@>=1.6.0:
|
||||
version "2.24.0"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
|
||||
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
|
||||
|
@ -23139,6 +23139,13 @@ react-modal@^3.8.1:
|
|||
react-lifecycles-compat "^3.0.0"
|
||||
warning "^3.0.0"
|
||||
|
||||
react-moment-proptypes@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/react-moment-proptypes/-/react-moment-proptypes-1.6.0.tgz#8ec266ee392a08ba3412d2df2eebf833ab1046df"
|
||||
integrity sha512-4h7EuhDMTzQqZ+02KUUO+AVA7PqhbD88yXB740nFpNDyDS/bj9jiPyn2rwr9sa8oDyaE1ByFN9+t5XPyPTmN6g==
|
||||
dependencies:
|
||||
moment ">=1.6.0"
|
||||
|
||||
react-motion@^0.4.8:
|
||||
version "0.4.8"
|
||||
resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.4.8.tgz#23bb2dd27c2d8e00d229e45572d105efcf40a35e"
|
||||
|
|
Loading…
Reference in a new issue