mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Merge pull request #6499 from bevacqua/feature/duration-formatter
Implemented number field formatter for durations
This commit is contained in:
commit
73beb4b199
7 changed files with 190 additions and 0 deletions
|
@ -11,6 +11,7 @@ var config;
|
|||
var formatIds = [
|
||||
'bytes',
|
||||
'date',
|
||||
'duration',
|
||||
'ip',
|
||||
'number',
|
||||
'percent',
|
||||
|
|
50
src/ui/public/stringify/__tests__/_duration.js
Normal file
50
src/ui/public/stringify/__tests__/_duration.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
import expect from 'expect.js';
|
||||
import ngMock from 'ngMock';
|
||||
import RegistryFieldFormatsProvider from 'ui/registry/field_formats';
|
||||
|
||||
describe('Duration Format', function () {
|
||||
let fieldFormats;
|
||||
let DurationFormat;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
fieldFormats = Private(RegistryFieldFormatsProvider);
|
||||
DurationFormat = fieldFormats.getType('duration');
|
||||
}));
|
||||
|
||||
test({ inputFormat: 'seconds', outputFormat: 'humanize' })
|
||||
(-60, 'minus a minute')
|
||||
(60, 'a minute')
|
||||
(125, '2 minutes');
|
||||
|
||||
test({ inputFormat: 'minutes', outputFormat: 'humanize' })
|
||||
(-60, 'minus an hour')
|
||||
(60, 'an hour')
|
||||
(125, '2 hours');
|
||||
|
||||
test({ inputFormat: 'minutes', outputFormat: 'asHours' }) // outputPrecision defaults to: 2
|
||||
(-60, '-1.00')
|
||||
(60, '1.00')
|
||||
(125, '2.08');
|
||||
|
||||
test({ inputFormat: 'seconds', outputFormat: 'asSeconds', outputPrecision: 0 })
|
||||
(-60, '-60')
|
||||
(60, '60')
|
||||
(125, '125');
|
||||
|
||||
test({ inputFormat: 'seconds', outputFormat: 'asSeconds', outputPrecision: 2 })
|
||||
(-60, '-60.00')
|
||||
(-32.333, '-32.33')
|
||||
(60, '60.00')
|
||||
(125, '125.00');
|
||||
|
||||
function test({ inputFormat, outputFormat, outputPrecision }) {
|
||||
return function testFixture(input, output) {
|
||||
it(`should format ${input} ${inputFormat} through ${outputFormat}${outputPrecision ? `, ${outputPrecision} decimals` : ''}`, () => {
|
||||
const duration = new DurationFormat({ inputFormat, outputFormat, outputPrecision });
|
||||
expect(duration.convert(input)).to.eql(output);
|
||||
});
|
||||
return testFixture;
|
||||
};
|
||||
}
|
||||
});
|
|
@ -5,6 +5,7 @@ import './_string';
|
|||
import './_url';
|
||||
import './_color';
|
||||
import './_date';
|
||||
import './_duration';
|
||||
import './_truncate';
|
||||
describe('Stringify Component', function () {
|
||||
});
|
||||
|
|
28
src/ui/public/stringify/editors/duration.html
Normal file
28
src/ui/public/stringify/editors/duration.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<div class="editor-duration">
|
||||
<div class="form-group">
|
||||
<label>Input Format</label>
|
||||
<select
|
||||
ng-model="editor.formatParams.inputFormat"
|
||||
ng-options="inputFormat.kind as inputFormat.text for inputFormat in editor.field.format.type.inputFormats"
|
||||
class="form-control">
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Output Format</label>
|
||||
<select
|
||||
ng-model="editor.formatParams.outputFormat"
|
||||
ng-options="outputFormat.method as outputFormat.text for outputFormat in editor.field.format.type.outputFormats"
|
||||
class="form-control">
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" ng-hide="editor.field.format.isHuman()">
|
||||
<label>Decimal Places</label>
|
||||
<input type="number" min="0" max="20" ng-model="editor.formatParams.outputPrecision" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<field-format-editor-samples
|
||||
ng-model="editor.formatParams"
|
||||
inputs="cntrl.sampleInputs">
|
||||
</field-format-editor-samples>
|
||||
</div>
|
10
src/ui/public/stringify/editors/duration.less
Normal file
10
src/ui/public/stringify/editors/duration.less
Normal file
|
@ -0,0 +1,10 @@
|
|||
.editor-duration {
|
||||
display: flex;
|
||||
> .form-group {
|
||||
flex: 1 1 1%;
|
||||
padding-right: 5px;
|
||||
&:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import fieldFormats from 'ui/registry/field_formats';
|
|||
import stringifyUrl from 'ui/stringify/types/Url';
|
||||
import stringifyBytes from 'ui/stringify/types/Bytes';
|
||||
import stringifyDate from 'ui/stringify/types/Date';
|
||||
import stringifyDuration from 'ui/stringify/types/duration';
|
||||
import stringifyIp from 'ui/stringify/types/Ip';
|
||||
import stringifyNumber from 'ui/stringify/types/Number';
|
||||
import stringifyPercent from 'ui/stringify/types/Percent';
|
||||
|
@ -12,6 +13,7 @@ import stringifyTruncate from 'ui/stringify/types/truncate';
|
|||
fieldFormats.register(stringifyUrl);
|
||||
fieldFormats.register(stringifyBytes);
|
||||
fieldFormats.register(stringifyDate);
|
||||
fieldFormats.register(stringifyDuration);
|
||||
fieldFormats.register(stringifyIp);
|
||||
fieldFormats.register(stringifyNumber);
|
||||
fieldFormats.register(stringifyPercent);
|
||||
|
|
98
src/ui/public/stringify/types/duration.js
Normal file
98
src/ui/public/stringify/types/duration.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
import 'ui/stringify/editors/duration.less';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import IndexPatternsFieldFormatProvider from 'ui/index_patterns/_field_format/FieldFormat';
|
||||
import durationTemplate from 'ui/stringify/editors/duration.html';
|
||||
|
||||
export default function DurationFormatProvider(Private) {
|
||||
const ratioToSeconds = {
|
||||
picoseconds: 0.000000000001,
|
||||
nanoseconds: 0.000000001,
|
||||
microseconds: 0.000001
|
||||
};
|
||||
const FieldFormat = Private(IndexPatternsFieldFormatProvider);
|
||||
const HUMAN_FRIENDLY = 'humanize';
|
||||
const DEFAULT_OUTPUT_PRECISION = 2;
|
||||
const DEFAULT_INPUT_FORMAT = { text: 'Seconds', kind: 'seconds' };
|
||||
const inputFormats = [
|
||||
{ text: 'Picoseconds', kind: 'picoseconds' },
|
||||
{ text: 'Nanoseconds', kind: 'nanoseconds' },
|
||||
{ text: 'Microseconds', kind: 'microseconds' },
|
||||
{ text: 'Milliseconds', kind: 'milliseconds' },
|
||||
DEFAULT_INPUT_FORMAT,
|
||||
{ text: 'Minutes', kind: 'minutes' },
|
||||
{ text: 'Hours', kind: 'hours' },
|
||||
{ text: 'Days', kind: 'days' },
|
||||
{ text: 'Weeks', kind: 'weeks' },
|
||||
{ text: 'Months', kind: 'months' },
|
||||
{ text: 'Years', kind: 'years' }
|
||||
];
|
||||
const DEFAULT_OUTPUT_FORMAT = { text: 'Human Readable', method: 'humanize' };
|
||||
const outputFormats = [
|
||||
DEFAULT_OUTPUT_FORMAT,
|
||||
{ text: 'Milliseconds', method: 'asMilliseconds' },
|
||||
{ text: 'Seconds', method: 'asSeconds' },
|
||||
{ text: 'Minutes', method: 'asMinutes' },
|
||||
{ text: 'Hours', method: 'asHours' },
|
||||
{ text: 'Days', method: 'asDays' },
|
||||
{ text: 'Weeks', method: 'asWeeks' },
|
||||
{ text: 'Months', method: 'asMonths' },
|
||||
{ text: 'Years', method: 'asYears' }
|
||||
];
|
||||
|
||||
class Duration extends FieldFormat {
|
||||
isHuman() {
|
||||
return this.param('outputFormat') === HUMAN_FRIENDLY;
|
||||
}
|
||||
_convert(val) {
|
||||
const inputFormat = this.param('inputFormat');
|
||||
const outputFormat = this.param('outputFormat');
|
||||
const outputPrecision = this.param('outputPrecision');
|
||||
const human = this.isHuman();
|
||||
const prefix = val < 0 && human ? 'minus ' : '';
|
||||
const duration = parseInputAsDuration(val, inputFormat);
|
||||
const formatted = duration[outputFormat]();
|
||||
const precise = human ? formatted : formatted.toFixed(outputPrecision);
|
||||
return prefix + precise;
|
||||
}
|
||||
}
|
||||
|
||||
Duration.id = 'duration';
|
||||
Duration.title = 'Duration';
|
||||
Duration.fieldType = 'number';
|
||||
|
||||
Duration.inputFormats = inputFormats;
|
||||
Duration.outputFormats = outputFormats;
|
||||
|
||||
Duration.editor = {
|
||||
template: durationTemplate,
|
||||
controllerAs: 'cntrl',
|
||||
controller($scope, $interval) {
|
||||
this.sampleInputs = [
|
||||
-123,
|
||||
1,
|
||||
12,
|
||||
123,
|
||||
658,
|
||||
1988,
|
||||
3857,
|
||||
123292,
|
||||
923528271
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
Duration.paramDefaults = {
|
||||
inputFormat: DEFAULT_INPUT_FORMAT.kind,
|
||||
outputFormat: DEFAULT_OUTPUT_FORMAT.method,
|
||||
outputPrecision: DEFAULT_OUTPUT_PRECISION
|
||||
};
|
||||
|
||||
return Duration;
|
||||
|
||||
function parseInputAsDuration(val, inputFormat) {
|
||||
const ratio = ratioToSeconds[inputFormat] || 1;
|
||||
const kind = inputFormat in ratioToSeconds ? 'seconds' : inputFormat;
|
||||
return moment.duration(val * ratio, kind);
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue