diff --git a/src/core_plugins/metrics/public/components/data_format_picker.js b/src/core_plugins/metrics/public/components/data_format_picker.js index 346ec7e2a482..fafc9e8d78d8 100644 --- a/src/core_plugins/metrics/public/components/data_format_picker.js +++ b/src/core_plugins/metrics/public/components/data_format_picker.js @@ -1,6 +1,8 @@ import React, { Component, PropTypes } from 'react'; import _ from 'lodash'; import Select from 'react-select'; +import { durationOutputOptions, durationInputOptions } from './lib/durations'; +const durationFormatTest = /[pnumshdwMY]+,[pnumshdwMY]+/; class DataFormatPicker extends Component { @@ -8,6 +10,17 @@ class DataFormatPicker extends Component { super(props); this.handleChange = this.handleChange.bind(this); this.handleCustomChange = this.handleCustomChange.bind(this); + let from = 'ms'; + let to = 'ms'; + let decimals = 2; + if (durationFormatTest.test(props.value)) { + [from, to, decimals] = props.value.split(','); + } + this.state = { + from, + to, + decimals + }; } handleCustomChange() { @@ -17,25 +30,94 @@ class DataFormatPicker extends Component { handleChange(value) { if (value.value === 'custom') { this.handleCustomChange(); + } else if (value.value === 'duration') { + const { from, to, decimals } = this.state; + this.props.onChange({ + value: `${from},${to},${decimals}` + }); } else { this.props.onChange(value); } } + handleDurationChange(name) { + return (value) => { + if (name === 'decimals') { + value = this.decimals; + } + this.setState({ + [name]: value.value + }, () => { + const { from, to, decimals } = this.state; + this.props.onChange({ + value: `${from},${to},${decimals}` + }); + }); + }; + } + render() { const value = this.props.value || ''; let defaultValue = value; if (!_.includes(['bytes', 'number', 'percent'], value)) { defaultValue = 'custom'; } + if (durationFormatTest.test(value)) { + defaultValue = 'duration'; + } const options = [ { label: 'Bytes', value: 'bytes' }, { label: 'Number', value: 'number' }, { label: 'Percent', value: 'percent' }, + { label: 'Duration', value: 'duration' }, { label: 'Custom', value: 'custom' } ]; let custom; + if (defaultValue === 'duration') { + const [from, to, decimals] = value.split(','); + return ( +
+
+ {this.props.label} +
+
+ +
+
To
+
+ this.decimals = el} + onChange={this.handleDurationChange('decimals')} + type="text" + /> +
+ ); + } if (defaultValue === 'custom') { custom = (
diff --git a/src/core_plugins/metrics/public/components/lib/durations.js b/src/core_plugins/metrics/public/components/lib/durations.js new file mode 100644 index 000000000000..4e15125ea56a --- /dev/null +++ b/src/core_plugins/metrics/public/components/lib/durations.js @@ -0,0 +1,18 @@ +export const durationOutputOptions = [ + { label: 'milliseconds', value: 'ms' }, + { label: 'seconds', value: 's' }, + { label: 'minutes', value: 'm' }, + { label: 'hours', value: 'h' }, + { label: 'days', value: 'd' }, + { label: 'weeks', value: 'w' }, + { label: 'months', value: 'M' }, + { label: 'years', value: 'Y' } +]; + +export const durationInputOptions = [ + { label: 'picoseconds', value: 'ps' }, + { label: 'nanoseconds', value: 'ns' }, + { label: 'microseconds', value: 'us' }, + ...durationOutputOptions +]; + diff --git a/src/core_plugins/metrics/public/components/lib/tick_formatter.js b/src/core_plugins/metrics/public/components/lib/tick_formatter.js index dff3a7b6b20f..05a9d25342a4 100644 --- a/src/core_plugins/metrics/public/components/lib/tick_formatter.js +++ b/src/core_plugins/metrics/public/components/lib/tick_formatter.js @@ -1,6 +1,8 @@ import numeral from '@elastic/numeral'; -import _ from 'lodash'; import handlebars from 'handlebars/dist/handlebars'; +import { durationInputOptions } from './durations'; +import { DurationFormat } from '../../../../kibana/common/field_formats/types/duration'; +import { capitalize, isNumber } from 'lodash'; const formatLookup = { 'bytes': '0.0b', @@ -8,19 +10,37 @@ const formatLookup = { 'percent': '0.[00]%' }; +const durationsLookup = durationInputOptions.reduce((acc, row) => { + acc[row.value] = row.label; + return acc; +}, {}); + export default (format = '0,0.[00]', template) => { if (!template) template = '{{value}}'; const render = handlebars.compile(template); + const durationFormatTest = /[pnumshdwMY]+,[pnumshdwMY]+,\d+/; return (val) => { const formatString = formatLookup[format] || format; let value; - if (!_.isNumber(val)) { + if (!isNumber(val)) { value = 0; } else { - try { - value = numeral(val).format(formatString); - } catch (e) { - value = val; + if (durationFormatTest.test(format)) { + const [from, to, decimals] = format.split(','); + const inputFormat = durationsLookup[from]; + const outputFormat = `as${capitalize(durationsLookup[to])}`; + const formatter = new DurationFormat({ + inputFormat, + outputFormat, + outputPrecision: decimals + }); + value = formatter.convert(val, 'text'); + } else { + try { + value = numeral(val).format(formatString); + } catch (e) { + value = val; + } } } try {