mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
Fixes the use of calendar_interval instead of interval for date histograms.
This commit is contained in:
parent
4f837c214c
commit
64e1f5a4ba
14 changed files with 133 additions and 39 deletions
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -56,7 +56,7 @@ function getDefaultGroupByConfig(
|
|||
aggName,
|
||||
dropDownName,
|
||||
field: fieldName,
|
||||
interval: '1m',
|
||||
calendar_interval: '1m',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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]}
|
||||
|
|
|
@ -23,7 +23,7 @@ exports[`Data Frame: <GroupByLabelSummary /> Date histogram aggregation 1`] = `
|
|||
className="mlGroupByLabel__text"
|
||||
color="subdued"
|
||||
>
|
||||
10m
|
||||
1m
|
||||
</EuiTextColor>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
)}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
)}
|
||||
|
|
|
@ -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) => {};
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue