[ML] Data Frames: Fix calendar_interval for date histograms. (#36905) (#37157)

Fixes the use of calendar_interval instead of interval for date histograms.
This commit is contained in:
Walter Rafelsberger 2019-05-25 18:47:51 +02:00 committed by GitHub
parent 4f837c214c
commit 64e1f5a4ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 133 additions and 39 deletions

View file

@ -70,7 +70,7 @@ export enum DATE_HISTOGRAM_FORMAT {
interface GroupByDateHistogram extends GroupByConfigBase {
agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.DATE_HISTOGRAM;
format?: DATE_HISTOGRAM_FORMAT;
interval: string;
calendar_interval: string;
}
interface GroupByHistogram extends GroupByConfigBase {
@ -86,7 +86,11 @@ export type GroupByConfigWithInterval = GroupByDateHistogram | GroupByHistogram;
export type PivotGroupByConfig = GroupByDateHistogram | GroupByHistogram | GroupByTerms;
export type PivotGroupByConfigDict = Dictionary<PivotGroupByConfig>;
export function groupByConfigHasInterval(arg: any): arg is GroupByConfigWithInterval {
export function isGroupByDateHistogram(arg: any): arg is GroupByDateHistogram {
return arg.hasOwnProperty('calendar_interval');
}
export function isGroupByHistogram(arg: any): arg is GroupByHistogram {
return arg.hasOwnProperty('interval');
}
@ -107,7 +111,7 @@ export interface DateHistogramAgg {
date_histogram: {
field: FieldName;
format?: DATE_HISTOGRAM_FORMAT;
interval: string;
calendar_interval: string;
};
}

View file

@ -105,7 +105,7 @@ export function getDataFramePreviewRequest(
const dateHistogramAgg: DateHistogramAgg = {
date_histogram: {
field: g.field,
interval: g.interval,
calendar_interval: g.calendar_interval,
},
};
@ -113,7 +113,7 @@ export function getDataFramePreviewRequest(
// date_histrogram aggregation formats like 'yyyy-MM-dd'. The following code extracts
// the interval unit from the configurations interval and adds a matching
// aggregation format to the configuration.
const timeUnitMatch = g.interval.match(dateHistogramIntervalFormatRegex);
const timeUnitMatch = g.calendar_interval.match(dateHistogramIntervalFormatRegex);
if (timeUnitMatch !== null && Array.isArray(timeUnitMatch) && timeUnitMatch.length === 2) {
// the following is just a TS compatible way of using the
// matched string like `d` as the property to access the enum.

View file

@ -56,7 +56,7 @@ function getDefaultGroupByConfig(
aggName,
dropDownName,
field: fieldName,
interval: '1m',
calendar_interval: '1m',
};
}
}

View file

@ -31,7 +31,8 @@ import {
AggName,
DropDownLabel,
getPivotQuery,
groupByConfigHasInterval,
isGroupByDateHistogram,
isGroupByHistogram,
isKibanaContext,
KibanaContext,
KibanaContextValue,
@ -179,7 +180,10 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
pivotAggsArr.map(d => `${d.agg} ${d.field} ${d.aggName}`).join(' '),
pivotGroupByArr
.map(
d => `${d.agg} ${d.field} ${groupByConfigHasInterval(d) ? d.interval : ''} ${d.aggName}`
d =>
`${d.agg} ${d.field} ${isGroupByHistogram(d) ? d.interval : ''} ${
isGroupByDateHistogram(d) ? d.calendar_interval : ''
} ${d.aggName}`
)
.join(' '),
search,

View file

@ -15,7 +15,8 @@ import { Dictionary } from '../../../../common/types/common';
import {
DataFramePreviewRequest,
getDataFramePreviewRequest,
groupByConfigHasInterval,
isGroupByDateHistogram,
isGroupByHistogram,
PivotAggsConfigDict,
PivotGroupByConfigDict,
PivotQuery,
@ -79,7 +80,10 @@ export const usePivotPreviewData = (
aggsArr.map(a => `${a.agg} ${a.field} ${a.aggName}`).join(' '),
groupByArr
.map(
g => `${g.agg} ${g.field} ${g.aggName} ${groupByConfigHasInterval(g) ? g.interval : ''}`
g =>
`${g.agg} ${g.field} ${g.aggName} ${
isGroupByDateHistogram(g) ? g.calendar_interval : ''
} ${isGroupByHistogram(g) ? g.interval : ''}`
)
.join(' '),
JSON.stringify(query),

View file

@ -23,7 +23,7 @@ exports[`Data Frame: <GroupByLabelForm /> Date histogram aggregation 1`] = `
className="mlGroupByLabel__text"
color="subdued"
>
10m
1m
</EuiTextColor>
</EuiFlexItem>
<EuiFlexItem
@ -55,9 +55,9 @@ exports[`Data Frame: <GroupByLabelForm /> Date histogram aggregation 1`] = `
Object {
"agg": "date_histogram",
"aggName": "the-group-by-agg-name",
"calendar_interval": "1m",
"dropDownName": "the-group-by-drop-down-name",
"field": "the-group-by-field",
"interval": "10m",
}
}
onChange={[Function]}

View file

@ -23,7 +23,7 @@ exports[`Data Frame: <GroupByLabelSummary /> Date histogram aggregation 1`] = `
className="mlGroupByLabel__text"
color="subdued"
>
10m
1m
</EuiTextColor>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -35,13 +35,45 @@ exports[`Data Frame: Group By <PopoverForm /> Minimal initialization 1`] = `
label="Interval"
labelType="label"
>
<EuiFieldText
<EuiSelect
compressed={false}
defaultValue="10m"
fullWidth={false}
isInvalid={false}
hasNoInitialSelection={false}
isLoading={false}
onChange={[Function]}
options={
Array [
Object {
"text": "1m",
"value": "1m",
},
Object {
"text": "1h",
"value": "1h",
},
Object {
"text": "1d",
"value": "1d",
},
Object {
"text": "1w",
"value": "1w",
},
Object {
"text": "1M",
"value": "1M",
},
Object {
"text": "1q",
"value": "1q",
},
Object {
"text": "1y",
"value": "1y",
},
]
}
value="1m"
/>
</EuiFormRow>
<EuiFormRow

View file

@ -18,7 +18,7 @@ describe('Data Frame: <GroupByLabelForm />', () => {
field: 'the-group-by-field',
aggName: 'the-group-by-agg-name',
dropDownName: 'the-group-by-drop-down-name',
interval: '10m',
calendar_interval: '1m',
};
const props = {
item,

View file

@ -12,7 +12,8 @@ import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiPopover, EuiTextColor } fr
import {
AggName,
groupByConfigHasInterval,
isGroupByDateHistogram,
isGroupByHistogram,
PivotGroupByConfig,
PivotGroupByConfigDict,
} from '../../common';
@ -41,15 +42,23 @@ export const GroupByLabelForm: React.SFC<Props> = ({
setPopoverVisibility(false);
}
let interval: string | undefined;
if (isGroupByDateHistogram(item)) {
interval = item.calendar_interval;
} else if (isGroupByHistogram(item)) {
interval = item.interval;
}
return (
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false}>
<EuiFlexItem className="mlGroupByLabel--text">
<span className="mlGroupByLabel__text">{item.aggName}</span>
</EuiFlexItem>
{groupByConfigHasInterval(item) && (
{interval !== undefined && (
<EuiFlexItem grow={false} className="mlGroupByLabel--text mlGroupByLabel--interval">
<EuiTextColor color="subdued" className="mlGroupByLabel__text">
{item.interval}
{interval}
</EuiTextColor>
</EuiFlexItem>
)}

View file

@ -18,7 +18,7 @@ describe('Data Frame: <GroupByLabelSummary />', () => {
field: 'the-group-by-field',
aggName: 'the-group-by-agg-name',
dropDownName: 'the-group-by-drop-down-name',
interval: '10m',
calendar_interval: '1m',
};
const props = {
item,

View file

@ -8,7 +8,7 @@ import React from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiTextColor } from '@elastic/eui';
import { groupByConfigHasInterval, PivotGroupByConfig } from '../../common';
import { isGroupByDateHistogram, isGroupByHistogram, PivotGroupByConfig } from '../../common';
interface Props {
item: PivotGroupByConfig;
@ -16,15 +16,23 @@ interface Props {
}
export const GroupByLabelSummary: React.SFC<Props> = ({ item, optionsDataId }) => {
let interval: string | undefined;
if (isGroupByDateHistogram(item)) {
interval = item.calendar_interval;
} else if (isGroupByHistogram(item)) {
interval = item.interval;
}
return (
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false}>
<EuiFlexItem className="mlGroupByLabel--text">
<span className="mlGroupByLabel__text">{optionsDataId}</span>
</EuiFlexItem>
{groupByConfigHasInterval(item) && (
{interval !== undefined && (
<EuiFlexItem grow={false} className="mlGroupByLabel--text mlGroupByLabel--interval">
<EuiTextColor color="subdued" className="mlGroupByLabel__text">
{item.interval}
{interval}
</EuiTextColor>
</EuiFlexItem>
)}

View file

@ -80,7 +80,7 @@ describe('Data Frame: Group By <PopoverForm />', () => {
aggName: 'the-agg-name',
dropDownName: 'the-drop-down-name',
field: 'the-field',
interval: '10m',
calendar_interval: '1m',
};
const otherAggNames: AggName[] = [];
const onChange = (item: PivotGroupByConfig) => {};

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useState } from 'react';
import React, { Fragment, useState } from 'react';
import { i18n } from '@kbn/i18n';
@ -15,7 +15,8 @@ import { dictionaryToArray } from '../../../../common/types/common';
import {
AggName,
dateHistogramIntervalFormatRegex,
groupByConfigHasInterval,
isGroupByDateHistogram,
isGroupByHistogram,
histogramIntervalFormatRegex,
isAggName,
PivotGroupByConfig,
@ -64,6 +65,16 @@ interface SelectOption {
type optionalInterval = string | undefined;
function getDefaultInterval(defaultData: PivotGroupByConfig): string | undefined {
if (isGroupByDateHistogram(defaultData)) {
return defaultData.calendar_interval;
} else if (isGroupByHistogram(defaultData)) {
return defaultData.interval;
}
return undefined;
}
interface Props {
defaultData: PivotGroupByConfig;
otherAggNames: AggName[];
@ -80,15 +91,17 @@ export const PopoverForm: React.SFC<Props> = ({
const [agg, setAgg] = useState(defaultData.agg);
const [aggName, setAggName] = useState(defaultData.aggName);
const [field, setField] = useState(defaultData.field);
const [interval, setInterval] = useState(
groupByConfigHasInterval(defaultData) ? defaultData.interval : undefined
);
const [interval, setInterval] = useState(getDefaultInterval(defaultData));
function getUpdatedItem(): PivotGroupByConfig {
const updatedItem = { ...defaultData, agg, aggName, field };
if (groupByConfigHasInterval(updatedItem) && interval !== undefined) {
if (isGroupByHistogram(updatedItem) && interval !== undefined) {
updatedItem.interval = interval;
} else if (isGroupByDateHistogram(updatedItem) && interval !== undefined) {
updatedItem.calendar_interval = interval;
}
// Casting to PivotGroupByConfig because TS would otherwise complain about the
// PIVOT_SUPPORTED_GROUP_BY_AGGS type for `agg`.
return updatedItem as PivotGroupByConfig;
@ -130,10 +143,11 @@ export const PopoverForm: React.SFC<Props> = ({
}
const validInterval =
groupByConfigHasInterval(defaultData) && isIntervalValid(interval, defaultData.agg);
(isGroupByDateHistogram(defaultData) || isGroupByHistogram(defaultData)) &&
isIntervalValid(interval, defaultData.agg);
let formValid = validAggName;
if (formValid && groupByConfigHasInterval(defaultData)) {
if (formValid && (isGroupByDateHistogram(defaultData) || isGroupByHistogram(defaultData))) {
formValid = isIntervalValid(interval, defaultData.agg);
}
@ -178,7 +192,7 @@ export const PopoverForm: React.SFC<Props> = ({
/>
</EuiFormRow>
)}
{groupByConfigHasInterval(defaultData) && (
{(isGroupByDateHistogram(defaultData) || isGroupByHistogram(defaultData)) && (
<EuiFormRow
error={
!validInterval && [
@ -192,11 +206,30 @@ export const PopoverForm: React.SFC<Props> = ({
defaultMessage: 'Interval',
})}
>
<EuiFieldText
defaultValue={interval}
isInvalid={!validInterval}
onChange={e => setInterval(e.target.value)}
/>
<Fragment>
{isGroupByHistogram(defaultData) && (
<EuiFieldText
defaultValue={interval}
isInvalid={!validInterval}
onChange={e => setInterval(e.target.value)}
/>
)}
{isGroupByDateHistogram(defaultData) && (
<EuiSelect
options={[
{ value: '1m', text: '1m' },
{ value: '1h', text: '1h' },
{ value: '1d', text: '1d' },
{ value: '1w', text: '1w' },
{ value: '1M', text: '1M' },
{ value: '1q', text: '1q' },
{ value: '1y', text: '1y' },
]}
value={interval}
onChange={e => setInterval(e.target.value)}
/>
)}
</Fragment>
</EuiFormRow>
)}
<EuiFormRow hasEmptyLabelSpace>