mirror of https://github.com/apache/superset.git
Update time filter to use `react-datetime` (#5819)
* Update time filter to use react-datetime * Clean up code * Many small fixes and improvements * Fix small things
This commit is contained in:
parent
6d573724aa
commit
6c9be9d67b
File diff suppressed because it is too large
Load Diff
|
@ -92,12 +92,11 @@
|
|||
"react-addons-css-transition-group": "^15.6.0",
|
||||
"react-addons-shallow-compare": "^15.4.2",
|
||||
"react-bootstrap": "^0.31.5",
|
||||
"react-bootstrap-datetimepicker": "0.0.22",
|
||||
"react-bootstrap-dialog": "^0.10.0",
|
||||
"react-bootstrap-slider": "2.1.5",
|
||||
"react-bootstrap-table": "^4.3.1",
|
||||
"react-color": "^2.13.8",
|
||||
"react-datetime": "2.14.0",
|
||||
"react-datetime": "^2.14.0",
|
||||
"react-dnd": "^2.5.4",
|
||||
"react-dnd-html5-backend": "^2.5.4",
|
||||
"react-dom": "^15.6.2",
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.rdtPicker table {
|
||||
font-size: 12;
|
||||
}
|
|
@ -5,6 +5,7 @@ import {
|
|||
DropdownButton,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
Glyphicon,
|
||||
InputGroup,
|
||||
Label,
|
||||
MenuItem,
|
||||
|
@ -14,11 +15,11 @@ import {
|
|||
Tab,
|
||||
Tabs,
|
||||
} from 'react-bootstrap';
|
||||
import Datetime from 'react-datetime';
|
||||
import 'react-datetime/css/react-datetime.css';
|
||||
import DateTimeField from 'react-bootstrap-datetimepicker';
|
||||
import 'react-bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css';
|
||||
import moment from 'moment';
|
||||
|
||||
import './DateFilterControl.css';
|
||||
import ControlHeader from '../ControlHeader';
|
||||
import { t } from '../../../locales';
|
||||
import PopoverSection from '../../../components/PopoverSection';
|
||||
|
@ -45,7 +46,6 @@ const TIME_GRAIN_OPTIONS = ['seconds', 'minutes', 'hours', 'days', 'weeks', 'mon
|
|||
const MOMENT_FORMAT = 'YYYY-MM-DD[T]HH:mm:ss';
|
||||
const DEFAULT_SINCE = moment().startOf('day').subtract(7, 'days').format(MOMENT_FORMAT);
|
||||
const DEFAULT_UNTIL = moment().startOf('day').format(MOMENT_FORMAT);
|
||||
const INVALID_DATE_MESSAGE = 'Invalid date';
|
||||
const SEPARATOR = ' : ';
|
||||
const FREEFORM_TOOLTIP = t(
|
||||
'Superset supports smart date parsing. Strings like `last sunday` or ' +
|
||||
|
@ -68,19 +68,60 @@ const defaultProps = {
|
|||
value: 'Last week',
|
||||
};
|
||||
|
||||
|
||||
function isFreeform(s) {
|
||||
function isValidMoment(s) {
|
||||
/* Moment sometimes consider invalid dates as valid, eg, "10 years ago" gets
|
||||
* parsed as "Fri Jan 01 2010 00:00:00" local time. This function does a
|
||||
* better check by comparing a string with a parse/format roundtrip.
|
||||
*/
|
||||
return (s !== moment(s, MOMENT_FORMAT).format(MOMENT_FORMAT));
|
||||
return (s === moment(s, MOMENT_FORMAT).format(MOMENT_FORMAT));
|
||||
}
|
||||
|
||||
function getStateFromSeparator(value) {
|
||||
const [since, until] = value.split(SEPARATOR, 2);
|
||||
return { since, until, type: TYPES.CUSTOM_START_END };
|
||||
}
|
||||
|
||||
function getStateFromCommonTimeFrame(value) {
|
||||
const units = value.split(' ')[1] + 's';
|
||||
return {
|
||||
type: TYPES.DEFAULTS,
|
||||
common: value,
|
||||
since: moment().startOf('day').subtract(1, units).format(MOMENT_FORMAT),
|
||||
until: moment().startOf('day').format(MOMENT_FORMAT),
|
||||
};
|
||||
}
|
||||
|
||||
function getStateFromCustomRange(value) {
|
||||
const [rel, num, grain] = value.split(' ', 3);
|
||||
let since;
|
||||
let until;
|
||||
if (rel === RELATIVE_TIME_OPTIONS.LAST) {
|
||||
until = moment().startOf('day').format(MOMENT_FORMAT);
|
||||
since = moment()
|
||||
.startOf('day')
|
||||
.subtract(num, grain)
|
||||
.format(MOMENT_FORMAT);
|
||||
} else {
|
||||
until = moment()
|
||||
.startOf('day')
|
||||
.add(num, grain)
|
||||
.format(MOMENT_FORMAT);
|
||||
since = moment().startOf('day').format(MOMENT_FORMAT);
|
||||
}
|
||||
return {
|
||||
type: TYPES.CUSTOM_RANGE,
|
||||
common: null,
|
||||
rel,
|
||||
num,
|
||||
grain,
|
||||
since,
|
||||
until,
|
||||
};
|
||||
}
|
||||
|
||||
export default class DateFilterControl extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const value = props.value || defaultProps.value;
|
||||
this.state = {
|
||||
type: TYPES.DEFAULTS,
|
||||
|
||||
|
@ -95,29 +136,36 @@ export default class DateFilterControl extends React.Component {
|
|||
// distinct start/end values, either ISO or freeform
|
||||
since: DEFAULT_SINCE,
|
||||
until: DEFAULT_UNTIL,
|
||||
freeformInputs: {},
|
||||
|
||||
// react-datetime has a `closeOnSelect` prop, but it's buggy... so we
|
||||
// handle the calendar visibility here ourselves
|
||||
showSinceCalendar: false,
|
||||
showUntilCalendar: false,
|
||||
sinceViewMode: 'days',
|
||||
untilViewMode: 'days',
|
||||
};
|
||||
if (value.indexOf(SEPARATOR) >= 0) {
|
||||
this.state.type = TYPES.CUSTOM_START_END;
|
||||
[this.state.since, this.state.until] = value.split(SEPARATOR, 2);
|
||||
} else {
|
||||
this.state.type = TYPES.DEFAULTS;
|
||||
if (COMMON_TIME_FRAMES.indexOf(value) >= 0) {
|
||||
this.state.common = value;
|
||||
} else {
|
||||
this.state.common = null;
|
||||
[this.state.rel, this.state.num, this.state.grain] = value.split(' ', 3);
|
||||
}
|
||||
}
|
||||
this.state.freeformInputs.since = isFreeform(this.state.since);
|
||||
this.state.freeformInputs.until = isFreeform(this.state.until);
|
||||
|
||||
// We need direct access to the state of the `DateTimeField` component
|
||||
this.dateTimeFieldRefs = {};
|
||||
|
||||
this.close = this.close.bind(this);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.isValidSince = this.isValidSince.bind(this);
|
||||
this.isValidUntil = this.isValidUntil.bind(this);
|
||||
this.onEnter = this.onEnter.bind(this);
|
||||
this.renderInput = this.renderInput.bind(this);
|
||||
this.setCustomRange = this.setCustomRange.bind(this);
|
||||
this.setCustomStartEnd = this.setCustomStartEnd.bind(this);
|
||||
this.setTypeCustomRange = this.setTypeCustomRange.bind(this);
|
||||
this.setTypeCustomStartEnd = this.setTypeCustomStartEnd.bind(this);
|
||||
this.toggleCalendar = this.toggleCalendar.bind(this);
|
||||
}
|
||||
componentDidMount() {
|
||||
const value = this.props.value;
|
||||
if (value.indexOf(SEPARATOR) >= 0) {
|
||||
this.state = { ...this.state, ...getStateFromSeparator(value) };
|
||||
} else if (COMMON_TIME_FRAMES.indexOf(value) >= 0) {
|
||||
this.state = { ...this.state, ...getStateFromCommonTimeFrame(value) };
|
||||
} else {
|
||||
this.state = { ...this.state, ...getStateFromCustomRange(value) };
|
||||
}
|
||||
document.addEventListener('click', this.handleClick);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
|
@ -128,66 +176,37 @@ export default class DateFilterControl extends React.Component {
|
|||
this.close();
|
||||
}
|
||||
}
|
||||
setDefaults(timeFrame) {
|
||||
const nextState = {
|
||||
type: TYPES.DEFAULTS,
|
||||
common: timeFrame,
|
||||
until: moment().startOf('day').format(MOMENT_FORMAT),
|
||||
};
|
||||
const units = timeFrame.split(' ')[1] + 's';
|
||||
nextState.since = moment().startOf('day').subtract(1, units).format(MOMENT_FORMAT);
|
||||
this.setState(nextState, this.updateRefs);
|
||||
}
|
||||
setCustomRange(key, value) {
|
||||
const nextState = { ...this.state, type: TYPES.CUSTOM_RANGE };
|
||||
if (key !== undefined && value !== undefined) {
|
||||
nextState[key] = value;
|
||||
}
|
||||
if (nextState.rel === RELATIVE_TIME_OPTIONS.LAST) {
|
||||
nextState.until = moment().startOf('day').format(MOMENT_FORMAT);
|
||||
nextState.since = moment()
|
||||
.startOf('day')
|
||||
.subtract(nextState.num, nextState.grain)
|
||||
.format(MOMENT_FORMAT);
|
||||
} else {
|
||||
nextState.until = moment()
|
||||
.startOf('day')
|
||||
.add(nextState.num, nextState.grain)
|
||||
.format(MOMENT_FORMAT);
|
||||
nextState.since = moment().startOf('day').format(MOMENT_FORMAT);
|
||||
}
|
||||
this.setState(nextState, this.updateRefs);
|
||||
const updatedState = { ...this.state, [key]: value };
|
||||
const combinedValue = [updatedState.rel, updatedState.num, updatedState.grain].join(' ');
|
||||
this.setState(getStateFromCustomRange(combinedValue));
|
||||
}
|
||||
setCustomStartEnd(key, value) {
|
||||
const nextState = {
|
||||
const closeCalendar = (
|
||||
(key === 'since' && this.state.sinceViewMode === 'days') ||
|
||||
(key === 'until' && this.state.untilViewMode === 'days')
|
||||
);
|
||||
this.setState({
|
||||
type: TYPES.CUSTOM_START_END,
|
||||
freeformInputs: { ...this.state.freeformInputs },
|
||||
};
|
||||
if (value === INVALID_DATE_MESSAGE) {
|
||||
// the DateTimeField component will return `Invalid date` for freeform
|
||||
// text, so we need to cheat and steal the value from the state
|
||||
const freeformValue = this.dateTimeFieldRefs[key].state.inputValue;
|
||||
nextState.freeformInputs[key] = true;
|
||||
nextState[key] = freeformValue;
|
||||
} else {
|
||||
nextState.freeformInputs[key] = false;
|
||||
nextState[key] = value;
|
||||
}
|
||||
this.setState(nextState, this.updateRefs);
|
||||
[key]: typeof value === 'string' ? value : value.format(MOMENT_FORMAT),
|
||||
showSinceCalendar: this.state.showSinceCalendar && !closeCalendar,
|
||||
showUntilCalendar: this.state.showUntilCalendar && !closeCalendar,
|
||||
sinceViewMode: closeCalendar ? 'days' : this.state.sinceViewMode,
|
||||
untilViewMode: closeCalendar ? 'days' : this.state.untilViewMode,
|
||||
});
|
||||
}
|
||||
setTypeCustomRange() {
|
||||
this.setState({ type: TYPES.CUSTOM_RANGE });
|
||||
}
|
||||
setTypeCustomStartEnd() {
|
||||
this.setState({ type: TYPES.CUSTOM_START_END });
|
||||
}
|
||||
handleClick(e) {
|
||||
// switch to `TYPES.CUSTOM_START_END` when the calendar is clicked
|
||||
if (this.startEndSectionRef && this.startEndSectionRef.contains(e.target)) {
|
||||
this.setState({ type: TYPES.CUSTOM_START_END });
|
||||
this.setTypeCustomStartEnd();
|
||||
}
|
||||
}
|
||||
updateRefs() {
|
||||
/* This is required because the <DateTimeField> component does not accept
|
||||
* freeform dates as props, since they can't be parsed by `moment`.
|
||||
*/
|
||||
this.dateTimeFieldRefs.since.setState({ inputValue: this.state.since });
|
||||
this.dateTimeFieldRefs.until.setState({ inputValue: this.state.until });
|
||||
}
|
||||
close() {
|
||||
let val;
|
||||
if (this.state.type === TYPES.DEFAULTS) {
|
||||
|
@ -199,11 +218,53 @@ export default class DateFilterControl extends React.Component {
|
|||
}
|
||||
this.props.onChange(val);
|
||||
this.refs.trigger.hide();
|
||||
this.setState({ showSinceCalendar: false, showUntilCalendar: false });
|
||||
}
|
||||
isValidSince(date) {
|
||||
return (!isValidMoment(this.state.until) || date <= moment(this.state.until, MOMENT_FORMAT));
|
||||
}
|
||||
isValidUntil(date) {
|
||||
return (!isValidMoment(this.state.since) || date >= moment(this.state.since, MOMENT_FORMAT));
|
||||
}
|
||||
toggleCalendar(key) {
|
||||
const nextState = {};
|
||||
if (key === 'showSinceCalendar') {
|
||||
nextState.showSinceCalendar = !this.state.showSinceCalendar;
|
||||
if (!this.state.showSinceCalendar) {
|
||||
nextState.showUntilCalendar = false;
|
||||
}
|
||||
} else if (key === 'showUntilCalendar') {
|
||||
nextState.showUntilCalendar = !this.state.showUntilCalendar;
|
||||
if (!this.state.showUntilCalendar) {
|
||||
nextState.showSinceCalendar = false;
|
||||
}
|
||||
}
|
||||
this.setState(nextState);
|
||||
}
|
||||
renderInput(props, key) {
|
||||
return (
|
||||
<FormGroup>
|
||||
<InputGroup>
|
||||
<FormControl
|
||||
{...props}
|
||||
type="text"
|
||||
onKeyPress={this.onEnter}
|
||||
onFocus={this.setTypeCustomStartEnd}
|
||||
onClick={() => {}}
|
||||
/>
|
||||
<InputGroup.Button onClick={() => this.toggleCalendar(key)}>
|
||||
<Button>
|
||||
<Glyphicon glyph="calendar" style={{ padding: 3 }} />
|
||||
</Button>
|
||||
</InputGroup.Button>
|
||||
</InputGroup>
|
||||
</FormGroup>
|
||||
);
|
||||
}
|
||||
renderPopover() {
|
||||
const grainOptions = TIME_GRAIN_OPTIONS.map(grain => (
|
||||
<MenuItem
|
||||
onSelect={this.setCustomRange.bind(this, 'grain')}
|
||||
onSelect={value => this.setCustomRange('grain', value)}
|
||||
key={grain}
|
||||
eventKey={grain}
|
||||
active={grain === this.state.grain}
|
||||
|
@ -215,7 +276,7 @@ export default class DateFilterControl extends React.Component {
|
|||
<Radio
|
||||
key={timeFrame.replace(' ', '').toLowerCase()}
|
||||
checked={this.state.common === timeFrame}
|
||||
onChange={this.setDefaults.bind(this, timeFrame)}
|
||||
onChange={() => this.setState(getStateFromCommonTimeFrame(timeFrame))}
|
||||
>
|
||||
{timeFrame}
|
||||
</Radio>
|
||||
|
@ -236,7 +297,7 @@ export default class DateFilterControl extends React.Component {
|
|||
<PopoverSection
|
||||
title="Relative to today"
|
||||
isSelected={this.state.type === TYPES.CUSTOM_RANGE}
|
||||
onSelect={this.setCustomRange.bind(this)}
|
||||
onSelect={this.setTypeCustomRange}
|
||||
>
|
||||
<div className="clearfix centered" style={{ marginTop: '12px' }}>
|
||||
<div style={{ width: '60px', marginTop: '-4px' }} className="input-inline">
|
||||
|
@ -245,17 +306,17 @@ export default class DateFilterControl extends React.Component {
|
|||
componentClass={InputGroup.Button}
|
||||
id="input-dropdown-rel"
|
||||
title={this.state.rel}
|
||||
onFocus={this.setCustomRange.bind(this)}
|
||||
onFocus={this.setTypeCustomRange}
|
||||
>
|
||||
<MenuItem
|
||||
onSelect={this.setCustomRange.bind(this, 'rel')}
|
||||
onSelect={value => this.setCustomRange('rel', value)}
|
||||
key={RELATIVE_TIME_OPTIONS.LAST}
|
||||
eventKey={RELATIVE_TIME_OPTIONS.LAST}
|
||||
active={this.state.rel === RELATIVE_TIME_OPTIONS.LAST}
|
||||
>Last
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onSelect={this.setCustomRange.bind(this, 'rel')}
|
||||
onSelect={value => this.setCustomRange('rel', value)}
|
||||
key={RELATIVE_TIME_OPTIONS.NEXT}
|
||||
eventKey={RELATIVE_TIME_OPTIONS.NEXT}
|
||||
active={this.state.rel === RELATIVE_TIME_OPTIONS.NEXT}
|
||||
|
@ -267,11 +328,9 @@ export default class DateFilterControl extends React.Component {
|
|||
<FormControl
|
||||
bsSize="small"
|
||||
type="text"
|
||||
onChange={event => (
|
||||
this.setCustomRange.call(this, 'num', event.target.value)
|
||||
)}
|
||||
onFocus={this.setCustomRange.bind(this)}
|
||||
onKeyPress={this.onEnter.bind(this)}
|
||||
onChange={event => this.setCustomRange('num', event.target.value)}
|
||||
onFocus={this.setTypeCustomRange}
|
||||
onKeyPress={this.onEnter}
|
||||
value={this.state.num}
|
||||
style={{ height: '30px' }}
|
||||
/>
|
||||
|
@ -282,7 +341,7 @@ export default class DateFilterControl extends React.Component {
|
|||
componentClass={InputGroup.Button}
|
||||
id="input-dropdown-grain"
|
||||
title={this.state.grain}
|
||||
onFocus={this.setCustomRange.bind(this)}
|
||||
onFocus={this.setTypeCustomRange}
|
||||
>
|
||||
{grainOptions}
|
||||
</DropdownButton>
|
||||
|
@ -292,48 +351,37 @@ export default class DateFilterControl extends React.Component {
|
|||
<PopoverSection
|
||||
title="Start / end"
|
||||
isSelected={this.state.type === TYPES.CUSTOM_START_END}
|
||||
onSelect={this.setCustomStartEnd.bind(this)}
|
||||
onSelect={this.setTypeCustomStartEnd}
|
||||
info={FREEFORM_TOOLTIP}
|
||||
>
|
||||
<div ref={(ref) => { this.startEndSectionRef = ref; }}>
|
||||
<InputGroup>
|
||||
<div style={{ margin: '5px 0' }}>
|
||||
<DateTimeField
|
||||
ref={(ref) => { this.dateTimeFieldRefs.since = ref; }}
|
||||
dateTime={
|
||||
this.state.freeformInputs.since ?
|
||||
DEFAULT_SINCE :
|
||||
this.state.since
|
||||
}
|
||||
defaultText={this.state.since}
|
||||
onChange={this.setCustomStartEnd.bind(this, 'since')}
|
||||
maxDate={moment(this.state.until, MOMENT_FORMAT)}
|
||||
format={MOMENT_FORMAT}
|
||||
inputFormat={MOMENT_FORMAT}
|
||||
onClick={this.setCustomStartEnd.bind(this)}
|
||||
inputProps={{
|
||||
onKeyPress: this.onEnter.bind(this),
|
||||
onFocus: this.setCustomStartEnd.bind(this),
|
||||
}}
|
||||
<Datetime
|
||||
value={this.state.since}
|
||||
defaultValue={this.state.since}
|
||||
viewDate={this.state.since}
|
||||
onChange={value => this.setCustomStartEnd('since', value)}
|
||||
isValidDate={this.isValidSince}
|
||||
onClick={this.setTypeCustomStartEnd}
|
||||
renderInput={props => this.renderInput(props, 'showSinceCalendar')}
|
||||
open={this.state.showSinceCalendar}
|
||||
viewMode={this.state.sinceViewMode}
|
||||
onViewModeChange={sinceViewMode => this.setState({ sinceViewMode })}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ margin: '5px 0' }}>
|
||||
<DateTimeField
|
||||
ref={(ref) => { this.dateTimeFieldRefs.until = ref; }}
|
||||
dateTime={
|
||||
this.state.freeformInputs.until ?
|
||||
DEFAULT_UNTIL :
|
||||
this.state.until
|
||||
}
|
||||
defaultText={this.state.until}
|
||||
onChange={this.setCustomStartEnd.bind(this, 'until')}
|
||||
minDate={moment(this.state.since, MOMENT_FORMAT).add(1, 'days')}
|
||||
format={MOMENT_FORMAT}
|
||||
inputFormat={MOMENT_FORMAT}
|
||||
inputProps={{
|
||||
onKeyPress: this.onEnter.bind(this),
|
||||
onFocus: this.setCustomStartEnd.bind(this),
|
||||
}}
|
||||
<Datetime
|
||||
value={this.state.until}
|
||||
defaultValue={this.state.until}
|
||||
viewDate={this.state.until}
|
||||
onChange={value => this.setCustomStartEnd('until', value)}
|
||||
isValidDate={this.isValidUntil}
|
||||
onClick={this.setTypeCustomStartEnd}
|
||||
renderInput={props => this.renderInput(props, 'showUntilCalendar')}
|
||||
open={this.state.showUntilCalendar}
|
||||
viewMode={this.state.untilViewMode}
|
||||
onViewModeChange={untilViewMode => this.setState({ untilViewMode })}
|
||||
/>
|
||||
</div>
|
||||
</InputGroup>
|
||||
|
@ -347,7 +395,7 @@ export default class DateFilterControl extends React.Component {
|
|||
bsSize="small"
|
||||
className="float-right ok"
|
||||
bsStyle="primary"
|
||||
onClick={this.close.bind(this)}
|
||||
onClick={this.close}
|
||||
>
|
||||
Ok
|
||||
</Button>
|
||||
|
|
|
@ -7,6 +7,7 @@ const propTypes = {
|
|||
value: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
PropTypes.object,
|
||||
]),
|
||||
};
|
||||
|
||||
|
|
|
@ -2200,12 +2200,6 @@ babel-register@^6.24.1, babel-register@^6.26.0, babel-register@^6.9.0:
|
|||
mkdirp "^0.5.1"
|
||||
source-map-support "^0.4.15"
|
||||
|
||||
babel-runtime@^5.6.18:
|
||||
version "5.8.38"
|
||||
resolved "http://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19"
|
||||
dependencies:
|
||||
core-js "^1.0.0"
|
||||
|
||||
babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||
|
@ -8107,7 +8101,7 @@ moment-timezone@0.5.5:
|
|||
dependencies:
|
||||
moment ">= 2.6.0"
|
||||
|
||||
"moment@>= 2.6.0", moment@^2.20.1, moment@^2.8.2:
|
||||
"moment@>= 2.6.0", moment@^2.20.1:
|
||||
version "2.22.2"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66"
|
||||
|
||||
|
@ -10009,14 +10003,6 @@ react-addons-test-utils@^15.6.2:
|
|||
version "15.6.2"
|
||||
resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.6.2.tgz#c12b6efdc2247c10da7b8770d185080a7b047156"
|
||||
|
||||
react-bootstrap-datetimepicker@0.0.22:
|
||||
version "0.0.22"
|
||||
resolved "https://registry.yarnpkg.com/react-bootstrap-datetimepicker/-/react-bootstrap-datetimepicker-0.0.22.tgz#07e448d993157d049ad0876d0f9a3c9c5029d9c5"
|
||||
dependencies:
|
||||
babel-runtime "^5.6.18"
|
||||
classnames "^2.1.2"
|
||||
moment "^2.8.2"
|
||||
|
||||
react-bootstrap-dialog@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/react-bootstrap-dialog/-/react-bootstrap-dialog-0.10.0.tgz#fca5c84804ea2b6debe3833c6d4b7480bcff0175"
|
||||
|
@ -10062,9 +10048,9 @@ react-color@^2.13.8:
|
|||
reactcss "^1.2.0"
|
||||
tinycolor2 "^1.4.1"
|
||||
|
||||
react-datetime@2.14.0:
|
||||
version "2.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-datetime/-/react-datetime-2.14.0.tgz#c7859c5b765275d7980f1cca27c03a727ff9ccef"
|
||||
react-datetime@^2.14.0:
|
||||
version "2.15.0"
|
||||
resolved "https://registry.yarnpkg.com/react-datetime/-/react-datetime-2.15.0.tgz#a8f7da6c58b6b45dbeea32d4e8485db17614e12c"
|
||||
dependencies:
|
||||
create-react-class "^15.5.2"
|
||||
object-assign "^3.0.0"
|
||||
|
|
Loading…
Reference in New Issue