[Index Patterns Field Formatter] Added human readable precise formatter for duration (#100540)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
19b8aa798c
commit
4aa3920746
|
@ -139,17 +139,182 @@ describe('Duration Format', () => {
|
|||
],
|
||||
});
|
||||
|
||||
testCase({
|
||||
inputFormat: 'nanoseconds',
|
||||
outputFormat: 'humanizePrecise',
|
||||
outputPrecision: 2,
|
||||
showSuffix: true,
|
||||
fixtures: [
|
||||
{
|
||||
input: 1988,
|
||||
output: '0.00 Milliseconds',
|
||||
},
|
||||
{
|
||||
input: 658,
|
||||
output: '0.00 Milliseconds',
|
||||
},
|
||||
{
|
||||
input: 3857,
|
||||
output: '0.00 Milliseconds',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
testCase({
|
||||
inputFormat: 'microseconds',
|
||||
outputFormat: 'humanizePrecise',
|
||||
outputPrecision: 2,
|
||||
showSuffix: true,
|
||||
fixtures: [
|
||||
{
|
||||
input: 1988,
|
||||
output: '1.99 Milliseconds',
|
||||
},
|
||||
{
|
||||
input: 658,
|
||||
output: '0.66 Milliseconds',
|
||||
},
|
||||
{
|
||||
input: 3857,
|
||||
output: '3.86 Milliseconds',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
testCase({
|
||||
inputFormat: 'microseconds',
|
||||
outputFormat: 'humanizePrecise',
|
||||
outputPrecision: 1,
|
||||
showSuffix: true,
|
||||
fixtures: [
|
||||
{
|
||||
input: 1988,
|
||||
output: '2.0 Milliseconds',
|
||||
},
|
||||
{
|
||||
input: 0,
|
||||
output: '0.0 Milliseconds',
|
||||
},
|
||||
{
|
||||
input: 658,
|
||||
output: '0.7 Milliseconds',
|
||||
},
|
||||
{
|
||||
input: 3857,
|
||||
output: '3.9 Milliseconds',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
testCase({
|
||||
inputFormat: 'seconds',
|
||||
outputFormat: 'humanizePrecise',
|
||||
outputPrecision: 0,
|
||||
showSuffix: true,
|
||||
fixtures: [
|
||||
{
|
||||
input: 600,
|
||||
output: '10 Minutes',
|
||||
},
|
||||
{
|
||||
input: 30,
|
||||
output: '30 Seconds',
|
||||
},
|
||||
{
|
||||
input: 3000,
|
||||
output: '50 Minutes',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
testCase({
|
||||
inputFormat: 'milliseconds',
|
||||
outputFormat: 'humanizePrecise',
|
||||
outputPrecision: 0,
|
||||
showSuffix: true,
|
||||
useShortSuffix: true,
|
||||
fixtures: [
|
||||
{
|
||||
input: -123,
|
||||
output: '-123 ms',
|
||||
},
|
||||
{
|
||||
input: 1,
|
||||
output: '1 ms',
|
||||
},
|
||||
{
|
||||
input: 600,
|
||||
output: '600 ms',
|
||||
},
|
||||
{
|
||||
input: 30,
|
||||
output: '30 ms',
|
||||
},
|
||||
{
|
||||
input: 3000,
|
||||
output: '3 s',
|
||||
},
|
||||
{
|
||||
input: 300000,
|
||||
output: '5 min',
|
||||
},
|
||||
{
|
||||
input: 30000000,
|
||||
output: '8 h',
|
||||
},
|
||||
{
|
||||
input: 90000000,
|
||||
output: '1 d',
|
||||
},
|
||||
{
|
||||
input: 9000000000,
|
||||
output: '3 mon',
|
||||
},
|
||||
{
|
||||
input: 99999999999,
|
||||
output: '3 y',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
testCase({
|
||||
inputFormat: 'milliseconds',
|
||||
outputFormat: 'humanizePrecise',
|
||||
outputPrecision: 0,
|
||||
showSuffix: true,
|
||||
useShortSuffix: true,
|
||||
includeSpaceWithSuffix: false,
|
||||
fixtures: [
|
||||
{
|
||||
input: -123,
|
||||
output: '-123ms',
|
||||
},
|
||||
{
|
||||
input: 1,
|
||||
output: '1ms',
|
||||
},
|
||||
{
|
||||
input: 600,
|
||||
output: '600ms',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
function testCase({
|
||||
inputFormat,
|
||||
outputFormat,
|
||||
outputPrecision,
|
||||
showSuffix,
|
||||
useShortSuffix,
|
||||
includeSpaceWithSuffix,
|
||||
fixtures,
|
||||
}: {
|
||||
inputFormat: string;
|
||||
outputFormat: string;
|
||||
outputPrecision: number | undefined;
|
||||
showSuffix: boolean | undefined;
|
||||
useShortSuffix?: boolean;
|
||||
includeSpaceWithSuffix?: boolean;
|
||||
fixtures: any[];
|
||||
}) {
|
||||
fixtures.forEach((fixture: Record<string, any>) => {
|
||||
|
@ -160,7 +325,14 @@ describe('Duration Format', () => {
|
|||
outputPrecision ? `, ${outputPrecision} decimals` : ''
|
||||
}`, () => {
|
||||
const duration = new DurationFormat(
|
||||
{ inputFormat, outputFormat, outputPrecision, showSuffix },
|
||||
{
|
||||
inputFormat,
|
||||
outputFormat,
|
||||
outputPrecision,
|
||||
showSuffix,
|
||||
useShortSuffix,
|
||||
includeSpaceWithSuffix,
|
||||
},
|
||||
jest.fn()
|
||||
);
|
||||
expect(duration.convert(input)).toBe(output);
|
||||
|
|
|
@ -18,6 +18,7 @@ const ratioToSeconds: Record<string, number> = {
|
|||
microseconds: 0.000001,
|
||||
};
|
||||
const HUMAN_FRIENDLY = 'humanize';
|
||||
const HUMAN_FRIENDLY_PRECISE = 'humanizePrecise';
|
||||
const DEFAULT_OUTPUT_PRECISION = 2;
|
||||
const DEFAULT_INPUT_FORMAT = {
|
||||
text: i18n.translate('data.fieldFormats.duration.inputFormats.seconds', {
|
||||
|
@ -89,59 +90,89 @@ const inputFormats = [
|
|||
},
|
||||
];
|
||||
const DEFAULT_OUTPUT_FORMAT = {
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.humanize', {
|
||||
defaultMessage: 'Human Readable',
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.humanize.approximate', {
|
||||
defaultMessage: 'Human-readable (approximate)',
|
||||
}),
|
||||
method: 'humanize',
|
||||
};
|
||||
const outputFormats = [
|
||||
{ ...DEFAULT_OUTPUT_FORMAT },
|
||||
{
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.humanize.precise', {
|
||||
defaultMessage: 'Human-readable (precise)',
|
||||
}),
|
||||
method: 'humanizePrecise',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.asMilliseconds', {
|
||||
defaultMessage: 'Milliseconds',
|
||||
}),
|
||||
shortText: i18n.translate('data.fieldFormats.duration.outputFormats.asMilliseconds.short', {
|
||||
defaultMessage: 'ms',
|
||||
}),
|
||||
method: 'asMilliseconds',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.asSeconds', {
|
||||
defaultMessage: 'Seconds',
|
||||
}),
|
||||
shortText: i18n.translate('data.fieldFormats.duration.outputFormats.asSeconds.short', {
|
||||
defaultMessage: 's',
|
||||
}),
|
||||
method: 'asSeconds',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.asMinutes', {
|
||||
defaultMessage: 'Minutes',
|
||||
}),
|
||||
shortText: i18n.translate('data.fieldFormats.duration.outputFormats.asMinutes.short', {
|
||||
defaultMessage: 'min',
|
||||
}),
|
||||
method: 'asMinutes',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.asHours', {
|
||||
defaultMessage: 'Hours',
|
||||
}),
|
||||
shortText: i18n.translate('data.fieldFormats.duration.outputFormats.asHours.short', {
|
||||
defaultMessage: 'h',
|
||||
}),
|
||||
method: 'asHours',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.asDays', {
|
||||
defaultMessage: 'Days',
|
||||
}),
|
||||
shortText: i18n.translate('data.fieldFormats.duration.outputFormats.asDays.short', {
|
||||
defaultMessage: 'd',
|
||||
}),
|
||||
method: 'asDays',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.asWeeks', {
|
||||
defaultMessage: 'Weeks',
|
||||
}),
|
||||
shortText: i18n.translate('data.fieldFormats.duration.outputFormats.asWeeks.short', {
|
||||
defaultMessage: 'w',
|
||||
}),
|
||||
method: 'asWeeks',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.asMonths', {
|
||||
defaultMessage: 'Months',
|
||||
}),
|
||||
shortText: i18n.translate('data.fieldFormats.duration.outputFormats.asMonths.short', {
|
||||
defaultMessage: 'mon',
|
||||
}),
|
||||
method: 'asMonths',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('data.fieldFormats.duration.outputFormats.asYears', {
|
||||
defaultMessage: 'Years',
|
||||
}),
|
||||
shortText: i18n.translate('data.fieldFormats.duration.outputFormats.asYears.short', {
|
||||
defaultMessage: 'y',
|
||||
}),
|
||||
method: 'asYears',
|
||||
},
|
||||
];
|
||||
|
@ -154,6 +185,29 @@ function parseInputAsDuration(val: number, inputFormat: string) {
|
|||
return moment.duration(val * ratio, kind);
|
||||
}
|
||||
|
||||
function formatInputHumanPrecise(
|
||||
val: number,
|
||||
inputFormat: string,
|
||||
outputPrecision: number,
|
||||
useShortSuffix: boolean,
|
||||
includeSpace: string
|
||||
) {
|
||||
const ratio = ratioToSeconds[inputFormat] || 1;
|
||||
const kind = (inputFormat in ratioToSeconds
|
||||
? 'seconds'
|
||||
: inputFormat) as unitOfTime.DurationConstructor;
|
||||
const valueInDuration = moment.duration(val * ratio, kind);
|
||||
|
||||
return formatDuration(
|
||||
val,
|
||||
valueInDuration,
|
||||
inputFormat,
|
||||
outputPrecision,
|
||||
useShortSuffix,
|
||||
includeSpace
|
||||
);
|
||||
}
|
||||
|
||||
export class DurationFormat extends FieldFormat {
|
||||
static id = FIELD_FORMAT_IDS.DURATION;
|
||||
static title = i18n.translate('data.fieldFormats.duration.title', {
|
||||
|
@ -167,11 +221,17 @@ export class DurationFormat extends FieldFormat {
|
|||
isHuman() {
|
||||
return this.param('outputFormat') === HUMAN_FRIENDLY;
|
||||
}
|
||||
|
||||
isHumanPrecise() {
|
||||
return this.param('outputFormat') === HUMAN_FRIENDLY_PRECISE;
|
||||
}
|
||||
|
||||
getParamDefaults() {
|
||||
return {
|
||||
inputFormat: DEFAULT_INPUT_FORMAT.kind,
|
||||
outputFormat: DEFAULT_OUTPUT_FORMAT.method,
|
||||
outputPrecision: DEFAULT_OUTPUT_PRECISION,
|
||||
includeSpaceWithSuffix: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -180,19 +240,84 @@ export class DurationFormat extends FieldFormat {
|
|||
const outputFormat = this.param('outputFormat') as keyof Duration;
|
||||
const outputPrecision = this.param('outputPrecision');
|
||||
const showSuffix = Boolean(this.param('showSuffix'));
|
||||
const useShortSuffix = Boolean(this.param('useShortSuffix'));
|
||||
const includeSpaceWithSuffix = this.param('includeSpaceWithSuffix');
|
||||
|
||||
const includeSpace = includeSpaceWithSuffix ? ' ' : '';
|
||||
|
||||
const human = this.isHuman();
|
||||
const humanPrecise = this.isHumanPrecise();
|
||||
|
||||
const prefix =
|
||||
val < 0 && human
|
||||
? i18n.translate('data.fieldFormats.duration.negativeLabel', {
|
||||
defaultMessage: 'minus',
|
||||
}) + ' '
|
||||
: '';
|
||||
const duration = parseInputAsDuration(val, inputFormat) as Record<keyof Duration, Function>;
|
||||
const formatted = duration[outputFormat]();
|
||||
const precise = human ? formatted : formatted.toFixed(outputPrecision);
|
||||
const type = outputFormats.find(({ method }) => method === outputFormat);
|
||||
const suffix = showSuffix && type ? ` ${type.text}` : '';
|
||||
|
||||
return prefix + precise + suffix;
|
||||
const duration = parseInputAsDuration(val, inputFormat) as Record<keyof Duration, Function>;
|
||||
const formatted = humanPrecise
|
||||
? formatInputHumanPrecise(val, inputFormat, outputPrecision, useShortSuffix, includeSpace)
|
||||
: duration[outputFormat]();
|
||||
|
||||
const precise = human || humanPrecise ? formatted : formatted.toFixed(outputPrecision);
|
||||
const type = outputFormats.find(({ method }) => method === outputFormat);
|
||||
|
||||
const unitText = useShortSuffix ? type?.shortText : type?.text;
|
||||
|
||||
const suffix = showSuffix && unitText && !human ? `${includeSpace}${unitText}` : '';
|
||||
|
||||
return humanPrecise ? precise : prefix + precise + suffix;
|
||||
};
|
||||
}
|
||||
|
||||
function formatDuration(
|
||||
val: number,
|
||||
duration: moment.Duration,
|
||||
inputFormat: string,
|
||||
outputPrecision: number,
|
||||
useShortSuffix: boolean,
|
||||
includeSpace: string
|
||||
) {
|
||||
// return nothing when the duration is falsy or not correctly parsed (P0D)
|
||||
if (!duration || !duration.isValid()) return;
|
||||
const units = [
|
||||
{ unit: duration.years(), nextUnitRate: 12, method: 'asYears' },
|
||||
{ unit: duration.months(), nextUnitRate: 4, method: 'asMonths' },
|
||||
{ unit: duration.weeks(), nextUnitRate: 7, method: 'asWeeks' },
|
||||
{ unit: duration.days(), nextUnitRate: 24, method: 'asDays' },
|
||||
{ unit: duration.hours(), nextUnitRate: 60, method: 'asHours' },
|
||||
{ unit: duration.minutes(), nextUnitRate: 60, method: 'asMinutes' },
|
||||
{ unit: duration.seconds(), nextUnitRate: 1000, method: 'asSeconds' },
|
||||
{ unit: duration.milliseconds(), nextUnitRate: 1000, method: 'asMilliseconds' },
|
||||
];
|
||||
|
||||
const getUnitText = (method: string) => {
|
||||
const type = outputFormats.find(({ method: methodT }) => method === methodT);
|
||||
return useShortSuffix ? type?.shortText : type?.text;
|
||||
};
|
||||
|
||||
for (let i = 0; i < units.length; i++) {
|
||||
const unitValue = units[i].unit;
|
||||
if (unitValue >= 1) {
|
||||
const unitText = getUnitText(units[i].method);
|
||||
|
||||
const value = Math.floor(unitValue);
|
||||
if (units?.[i + 1]) {
|
||||
const decimalPointValue = Math.floor(units[i + 1].unit);
|
||||
return (
|
||||
(value + decimalPointValue / units[i].nextUnitRate).toFixed(outputPrecision) +
|
||||
includeSpace +
|
||||
unitText
|
||||
);
|
||||
} else {
|
||||
return unitValue.toFixed(outputPrecision) + includeSpace + unitText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unitValue = units[units.length - 1].unit;
|
||||
const unitText = getUnitText(units[units.length - 1].method);
|
||||
|
||||
return unitValue.toFixed(outputPrecision) + includeSpace + unitText;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,184 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DurationFormatEditor should not render show suffix on dynamic output 1`] = `
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
isInvalid={false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Input format"
|
||||
id="indexPatternFieldEditor.duration.inputFormatLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSelect
|
||||
isInvalid={false}
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"text": "Seconds",
|
||||
"value": "seconds",
|
||||
},
|
||||
]
|
||||
}
|
||||
value=""
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
isInvalid={false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Output format"
|
||||
id="indexPatternFieldEditor.duration.outputFormatLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSelect
|
||||
isInvalid={false}
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"text": "Human Readable",
|
||||
"value": "humanize",
|
||||
},
|
||||
Object {
|
||||
"text": "Minutes",
|
||||
"value": "asMinutes",
|
||||
},
|
||||
]
|
||||
}
|
||||
value="dynamic"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
error={null}
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
isInvalid={false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Decimal places"
|
||||
id="indexPatternFieldEditor.duration.decimalPlacesLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiFieldNumber
|
||||
isInvalid={false}
|
||||
max={20}
|
||||
min={0}
|
||||
onChange={[Function]}
|
||||
value={2}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={false}
|
||||
disabled={false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Use short suffix"
|
||||
id="indexPatternFieldEditor.duration.showSuffixLabel.short"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={true}
|
||||
disabled={false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Include space between suffix and value"
|
||||
id="indexPatternFieldEditor.duration.includeSpace"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<FormatEditorSamples
|
||||
sampleType="text"
|
||||
samples={
|
||||
Array [
|
||||
Object {
|
||||
"input": -123,
|
||||
"output": "converted duration for -123",
|
||||
},
|
||||
Object {
|
||||
"input": 1,
|
||||
"output": "converted duration for 1",
|
||||
},
|
||||
Object {
|
||||
"input": 12,
|
||||
"output": "converted duration for 12",
|
||||
},
|
||||
Object {
|
||||
"input": 123,
|
||||
"output": "converted duration for 123",
|
||||
},
|
||||
Object {
|
||||
"input": 658,
|
||||
"output": "converted duration for 658",
|
||||
},
|
||||
Object {
|
||||
"input": 1988,
|
||||
"output": "converted duration for 1988",
|
||||
},
|
||||
Object {
|
||||
"input": 3857,
|
||||
"output": "converted duration for 3857",
|
||||
},
|
||||
Object {
|
||||
"input": 123292,
|
||||
"output": "converted duration for 123292",
|
||||
},
|
||||
Object {
|
||||
"input": 923528271,
|
||||
"output": "converted duration for 923528271",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`DurationFormatEditor should render human readable output normally 1`] = `
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
|
@ -223,6 +402,48 @@ exports[`DurationFormatEditor should render non-human readable output normally 1
|
|||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={false}
|
||||
disabled={true}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Use short suffix"
|
||||
id="indexPatternFieldEditor.duration.showSuffixLabel.short"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
fullWidth={false}
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiSwitch
|
||||
checked={true}
|
||||
disabled={true}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Include space between suffix and value"
|
||||
id="indexPatternFieldEditor.duration.includeSpace"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<FormatEditorSamples
|
||||
sampleType="text"
|
||||
samples={
|
||||
|
|
|
@ -11,6 +11,7 @@ import { shallow } from 'enzyme';
|
|||
|
||||
import { DurationFormatEditor } from './duration';
|
||||
import { FieldFormat } from 'src/plugins/data/public';
|
||||
import { EuiSwitch } from '@elastic/eui';
|
||||
|
||||
const fieldType = 'number';
|
||||
const format = {
|
||||
|
@ -22,9 +23,11 @@ const format = {
|
|||
inputFormat: 'seconds',
|
||||
outputFormat: 'humanize',
|
||||
outputPrecision: 10,
|
||||
includeSpaceWithSuffix: true,
|
||||
};
|
||||
}),
|
||||
isHuman: () => true,
|
||||
isHumanPrecise: () => false,
|
||||
type: {
|
||||
inputFormats: [
|
||||
{
|
||||
|
@ -78,6 +81,7 @@ describe('DurationFormatEditor', () => {
|
|||
inputFormat: 'seconds',
|
||||
outputFormat: 'asMinutes',
|
||||
outputPrecision: 10,
|
||||
includeSpaceWithSuffix: true,
|
||||
};
|
||||
}),
|
||||
isHuman: () => false,
|
||||
|
@ -91,6 +95,55 @@ describe('DurationFormatEditor', () => {
|
|||
onError={onError}
|
||||
/>
|
||||
);
|
||||
const labels = component.find(EuiSwitch);
|
||||
expect(labels.length).toEqual(3);
|
||||
expect(labels.get(0).props.label.props.defaultMessage).toEqual('Show suffix');
|
||||
expect(labels.get(1).props.label.props.defaultMessage).toEqual('Use short suffix');
|
||||
expect(labels.get(2).props.label.props.defaultMessage).toEqual(
|
||||
'Include space between suffix and value'
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should not render show suffix on dynamic output', async () => {
|
||||
const newFormat = {
|
||||
...format,
|
||||
getParamDefaults: jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
inputFormat: 'seconds',
|
||||
outputFormat: 'dynamic',
|
||||
outputPrecision: 2,
|
||||
includeSpaceWithSuffix: true,
|
||||
};
|
||||
}),
|
||||
isHuman: () => false,
|
||||
isHumanPrecise: () => true,
|
||||
};
|
||||
const component = shallow(
|
||||
<DurationFormatEditor
|
||||
fieldType={fieldType}
|
||||
format={(newFormat as unknown) as FieldFormat}
|
||||
formatParams={{ ...formatParams, outputFormat: 'dynamic' }}
|
||||
onChange={onChange}
|
||||
onError={onError}
|
||||
/>
|
||||
);
|
||||
|
||||
const labels = component.find(EuiSwitch);
|
||||
expect(labels.length).toEqual(2);
|
||||
const useShortSuffixSwitch = labels.get(0);
|
||||
|
||||
expect(useShortSuffixSwitch.props.label.props.defaultMessage).toEqual('Use short suffix');
|
||||
expect(useShortSuffixSwitch.props.disabled).toEqual(false);
|
||||
|
||||
const includeSpaceSwitch = labels.get(1);
|
||||
|
||||
expect(includeSpaceSwitch.props.disabled).toEqual(false);
|
||||
expect(includeSpaceSwitch.props.label.props.defaultMessage).toEqual(
|
||||
'Include space between suffix and value'
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -41,6 +41,8 @@ interface DurationFormatEditorFormatParams {
|
|||
inputFormat: string;
|
||||
outputFormat: string;
|
||||
showSuffix?: boolean;
|
||||
useShortSuffix?: boolean;
|
||||
includeSpaceWithSuffix?: boolean;
|
||||
}
|
||||
|
||||
export class DurationFormatEditor extends DefaultFormatEditor<
|
||||
|
@ -83,9 +85,14 @@ export class DurationFormatEditor extends DefaultFormatEditor<
|
|||
}
|
||||
|
||||
render() {
|
||||
const { format, formatParams } = this.props;
|
||||
const { format } = this.props;
|
||||
const { error, samples, hasDecimalError } = this.state;
|
||||
|
||||
const formatParams: DurationFormatEditorFormatParams = {
|
||||
includeSpaceWithSuffix: format.getParamDefaults().includeSpaceWithSuffix,
|
||||
...this.props.formatParams,
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
|
@ -159,17 +166,55 @@ export class DurationFormatEditor extends DefaultFormatEditor<
|
|||
isInvalid={!!error}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
{!(format as DurationFormat).isHumanPrecise() && (
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="indexPatternFieldEditor.duration.showSuffixLabel"
|
||||
defaultMessage="Show suffix"
|
||||
/>
|
||||
}
|
||||
checked={Boolean(formatParams.showSuffix)}
|
||||
onChange={(e) => {
|
||||
this.onChange({
|
||||
showSuffix: !formatParams.showSuffix,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
disabled={
|
||||
!Boolean(formatParams.showSuffix) && !(format as DurationFormat).isHumanPrecise()
|
||||
}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="indexPatternFieldEditor.duration.showSuffixLabel"
|
||||
defaultMessage="Show suffix"
|
||||
id="indexPatternFieldEditor.duration.showSuffixLabel.short"
|
||||
defaultMessage="Use short suffix"
|
||||
/>
|
||||
}
|
||||
checked={Boolean(formatParams.showSuffix)}
|
||||
checked={Boolean(formatParams.useShortSuffix)}
|
||||
onChange={(e) => {
|
||||
this.onChange({ showSuffix: !formatParams.showSuffix });
|
||||
this.onChange({ useShortSuffix: !formatParams.useShortSuffix });
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow>
|
||||
<EuiSwitch
|
||||
disabled={
|
||||
!Boolean(formatParams.showSuffix) && !(format as DurationFormat).isHumanPrecise()
|
||||
}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="indexPatternFieldEditor.duration.includeSpace"
|
||||
defaultMessage="Include space between suffix and value"
|
||||
/>
|
||||
}
|
||||
checked={Boolean(formatParams.includeSpaceWithSuffix)}
|
||||
onChange={(e) => {
|
||||
this.onChange({ includeSpaceWithSuffix: !formatParams.includeSpaceWithSuffix });
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -820,7 +820,6 @@
|
|||
"data.fieldFormats.duration.outputFormats.asSeconds": "秒",
|
||||
"data.fieldFormats.duration.outputFormats.asWeeks": "週間",
|
||||
"data.fieldFormats.duration.outputFormats.asYears": "年",
|
||||
"data.fieldFormats.duration.outputFormats.humanize": "人間に読解可能",
|
||||
"data.fieldFormats.duration.title": "期間",
|
||||
"data.fieldFormats.histogram.title": "ヒストグラム",
|
||||
"data.fieldFormats.ip.title": "IP アドレス",
|
||||
|
|
|
@ -823,7 +823,6 @@
|
|||
"data.fieldFormats.duration.outputFormats.asSeconds": "秒",
|
||||
"data.fieldFormats.duration.outputFormats.asWeeks": "周",
|
||||
"data.fieldFormats.duration.outputFormats.asYears": "年",
|
||||
"data.fieldFormats.duration.outputFormats.humanize": "可人工读取",
|
||||
"data.fieldFormats.duration.title": "持续时间",
|
||||
"data.fieldFormats.histogram.title": "直方图",
|
||||
"data.fieldFormats.ip.title": "IP 地址",
|
||||
|
|
Loading…
Reference in a new issue