[Input controls vis] replace react-input-range with EuiDualRange (#31119)

* [Input controls vis] replace react-input-range with EuiDualRange

* remove unneeded styles

* correctly format I18n with variables

* fix problems with long decimals

* fix one test case

* clean-up error message text, remove extra commas in jest test

* fix bug where values were returned as strings

* use i18n.translate instead of passing formatMessage into isRangeValid

* assert error message in isRangeValid unit test

* changes from node scripts/i18n_check --fix

* remove localization from RangeControl component since it no longer has any text, update snapshots

* another snapshot update

* ensure min and max are not null

* check for value before checking if min/max is null
This commit is contained in:
Nathan Reese 2019-03-11 16:25:29 -06:00 committed by GitHub
parent 5664bbe583
commit b5c958ea53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 344 additions and 441 deletions

View file

@ -201,7 +201,6 @@
"react-color": "^2.13.8",
"react-dom": "^16.8.0",
"react-grid-layout": "^0.16.2",
"react-input-range": "^1.3.0",
"react-markdown": "^3.1.4",
"react-redux": "^5.0.7",
"react-router-dom": "^4.3.1",

View file

@ -307,7 +307,7 @@ exports[`Renders range control 1`] = `
}
}
>
<InjectIntl(RangeControlUi)
<RangeControl
control={
Object {
"format": [Function],

View file

@ -7,19 +7,9 @@ exports[`disabled 1`] = `
id="mock-range-control"
label="range control"
>
<EuiRange
compressed={false}
<ValidatedDualRange
disabled={true}
fullWidth={false}
levels={Array []}
max={100}
min={0}
showInput={false}
showLabels={false}
showRange={false}
showTicks={false}
showValue={false}
step={1}
showInput={true}
/>
</FormRow>
`;
@ -31,87 +21,32 @@ exports[`renders RangeControl 1`] = `
id="mock-range-control"
label="range control"
>
<EuiFormRow
data-test-subj="rangeControlFormRow"
describedByIds={Array []}
error={Array []}
fullWidth={false}
hasEmptyLabelSpace={false}
isInvalid={false}
labelType="label"
>
<EuiFlexGroup
alignItems="center"
gutterSize="s"
>
<EuiFlexItem
grow={false}
>
<input
className="euiFieldNumber"
data-test-subj="rangeControlMinInputValue"
id="mock-range-control_min"
max={100}
min={0}
name="min"
onChange={[Function]}
type="number"
value=""
/>
</EuiFlexItem>
<EuiFlexItem
className="icvInputRange__container"
grow={false}
>
<InputRange
allowSameValues={false}
ariaLabelledby="mock-range-control"
classNames={
Object {
"activeTrack": "input-range__track input-range__track--active",
"disabledInputRange": "input-range input-range--disabled",
"inputRange": "input-range",
"labelContainer": "input-range__label-container",
"maxLabel": "input-range__label input-range__label--max",
"minLabel": "input-range__label input-range__label--min",
"slider": "input-range__slider",
"sliderContainer": "input-range__slider-container",
"track": "input-range__track input-range__track--background",
"valueLabel": "input-range__label input-range__label--value",
}
}
disabled={false}
draggableTrack={true}
formatLabel={[Function]}
maxValue={100}
minValue={0}
onChange={[Function]}
onChangeComplete={[Function]}
step={1}
value={
Object {
"max": 0,
"min": 0,
}
}
/>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
<input
className="euiFieldNumber"
data-test-subj="rangeControlMaxInputValue"
id="mock-range-control_max"
max={100}
min={0}
name="max"
onChange={[Function]}
type="number"
value=""
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>
<ValidatedDualRange
id="mock-range-control"
max={100}
min={0}
onChange={[Function]}
showInput={true}
showRange={true}
showTicks={true}
ticks={
Array [
Object {
"label": 0,
"value": 0,
},
Object {
"label": 100,
"value": 100,
},
]
}
value={
Array [
"",
"",
]
}
/>
</FormRow>
`;

View file

@ -2,25 +2,4 @@
width: 100%;
margin: 0 $euiSizeXS;
padding: $euiSizeS;
// Removes the browser's number stepper
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
// hide slider labels since they are displayed in inputs
.input-range__track .input-range__label-container {
display: none;
}
// do not center min/max labels - otherwise the overflow slider sides
.input-range__label-container {
left: 0% !important;
}
}
.icvInputRange__container {
min-width: $euiSize * 10 !important; // !important needed for IE
}

View file

@ -17,175 +17,98 @@
* under the License.
*/
import _ from 'lodash';
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import InputRange from 'react-input-range';
import { FormRow } from './form_row';
import { injectI18n } from '@kbn/i18n/react';
import { ValidatedDualRange } from 'ui/validated_range';
import {
EuiFormRow,
EuiFlexGroup,
EuiFlexItem,
EuiRange,
} from '@elastic/eui';
const toState = ({ control }) => {
const sliderValue = control.hasValue() ?
control.value :
// InputRange component does not have an "empty state"
// Faking an empty state by setting the slider value range to length of zero anchored at the range minimum
{
min: control.min,
max: control.min
};
const state = {
sliderValue,
minValue: control.hasValue() ? control.value.min : '',
maxValue: control.hasValue() ? control.value.max : '',
isRangeValid: true,
errorMessage: '',
};
return state;
};
class RangeControlUi extends Component {
constructor(props) {
super(props);
this.state = toState(props);
function roundWithPrecision(value, decimalPlaces, roundFunction) {
if (decimalPlaces <= 0) {
return roundFunction(value);
}
componentWillReceiveProps = (nextProps) => {
this.setState(toState(nextProps));
};
let results = value;
results = results * Math.pow(10, decimalPlaces);
results = roundFunction(results);
results = results / Math.pow(10, decimalPlaces);
return results;
}
handleOnChange = (value) => {
this.setState({
sliderValue: value,
minValue: value.min,
isRangeValid: true,
maxValue: value.max,
errorMessage: '',
});
};
export function ceilWithPrecision(value, decimalPlaces) {
return roundWithPrecision(value, decimalPlaces, Math.ceil);
}
handleOnChangeComplete = (value) => {
this.props.stageFilter(this.props.controlIndex, value);
};
export function floorWithPrecision(value, decimalPlaces) {
return roundWithPrecision(value, decimalPlaces, Math.floor);
}
handleMinChange = (evt) => {
this.handleChange(parseFloat(evt.target.value), this.state.maxValue);
};
export class RangeControl extends Component {
state = {};
handleMaxChange = (evt) => {
this.handleChange(this.state.minValue, parseFloat(evt.target.value));
};
static getDerivedStateFromProps(nextProps, prevState) {
const nextValue = nextProps.control.hasValue()
? [nextProps.control.value.min, nextProps.control.value.max]
: ['', ''];
handleChange = (min, max) => {
min = isNaN(min) ? '' : min;
max = isNaN(max) ? '' : max;
const isMinValid = min !== '';
const isMaxValid = max !== '';
let isRangeValid = true;
let errorMessage = '';
if ((!isMinValid && isMaxValid) || (isMinValid && !isMaxValid)) {
isRangeValid = false;
errorMessage = this.props.intl.formatMessage({
id: 'inputControl.vis.rangeControl.minMaxValidErrorMessage',
defaultMessage: 'both min and max must be set'
});
if (nextProps.control.hasValue() && nextProps.control.value.min == null) {
nextValue[0] = '';
}
if (nextProps.control.hasValue() && nextProps.control.value.max == null) {
nextValue[1] = '';
}
if (isMinValid && isMaxValid && max < min) {
isRangeValid = false;
errorMessage = this.props.intl.formatMessage({
id: 'inputControl.vis.rangeControl.maxValidErrorMessage',
defaultMessage: 'max must be greater or equal to min'
});
if (nextValue !== prevState.prevValue) {
return {
value: nextValue,
prevValue: nextValue,
};
}
this.setState({
minValue: min,
maxValue: max,
isRangeValid,
errorMessage,
});
return null;
}
onChangeComplete = _.debounce(value => {
const controlValue = {
min: value[0],
max: value[1]
};
this.props.stageFilter(this.props.controlIndex, controlValue);
}, 200);
if (isRangeValid && isMaxValid && isMinValid) {
this.handleOnChangeComplete({ min, max });
}
};
formatLabel = (value) => {
let formatedValue = value;
const decimalPlaces = _.get(this.props, 'control.options.decimalPlaces');
if (decimalPlaces !== null && decimalPlaces >= 0) {
formatedValue = value.toFixed(decimalPlaces);
}
return formatedValue;
};
renderControl() {
if (!this.props.control.isEnabled()) {
return (
<EuiRange
<ValidatedDualRange
disabled
showInput
/>
);
}
const decimalPlaces = _.get(this.props, 'control.options.decimalPlaces', 0);
const min = floorWithPrecision(this.props.control.min, decimalPlaces);
const max = ceilWithPrecision(this.props.control.max, decimalPlaces);
const ticks = [
{ value: min, label: min },
{ value: max, label: max }
];
return (
<EuiFormRow
isInvalid={!this.state.isRangeValid}
error={this.state.errorMessage ? [this.state.errorMessage] : []}
data-test-subj="rangeControlFormRow"
>
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem grow={false}>
<input
id={`${this.props.control.id}_min`}
name="min"
type="number"
data-test-subj="rangeControlMinInputValue"
className="euiFieldNumber"
value={this.state.minValue}
min={this.props.control.min}
max={this.props.control.max}
onChange={this.handleMinChange}
/>
</EuiFlexItem>
<EuiFlexItem grow={false} className="icvInputRange__container">
<InputRange
maxValue={this.props.control.max}
minValue={this.props.control.min}
step={this.props.control.options.step}
value={this.state.sliderValue}
onChange={this.handleOnChange}
onChangeComplete={this.handleOnChangeComplete}
draggableTrack={true}
ariaLabelledby={this.props.control.id}
formatLabel={this.formatLabel}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<input
id={`${this.props.control.id}_max`}
name="max"
type="number"
className="euiFieldNumber"
data-test-subj="rangeControlMaxInputValue"
value={this.state.maxValue}
min={this.props.control.min}
max={this.props.control.max}
onChange={this.handleMaxChange}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>
<ValidatedDualRange
id={this.props.control.id}
min={min}
max={max}
value={this.state.value}
onChange={this.onChangeComplete}
showInput
showRange
showTicks
ticks={ticks}
/>
);
}
@ -203,10 +126,8 @@ class RangeControlUi extends Component {
}
}
RangeControlUi.propTypes = {
RangeControl.propTypes = {
control: PropTypes.object.isRequired,
controlIndex: PropTypes.number.isRequired,
stageFilter: PropTypes.func.isRequired
};
export const RangeControl = injectI18n(RangeControlUi);

View file

@ -18,11 +18,12 @@
*/
import React from 'react';
import { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers';
import { findTestSubject } from '@elastic/eui/lib/test';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import {
RangeControl,
ceilWithPrecision,
floorWithPrecision,
} from './range_control';
const control = {
@ -43,7 +44,7 @@ const control = {
};
test('renders RangeControl', () => {
const component = shallowWithIntl(<RangeControl.WrappedComponent
const component = shallowWithIntl(<RangeControl
control={control}
controlIndex={0}
stageFilter={() => {}}
@ -66,7 +67,7 @@ test('disabled', () => {
return false;
}
};
const component = shallowWithIntl(<RangeControl.WrappedComponent
const component = shallowWithIntl(<RangeControl
control={disabledRangeControl}
controlIndex={0}
stageFilter={() => {}}
@ -74,59 +75,12 @@ test('disabled', () => {
expect(component).toMatchSnapshot(); // eslint-disable-line
});
describe('min and max input values', () => {
const component = mountWithIntl(<RangeControl.WrappedComponent
control={control}
controlIndex={0}
stageFilter={() => {}}
/>);
const BOTH_MIN_AND_MAX_MUST_BE_SET_ERROR = 'both min and max must be set';
const getMinInput = () => findTestSubject(component, 'rangeControlMinInputValue');
const getMaxInput = () => findTestSubject(component, 'rangeControlMaxInputValue');
const getRangeRow = () => findTestSubject(component, 'rangeControlFormRow');
test('are initially blank', () => {
expect(getMinInput().props().value).toBe('');
expect(getMaxInput().props().value).toBe('');
});
test('min can be set manually', () => {
getMinInput().simulate('change', { target: { value: 3 } });
expect(getMinInput().props().value).toBe(3);
});
test('when only min is specified an error is shown', () => {
expect(getRangeRow().text().indexOf(BOTH_MIN_AND_MAX_MUST_BE_SET_ERROR)).toBeGreaterThan(-1);
});
test('max can be set manually', () => {
getMaxInput().simulate('change', { target: { value: 6 } });
expect(getMaxInput().props().value).toBe(6);
});
test('when both min and max are set there is no error', () => {
expect(getRangeRow().text().indexOf(BOTH_MIN_AND_MAX_MUST_BE_SET_ERROR)).toBe(-1);
});
test('0 is a valid minimum value', () => {
getMinInput().simulate('change', { target: { value: 0 } });
expect(getMinInput().props().value).toBe(0);
expect(getRangeRow().text().indexOf(BOTH_MIN_AND_MAX_MUST_BE_SET_ERROR)).toBe(-1);
});
test('min can be deleted and there will be an error shown', () => {
getMinInput().simulate('change', { target: { value: '' } });
expect(getMinInput().props().value).toBe('');
expect(getRangeRow().text().indexOf(BOTH_MIN_AND_MAX_MUST_BE_SET_ERROR)).toBeGreaterThan(-1);
});
test('both max and min can be deleted and there will not be an error shown', () => {
getMaxInput().simulate('change', { target: { value: '' } });
expect(getMaxInput().props().value).toBe('');
expect(getRangeRow().text().indexOf(BOTH_MIN_AND_MAX_MUST_BE_SET_ERROR)).toBe(-1);
});
test('ceilWithPrecision', () => {
expect(ceilWithPrecision(999.133, 0)).toBe(1000);
expect(ceilWithPrecision(999.133, 2)).toBe(999.14);
});
test('floorWithPrecision', () => {
expect(floorWithPrecision(100.777, 0)).toBe(100);
expect(floorWithPrecision(100.777, 2)).toBe(100.77);
});

View file

@ -7,7 +7,6 @@
@import './navbar';
@import './config';
@import './pagination';
@import './react_input_range';
@import './sidebar';
@import './spinner';
@import './table';

View file

@ -1,104 +0,0 @@
// SASSTODO: rem values are actually based off of a 14px base
// so changing them to EUI variables would alter computed values
.input-range__slider {
appearance: none;
background: $euiColorPrimary;
border: 1px solid $euiColorPrimary;
border-radius: 100%;
cursor: pointer;
display: block;
height: 1rem;
margin-left: -0.5rem;
margin-top: -0.65rem;
outline: none;
position: absolute;
top: 50%;
transition: transform 0.3s ease-out, box-shadow 0.3s ease-out;
width: 1rem;
&:active {
transform: scale(1.3);
}
&:focus {
@include euiFocusRing('large');
}
}
.input-range--disabled .input-range__slider {
background: $euiColorLightShade;
border: 1px solid $euiColorLightShade;
box-shadow: none;
transform: none;
}
.input-range__slider-container {
transition: left 0.3s ease-out;
}
.input-range__label {
color: $euiColorMediumShade;
font-size: 0.8rem;
transform: translateZ(0);
white-space: nowrap;
}
.input-range__label--min,
.input-range__label--max {
bottom: -1.4rem;
position: absolute;
}
.input-range__label--min {
left: 0;
}
.input-range__label--max {
right: 0;
}
.input-range__label--value {
position: absolute;
top: -1.8rem;
}
.input-range__label-container {
left: -50%;
position: relative;
}
.input-range__label--max .input-range__label-container {
left: 50%;
}
.input-range__track {
background: $euiColorLightShade;
border-radius: 0.3rem;
cursor: pointer;
display: block;
height: 0.3rem;
position: relative;
transition: left 0.3s ease-out, width 0.3s ease-out;
}
.input-range--disabled .input-range__track {
background: $euiColorLightShade;
}
.input-range__track--background {
left: 0;
margin-top: -0.15rem;
position: absolute;
right: 0;
top: 50%;
}
.input-range__track--active {
background: $euiColorPrimary;
}
.input-range {
margin: 0 $euiSizeS;
position: relative;
width: calc(100% - #{$euiSize});
}

View file

@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export { ValidatedDualRange } from './validated_dual_range';

View file

@ -0,0 +1,66 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { i18n } from '@kbn/i18n';
const LOWER_VALUE_INDEX = 0;
const UPPER_VALUE_INDEX = 1;
export function isRangeValid(value, min, max) {
let lowerValue = isNaN(value[LOWER_VALUE_INDEX]) ? '' : value[LOWER_VALUE_INDEX];
let upperValue = isNaN(value[UPPER_VALUE_INDEX]) ? '' : value[UPPER_VALUE_INDEX];
const isLowerValueValid = lowerValue !== '';
const isUpperValueValid = upperValue !== '';
if (isLowerValueValid) {
lowerValue = parseFloat(lowerValue);
}
if (isUpperValueValid) {
upperValue = parseFloat(upperValue);
}
let isValid = true;
let errorMessage = '';
if ((!isLowerValueValid && isUpperValueValid) || (isLowerValueValid && !isUpperValueValid)) {
isValid = false;
errorMessage = i18n.translate('common.ui.dualRangeControl.mustSetBothErrorMessage', {
defaultMessage: 'Both lower and upper values must be set'
});
}
if ((isLowerValueValid && lowerValue < min) || (isUpperValueValid && upperValue > max)) {
isValid = false;
errorMessage = i18n.translate('common.ui.dualRangeControl.outsideOfRangeErrorMessage', {
defaultMessage: 'Values must be on or between {min} and {max}',
values: { min, max }
});
}
if (isLowerValueValid && isUpperValueValid && upperValue < lowerValue) {
isValid = false;
errorMessage = i18n.translate('common.ui.dualRangeControl.upperValidErrorMessage', {
defaultMessage: 'Upper value must be greater or equal to lower value'
});
}
return {
isValid,
errorMessage,
};
}

View file

@ -0,0 +1,65 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { isRangeValid } from './is_range_valid';
it('Should return true when lower and upper values are set and between min and max', () => {
const { isValid } = isRangeValid([2, 3], 1, 10);
expect(isValid).toBe(true);
});
it('Should handle string values and return true when lower and upper values are set and between min and max', () => {
const { isValid } = isRangeValid(['192', '1000'], 100, 1000);
expect(isValid).toBe(true);
});
it('Should return true when lower and upper values are not set (empty range)', () => {
const { isValid } = isRangeValid(['', ''], 1, 10);
expect(isValid).toBe(true);
});
it('Should return false when lower value is not set and upper value is set', () => {
const { isValid, errorMessage } = isRangeValid(['', 3], 1, 10);
expect(isValid).toBe(false);
expect(errorMessage).toBe('Both lower and upper values must be set');
});
it('Should return false when lower value is set and upper value is not set', () => {
const { isValid, errorMessage } = isRangeValid([2, ''], 1, 10);
expect(isValid).toBe(false);
expect(errorMessage).toBe('Both lower and upper values must be set');
});
it('Should return false when lower value is greater than upper value', () => {
const { isValid, errorMessage } = isRangeValid([3, 2], 1, 10);
expect(isValid).toBe(false);
expect(errorMessage).toBe('Upper value must be greater or equal to lower value');
});
it('Should return false when lower value is less than min', () => {
const { isValid, errorMessage } = isRangeValid([0, 2], 1, 10);
expect(isValid).toBe(false);
expect(errorMessage).toBe('Values must be on or between 1 and 10');
});
it('Should return false when upper value is greater than max', () => {
const { isValid, errorMessage } = isRangeValid([2, 12], 1, 10);
expect(isValid).toBe(false);
expect(errorMessage).toBe('Values must be on or between 1 and 10');
});

View file

@ -0,0 +1,84 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React, { Component } from 'react';
import { isRangeValid } from './is_range_valid';
import {
EuiFormRow,
EuiDualRange,
} from '@elastic/eui';
// Wrapper around EuiDualRange that ensures onChange callback is only called when range value
// is valid and within min/max
export class ValidatedDualRange extends Component {
state = {};
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.value !== prevState.prevValue) {
const { isValid, errorMessage } = isRangeValid(
nextProps.value,
nextProps.min,
nextProps.max);
return {
value: nextProps.value,
prevValue: nextProps.value,
isValid,
errorMessage,
};
}
return null;
}
onChange = (value) => {
const { isValid, errorMessage } = isRangeValid(value, this.props.min, this.props.max);
this.setState({
value,
isValid,
errorMessage,
});
if (isValid) {
this.props.onChange(value);
}
};
render() {
const {
value, // eslint-disable-line no-unused-vars
onChange, // eslint-disable-line no-unused-vars
...rest
} = this.props;
return (
<EuiFormRow
isInvalid={!this.state.isValid}
error={this.state.errorMessage ? [this.state.errorMessage] : []}
>
<EuiDualRange
value={this.state.value}
onChange={this.onChange}
{...rest}
/>
</EuiFormRow>
);
}
}

View file

@ -777,8 +777,6 @@
"inputControl.vis.inputControlVis.clearFormButtonLabel": "清除表单",
"inputControl.vis.listControl.selectPlaceholder": "选择......",
"inputControl.vis.listControl.selectTextPlaceholder": "选择......",
"inputControl.vis.rangeControl.maxValidErrorMessage": "最大值必须大于或等于最小值",
"inputControl.vis.rangeControl.minMaxValidErrorMessage": "必须设置最小值和最大值",
"inspectorViews.data.dataDescriptionTooltip": "查看可视化后面的数据",
"inspectorViews.data.dataTitle": "数据",
"inspectorViews.data.downloadCSVButtonLabel": "下载 CSV",
@ -8193,4 +8191,4 @@
"xpack.watcher.watchActionsTitle": "满足后将执行 {watchActionsCount, plural, one{# 个操作} other {# 个操作}}",
"xpack.watcher.watcherDescription": "通过创建、管理和监测警报来检测数据中的更改。"
}
}
}

View file

@ -3785,11 +3785,6 @@ attr-accept@^1.1.3:
dependencies:
core-js "^2.5.0"
autobind-decorator@^1.3.4:
version "1.4.3"
resolved "https://registry.yarnpkg.com/autobind-decorator/-/autobind-decorator-1.4.3.tgz#4c96ffa77b10622ede24f110f5dbbf56691417d1"
integrity sha1-TJb/p3sQYi7eJPEQ9du/VmkUF9E=
autolinker@~0.15.0:
version "0.15.3"
resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832"
@ -19149,14 +19144,6 @@ react-input-autosize@^2.1.2, react-input-autosize@^2.2.1:
dependencies:
prop-types "^15.5.8"
react-input-range@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/react-input-range/-/react-input-range-1.3.0.tgz#f96d001631ab817417f1e26d8f9f9684b4827f59"
integrity sha1-+W0AFjGrgXQX8eJtj5+WhLSCf1k=
dependencies:
autobind-decorator "^1.3.4"
prop-types "^15.5.8"
react-inspector@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-2.3.0.tgz#fc9c1d38ab687fc0d190dcaf133ae40158968fc8"