* Convert `ui/agg_types/buckets` to TypeScript / Jest * fix eslint issues * fix CI * fix JEST test * fix mocha tests * Fix PR comments
This commit is contained in:
parent
baeb7d4d25
commit
c3b9013082
2
packages/kbn-es-query/src/filters/index.d.ts
vendored
2
packages/kbn-es-query/src/filters/index.d.ts
vendored
|
@ -41,7 +41,7 @@ export function buildPhrasesFilter(
|
||||||
indexPattern: IndexPattern
|
indexPattern: IndexPattern
|
||||||
): PhrasesFilter;
|
): PhrasesFilter;
|
||||||
|
|
||||||
export function buildQueryFilter(query: any, index: string): CustomFilter;
|
export function buildQueryFilter(query: any, index: string, alias?: string): CustomFilter;
|
||||||
|
|
||||||
export function buildRangeFilter(
|
export function buildRangeFilter(
|
||||||
field: Field,
|
field: Field,
|
||||||
|
|
|
@ -28,7 +28,12 @@ import { GeoPolygonFilter, isGeoPolygonFilter } from './geo_polygon_filter';
|
||||||
import { PhraseFilter, isPhraseFilter, isScriptedPhraseFilter } from './phrase_filter';
|
import { PhraseFilter, isPhraseFilter, isScriptedPhraseFilter } from './phrase_filter';
|
||||||
import { PhrasesFilter, isPhrasesFilter } from './phrases_filter';
|
import { PhrasesFilter, isPhrasesFilter } from './phrases_filter';
|
||||||
import { QueryStringFilter, isQueryStringFilter } from './query_string_filter';
|
import { QueryStringFilter, isQueryStringFilter } from './query_string_filter';
|
||||||
import { RangeFilter, isRangeFilter, isScriptedRangeFilter } from './range_filter';
|
import {
|
||||||
|
RangeFilter,
|
||||||
|
isRangeFilter,
|
||||||
|
isScriptedRangeFilter,
|
||||||
|
RangeFilterParams,
|
||||||
|
} from './range_filter';
|
||||||
import { MatchAllFilter, isMatchAllFilter } from './match_all_filter';
|
import { MatchAllFilter, isMatchAllFilter } from './match_all_filter';
|
||||||
import { MissingFilter, isMissingFilter } from './missing_filter';
|
import { MissingFilter, isMissingFilter } from './missing_filter';
|
||||||
|
|
||||||
|
@ -50,6 +55,7 @@ export {
|
||||||
RangeFilter,
|
RangeFilter,
|
||||||
isRangeFilter,
|
isRangeFilter,
|
||||||
isScriptedRangeFilter,
|
isScriptedRangeFilter,
|
||||||
|
RangeFilterParams,
|
||||||
MatchAllFilter,
|
MatchAllFilter,
|
||||||
isMatchAllFilter,
|
isMatchAllFilter,
|
||||||
MissingFilter,
|
MissingFilter,
|
||||||
|
|
|
@ -19,23 +19,16 @@
|
||||||
import { get, keys } from 'lodash';
|
import { get, keys } from 'lodash';
|
||||||
import { Filter, FilterMeta } from './meta_filter';
|
import { Filter, FilterMeta } from './meta_filter';
|
||||||
|
|
||||||
interface FilterRange {
|
export interface RangeFilterParams {
|
||||||
from?: number | string;
|
from?: number | string;
|
||||||
to?: number | string;
|
to?: number | string;
|
||||||
}
|
|
||||||
|
|
||||||
interface FilterRangeGt {
|
|
||||||
gt?: number | string;
|
gt?: number | string;
|
||||||
lt?: number | string;
|
lt?: number | string;
|
||||||
}
|
|
||||||
|
|
||||||
interface FilterRangeGte {
|
|
||||||
gte?: number | string;
|
gte?: number | string;
|
||||||
lte?: number | string;
|
lte?: number | string;
|
||||||
|
format?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RangeFilterParams = FilterRange & FilterRangeGt & FilterRangeGte;
|
|
||||||
|
|
||||||
export type RangeFilterMeta = FilterMeta & {
|
export type RangeFilterMeta = FilterMeta & {
|
||||||
params: RangeFilterParams;
|
params: RangeFilterParams;
|
||||||
field?: any;
|
field?: any;
|
||||||
|
|
|
@ -38,7 +38,8 @@ describe('Significant Terms Agg', function () {
|
||||||
$rootScope.agg = {
|
$rootScope.agg = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
params: aggParams,
|
params: aggParams,
|
||||||
type: significantTerms
|
type: significantTerms,
|
||||||
|
getParam: key => aggParams[key],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,8 @@ describe('Terms Agg', function () {
|
||||||
type: terms,
|
type: terms,
|
||||||
vis: {
|
vis: {
|
||||||
aggs: []
|
aggs: []
|
||||||
}
|
},
|
||||||
|
getParam: key => aggParams[key],
|
||||||
};
|
};
|
||||||
$rootScope.metricAggs = metricAggs;
|
$rootScope.metricAggs = metricAggs;
|
||||||
$controller(orderAggController, { $scope: $rootScope });
|
$controller(orderAggController, { $scope: $rootScope });
|
||||||
|
|
|
@ -26,20 +26,23 @@
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { AggType, FieldParamType, BucketAggType } from '.';
|
import { AggType } from './agg_type';
|
||||||
|
import { FieldParamType } from './param_types/field';
|
||||||
import { AggGroupNames } from '../vis/editors/default/agg_groups';
|
import { AggGroupNames } from '../vis/editors/default/agg_groups';
|
||||||
// @ts-ignore
|
|
||||||
import { fieldFormats } from '../registry/field_formats';
|
|
||||||
import { writeParams } from './agg_params';
|
import { writeParams } from './agg_params';
|
||||||
import { AggConfigs } from './agg_configs';
|
import { AggConfigs } from './agg_configs';
|
||||||
import { Schema } from '../vis/editors/default/schemas';
|
import { Schema } from '../vis/editors/default/schemas';
|
||||||
|
import { ContentType } from '../../../../plugins/data/common';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { fieldFormats } from '../registry/field_formats';
|
||||||
|
|
||||||
export interface AggConfigOptions {
|
export interface AggConfigOptions {
|
||||||
id: string;
|
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
type: string;
|
type: string;
|
||||||
schema: string;
|
|
||||||
params: any;
|
params: any;
|
||||||
|
id?: string;
|
||||||
|
schema?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unknownSchema: Schema = {
|
const unknownSchema: Schema = {
|
||||||
|
@ -139,7 +142,10 @@ export class AggConfig {
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
this.setType(opts.type);
|
this.setType(opts.type);
|
||||||
this.setSchema(opts.schema);
|
|
||||||
|
if (opts.schema) {
|
||||||
|
this.setSchema(opts.schema);
|
||||||
|
}
|
||||||
|
|
||||||
// set the params to the values from opts, or just to the defaults
|
// set the params to the values from opts, or just to the defaults
|
||||||
this.setParams(opts.params || {});
|
this.setParams(opts.params || {});
|
||||||
|
@ -253,7 +259,7 @@ export class AggConfig {
|
||||||
* @return {void|Object} - if the config has a dsl representation, it is
|
* @return {void|Object} - if the config has a dsl representation, it is
|
||||||
* returned, else undefined is returned
|
* returned, else undefined is returned
|
||||||
*/
|
*/
|
||||||
toDsl(aggConfigs: AggConfigs) {
|
toDsl(aggConfigs?: AggConfigs) {
|
||||||
if (this.type.hasNoDsl) return;
|
if (this.type.hasNoDsl) return;
|
||||||
const output = this.write(aggConfigs) as any;
|
const output = this.write(aggConfigs) as any;
|
||||||
|
|
||||||
|
@ -327,8 +333,8 @@ export class AggConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
getKey(bucket: any, key: string) {
|
getKey(bucket: any, key: string) {
|
||||||
if (this.type instanceof BucketAggType) {
|
if (this.type.getKey) {
|
||||||
return (this.type as BucketAggType).getKey(bucket, key, this);
|
return this.type.getKey(bucket, key, this);
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -336,6 +342,7 @@ export class AggConfig {
|
||||||
|
|
||||||
getFieldDisplayName() {
|
getFieldDisplayName() {
|
||||||
const field = this.getField();
|
const field = this.getField();
|
||||||
|
|
||||||
return field ? field.displayName || this.fieldName() : '';
|
return field ? field.displayName || this.fieldName() : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,13 +372,16 @@ export class AggConfig {
|
||||||
return this.aggConfigs.timeRange;
|
return this.aggConfigs.timeRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldFormatter(contentType: string, defaultFormat: any) {
|
fieldFormatter(contentType?: ContentType, defaultFormat?: any) {
|
||||||
const format = this.type && this.type.getFormat(this);
|
const format = this.type && this.type.getFormat(this);
|
||||||
if (format) return format.getConverterFor(contentType);
|
|
||||||
|
if (format) {
|
||||||
|
return format.getConverterFor(contentType);
|
||||||
|
}
|
||||||
return this.fieldOwnFormatter(contentType, defaultFormat);
|
return this.fieldOwnFormatter(contentType, defaultFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldOwnFormatter(contentType: string, defaultFormat: any) {
|
fieldOwnFormatter(contentType?: ContentType, defaultFormat?: any) {
|
||||||
const field = this.getField();
|
const field = this.getField();
|
||||||
let format = field && field.format;
|
let format = field && field.format;
|
||||||
if (!format) format = defaultFormat;
|
if (!format) format = defaultFormat;
|
||||||
|
|
|
@ -20,17 +20,19 @@
|
||||||
import { constant, noop, identity } from 'lodash';
|
import { constant, noop, identity } from 'lodash';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { AggParam, initParams } from './agg_params';
|
import { AggParam, initParams } from './agg_params';
|
||||||
// @ts-ignore
|
|
||||||
import { FieldFormat, fieldFormats } from '../registry/field_formats';
|
|
||||||
import { AggConfig } from '../vis';
|
import { AggConfig } from '../vis';
|
||||||
import { AggConfigs } from './agg_configs';
|
import { AggConfigs } from './agg_configs';
|
||||||
import { SearchSource } from '../courier';
|
import { SearchSource } from '../courier';
|
||||||
import { Adapters } from '../inspector';
|
import { Adapters } from '../inspector';
|
||||||
import { BaseParamType } from './param_types/base';
|
import { BaseParamType } from './param_types/base';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { FieldFormat, fieldFormats } from '../registry/field_formats';
|
||||||
|
|
||||||
export interface AggTypeConfig<
|
export interface AggTypeConfig<
|
||||||
TAggConfig extends AggConfig = AggConfig,
|
TAggConfig extends AggConfig = AggConfig,
|
||||||
TParam extends AggParam = TAggConfig['params'][number]
|
TParam extends AggParam = AggParam
|
||||||
> {
|
> {
|
||||||
name: string;
|
name: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -50,7 +52,8 @@ export interface AggTypeConfig<
|
||||||
aggConfigs: AggConfigs,
|
aggConfigs: AggConfigs,
|
||||||
aggConfig: TAggConfig,
|
aggConfig: TAggConfig,
|
||||||
searchSource: SearchSource,
|
searchSource: SearchSource,
|
||||||
inspectorAdapters: Adapters
|
inspectorAdapters: Adapters,
|
||||||
|
abortSignal?: AbortSignal
|
||||||
) => Promise<any>;
|
) => Promise<any>;
|
||||||
getFormat?: (agg: TAggConfig) => FieldFormat;
|
getFormat?: (agg: TAggConfig) => FieldFormat;
|
||||||
getValue?: (agg: TAggConfig, bucket: any) => any;
|
getValue?: (agg: TAggConfig, bucket: any) => any;
|
||||||
|
@ -62,7 +65,7 @@ const getFormat = (agg: AggConfig) => {
|
||||||
return field ? field.format : fieldFormats.getDefaultInstance('string');
|
return field ? field.format : fieldFormats.getDefaultInstance('string');
|
||||||
};
|
};
|
||||||
|
|
||||||
export class AggType<TAggConfig extends AggConfig = AggConfig> {
|
export class AggType<TAggConfig extends AggConfig = AggConfig, TParam extends AggParam = AggParam> {
|
||||||
/**
|
/**
|
||||||
* the unique, unchanging, name that we have assigned this aggType
|
* the unique, unchanging, name that we have assigned this aggType
|
||||||
*
|
*
|
||||||
|
@ -131,7 +134,7 @@ export class AggType<TAggConfig extends AggConfig = AggConfig> {
|
||||||
* @property params
|
* @property params
|
||||||
* @type {AggParams}
|
* @type {AggParams}
|
||||||
*/
|
*/
|
||||||
params: TAggConfig['params'];
|
params: TParam[];
|
||||||
/**
|
/**
|
||||||
* Designed for multi-value metric aggs, this method can return a
|
* Designed for multi-value metric aggs, this method can return a
|
||||||
* set of AggConfigs that should replace this aggConfig in requests
|
* set of AggConfigs that should replace this aggConfig in requests
|
||||||
|
@ -188,6 +191,8 @@ export class AggType<TAggConfig extends AggConfig = AggConfig> {
|
||||||
|
|
||||||
getValue: (agg: TAggConfig, bucket: any) => any;
|
getValue: (agg: TAggConfig, bucket: any) => any;
|
||||||
|
|
||||||
|
getKey?: (bucket: any, key: any, agg: TAggConfig) => any;
|
||||||
|
|
||||||
paramByName = (name: string) => {
|
paramByName = (name: string) => {
|
||||||
return this.params.find((p: AggParam) => p.name === name);
|
return this.params.find((p: AggParam) => p.name === name);
|
||||||
};
|
};
|
||||||
|
@ -215,7 +220,7 @@ export class AggType<TAggConfig extends AggConfig = AggConfig> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.params && config.params.length && config.params[0] instanceof BaseParamType) {
|
if (config.params && config.params.length && config.params[0] instanceof BaseParamType) {
|
||||||
this.params = config.params as TAggConfig['params'];
|
this.params = config.params as TParam[];
|
||||||
} else {
|
} else {
|
||||||
// always append the raw JSON param
|
// always append the raw JSON param
|
||||||
const params: any[] = config.params ? [...config.params] : [];
|
const params: any[] = config.params ? [...config.params] : [];
|
||||||
|
|
|
@ -17,13 +17,32 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AggType, AggTypeConfig } from '../agg_type';
|
import { AggParamType } from '../param_types/agg';
|
||||||
import { AggConfig } from '../../vis';
|
import { AggConfig } from '../../vis';
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
import { AggType, AggTypeConfig } from '../agg_type';
|
||||||
|
|
||||||
export class BucketAggType extends AggType {
|
export type IBucketAggConfig = AggConfig;
|
||||||
getKey: (bucket: any, key: any, agg: AggConfig) => any;
|
|
||||||
|
|
||||||
constructor(config: AggTypeConfig) {
|
export interface BucketAggParam extends AggParamType {
|
||||||
|
scriptable?: boolean;
|
||||||
|
filterFieldTypes?: KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BucketAggTypeConfig<TBucketAggConfig extends IBucketAggConfig>
|
||||||
|
extends AggTypeConfig<TBucketAggConfig, BucketAggParam> {
|
||||||
|
getKey?: (bucket: any, key: any, agg: AggConfig) => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bucketType = 'buckets';
|
||||||
|
|
||||||
|
export class BucketAggType<
|
||||||
|
TBucketAggConfig extends IBucketAggConfig = IBucketAggConfig
|
||||||
|
> extends AggType<TBucketAggConfig, BucketAggParam> {
|
||||||
|
getKey: (bucket: any, key: any, agg: IBucketAggConfig) => any;
|
||||||
|
type = bucketType;
|
||||||
|
|
||||||
|
constructor(config: BucketAggTypeConfig<TBucketAggConfig>) {
|
||||||
super(config);
|
super(config);
|
||||||
|
|
||||||
this.getKey =
|
this.getKey =
|
||||||
|
@ -33,3 +52,7 @@ export class BucketAggType extends AggType {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isBucketAggType(aggConfig: any): aggConfig is BucketAggType {
|
||||||
|
return aggConfig && aggConfig.type === bucketType;
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { IBucketAggConfig } from './_bucket_agg_type';
|
||||||
|
|
||||||
export const intervalOptions = [
|
export const intervalOptions = [
|
||||||
{
|
{
|
||||||
|
@ -24,58 +25,58 @@ export const intervalOptions = [
|
||||||
defaultMessage: 'Auto',
|
defaultMessage: 'Auto',
|
||||||
}),
|
}),
|
||||||
val: 'auto',
|
val: 'auto',
|
||||||
enabled: function (agg) {
|
enabled(agg: IBucketAggConfig) {
|
||||||
// not only do we need a time field, but the selected field needs
|
// not only do we need a time field, but the selected field needs
|
||||||
// to be the time field. (see #3028)
|
// to be the time field. (see #3028)
|
||||||
return agg.fieldIsTimeField();
|
return agg.fieldIsTimeField();
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName', {
|
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName', {
|
||||||
defaultMessage: 'Millisecond',
|
defaultMessage: 'Millisecond',
|
||||||
}),
|
}),
|
||||||
val: 'ms'
|
val: 'ms',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.secondDisplayName', {
|
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.secondDisplayName', {
|
||||||
defaultMessage: 'Second',
|
defaultMessage: 'Second',
|
||||||
}),
|
}),
|
||||||
val: 's'
|
val: 's',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName', {
|
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName', {
|
||||||
defaultMessage: 'Minute',
|
defaultMessage: 'Minute',
|
||||||
}),
|
}),
|
||||||
val: 'm'
|
val: 'm',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName', {
|
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName', {
|
||||||
defaultMessage: 'Hourly',
|
defaultMessage: 'Hourly',
|
||||||
}),
|
}),
|
||||||
val: 'h'
|
val: 'h',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName', {
|
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName', {
|
||||||
defaultMessage: 'Daily',
|
defaultMessage: 'Daily',
|
||||||
}),
|
}),
|
||||||
val: 'd'
|
val: 'd',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName', {
|
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName', {
|
||||||
defaultMessage: 'Weekly',
|
defaultMessage: 'Weekly',
|
||||||
}),
|
}),
|
||||||
val: 'w'
|
val: 'w',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName', {
|
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName', {
|
||||||
defaultMessage: 'Monthly',
|
defaultMessage: 'Monthly',
|
||||||
}),
|
}),
|
||||||
val: 'M'
|
val: 'M',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName', {
|
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName', {
|
||||||
defaultMessage: 'Yearly',
|
defaultMessage: 'Yearly',
|
||||||
}),
|
}),
|
||||||
val: 'y'
|
val: 'y',
|
||||||
}
|
},
|
||||||
];
|
];
|
|
@ -59,7 +59,9 @@ const getAggResultBuckets = (aggConfigs, response, aggWithOtherBucket, key) => {
|
||||||
const aggKey = _.keys(responseAgg)[aggId];
|
const aggKey = _.keys(responseAgg)[aggId];
|
||||||
const aggConfig = _.find(aggConfigs.aggs, agg => agg.id === aggKey);
|
const aggConfig = _.find(aggConfigs.aggs, agg => agg.id === aggKey);
|
||||||
const bucket = _.find(agg.buckets, (bucket, bucketObjKey) => {
|
const bucket = _.find(agg.buckets, (bucket, bucketObjKey) => {
|
||||||
const bucketKey = aggConfig.getKey(bucket, Number.isInteger(bucketObjKey) ? null : bucketObjKey).toString();
|
const bucketKey = aggConfig
|
||||||
|
.getKey(bucket, Number.isInteger(bucketObjKey) ? null : bucketObjKey)
|
||||||
|
.toString();
|
||||||
return bucketKey === keyParts[i];
|
return bucketKey === keyParts[i];
|
||||||
});
|
});
|
||||||
if (bucket) {
|
if (bucket) {
|
||||||
|
@ -93,7 +95,7 @@ const getAggConfigResultMissingBuckets = (responseAggs, aggId) => {
|
||||||
_.each(agg.buckets, bucket => {
|
_.each(agg.buckets, bucket => {
|
||||||
resultBuckets = [
|
resultBuckets = [
|
||||||
...resultBuckets,
|
...resultBuckets,
|
||||||
...getAggConfigResultMissingBuckets(bucket, aggId, missingKey)
|
...getAggConfigResultMissingBuckets(bucket, aggId, missingKey),
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -109,14 +111,11 @@ const getAggConfigResultMissingBuckets = (responseAggs, aggId) => {
|
||||||
* @param otherAgg: AggConfig of the aggregation with other bucket
|
* @param otherAgg: AggConfig of the aggregation with other bucket
|
||||||
*/
|
*/
|
||||||
const getOtherAggTerms = (requestAgg, key, otherAgg) => {
|
const getOtherAggTerms = (requestAgg, key, otherAgg) => {
|
||||||
return requestAgg['other-filter'].filters.filters[key].bool.must_not.filter(filter =>
|
return requestAgg['other-filter'].filters.filters[key].bool.must_not
|
||||||
filter.match_phrase && filter.match_phrase[otherAgg.params.field.name]
|
.filter(filter => filter.match_phrase && filter.match_phrase[otherAgg.params.field.name])
|
||||||
).map(filter =>
|
.map(filter => filter.match_phrase[otherAgg.params.field.name].query);
|
||||||
filter.match_phrase[otherAgg.params.field.name].query
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => {
|
export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => {
|
||||||
const bucketAggs = aggConfigs.aggs.filter(agg => agg.type.type === AggGroupNames.Buckets);
|
const bucketAggs = aggConfigs.aggs.filter(agg => agg.type.type === AggGroupNames.Buckets);
|
||||||
const index = bucketAggs.findIndex(agg => agg.id === aggWithOtherBucket.id);
|
const index = bucketAggs.findIndex(agg => agg.id === aggWithOtherBucket.id);
|
||||||
|
@ -124,15 +123,18 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) =>
|
||||||
const indexPattern = aggWithOtherBucket.params.field.indexPattern;
|
const indexPattern = aggWithOtherBucket.params.field.indexPattern;
|
||||||
|
|
||||||
// create filters aggregation
|
// create filters aggregation
|
||||||
const filterAgg = aggConfigs.createAggConfig({
|
const filterAgg = aggConfigs.createAggConfig(
|
||||||
type: 'filters',
|
{
|
||||||
id: 'other',
|
type: 'filters',
|
||||||
params: {
|
id: 'other',
|
||||||
filters: [],
|
params: {
|
||||||
|
filters: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, {
|
{
|
||||||
addToAggConfigs: false,
|
addToAggConfigs: false,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// nest all the child aggregations of aggWithOtherBucket
|
// nest all the child aggregations of aggWithOtherBucket
|
||||||
const resultAgg = {
|
const resultAgg = {
|
||||||
|
@ -156,16 +158,33 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) =>
|
||||||
const currentAgg = bucketAggs[aggIndex];
|
const currentAgg = bucketAggs[aggIndex];
|
||||||
if (aggIndex < index) {
|
if (aggIndex < index) {
|
||||||
_.each(agg.buckets, (bucket, bucketObjKey) => {
|
_.each(agg.buckets, (bucket, bucketObjKey) => {
|
||||||
const bucketKey = currentAgg.getKey(bucket, Number.isInteger(bucketObjKey) ? null : bucketObjKey);
|
const bucketKey = currentAgg.getKey(
|
||||||
|
bucket,
|
||||||
|
Number.isInteger(bucketObjKey) ? null : bucketObjKey
|
||||||
|
);
|
||||||
const filter = _.cloneDeep(bucket.filters) || currentAgg.createFilter(bucketKey);
|
const filter = _.cloneDeep(bucket.filters) || currentAgg.createFilter(bucketKey);
|
||||||
const newFilters = _.flatten([...filters, filter]);
|
const newFilters = _.flatten([...filters, filter]);
|
||||||
walkBucketTree(newAggIndex, bucket, newAgg.id, newFilters, `${key}-${bucketKey.toString()}`);
|
walkBucketTree(
|
||||||
|
newAggIndex,
|
||||||
|
bucket,
|
||||||
|
newAgg.id,
|
||||||
|
newFilters,
|
||||||
|
`${key}-${bucketKey.toString()}`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aggWithOtherBucket.params.missingBucket || agg.buckets.some(bucket => bucket.key === '__missing__')) {
|
if (
|
||||||
filters.push(buildExistsFilter(aggWithOtherBucket.params.field, aggWithOtherBucket.params.field.indexPattern));
|
!aggWithOtherBucket.params.missingBucket ||
|
||||||
|
agg.buckets.some(bucket => bucket.key === '__missing__')
|
||||||
|
) {
|
||||||
|
filters.push(
|
||||||
|
buildExistsFilter(
|
||||||
|
aggWithOtherBucket.params.field,
|
||||||
|
aggWithOtherBucket.params.field.indexPattern
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create not filters for all the buckets
|
// create not filters for all the buckets
|
||||||
|
@ -177,7 +196,7 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) =>
|
||||||
});
|
});
|
||||||
|
|
||||||
resultAgg.filters.filters[key] = {
|
resultAgg.filters.filters[key] = {
|
||||||
bool: buildQueryFromFilters(filters, indexPattern)
|
bool: buildQueryFromFilters(filters, indexPattern),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
walkBucketTree(0, response.aggregations, bucketAggs[0].id, [], '');
|
walkBucketTree(0, response.aggregations, bucketAggs[0].id, [], '');
|
||||||
|
@ -189,26 +208,43 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) =>
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
return {
|
return {
|
||||||
'other-filter': resultAgg
|
'other-filter': resultAgg,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mergeOtherBucketAggResponse = (aggsConfig, response, otherResponse, otherAgg, requestAgg) => {
|
export const mergeOtherBucketAggResponse = (
|
||||||
|
aggsConfig,
|
||||||
|
response,
|
||||||
|
otherResponse,
|
||||||
|
otherAgg,
|
||||||
|
requestAgg
|
||||||
|
) => {
|
||||||
const updatedResponse = _.cloneDeep(response);
|
const updatedResponse = _.cloneDeep(response);
|
||||||
_.each(otherResponse.aggregations['other-filter'].buckets, (bucket, key) => {
|
_.each(otherResponse.aggregations['other-filter'].buckets, (bucket, key) => {
|
||||||
if (!bucket.doc_count) return;
|
if (!bucket.doc_count) return;
|
||||||
const bucketKey = key.replace(/^-/, '');
|
const bucketKey = key.replace(/^-/, '');
|
||||||
const aggResultBuckets = getAggResultBuckets(aggsConfig, updatedResponse.aggregations, otherAgg, bucketKey);
|
const aggResultBuckets = getAggResultBuckets(
|
||||||
|
aggsConfig,
|
||||||
|
updatedResponse.aggregations,
|
||||||
|
otherAgg,
|
||||||
|
bucketKey
|
||||||
|
);
|
||||||
const requestFilterTerms = getOtherAggTerms(requestAgg, key, otherAgg);
|
const requestFilterTerms = getOtherAggTerms(requestAgg, key, otherAgg);
|
||||||
|
|
||||||
const phraseFilter = buildPhrasesFilter(otherAgg.params.field, requestFilterTerms, otherAgg.params.field.indexPattern);
|
const phraseFilter = buildPhrasesFilter(
|
||||||
|
otherAgg.params.field,
|
||||||
|
requestFilterTerms,
|
||||||
|
otherAgg.params.field.indexPattern
|
||||||
|
);
|
||||||
phraseFilter.meta.negate = true;
|
phraseFilter.meta.negate = true;
|
||||||
bucket.filters = [ phraseFilter ];
|
bucket.filters = [phraseFilter];
|
||||||
bucket.key = '__other__';
|
bucket.key = '__other__';
|
||||||
|
|
||||||
if (aggResultBuckets.some(bucket => bucket.key === '__missing__')) {
|
if (aggResultBuckets.some(bucket => bucket.key === '__missing__')) {
|
||||||
bucket.filters.push(buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern));
|
bucket.filters.push(
|
||||||
|
buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
aggResultBuckets.push(bucket);
|
aggResultBuckets.push(bucket);
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,7 +17,15 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AggConfig } from 'ui/agg_types/agg_config';
|
export enum BUCKET_TYPES {
|
||||||
|
FILTER = 'filter',
|
||||||
export function isStringType(type: AggConfig): boolean;
|
HISTOGRAM = 'histogram',
|
||||||
export function isType(type: string): (agg: AggConfig) => boolean;
|
IP_RANGE = 'ip_range',
|
||||||
|
DATE_RANGE = 'date_range',
|
||||||
|
RANGE = 'range',
|
||||||
|
TERMS = 'terms',
|
||||||
|
SIGNIFICANT_TERMS = 'significant_terms',
|
||||||
|
GEOHASH_GRID = 'geohash_grid',
|
||||||
|
GEOTILE_GRID = 'geotile_grid',
|
||||||
|
DATE_HISTOGRAM = 'date_histogram',
|
||||||
|
}
|
|
@ -19,14 +19,19 @@
|
||||||
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { buildRangeFilter } from '@kbn/es-query';
|
import { buildRangeFilter } from '@kbn/es-query';
|
||||||
|
import { IBucketDateHistogramAggConfig } from '../date_histogram';
|
||||||
|
|
||||||
export function createFilterDateHistogram(agg, key) {
|
export const createFilterDateHistogram = (agg: IBucketDateHistogramAggConfig, key: string) => {
|
||||||
const start = moment(key);
|
const start = moment(key);
|
||||||
const interval = agg.buckets.getInterval();
|
const interval = agg.buckets.getInterval();
|
||||||
|
|
||||||
return buildRangeFilter(agg.params.field, {
|
return buildRangeFilter(
|
||||||
gte: start.toISOString(),
|
agg.params.field,
|
||||||
lt: start.add(interval).toISOString(),
|
{
|
||||||
format: 'strict_date_optional_time'
|
gte: start.toISOString(),
|
||||||
}, agg.getIndexPattern());
|
lt: start.add(interval).toISOString(),
|
||||||
}
|
format: 'strict_date_optional_time',
|
||||||
|
},
|
||||||
|
agg.getIndexPattern()
|
||||||
|
);
|
||||||
|
};
|
|
@ -17,19 +17,20 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import chrome from '../../../chrome';
|
import { buildRangeFilter, RangeFilterParams } from '@kbn/es-query';
|
||||||
|
import { npSetup } from 'ui/new_platform';
|
||||||
|
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { dateRange } from '../../../utils/date_range';
|
import { dateRange } from '../../../utils/date_range';
|
||||||
import { buildRangeFilter } from '@kbn/es-query';
|
|
||||||
|
|
||||||
const config = chrome.getUiSettingsClient();
|
export const createFilterDateRange = (agg: IBucketAggConfig, rangeString: string) => {
|
||||||
|
const range = dateRange.parse(rangeString, npSetup.core.uiSettings.get('dateFormat'));
|
||||||
|
|
||||||
export function createFilterDateRange(agg, key) {
|
const filter: RangeFilterParams = {};
|
||||||
const range = dateRange.parse(key, config.get('dateFormat'));
|
|
||||||
|
|
||||||
const filter = {};
|
|
||||||
if (range.from) filter.gte = range.from.toISOString();
|
if (range.from) filter.gte = range.from.toISOString();
|
||||||
if (range.to) filter.lt = range.to.toISOString();
|
if (range.to) filter.lt = range.to.toISOString();
|
||||||
if (range.to && range.from) filter.format = 'strict_date_optional_time';
|
if (range.to && range.from) filter.format = 'strict_date_optional_time';
|
||||||
|
|
||||||
return buildRangeFilter(agg.params.field, filter, agg.getIndexPattern());
|
return buildRangeFilter(agg.params.field, filter, agg.getIndexPattern());
|
||||||
}
|
};
|
|
@ -17,15 +17,17 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { get } from 'lodash';
|
||||||
import { buildQueryFilter } from '@kbn/es-query';
|
import { buildQueryFilter } from '@kbn/es-query';
|
||||||
import _ from 'lodash';
|
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||||
|
|
||||||
export function createFilterFilters(aggConfig, key) {
|
export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => {
|
||||||
// have the aggConfig write agg dsl params
|
// have the aggConfig write agg dsl params
|
||||||
const dslFilters = _.get(aggConfig.toDsl(), 'filters.filters');
|
const dslFilters: any = get(aggConfig.toDsl(), 'filters.filters');
|
||||||
const filter = dslFilters[key];
|
const filter = dslFilters[key];
|
||||||
|
const indexPattern = aggConfig.getIndexPattern();
|
||||||
|
|
||||||
if (filter) {
|
if (filter && indexPattern && indexPattern.id) {
|
||||||
return buildQueryFilter(filter.query, aggConfig.getIndexPattern().id, key);
|
return buildQueryFilter(filter.query, indexPattern.id, key);
|
||||||
}
|
}
|
||||||
}
|
};
|
|
@ -17,15 +17,17 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { buildRangeFilter } from '@kbn/es-query';
|
import { buildRangeFilter, RangeFilterParams } from '@kbn/es-query';
|
||||||
|
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||||
|
|
||||||
export function createFilterHistogram(aggConfig, key) {
|
export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => {
|
||||||
const value = parseInt(key, 10);
|
const value = parseInt(key, 10);
|
||||||
|
const params: RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval };
|
||||||
|
|
||||||
return buildRangeFilter(
|
return buildRangeFilter(
|
||||||
aggConfig.params.field,
|
aggConfig.params.field,
|
||||||
{ gte: value, lt: value + aggConfig.params.interval },
|
params,
|
||||||
aggConfig.getIndexPattern(),
|
aggConfig.getIndexPattern(),
|
||||||
aggConfig.fieldFormatter()(key)
|
aggConfig.fieldFormatter()(key)
|
||||||
);
|
);
|
||||||
}
|
};
|
|
@ -17,20 +17,27 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { buildRangeFilter, RangeFilterParams } from '@kbn/es-query';
|
||||||
import { CidrMask } from '../../../utils/cidr_mask';
|
import { CidrMask } from '../../../utils/cidr_mask';
|
||||||
import { buildRangeFilter } from '@kbn/es-query';
|
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||||
|
|
||||||
|
export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: string) => {
|
||||||
|
let range: RangeFilterParams;
|
||||||
|
|
||||||
export function createFilterIpRange(aggConfig, key) {
|
|
||||||
let range;
|
|
||||||
if (aggConfig.params.ipRangeType === 'mask') {
|
if (aggConfig.params.ipRangeType === 'mask') {
|
||||||
range = new CidrMask(key).getRange();
|
range = new CidrMask(key).getRange();
|
||||||
} else {
|
} else {
|
||||||
const [from, to] = key.split(/\s+to\s+/);
|
const [from, to] = key.split(/\s+to\s+/);
|
||||||
|
|
||||||
range = {
|
range = {
|
||||||
from: from === '-Infinity' ? -Infinity : from,
|
from: from === '-Infinity' ? -Infinity : from,
|
||||||
to: to === 'Infinity' ? Infinity : to
|
to: to === 'Infinity' ? Infinity : to,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildRangeFilter(aggConfig.params.field, { gte: range.from, lte: range.to }, aggConfig.getIndexPattern());
|
return buildRangeFilter(
|
||||||
}
|
aggConfig.params.field,
|
||||||
|
{ gte: range.from, lte: range.to },
|
||||||
|
aggConfig.getIndexPattern()
|
||||||
|
);
|
||||||
|
};
|
|
@ -18,12 +18,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { buildRangeFilter } from '@kbn/es-query';
|
import { buildRangeFilter } from '@kbn/es-query';
|
||||||
|
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||||
|
|
||||||
export function createFilterRange(aggConfig, key) {
|
export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => {
|
||||||
return buildRangeFilter(
|
return buildRangeFilter(
|
||||||
aggConfig.params.field,
|
aggConfig.params.field,
|
||||||
key,
|
params,
|
||||||
aggConfig.getIndexPattern(),
|
aggConfig.getIndexPattern(),
|
||||||
aggConfig.fieldFormatter()(key)
|
aggConfig.fieldFormatter()(params)
|
||||||
);
|
);
|
||||||
}
|
};
|
|
@ -17,9 +17,10 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { buildPhraseFilter, buildPhrasesFilter, buildExistsFilter } from '@kbn/es-query';
|
import { Filter, buildPhraseFilter, buildPhrasesFilter, buildExistsFilter } from '@kbn/es-query';
|
||||||
|
import { IBucketAggConfig } from '../_bucket_agg_type';
|
||||||
|
|
||||||
export function createFilterTerms(aggConfig, key, params) {
|
export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, params: any) => {
|
||||||
const field = aggConfig.params.field;
|
const field = aggConfig.params.field;
|
||||||
const indexPattern = field.indexPattern;
|
const indexPattern = field.indexPattern;
|
||||||
|
|
||||||
|
@ -29,9 +30,9 @@ export function createFilterTerms(aggConfig, key, params) {
|
||||||
const phraseFilter = buildPhrasesFilter(field, terms, indexPattern);
|
const phraseFilter = buildPhrasesFilter(field, terms, indexPattern);
|
||||||
phraseFilter.meta.negate = true;
|
phraseFilter.meta.negate = true;
|
||||||
|
|
||||||
const filters = [phraseFilter];
|
const filters: Filter[] = [phraseFilter];
|
||||||
|
|
||||||
if (terms.some(term => term === '__missing__')) {
|
if (terms.some((term: string) => term === '__missing__')) {
|
||||||
filters.push(buildExistsFilter(field, indexPattern));
|
filters.push(buildExistsFilter(field, indexPattern));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,4 +43,4 @@ export function createFilterTerms(aggConfig, key, params) {
|
||||||
return existsFilter;
|
return existsFilter;
|
||||||
}
|
}
|
||||||
return buildPhraseFilter(field, key, indexPattern);
|
return buildPhraseFilter(field, key, indexPattern);
|
||||||
}
|
};
|
|
@ -18,10 +18,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import chrome from '../../chrome';
|
|
||||||
import moment from 'moment-timezone';
|
import moment from 'moment-timezone';
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { TimeBuckets } from '../../time_buckets';
|
import { BUCKET_TYPES } from 'ui/agg_types/buckets/bucket_agg_types';
|
||||||
|
import chrome from '../../chrome';
|
||||||
|
import { BucketAggParam, BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
|
||||||
import { createFilterDateHistogram } from './create_filter/date_histogram';
|
import { createFilterDateHistogram } from './create_filter/date_histogram';
|
||||||
import { intervalOptions } from './_interval_options';
|
import { intervalOptions } from './_interval_options';
|
||||||
import { TimeIntervalParamEditor } from '../../vis/editors/default/controls/time_interval';
|
import { TimeIntervalParamEditor } from '../../vis/editors/default/controls/time_interval';
|
||||||
|
@ -29,51 +30,72 @@ import { timefilter } from '../../timefilter';
|
||||||
import { DropPartialsParamEditor } from '../../vis/editors/default/controls/drop_partials';
|
import { DropPartialsParamEditor } from '../../vis/editors/default/controls/drop_partials';
|
||||||
import { ScaleMetricsParamEditor } from '../../vis/editors/default/controls/scale_metrics';
|
import { ScaleMetricsParamEditor } from '../../vis/editors/default/controls/scale_metrics';
|
||||||
import { dateHistogramInterval } from '../../../../core_plugins/data/public';
|
import { dateHistogramInterval } from '../../../../core_plugins/data/public';
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
import { writeParams } from '../agg_params';
|
import { writeParams } from '../agg_params';
|
||||||
|
import { AggConfigs } from '../agg_configs';
|
||||||
|
import { AggConfig } from '../agg_config';
|
||||||
|
import { isMetricAggType } from '../metrics/metric_agg_type';
|
||||||
|
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { TimeBuckets } from '../../time_buckets';
|
||||||
|
|
||||||
const config = chrome.getUiSettingsClient();
|
const config = chrome.getUiSettingsClient();
|
||||||
const detectedTimezone = moment.tz.guess();
|
const detectedTimezone = moment.tz.guess();
|
||||||
const tzOffset = moment().format('Z');
|
const tzOffset = moment().format('Z');
|
||||||
|
|
||||||
function getInterval(agg) {
|
const getInterval = (agg: IBucketAggConfig): string => _.get(agg, ['params', 'interval']);
|
||||||
return _.get(agg, ['params', 'interval']);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setBounds(agg, force) {
|
export const setBounds = (agg: IBucketDateHistogramAggConfig, force?: boolean) => {
|
||||||
if (agg.buckets._alreadySet && !force) return;
|
if (agg.buckets._alreadySet && !force) return;
|
||||||
agg.buckets._alreadySet = true;
|
agg.buckets._alreadySet = true;
|
||||||
const bounds = agg.params.timeRange ? timefilter.calculateBounds(agg.params.timeRange) : null;
|
const bounds = agg.params.timeRange ? timefilter.calculateBounds(agg.params.timeRange) : null;
|
||||||
agg.buckets.setBounds(agg.fieldIsTimeField() && bounds);
|
agg.buckets.setBounds(agg.fieldIsTimeField() && bounds);
|
||||||
|
};
|
||||||
|
|
||||||
|
// will be replaced by src/legacy/ui/public/time_buckets/time_buckets.js
|
||||||
|
interface TimeBuckets {
|
||||||
|
_alreadySet?: boolean;
|
||||||
|
setBounds: Function;
|
||||||
|
getScaledDateFormatter: Function;
|
||||||
|
setInterval: Function;
|
||||||
|
getInterval: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IBucketDateHistogramAggConfig extends IBucketAggConfig {
|
||||||
|
buckets: TimeBuckets;
|
||||||
|
}
|
||||||
|
|
||||||
export const dateHistogramBucketAgg = new BucketAggType({
|
export function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHistogramAggConfig {
|
||||||
name: 'date_histogram',
|
return Boolean(agg.buckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dateHistogramBucketAgg = new BucketAggType<IBucketDateHistogramAggConfig>({
|
||||||
|
name: BUCKET_TYPES.DATE_HISTOGRAM,
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.dateHistogramTitle', {
|
title: i18n.translate('common.ui.aggTypes.buckets.dateHistogramTitle', {
|
||||||
defaultMessage: 'Date Histogram',
|
defaultMessage: 'Date Histogram',
|
||||||
}),
|
}),
|
||||||
ordered: {
|
ordered: {
|
||||||
date: true
|
date: true,
|
||||||
},
|
},
|
||||||
makeLabel: function (agg) {
|
makeLabel(agg) {
|
||||||
const output = writeParams(this.params, agg);
|
const output: Record<string, any> = writeParams(this.params as BucketAggParam[], agg);
|
||||||
const field = agg.getFieldDisplayName();
|
const field = agg.getFieldDisplayName();
|
||||||
return i18n.translate('common.ui.aggTypes.buckets.dateHistogramLabel', {
|
return i18n.translate('common.ui.aggTypes.buckets.dateHistogramLabel', {
|
||||||
defaultMessage: '{fieldName} per {intervalDescription}',
|
defaultMessage: '{fieldName} per {intervalDescription}',
|
||||||
values: {
|
values: {
|
||||||
fieldName: field,
|
fieldName: field,
|
||||||
intervalDescription: output.metricScaleText || output.bucketInterval.description,
|
intervalDescription: output.metricScaleText || output.bucketInterval.description,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
createFilter: createFilterDateHistogram,
|
createFilter: createFilterDateHistogram,
|
||||||
decorateAggConfig: function () {
|
decorateAggConfig() {
|
||||||
let buckets;
|
let buckets: any;
|
||||||
return {
|
return {
|
||||||
buckets: {
|
buckets: {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
get: function () {
|
get() {
|
||||||
if (buckets) return buckets;
|
if (buckets) return buckets;
|
||||||
|
|
||||||
buckets = new TimeBuckets();
|
buckets = new TimeBuckets();
|
||||||
|
@ -81,28 +103,28 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
||||||
setBounds(this);
|
setBounds(this);
|
||||||
|
|
||||||
return buckets;
|
return buckets;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getFormat: function (agg) {
|
getFormat(agg) {
|
||||||
return agg.buckets.getScaledDateFormatter();
|
return agg.buckets.getScaledDateFormatter();
|
||||||
},
|
},
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'field',
|
name: 'field',
|
||||||
type: 'field',
|
type: 'field',
|
||||||
filterFieldTypes: 'date',
|
filterFieldTypes: KBN_FIELD_TYPES.DATE,
|
||||||
default: function (agg) {
|
default(agg: IBucketDateHistogramAggConfig) {
|
||||||
return agg.getIndexPattern().timeFieldName;
|
return agg.getIndexPattern().timeFieldName;
|
||||||
},
|
},
|
||||||
onChange: function (agg) {
|
onChange(agg: IBucketDateHistogramAggConfig) {
|
||||||
if (_.get(agg, 'params.interval') === 'auto' && !agg.fieldIsTimeField()) {
|
if (_.get(agg, 'params.interval') === 'auto' && !agg.fieldIsTimeField()) {
|
||||||
delete agg.params.interval;
|
delete agg.params.interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
setBounds(agg, true);
|
setBounds(agg, true);
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'timeRange',
|
name: 'timeRange',
|
||||||
|
@ -124,7 +146,7 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
||||||
{
|
{
|
||||||
name: 'interval',
|
name: 'interval',
|
||||||
editorComponent: TimeIntervalParamEditor,
|
editorComponent: TimeIntervalParamEditor,
|
||||||
deserialize: function (state, agg) {
|
deserialize(state: any, agg: IBucketDateHistogramAggConfig) {
|
||||||
// For upgrading from 7.0.x to 7.1.x - intervals are now stored as key of options or custom value
|
// For upgrading from 7.0.x to 7.1.x - intervals are now stored as key of options or custom value
|
||||||
if (state === 'custom') {
|
if (state === 'custom') {
|
||||||
return _.get(agg, 'params.customInterval');
|
return _.get(agg, 'params.customInterval');
|
||||||
|
@ -141,10 +163,10 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
||||||
},
|
},
|
||||||
default: 'auto',
|
default: 'auto',
|
||||||
options: intervalOptions,
|
options: intervalOptions,
|
||||||
modifyAggConfigOnSearchRequestStart: function (agg) {
|
modifyAggConfigOnSearchRequestStart(agg: IBucketDateHistogramAggConfig) {
|
||||||
setBounds(agg, true);
|
setBounds(agg, true);
|
||||||
},
|
},
|
||||||
write: function (agg, output, aggs) {
|
write(agg: IBucketDateHistogramAggConfig, output: Record<string, any>, aggs: AggConfigs) {
|
||||||
setBounds(agg, true);
|
setBounds(agg, true);
|
||||||
agg.buckets.setInterval(getInterval(agg));
|
agg.buckets.setInterval(getInterval(agg));
|
||||||
const { useNormalizedEsInterval, scaleMetricValues } = agg.params;
|
const { useNormalizedEsInterval, scaleMetricValues } = agg.params;
|
||||||
|
@ -166,31 +188,41 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
||||||
|
|
||||||
const scaleMetrics = scaleMetricValues && interval.scaled && interval.scale < 1;
|
const scaleMetrics = scaleMetricValues && interval.scaled && interval.scale < 1;
|
||||||
if (scaleMetrics && aggs) {
|
if (scaleMetrics && aggs) {
|
||||||
const metrics = aggs.aggs.filter(agg => agg.type && agg.type.type === 'metrics');
|
const metrics = aggs.aggs.filter(a => isMetricAggType(a.type));
|
||||||
const all = _.every(metrics, function (agg) {
|
const all = _.every(metrics, (a: AggConfig) => {
|
||||||
return agg.type.isScalable();
|
const { type } = a;
|
||||||
|
|
||||||
|
if (isMetricAggType(type)) {
|
||||||
|
return type.isScalable();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (all) {
|
if (all) {
|
||||||
output.metricScale = interval.scale;
|
output.metricScale = interval.scale;
|
||||||
output.metricScaleText = interval.preScaled.description;
|
output.metricScaleText = interval.preScaled.description;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
} as BucketAggParam,
|
||||||
{
|
{
|
||||||
name: 'time_zone',
|
name: 'time_zone',
|
||||||
default: undefined,
|
default: undefined,
|
||||||
// We don't ever want this parameter to be serialized out (when saving or to URLs)
|
// We don't ever want this parameter to be serialized out (when saving or to URLs)
|
||||||
// since we do all the logic handling it "on the fly" in the `write` method, to prevent
|
// since we do all the logic handling it "on the fly" in the `write` method, to prevent
|
||||||
// time_zones being persisted into saved_objects
|
// time_zones being persisted into saved_objects
|
||||||
serialize: () => undefined,
|
serialize: _.noop,
|
||||||
write: (agg, output) => {
|
write(agg: IBucketDateHistogramAggConfig, output: Record<string, any>) {
|
||||||
// If a time_zone has been set explicitly always prefer this.
|
// If a time_zone has been set explicitly always prefer this.
|
||||||
let tz = agg.params.time_zone;
|
let tz = agg.params.time_zone;
|
||||||
if (!tz && agg.params.field) {
|
if (!tz && agg.params.field) {
|
||||||
// If a field has been configured check the index pattern's typeMeta if a date_histogram on that
|
// If a field has been configured check the index pattern's typeMeta if a date_histogram on that
|
||||||
// field requires a specific time_zone
|
// field requires a specific time_zone
|
||||||
tz = _.get(agg.getIndexPattern(), ['typeMeta', 'aggs', 'date_histogram', agg.params.field.name, 'time_zone']);
|
tz = _.get(agg.getIndexPattern(), [
|
||||||
|
'typeMeta',
|
||||||
|
'aggs',
|
||||||
|
'date_histogram',
|
||||||
|
agg.params.field.name,
|
||||||
|
'time_zone',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
if (!tz) {
|
if (!tz) {
|
||||||
// If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz
|
// If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz
|
||||||
|
@ -199,7 +231,7 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
||||||
}
|
}
|
||||||
output.params.time_zone = tz;
|
output.params.time_zone = tz;
|
||||||
},
|
},
|
||||||
},
|
} as BucketAggParam,
|
||||||
{
|
{
|
||||||
name: 'drop_partials',
|
name: 'drop_partials',
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -211,29 +243,27 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'format'
|
name: 'format',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'min_doc_count',
|
name: 'min_doc_count',
|
||||||
default: 1
|
default: 1,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'extended_bounds',
|
name: 'extended_bounds',
|
||||||
default: {},
|
default: {},
|
||||||
write: function (agg, output) {
|
write(agg: IBucketDateHistogramAggConfig, output: Record<string, any>) {
|
||||||
const val = agg.params.extended_bounds;
|
const val = agg.params.extended_bounds;
|
||||||
|
|
||||||
if (val.min != null || val.max != null) {
|
if (val.min != null || val.max != null) {
|
||||||
output.params.extended_bounds = {
|
output.params.extended_bounds = {
|
||||||
min: moment(val.min).valueOf(),
|
min: moment(val.min).valueOf(),
|
||||||
max: moment(val.max).valueOf()
|
max: moment(val.max).valueOf(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
} as BucketAggParam,
|
||||||
]
|
],
|
||||||
});
|
});
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
|
||||||
* license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright
|
|
||||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
|
||||||
* the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
import { get } from 'lodash';
|
|
||||||
import chrome from '../../chrome';
|
|
||||||
import moment from 'moment-timezone';
|
|
||||||
import { dateRange } from '../../utils/date_range';
|
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
|
||||||
import { createFilterDateRange } from './create_filter/date_range';
|
|
||||||
import { fieldFormats } from '../../registry/field_formats';
|
|
||||||
import { DateRangesParamEditor } from '../../vis/editors/default/controls/date_ranges';
|
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
|
|
||||||
const config = chrome.getUiSettingsClient();
|
|
||||||
const detectedTimezone = moment.tz.guess();
|
|
||||||
const tzOffset = moment().format('Z');
|
|
||||||
|
|
||||||
export const dateRangeBucketAgg = new BucketAggType({
|
|
||||||
name: 'date_range',
|
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.dateRangeTitle', {
|
|
||||||
defaultMessage: 'Date Range',
|
|
||||||
}),
|
|
||||||
createFilter: createFilterDateRange,
|
|
||||||
getKey: function (bucket, key, agg) {
|
|
||||||
const formatter = agg.fieldOwnFormatter('text', fieldFormats.getDefaultInstance('date'));
|
|
||||||
return dateRange.toString(bucket, formatter);
|
|
||||||
},
|
|
||||||
getFormat: function () {
|
|
||||||
return fieldFormats.getDefaultInstance('string');
|
|
||||||
},
|
|
||||||
makeLabel: function (aggConfig) {
|
|
||||||
return aggConfig.getFieldDisplayName() + ' date ranges';
|
|
||||||
},
|
|
||||||
params: [{
|
|
||||||
name: 'field',
|
|
||||||
type: 'field',
|
|
||||||
filterFieldTypes: 'date',
|
|
||||||
default: function (agg) {
|
|
||||||
return agg.getIndexPattern().timeFieldName;
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
name: 'ranges',
|
|
||||||
default: [{
|
|
||||||
from: 'now-1w/w',
|
|
||||||
to: 'now'
|
|
||||||
}],
|
|
||||||
editorComponent: DateRangesParamEditor,
|
|
||||||
}, {
|
|
||||||
name: 'time_zone',
|
|
||||||
default: undefined,
|
|
||||||
// Implimentation method is the same as that of date_histogram
|
|
||||||
serialize: () => undefined,
|
|
||||||
write: (agg, output) => {
|
|
||||||
let tz = agg.params.time_zone;
|
|
||||||
if (!tz && agg.params.field) {
|
|
||||||
tz = get(agg.getIndexPattern(), ['typeMeta', 'aggs', 'date_range', agg.params.field.name, 'time_zone']);
|
|
||||||
}
|
|
||||||
if (!tz) {
|
|
||||||
const isDefaultTimezone = config.isDefault('dateFormat:tz');
|
|
||||||
tz = isDefaultTimezone ? detectedTimezone || tzOffset : config.get('dateFormat:tz');
|
|
||||||
}
|
|
||||||
output.params.time_zone = tz;
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
});
|
|
102
src/legacy/ui/public/agg_types/buckets/date_range.ts
Normal file
102
src/legacy/ui/public/agg_types/buckets/date_range.ts
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
import { get } from 'lodash';
|
||||||
|
import moment from 'moment-timezone';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { npStart } from 'ui/new_platform';
|
||||||
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
|
import { BucketAggType } from './_bucket_agg_type';
|
||||||
|
import { createFilterDateRange } from './create_filter/date_range';
|
||||||
|
import { AggConfig } from '../agg_config';
|
||||||
|
import { DateRangesParamEditor } from '../../vis/editors/default/controls/date_ranges';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { fieldFormats } from '../../registry/field_formats';
|
||||||
|
// @ts-ignore
|
||||||
|
import { dateRange } from '../../utils/date_range';
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
|
const dateRangeTitle = i18n.translate('common.ui.aggTypes.buckets.dateRangeTitle', {
|
||||||
|
defaultMessage: 'Date Range',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const dateRangeBucketAgg = new BucketAggType({
|
||||||
|
name: BUCKET_TYPES.DATE_RANGE,
|
||||||
|
title: dateRangeTitle,
|
||||||
|
createFilter: createFilterDateRange,
|
||||||
|
getKey(bucket, key, agg) {
|
||||||
|
const formatter = agg.fieldOwnFormatter('text', fieldFormats.getDefaultInstance('date'));
|
||||||
|
return dateRange.toString(bucket, formatter);
|
||||||
|
},
|
||||||
|
getFormat() {
|
||||||
|
return fieldFormats.getDefaultInstance('string');
|
||||||
|
},
|
||||||
|
makeLabel(aggConfig) {
|
||||||
|
return aggConfig.getFieldDisplayName() + ' date ranges';
|
||||||
|
},
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
name: 'field',
|
||||||
|
type: 'field',
|
||||||
|
filterFieldTypes: KBN_FIELD_TYPES.DATE,
|
||||||
|
default(agg: AggConfig) {
|
||||||
|
return agg.getIndexPattern().timeFieldName;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ranges',
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
from: 'now-1w/w',
|
||||||
|
to: 'now',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
editorComponent: DateRangesParamEditor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'time_zone',
|
||||||
|
default: undefined,
|
||||||
|
// Implimentation method is the same as that of date_histogram
|
||||||
|
serialize: () => undefined,
|
||||||
|
write: (agg: AggConfig, output: Record<string, any>) => {
|
||||||
|
const field = agg.getParam('field');
|
||||||
|
let tz = agg.getParam('time_zone');
|
||||||
|
|
||||||
|
if (!tz && field) {
|
||||||
|
tz = get(agg.getIndexPattern(), [
|
||||||
|
'typeMeta',
|
||||||
|
'aggs',
|
||||||
|
'date_range',
|
||||||
|
field.name,
|
||||||
|
'time_zone',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (!tz) {
|
||||||
|
const config = npStart.core.uiSettings;
|
||||||
|
const detectedTimezone = moment.tz.guess();
|
||||||
|
const tzOffset = moment().format('Z');
|
||||||
|
const isDefaultTimezone = config.isDefault('dateFormat:tz');
|
||||||
|
|
||||||
|
tz = isDefaultTimezone ? detectedTimezone || tzOffset : config.get('dateFormat:tz');
|
||||||
|
}
|
||||||
|
output.params.time_zone = tz;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
|
@ -16,18 +16,20 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { BucketAggType } from './_bucket_agg_type';
|
||||||
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
|
|
||||||
|
const filterTitle = i18n.translate('common.ui.aggTypes.buckets.filterTitle', {
|
||||||
|
defaultMessage: 'Filter',
|
||||||
|
});
|
||||||
|
|
||||||
export const filterBucketAgg = new BucketAggType({
|
export const filterBucketAgg = new BucketAggType({
|
||||||
name: 'filter',
|
name: BUCKET_TYPES.FILTER,
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.filterTitle', {
|
title: filterTitle,
|
||||||
defaultMessage: 'Filter',
|
|
||||||
}),
|
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'geo_bounding_box'
|
name: 'geo_bounding_box',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
|
@ -20,69 +20,79 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import angular from 'angular';
|
import angular from 'angular';
|
||||||
|
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
|
||||||
import { createFilterFilters } from './create_filter/filters';
|
|
||||||
import { FiltersParamEditor } from '../../vis/editors/default/controls/filters';
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { Storage } from 'ui/storage';
|
import { Storage } from 'ui/storage';
|
||||||
|
|
||||||
import chrome from 'ui/chrome';
|
import chrome from 'ui/chrome';
|
||||||
import { buildEsQuery } from '@kbn/es-query';
|
import { buildEsQuery } from '@kbn/es-query';
|
||||||
|
import { FiltersParamEditor, FilterValue } from '../../vis/editors/default/controls/filters';
|
||||||
|
import { createFilterFilters } from './create_filter/filters';
|
||||||
|
import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
|
||||||
import { setup as data } from '../../../../core_plugins/data/public/legacy';
|
import { setup as data } from '../../../../core_plugins/data/public/legacy';
|
||||||
|
|
||||||
const { getQueryLog } = data.query.helpers;
|
const { getQueryLog } = data.query.helpers;
|
||||||
const config = chrome.getUiSettingsClient();
|
const config = chrome.getUiSettingsClient();
|
||||||
const storage = new Storage(window.localStorage);
|
const storage = new Storage(window.localStorage);
|
||||||
|
|
||||||
|
const filtersTitle = i18n.translate('common.ui.aggTypes.buckets.filtersTitle', {
|
||||||
|
defaultMessage: 'Filters',
|
||||||
|
description:
|
||||||
|
'The name of an aggregation, that allows to specify multiple individual filters to group data by.',
|
||||||
|
});
|
||||||
|
|
||||||
export const filtersBucketAgg = new BucketAggType({
|
export const filtersBucketAgg = new BucketAggType({
|
||||||
name: 'filters',
|
name: 'filters',
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.filtersTitle', {
|
title: filtersTitle,
|
||||||
defaultMessage: 'Filters',
|
|
||||||
description: 'The name of an aggregation, that allows to specify multiple individual filters to group data by.'
|
|
||||||
}),
|
|
||||||
createFilter: createFilterFilters,
|
createFilter: createFilterFilters,
|
||||||
customLabels: false,
|
customLabels: false,
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'filters',
|
name: 'filters',
|
||||||
editorComponent: FiltersParamEditor,
|
editorComponent: FiltersParamEditor,
|
||||||
default: [ { input: { query: '', language: config.get('search:queryLanguage') }, label: '' } ],
|
default: [{ input: { query: '', language: config.get('search:queryLanguage') }, label: '' }],
|
||||||
write: function (aggConfig, output) {
|
write(aggConfig: IBucketAggConfig, output: Record<string, any>) {
|
||||||
const inFilters = aggConfig.params.filters;
|
const inFilters: FilterValue[] = aggConfig.params.filters;
|
||||||
if (!_.size(inFilters)) return;
|
if (!_.size(inFilters)) return;
|
||||||
|
|
||||||
inFilters.forEach((filter) => {
|
inFilters.forEach(filter => {
|
||||||
const persistedLog = getQueryLog(config, storage, 'filtersAgg', filter.input.language);
|
const persistedLog = getQueryLog(config, storage, 'filtersAgg', filter.input.language);
|
||||||
persistedLog.add(filter.input.query);
|
persistedLog.add(filter.input.query);
|
||||||
});
|
});
|
||||||
|
|
||||||
const outFilters = _.transform(inFilters, function (filters, filter) {
|
const outFilters = _.transform(
|
||||||
const input = _.cloneDeep(filter.input);
|
inFilters,
|
||||||
|
function(filters, filter) {
|
||||||
|
const input = _.cloneDeep(filter.input);
|
||||||
|
|
||||||
if (!input) {
|
if (!input) {
|
||||||
console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console
|
console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = buildEsQuery(aggConfig.getIndexPattern(), [input], [], config);
|
const query = buildEsQuery(aggConfig.getIndexPattern(), [input], [], config);
|
||||||
|
|
||||||
if (!query) {
|
if (!query) {
|
||||||
console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console
|
console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const matchAllLabel = filter.input.query === '' ? '*' : '';
|
const matchAllLabel = filter.input.query === '' ? '*' : '';
|
||||||
const label = filter.label
|
const label =
|
||||||
|| matchAllLabel
|
filter.label ||
|
||||||
|| (typeof filter.input.query === 'string' ? filter.input.query : angular.toJson(filter.input.query));
|
matchAllLabel ||
|
||||||
filters[label] = { query };
|
(typeof filter.input.query === 'string'
|
||||||
}, {});
|
? filter.input.query
|
||||||
|
: angular.toJson(filter.input.query));
|
||||||
|
filters[label] = { query };
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
if (!_.size(outFilters)) return;
|
if (!_.size(outFilters)) return;
|
||||||
|
|
||||||
const params = output.params || (output.params = {});
|
const params = output.params || (output.params = {});
|
||||||
params.filters = outFilters;
|
params.filters = outFilters;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
|
@ -17,16 +17,21 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
import chrome from '../../chrome';
|
import chrome from '../../chrome';
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
|
||||||
import { AutoPrecisionParamEditor } from '../../vis/editors/default/controls/auto_precision';
|
import { AutoPrecisionParamEditor } from '../../vis/editors/default/controls/auto_precision';
|
||||||
import { UseGeocentroidParamEditor } from '../../vis/editors/default/controls/use_geocentroid';
|
import { UseGeocentroidParamEditor } from '../../vis/editors/default/controls/use_geocentroid';
|
||||||
import { IsFilteredByCollarParamEditor } from '../../vis/editors/default/controls/is_filtered_by_collar';
|
import { IsFilteredByCollarParamEditor } from '../../vis/editors/default/controls/is_filtered_by_collar';
|
||||||
import { PrecisionParamEditor } from '../../vis/editors/default/controls/precision';
|
import { PrecisionParamEditor } from '../../vis/editors/default/controls/precision';
|
||||||
import { geohashColumns } from '../../utils/decode_geo_hash';
|
import { geohashColumns } from '../../utils/decode_geo_hash';
|
||||||
import { geoContains, scaleBounds } from '../../utils/geo_utils';
|
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
import { AggGroupNames } from '../../vis/editors/default/agg_groups';
|
import { AggGroupNames } from '../../vis/editors/default/agg_groups';
|
||||||
|
import { AggConfig } from '../agg_config';
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { geoContains, scaleBounds } from '../../utils/geo_utils';
|
||||||
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
|
|
||||||
const config = chrome.getUiSettingsClient();
|
const config = chrome.getUiSettingsClient();
|
||||||
|
|
||||||
|
@ -36,14 +41,15 @@ const maxPrecision = parseInt(config.get('visualization:tileMap:maxPrecision'),
|
||||||
* Map Leaflet zoom levels to geohash precision levels.
|
* Map Leaflet zoom levels to geohash precision levels.
|
||||||
* The size of a geohash column-width on the map should be at least `minGeohashPixels` pixels wide.
|
* The size of a geohash column-width on the map should be at least `minGeohashPixels` pixels wide.
|
||||||
*/
|
*/
|
||||||
const zoomPrecision = {};
|
const zoomPrecision: any = {};
|
||||||
const minGeohashPixels = 16;
|
const minGeohashPixels = 16;
|
||||||
|
|
||||||
for (let zoom = 0; zoom <= 21; zoom += 1) {
|
for (let zoom = 0; zoom <= 21; zoom += 1) {
|
||||||
const worldPixels = 256 * Math.pow(2, zoom);
|
const worldPixels = 256 * Math.pow(2, zoom);
|
||||||
zoomPrecision[zoom] = 1;
|
zoomPrecision[zoom] = 1;
|
||||||
for (let precision = 2; precision <= maxPrecision; precision += 1) {
|
for (let precision = 2; precision <= maxPrecision; precision += 1) {
|
||||||
const columns = geohashColumns(precision);
|
const columns = geohashColumns(precision);
|
||||||
if ((worldPixels / columns) >= minGeohashPixels) {
|
if (worldPixels / columns >= minGeohashPixels) {
|
||||||
zoomPrecision[zoom] = precision;
|
zoomPrecision[zoom] = precision;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -51,11 +57,10 @@ for (let zoom = 0; zoom <= 21; zoom += 1) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrecision(precision) {
|
function getPrecision(val: string) {
|
||||||
|
let precision = parseInt(val, 10);
|
||||||
|
|
||||||
precision = parseInt(precision, 10);
|
if (Number.isNaN(precision)) {
|
||||||
|
|
||||||
if (isNaN(precision)) {
|
|
||||||
precision = defaultPrecision;
|
precision = defaultPrecision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,20 +71,29 @@ function getPrecision(precision) {
|
||||||
return precision;
|
return precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isOutsideCollar(bounds, collar) {
|
const isOutsideCollar = (bounds: unknown, collar: MapCollar) =>
|
||||||
return bounds && collar && !geoContains(collar, bounds);
|
bounds && collar && !geoContains(collar, bounds);
|
||||||
|
|
||||||
|
const geohashGridTitle = i18n.translate('common.ui.aggTypes.buckets.geohashGridTitle', {
|
||||||
|
defaultMessage: 'Geohash',
|
||||||
|
});
|
||||||
|
|
||||||
|
interface MapCollar {
|
||||||
|
zoom: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const geoHashBucketAgg = new BucketAggType({
|
export interface IBucketGeoHashGridAggConfig extends IBucketAggConfig {
|
||||||
name: 'geohash_grid',
|
lastMapCollar: MapCollar;
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.geohashGridTitle', {
|
}
|
||||||
defaultMessage: 'Geohash',
|
|
||||||
}),
|
export const geoHashBucketAgg = new BucketAggType<IBucketGeoHashGridAggConfig>({
|
||||||
|
name: BUCKET_TYPES.GEOHASH_GRID,
|
||||||
|
title: geohashGridTitle,
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'field',
|
name: 'field',
|
||||||
type: 'field',
|
type: 'field',
|
||||||
filterFieldTypes: 'geo_point'
|
filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'autoPrecision',
|
name: 'autoPrecision',
|
||||||
|
@ -92,12 +106,13 @@ export const geoHashBucketAgg = new BucketAggType({
|
||||||
editorComponent: PrecisionParamEditor,
|
editorComponent: PrecisionParamEditor,
|
||||||
default: defaultPrecision,
|
default: defaultPrecision,
|
||||||
deserialize: getPrecision,
|
deserialize: getPrecision,
|
||||||
write: function (aggConfig, output) {
|
write(aggConfig, output) {
|
||||||
const currZoom = aggConfig.params.mapZoom;
|
const currZoom = aggConfig.params.mapZoom;
|
||||||
const autoPrecisionVal = zoomPrecision[currZoom];
|
const autoPrecisionVal = zoomPrecision[currZoom];
|
||||||
output.params.precision = aggConfig.params.autoPrecision ?
|
output.params.precision = aggConfig.params.autoPrecision
|
||||||
autoPrecisionVal : getPrecision(aggConfig.params.precision);
|
? autoPrecisionVal
|
||||||
}
|
: getPrecision(aggConfig.params.precision);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'useGeocentroid',
|
name: 'useGeocentroid',
|
||||||
|
@ -125,17 +140,21 @@ export const geoHashBucketAgg = new BucketAggType({
|
||||||
name: 'mapBounds',
|
name: 'mapBounds',
|
||||||
default: null,
|
default: null,
|
||||||
write: () => {},
|
write: () => {},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
getRequestAggs: function (agg) {
|
getRequestAggs(agg) {
|
||||||
const aggs = [];
|
const aggs: AggConfig[] = [];
|
||||||
const params = agg.params;
|
const params = agg.params;
|
||||||
|
|
||||||
if (params.isFilteredByCollar && agg.getField()) {
|
if (params.isFilteredByCollar && agg.getField()) {
|
||||||
const { mapBounds, mapZoom } = params;
|
const { mapBounds, mapZoom } = params;
|
||||||
if (mapBounds) {
|
if (mapBounds) {
|
||||||
let mapCollar;
|
let mapCollar;
|
||||||
if (!agg.lastMapCollar || agg.lastMapCollar.zoom !== mapZoom || isOutsideCollar(mapBounds, agg.lastMapCollar)) {
|
if (
|
||||||
|
!agg.lastMapCollar ||
|
||||||
|
agg.lastMapCollar.zoom !== mapZoom ||
|
||||||
|
isOutsideCollar(mapBounds, agg.lastMapCollar)
|
||||||
|
) {
|
||||||
mapCollar = scaleBounds(mapBounds);
|
mapCollar = scaleBounds(mapBounds);
|
||||||
mapCollar.zoom = mapZoom;
|
mapCollar.zoom = mapZoom;
|
||||||
agg.lastMapCollar = mapCollar;
|
agg.lastMapCollar = mapCollar;
|
||||||
|
@ -146,35 +165,45 @@ export const geoHashBucketAgg = new BucketAggType({
|
||||||
ignore_unmapped: true,
|
ignore_unmapped: true,
|
||||||
[agg.getField().name]: {
|
[agg.getField().name]: {
|
||||||
top_left: mapCollar.top_left,
|
top_left: mapCollar.top_left,
|
||||||
bottom_right: mapCollar.bottom_right
|
bottom_right: mapCollar.bottom_right,
|
||||||
}
|
|
||||||
};
|
|
||||||
aggs.push(agg.aggConfigs.createAggConfig({
|
|
||||||
type: 'filter',
|
|
||||||
id: 'filter_agg',
|
|
||||||
enabled: true,
|
|
||||||
params: {
|
|
||||||
geo_bounding_box: boundingBox
|
|
||||||
},
|
},
|
||||||
schema: {
|
};
|
||||||
group: AggGroupNames.Buckets
|
aggs.push(
|
||||||
}
|
agg.aggConfigs.createAggConfig(
|
||||||
}, { addToAggConfigs: false }));
|
{
|
||||||
|
type: 'filter',
|
||||||
|
id: 'filter_agg',
|
||||||
|
enabled: true,
|
||||||
|
params: {
|
||||||
|
geo_bounding_box: boundingBox,
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
group: AggGroupNames.Buckets,
|
||||||
|
},
|
||||||
|
} as any,
|
||||||
|
{ addToAggConfigs: false }
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aggs.push(agg);
|
aggs.push(agg);
|
||||||
|
|
||||||
if (params.useGeocentroid) {
|
if (params.useGeocentroid) {
|
||||||
aggs.push(agg.aggConfigs.createAggConfig({
|
aggs.push(
|
||||||
type: 'geo_centroid',
|
agg.aggConfigs.createAggConfig(
|
||||||
enabled: true,
|
{
|
||||||
params: {
|
type: 'geo_centroid',
|
||||||
field: agg.getField()
|
enabled: true,
|
||||||
}
|
params: {
|
||||||
}, { addToAggConfigs: false }));
|
field: agg.getField(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ addToAggConfigs: false }
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return aggs;
|
return aggs as IBucketGeoHashGridAggConfig[];
|
||||||
}
|
},
|
||||||
});
|
});
|
|
@ -17,47 +17,56 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from 'lodash';
|
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { noop } from 'lodash';
|
||||||
|
import { METRIC_TYPES } from 'ui/agg_types/metrics/metric_agg_types';
|
||||||
|
import { AggConfigOptions } from 'ui/agg_types/agg_config';
|
||||||
|
|
||||||
|
import { BucketAggType } from './_bucket_agg_type';
|
||||||
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
|
const geotileGridTitle = i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', {
|
||||||
|
defaultMessage: 'Geotile',
|
||||||
|
});
|
||||||
|
|
||||||
export const geoTileBucketAgg = new BucketAggType({
|
export const geoTileBucketAgg = new BucketAggType({
|
||||||
name: 'geotile_grid',
|
name: BUCKET_TYPES.GEOTILE_GRID,
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', {
|
title: geotileGridTitle,
|
||||||
defaultMessage: 'Geotile',
|
|
||||||
}),
|
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'field',
|
name: 'field',
|
||||||
type: 'field',
|
type: 'field',
|
||||||
filterFieldTypes: 'geo_point'
|
filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'useGeocentroid',
|
name: 'useGeocentroid',
|
||||||
default: true,
|
default: true,
|
||||||
write: _.noop
|
write: noop,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'precision',
|
name: 'precision',
|
||||||
default: 0,
|
default: 0,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
getRequestAggs: function (agg) {
|
getRequestAggs(agg) {
|
||||||
const aggs = [];
|
const aggs = [];
|
||||||
const params = agg.params;
|
const useGeocentroid = agg.getParam('useGeocentroid');
|
||||||
|
|
||||||
aggs.push(agg);
|
aggs.push(agg);
|
||||||
|
|
||||||
if (params.useGeocentroid) {
|
if (useGeocentroid) {
|
||||||
aggs.push(agg.aggConfigs.createAggConfig({
|
const aggConfig: AggConfigOptions = {
|
||||||
type: 'geo_centroid',
|
type: METRIC_TYPES.GEO_CENTROID,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
params: {
|
params: {
|
||||||
field: agg.getField()
|
field: agg.getField(),
|
||||||
}
|
},
|
||||||
}, { addToAggConfigs: false }));
|
};
|
||||||
|
|
||||||
|
aggs.push(agg.aggConfigs.createAggConfig(aggConfig, { addToAggConfigs: false }));
|
||||||
}
|
}
|
||||||
|
|
||||||
return aggs;
|
return aggs;
|
||||||
}
|
},
|
||||||
});
|
});
|
|
@ -18,51 +18,64 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
import { toastNotifications } from 'ui/notify';
|
import { toastNotifications } from 'ui/notify';
|
||||||
|
|
||||||
import chrome from '../../chrome';
|
import chrome from '../../chrome';
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
import { BucketAggType, IBucketAggConfig, BucketAggParam } from './_bucket_agg_type';
|
||||||
import { createFilterHistogram } from './create_filter/histogram';
|
import { createFilterHistogram } from './create_filter/histogram';
|
||||||
import { NumberIntervalParamEditor } from '../../vis/editors/default/controls/number_interval';
|
import { NumberIntervalParamEditor } from '../../vis/editors/default/controls/number_interval';
|
||||||
import { MinDocCountParamEditor } from '../../vis/editors/default/controls/min_doc_count';
|
import { MinDocCountParamEditor } from '../../vis/editors/default/controls/min_doc_count';
|
||||||
import { HasExtendedBoundsParamEditor } from '../../vis/editors/default/controls/has_extended_bounds';
|
import { HasExtendedBoundsParamEditor } from '../../vis/editors/default/controls/has_extended_bounds';
|
||||||
import { ExtendedBoundsParamEditor } from '../../vis/editors/default/controls/extended_bounds';
|
import { ExtendedBoundsParamEditor } from '../../vis/editors/default/controls/extended_bounds';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { AggConfig } from '../agg_config';
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
|
|
||||||
|
interface AutoBounds {
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBucketHistogramAggConfig extends IBucketAggConfig {
|
||||||
|
setAutoBounds: (bounds: AutoBounds) => void;
|
||||||
|
getAutoBounds: () => AutoBounds;
|
||||||
|
}
|
||||||
|
|
||||||
const config = chrome.getUiSettingsClient();
|
const config = chrome.getUiSettingsClient();
|
||||||
export const histogramBucketAgg = new BucketAggType({
|
export const histogramBucketAgg = new BucketAggType<IBucketHistogramAggConfig>({
|
||||||
name: 'histogram',
|
name: BUCKET_TYPES.HISTOGRAM,
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.histogramTitle', {
|
title: i18n.translate('common.ui.aggTypes.buckets.histogramTitle', {
|
||||||
defaultMessage: 'Histogram',
|
defaultMessage: 'Histogram',
|
||||||
}),
|
}),
|
||||||
ordered: {},
|
ordered: {},
|
||||||
makeLabel: function (aggConfig) {
|
makeLabel(aggConfig) {
|
||||||
return aggConfig.getFieldDisplayName();
|
return aggConfig.getFieldDisplayName();
|
||||||
},
|
},
|
||||||
createFilter: createFilterHistogram,
|
createFilter: createFilterHistogram,
|
||||||
decorateAggConfig: function () {
|
decorateAggConfig() {
|
||||||
let autoBounds;
|
let autoBounds: AutoBounds;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setAutoBounds: {
|
setAutoBounds: {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
value(newValue) {
|
value(newValue: AutoBounds) {
|
||||||
autoBounds = newValue;
|
autoBounds = newValue;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
getAutoBounds: {
|
getAutoBounds: {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
value() {
|
value() {
|
||||||
return autoBounds;
|
return autoBounds;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'field',
|
name: 'field',
|
||||||
type: 'field',
|
type: 'field',
|
||||||
filterFieldTypes: 'number'
|
filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -76,7 +89,11 @@ export const histogramBucketAgg = new BucketAggType({
|
||||||
{
|
{
|
||||||
name: 'interval',
|
name: 'interval',
|
||||||
editorComponent: NumberIntervalParamEditor,
|
editorComponent: NumberIntervalParamEditor,
|
||||||
modifyAggConfigOnSearchRequestStart(aggConfig, searchSource, searchRequest) {
|
modifyAggConfigOnSearchRequestStart(
|
||||||
|
aggConfig: IBucketHistogramAggConfig,
|
||||||
|
searchSource: any,
|
||||||
|
searchRequest: any
|
||||||
|
) {
|
||||||
const field = aggConfig.getField();
|
const field = aggConfig.getField();
|
||||||
const aggBody = field.scripted
|
const aggBody = field.scripted
|
||||||
? { script: { source: field.script, lang: field.lang } }
|
? { script: { source: field.script, lang: field.lang } }
|
||||||
|
@ -87,31 +104,35 @@ export const histogramBucketAgg = new BucketAggType({
|
||||||
.setField('size', 0)
|
.setField('size', 0)
|
||||||
.setField('aggs', {
|
.setField('aggs', {
|
||||||
maxAgg: {
|
maxAgg: {
|
||||||
max: aggBody
|
max: aggBody,
|
||||||
},
|
},
|
||||||
minAgg: {
|
minAgg: {
|
||||||
min: aggBody
|
min: aggBody,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
searchRequest.whenAborted(() => childSearchSource.cancelQueued());
|
searchRequest.whenAborted(() => childSearchSource.cancelQueued());
|
||||||
|
|
||||||
return childSearchSource.fetch()
|
return childSearchSource
|
||||||
.then((resp) => {
|
.fetch()
|
||||||
|
.then((resp: any) => {
|
||||||
aggConfig.setAutoBounds({
|
aggConfig.setAutoBounds({
|
||||||
min: _.get(resp, 'aggregations.minAgg.value'),
|
min: _.get(resp, 'aggregations.minAgg.value'),
|
||||||
max: _.get(resp, 'aggregations.maxAgg.value')
|
max: _.get(resp, 'aggregations.maxAgg.value'),
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch((e: Error) => {
|
||||||
if (e.name === 'AbortError') return;
|
if (e.name === 'AbortError') return;
|
||||||
toastNotifications.addWarning(i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', {
|
toastNotifications.addWarning(
|
||||||
// eslint-disable-next-line max-len
|
i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', {
|
||||||
defaultMessage: 'Unable to retrieve max and min values to auto-scale histogram buckets. This may lead to poor visualization performance.'
|
// eslint-disable-next-line max-len
|
||||||
}));
|
defaultMessage:
|
||||||
|
'Unable to retrieve max and min values to auto-scale histogram buckets. This may lead to poor visualization performance.',
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
write: function (aggConfig, output) {
|
write(aggConfig: IBucketHistogramAggConfig, output: Record<string, any>) {
|
||||||
let interval = parseFloat(aggConfig.params.interval);
|
let interval = parseFloat(aggConfig.params.interval);
|
||||||
if (interval <= 0) {
|
if (interval <= 0) {
|
||||||
interval = 1;
|
interval = 1;
|
||||||
|
@ -146,29 +167,26 @@ export const histogramBucketAgg = new BucketAggType({
|
||||||
}
|
}
|
||||||
|
|
||||||
output.params.interval = interval;
|
output.params.interval = interval;
|
||||||
}
|
},
|
||||||
},
|
} as BucketAggParam,
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'min_doc_count',
|
name: 'min_doc_count',
|
||||||
default: false,
|
default: false,
|
||||||
editorComponent: MinDocCountParamEditor,
|
editorComponent: MinDocCountParamEditor,
|
||||||
write: function (aggConfig, output) {
|
write(aggConfig: AggConfig, output: Record<string, any>) {
|
||||||
if (aggConfig.params.min_doc_count) {
|
if (aggConfig.params.min_doc_count) {
|
||||||
output.params.min_doc_count = 0;
|
output.params.min_doc_count = 0;
|
||||||
} else {
|
} else {
|
||||||
output.params.min_doc_count = 1;
|
output.params.min_doc_count = 1;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'has_extended_bounds',
|
name: 'has_extended_bounds',
|
||||||
default: false,
|
default: false,
|
||||||
editorComponent: HasExtendedBoundsParamEditor,
|
editorComponent: HasExtendedBoundsParamEditor,
|
||||||
write: () => {},
|
write: () => {},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'extended_bounds',
|
name: 'extended_bounds',
|
||||||
default: {
|
default: {
|
||||||
|
@ -176,16 +194,14 @@ export const histogramBucketAgg = new BucketAggType({
|
||||||
max: '',
|
max: '',
|
||||||
},
|
},
|
||||||
editorComponent: ExtendedBoundsParamEditor,
|
editorComponent: ExtendedBoundsParamEditor,
|
||||||
write: function (aggConfig, output) {
|
write(aggConfig: AggConfig, output: Record<string, any>) {
|
||||||
const { min, max } = aggConfig.params.extended_bounds;
|
const { min, max } = aggConfig.params.extended_bounds;
|
||||||
|
|
||||||
if (aggConfig.params.has_extended_bounds &&
|
if (aggConfig.params.has_extended_bounds && (min || min === 0) && (max || max === 0)) {
|
||||||
(min || min === 0) &&
|
|
||||||
(max || max === 0)) {
|
|
||||||
output.params.extended_bounds = { min, max };
|
output.params.extended_bounds = { min, max };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
shouldShow: aggConfig => aggConfig.params.has_extended_bounds
|
shouldShow: (aggConfig: AggConfig) => aggConfig.params.has_extended_bounds,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { ComponentType } from 'react';
|
||||||
|
import { AggParamEditorProps } from 'ui/vis/editors/default';
|
||||||
|
|
||||||
|
export const wrapWithInlineComp = <T extends unknown>(
|
||||||
|
WrapComponent: ComponentType<AggParamEditorProps<T>>
|
||||||
|
) => (props: AggParamEditorProps<T>) => (
|
||||||
|
<div className={`visEditorAggParam--half visEditorAggParam--half-${props.aggParam.name}`}>
|
||||||
|
<WrapComponent {...props} />
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -17,68 +17,72 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from 'lodash';
|
import { get, noop, map, omit, isNull } from 'lodash';
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { createFilterIpRange } from './create_filter/ip_range';
|
import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
|
||||||
import { IpRangeTypeParamEditor } from '../../vis/editors/default/controls/ip_range_type';
|
import { IpRangeTypeParamEditor } from '../../vis/editors/default/controls/ip_range_type';
|
||||||
import { IpRangesParamEditor } from '../../vis/editors/default/controls/ip_ranges';
|
import { IpRangesParamEditor } from '../../vis/editors/default/controls/ip_ranges';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { createFilterIpRange } from './create_filter/ip_range';
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
|
const ipRangeTitle = i18n.translate('common.ui.aggTypes.buckets.ipRangeTitle', {
|
||||||
|
defaultMessage: 'IPv4 Range',
|
||||||
|
});
|
||||||
|
|
||||||
export const ipRangeBucketAgg = new BucketAggType({
|
export const ipRangeBucketAgg = new BucketAggType({
|
||||||
name: 'ip_range',
|
name: BUCKET_TYPES.IP_RANGE,
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.ipRangeTitle', {
|
title: ipRangeTitle,
|
||||||
defaultMessage: 'IPv4 Range',
|
|
||||||
}),
|
|
||||||
createFilter: createFilterIpRange,
|
createFilter: createFilterIpRange,
|
||||||
getKey: function (bucket, key) {
|
getKey(bucket, key) {
|
||||||
if (key) return key;
|
if (key) return key;
|
||||||
const from = _.get(bucket, 'from', '-Infinity');
|
const from = get(bucket, 'from', '-Infinity');
|
||||||
const to = _.get(bucket, 'to', 'Infinity');
|
const to = get(bucket, 'to', 'Infinity');
|
||||||
|
|
||||||
return `${from} to ${to}`;
|
return `${from} to ${to}`;
|
||||||
},
|
},
|
||||||
makeLabel: function (aggConfig) {
|
makeLabel(aggConfig) {
|
||||||
return i18n.translate('common.ui.aggTypes.buckets.ipRangeLabel', {
|
return i18n.translate('common.ui.aggTypes.buckets.ipRangeLabel', {
|
||||||
defaultMessage: '{fieldName} IP ranges',
|
defaultMessage: '{fieldName} IP ranges',
|
||||||
values: {
|
values: {
|
||||||
fieldName: aggConfig.getFieldDisplayName()
|
fieldName: aggConfig.getFieldDisplayName(),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'field',
|
name: 'field',
|
||||||
type: 'field',
|
type: 'field',
|
||||||
filterFieldTypes: 'ip'
|
filterFieldTypes: KBN_FIELD_TYPES.IP,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: 'ipRangeType',
|
name: 'ipRangeType',
|
||||||
editorComponent: IpRangeTypeParamEditor,
|
editorComponent: IpRangeTypeParamEditor,
|
||||||
default: 'fromTo',
|
default: 'fromTo',
|
||||||
write: _.noop
|
write: noop,
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
name: 'ranges',
|
name: 'ranges',
|
||||||
default: {
|
default: {
|
||||||
fromTo: [
|
fromTo: [
|
||||||
{ from: '0.0.0.0', to: '127.255.255.255' },
|
{ from: '0.0.0.0', to: '127.255.255.255' },
|
||||||
{ from: '128.0.0.0', to: '191.255.255.255' }
|
{ from: '128.0.0.0', to: '191.255.255.255' },
|
||||||
],
|
],
|
||||||
mask: [
|
mask: [{ mask: '0.0.0.0/1' }, { mask: '128.0.0.0/2' }],
|
||||||
{ mask: '0.0.0.0/1' },
|
|
||||||
{ mask: '128.0.0.0/2' }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
editorComponent: IpRangesParamEditor,
|
editorComponent: IpRangesParamEditor,
|
||||||
write: function (aggConfig, output) {
|
write(aggConfig: IBucketAggConfig, output: Record<string, any>) {
|
||||||
const ipRangeType = aggConfig.params.ipRangeType;
|
const ipRangeType = aggConfig.params.ipRangeType;
|
||||||
let ranges = aggConfig.params.ranges[ipRangeType];
|
let ranges = aggConfig.params.ranges[ipRangeType];
|
||||||
|
|
||||||
if (ipRangeType === 'fromTo') {
|
if (ipRangeType === 'fromTo') {
|
||||||
ranges = _.map(ranges, (range) => {
|
ranges = map(ranges, (range: any) => omit(range, isNull));
|
||||||
return _.omit(range, _.isNull);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
output.params.ranges = ranges;
|
output.params.ranges = ranges;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
|
@ -18,35 +18,32 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { isString, isObject } from 'lodash';
|
import { isString, isObject } from 'lodash';
|
||||||
|
import { AggConfig } from 'ui/agg_types';
|
||||||
|
import { IBucketAggConfig, BucketAggType, BucketAggParam } from './_bucket_agg_type';
|
||||||
|
|
||||||
function isType(type) {
|
export const isType = (type: string) => {
|
||||||
return function (agg) {
|
return (agg: IBucketAggConfig): boolean => {
|
||||||
const field = agg.params.field;
|
const field = agg.params.field;
|
||||||
|
|
||||||
return field && field.type === type;
|
return field && field.type === type;
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const isStringType = isType('string');
|
export const isStringType = isType('string');
|
||||||
|
|
||||||
const migrateIncludeExcludeFormat = {
|
export const migrateIncludeExcludeFormat = {
|
||||||
serialize: function (value, agg) {
|
serialize(this: BucketAggParam, value: any, agg: AggConfig) {
|
||||||
if (this.shouldShow && !this.shouldShow(agg)) return;
|
if (this.shouldShow && !this.shouldShow(agg)) return;
|
||||||
if (!value || isString(value)) return value;
|
if (!value || isString(value)) return value;
|
||||||
else return value.pattern;
|
else return value.pattern;
|
||||||
},
|
},
|
||||||
write: function (aggConfig, output) {
|
write(this: BucketAggType<IBucketAggConfig>, aggConfig: AggConfig, output: Record<string, any>) {
|
||||||
const value = aggConfig.params[this.name];
|
const value = aggConfig.getParam(this.name);
|
||||||
|
|
||||||
if (isObject(value)) {
|
if (isObject(value)) {
|
||||||
output.params[this.name] = value.pattern;
|
output.params[this.name] = value.pattern;
|
||||||
} else if (value && isStringType(aggConfig)) {
|
} else if (value && isStringType(aggConfig)) {
|
||||||
output.params[this.name] = value;
|
output.params[this.name] = value;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
isType,
|
|
||||||
isStringType,
|
|
||||||
migrateIncludeExcludeFormat
|
|
||||||
};
|
};
|
|
@ -17,32 +17,38 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { IBucketAggConfig } from './_bucket_agg_type';
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
import { BucketAggType } from './_bucket_agg_type';
|
||||||
import { createFilterRange } from './create_filter/range';
|
|
||||||
import { FieldFormat } from '../../../../../plugins/data/common/field_formats';
|
import { FieldFormat } from '../../../../../plugins/data/common/field_formats';
|
||||||
import { RangeKey } from './range_key';
|
import { RangeKey } from './range_key';
|
||||||
import { RangesParamEditor } from '../../vis/editors/default/controls/ranges';
|
import { RangesEditor } from './range_editor';
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { createFilterRange } from './create_filter/range';
|
||||||
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
const keyCaches = new WeakMap();
|
const keyCaches = new WeakMap();
|
||||||
const formats = new WeakMap();
|
const formats = new WeakMap();
|
||||||
|
|
||||||
|
const rangeTitle = i18n.translate('common.ui.aggTypes.buckets.rangeTitle', {
|
||||||
|
defaultMessage: 'Range',
|
||||||
|
});
|
||||||
|
|
||||||
export const rangeBucketAgg = new BucketAggType({
|
export const rangeBucketAgg = new BucketAggType({
|
||||||
name: 'range',
|
name: BUCKET_TYPES.RANGE,
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.rangeTitle', {
|
title: rangeTitle,
|
||||||
defaultMessage: 'Range',
|
|
||||||
}),
|
|
||||||
createFilter: createFilterRange,
|
createFilter: createFilterRange,
|
||||||
makeLabel: function (aggConfig) {
|
makeLabel(aggConfig) {
|
||||||
return i18n.translate('common.ui.aggTypes.buckets.rangesLabel', {
|
return i18n.translate('common.ui.aggTypes.buckets.rangesLabel', {
|
||||||
defaultMessage: '{fieldName} ranges',
|
defaultMessage: '{fieldName} ranges',
|
||||||
values: {
|
values: {
|
||||||
fieldName: aggConfig.getFieldDisplayName()
|
fieldName: aggConfig.getFieldDisplayName(),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getKey: function (bucket, key, agg) {
|
getKey(bucket, key, agg) {
|
||||||
let keys = keyCaches.get(agg);
|
let keys = keyCaches.get(agg);
|
||||||
|
|
||||||
if (!keys) {
|
if (!keys) {
|
||||||
|
@ -60,11 +66,11 @@ export const rangeBucketAgg = new BucketAggType({
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
},
|
},
|
||||||
getFormat: function (agg) {
|
getFormat(agg) {
|
||||||
let format = formats.get(agg);
|
let aggFormat = formats.get(agg);
|
||||||
if (format) return format;
|
if (aggFormat) return aggFormat;
|
||||||
|
|
||||||
const RangeFormat = FieldFormat.from(function (range) {
|
const RangeFormat = FieldFormat.from((range: any) => {
|
||||||
const format = agg.fieldOwnFormatter();
|
const format = agg.fieldOwnFormatter();
|
||||||
const gte = '\u2265';
|
const gte = '\u2265';
|
||||||
const lt = '\u003c';
|
const lt = '\u003c';
|
||||||
|
@ -79,28 +85,25 @@ export const rangeBucketAgg = new BucketAggType({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
format = new RangeFormat();
|
aggFormat = new RangeFormat();
|
||||||
|
|
||||||
formats.set(agg, format);
|
formats.set(agg, aggFormat);
|
||||||
return format;
|
return aggFormat;
|
||||||
},
|
},
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
name: 'field',
|
name: 'field',
|
||||||
type: 'field',
|
type: 'field',
|
||||||
filterFieldTypes: ['number']
|
filterFieldTypes: [KBN_FIELD_TYPES.NUMBER],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'ranges',
|
name: 'ranges',
|
||||||
default: [
|
default: [{ from: 0, to: 1000 }, { from: 1000, to: 2000 }],
|
||||||
{ from: 0, to: 1000 },
|
editorComponent: RangesEditor,
|
||||||
{ from: 1000, to: 2000 }
|
write(aggConfig: IBucketAggConfig, output: Record<string, any>) {
|
||||||
],
|
|
||||||
editorComponent: ({ value, setValue }) => <RangesParamEditor value={value} setValue={setValue}/>,
|
|
||||||
write: function (aggConfig, output) {
|
|
||||||
output.params.ranges = aggConfig.params.ranges;
|
output.params.ranges = aggConfig.params.ranges;
|
||||||
output.params.keyed = true;
|
output.params.keyed = true;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
|
@ -18,10 +18,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { AggParamEditorProps } from 'ui/vis/editors/default';
|
||||||
|
import { RangesParamEditor } from '../../vis/editors/default/controls/ranges';
|
||||||
|
|
||||||
const wrapWithInlineComp = Component => props => (
|
export const RangesEditor = (props: AggParamEditorProps<any>) => (
|
||||||
<div className={`visEditorAggParam--half visEditorAggParam--half-${props.aggParam.name}`}>
|
<RangesParamEditor value={props.value} setValue={props.setValue} />
|
||||||
<Component {...props}/>
|
);
|
||||||
</div>);
|
|
||||||
|
|
||||||
export { wrapWithInlineComp };
|
|
|
@ -19,16 +19,19 @@
|
||||||
|
|
||||||
const id = Symbol('id');
|
const id = Symbol('id');
|
||||||
|
|
||||||
class RangeKey {
|
export class RangeKey {
|
||||||
constructor(bucket) {
|
[id]: string;
|
||||||
|
gte: string | number;
|
||||||
|
lt: string | number;
|
||||||
|
|
||||||
|
constructor(bucket: any) {
|
||||||
this.gte = bucket.from == null ? -Infinity : bucket.from;
|
this.gte = bucket.from == null ? -Infinity : bucket.from;
|
||||||
this.lt = bucket.to == null ? +Infinity : bucket.to;
|
this.lt = bucket.to == null ? +Infinity : bucket.to;
|
||||||
|
|
||||||
this[id] = RangeKey.idBucket(bucket);
|
this[id] = RangeKey.idBucket(bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static idBucket(bucket: any) {
|
||||||
static idBucket(bucket) {
|
|
||||||
return `from:${bucket.from},to:${bucket.to}`;
|
return `from:${bucket.from},to:${bucket.to}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,5 +39,3 @@ class RangeKey {
|
||||||
return this[id];
|
return this[id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { RangeKey };
|
|
|
@ -19,22 +19,26 @@
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { SizeParamEditor } from '../../vis/editors/default/controls/size';
|
import { SizeParamEditor } from '../../vis/editors/default/controls/size';
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
import { BucketAggType, BucketAggParam } from './_bucket_agg_type';
|
||||||
import { createFilterTerms } from './create_filter/terms';
|
import { createFilterTerms } from './create_filter/terms';
|
||||||
import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format';
|
import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format';
|
||||||
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
|
const significantTermsTitle = i18n.translate('common.ui.aggTypes.buckets.significantTermsTitle', {
|
||||||
|
defaultMessage: 'Significant Terms',
|
||||||
|
});
|
||||||
|
|
||||||
export const significantTermsBucketAgg = new BucketAggType({
|
export const significantTermsBucketAgg = new BucketAggType({
|
||||||
name: 'significant_terms',
|
name: BUCKET_TYPES.SIGNIFICANT_TERMS,
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.significantTermsTitle', {
|
title: significantTermsTitle,
|
||||||
defaultMessage: 'Significant Terms',
|
makeLabel(aggConfig) {
|
||||||
}),
|
|
||||||
makeLabel: function (aggConfig) {
|
|
||||||
return i18n.translate('common.ui.aggTypes.buckets.significantTermsLabel', {
|
return i18n.translate('common.ui.aggTypes.buckets.significantTermsLabel', {
|
||||||
defaultMessage: 'Top {size} unusual terms in {fieldName}',
|
defaultMessage: 'Top {size} unusual terms in {fieldName}',
|
||||||
values: {
|
values: {
|
||||||
size: aggConfig.params.size,
|
size: aggConfig.params.size,
|
||||||
fieldName: aggConfig.getFieldDisplayName(),
|
fieldName: aggConfig.getFieldDisplayName(),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
createFilter: createFilterTerms,
|
createFilter: createFilterTerms,
|
||||||
|
@ -43,7 +47,7 @@ export const significantTermsBucketAgg = new BucketAggType({
|
||||||
name: 'field',
|
name: 'field',
|
||||||
type: 'field',
|
type: 'field',
|
||||||
scriptable: false,
|
scriptable: false,
|
||||||
filterFieldTypes: 'string'
|
filterFieldTypes: KBN_FIELD_TYPES.STRING,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'size',
|
name: 'size',
|
||||||
|
@ -53,22 +57,22 @@ export const significantTermsBucketAgg = new BucketAggType({
|
||||||
{
|
{
|
||||||
name: 'exclude',
|
name: 'exclude',
|
||||||
displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.excludeLabel', {
|
displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.excludeLabel', {
|
||||||
defaultMessage: 'Exclude'
|
defaultMessage: 'Exclude',
|
||||||
}),
|
}),
|
||||||
type: 'string',
|
type: 'string',
|
||||||
advanced: true,
|
advanced: true,
|
||||||
shouldShow: isStringType,
|
shouldShow: isStringType,
|
||||||
...migrateIncludeExcludeFormat
|
...migrateIncludeExcludeFormat,
|
||||||
},
|
} as BucketAggParam,
|
||||||
{
|
{
|
||||||
name: 'include',
|
name: 'include',
|
||||||
displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.includeLabel', {
|
displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.includeLabel', {
|
||||||
defaultMessage: 'Include'
|
defaultMessage: 'Include',
|
||||||
}),
|
}),
|
||||||
type: 'string',
|
type: 'string',
|
||||||
advanced: true,
|
advanced: true,
|
||||||
shouldShow: isStringType,
|
shouldShow: isStringType,
|
||||||
...migrateIncludeExcludeFormat
|
...migrateIncludeExcludeFormat,
|
||||||
}
|
} as BucketAggParam,
|
||||||
]
|
],
|
||||||
});
|
});
|
|
@ -18,13 +18,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import chrome from 'ui/chrome';
|
import chrome from 'ui/chrome';
|
||||||
|
import { noop } from 'lodash';
|
||||||
|
import { SearchSource } from 'ui/courier';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { BucketAggType } from './_bucket_agg_type';
|
import { BucketAggType, BucketAggParam } from './_bucket_agg_type';
|
||||||
import { Schemas } from '../../vis/editors/default/schemas';
|
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||||
import { getRequestInspectorStats, getResponseInspectorStats } from '../../courier/utils/courier_inspector_utils';
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
import { AggConfigOptions } from '../agg_config';
|
||||||
|
import { IBucketAggConfig } from './_bucket_agg_type';
|
||||||
|
import {
|
||||||
|
getRequestInspectorStats,
|
||||||
|
getResponseInspectorStats,
|
||||||
|
} from '../../courier/utils/courier_inspector_utils';
|
||||||
import { createFilterTerms } from './create_filter/terms';
|
import { createFilterTerms } from './create_filter/terms';
|
||||||
import { wrapWithInlineComp } from './_inline_comp_wrapper';
|
import { wrapWithInlineComp } from './inline_comp_wrapper';
|
||||||
import { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket } from './_terms_other_bucket_helper';
|
|
||||||
import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format';
|
import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format';
|
||||||
import { OrderAggParamEditor } from '../../vis/editors/default/controls/order_agg';
|
import { OrderAggParamEditor } from '../../vis/editors/default/controls/order_agg';
|
||||||
import { OrderParamEditor } from '../../vis/editors/default/controls/order';
|
import { OrderParamEditor } from '../../vis/editors/default/controls/order';
|
||||||
|
@ -32,31 +39,47 @@ import { OrderByParamEditor, aggFilter } from '../../vis/editors/default/control
|
||||||
import { SizeParamEditor } from '../../vis/editors/default/controls/size';
|
import { SizeParamEditor } from '../../vis/editors/default/controls/size';
|
||||||
import { MissingBucketParamEditor } from '../../vis/editors/default/controls/missing_bucket';
|
import { MissingBucketParamEditor } from '../../vis/editors/default/controls/missing_bucket';
|
||||||
import { OtherBucketParamEditor } from '../../vis/editors/default/controls/other_bucket';
|
import { OtherBucketParamEditor } from '../../vis/editors/default/controls/other_bucket';
|
||||||
|
import { ContentType } from '../../../../../plugins/data/common';
|
||||||
|
import { AggConfigs } from '../agg_configs';
|
||||||
|
|
||||||
const orderAggSchema = (new Schemas([
|
import { Adapters } from '../../../../../plugins/inspector/public';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { Schemas } from '../../vis/editors/default/schemas';
|
||||||
|
|
||||||
|
import {
|
||||||
|
buildOtherBucketAgg,
|
||||||
|
mergeOtherBucketAggResponse,
|
||||||
|
updateMissingBucket,
|
||||||
|
// @ts-ignore
|
||||||
|
} from './_terms_other_bucket_helper';
|
||||||
|
|
||||||
|
const [orderAggSchema] = new Schemas([
|
||||||
{
|
{
|
||||||
group: 'none',
|
group: 'none',
|
||||||
name: 'orderAgg',
|
name: 'orderAgg',
|
||||||
// This string is never visible to the user so it doesn't need to be translated
|
// This string is never visible to the user so it doesn't need to be translated
|
||||||
title: 'Order Agg',
|
title: 'Order Agg',
|
||||||
hideCustomLabel: true,
|
hideCustomLabel: true,
|
||||||
aggFilter: aggFilter
|
aggFilter,
|
||||||
}
|
},
|
||||||
])).all[0];
|
]).all;
|
||||||
|
|
||||||
|
const termsTitle = i18n.translate('common.ui.aggTypes.buckets.termsTitle', {
|
||||||
|
defaultMessage: 'Terms',
|
||||||
|
});
|
||||||
|
|
||||||
export const termsBucketAgg = new BucketAggType({
|
export const termsBucketAgg = new BucketAggType({
|
||||||
name: 'terms',
|
name: BUCKET_TYPES.TERMS,
|
||||||
title: i18n.translate('common.ui.aggTypes.buckets.termsTitle', {
|
title: termsTitle,
|
||||||
defaultMessage: 'Terms',
|
makeLabel(agg) {
|
||||||
}),
|
|
||||||
makeLabel: function (agg) {
|
|
||||||
const params = agg.params;
|
const params = agg.params;
|
||||||
return agg.getFieldDisplayName() + ': ' + params.order.text;
|
return agg.getFieldDisplayName() + ': ' + params.order.text;
|
||||||
},
|
},
|
||||||
getFormat: function (bucket) {
|
getFormat(bucket) {
|
||||||
return {
|
return {
|
||||||
getConverterFor: (type) => {
|
getConverterFor: (type: ContentType) => {
|
||||||
return (val) => {
|
return (val: any) => {
|
||||||
if (val === '__other__') {
|
if (val === '__other__') {
|
||||||
return bucket.params.otherBucketLabel;
|
return bucket.params.otherBucketLabel;
|
||||||
}
|
}
|
||||||
|
@ -71,11 +94,18 @@ export const termsBucketAgg = new BucketAggType({
|
||||||
const converter = bucket.params.field.format.getConverterFor(type);
|
const converter = bucket.params.field.format.getConverterFor(type);
|
||||||
return converter(val, undefined, undefined, parsedUrl);
|
return converter(val, undefined, undefined, parsedUrl);
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
createFilter: createFilterTerms,
|
createFilter: createFilterTerms,
|
||||||
postFlightRequest: async (resp, aggConfigs, aggConfig, searchSource, inspectorAdapters, abortSignal) => {
|
postFlightRequest: async (
|
||||||
|
resp: any,
|
||||||
|
aggConfigs: AggConfigs,
|
||||||
|
aggConfig: IBucketAggConfig,
|
||||||
|
searchSource: SearchSource,
|
||||||
|
inspectorAdapters: Adapters,
|
||||||
|
abortSignal?: AbortSignal
|
||||||
|
) => {
|
||||||
if (!resp.aggregations) return resp;
|
if (!resp.aggregations) return resp;
|
||||||
const nestedSearchSource = searchSource.createChild();
|
const nestedSearchSource = searchSource.createChild();
|
||||||
if (aggConfig.params.otherBucket) {
|
if (aggConfig.params.otherBucket) {
|
||||||
|
@ -88,23 +118,24 @@ export const termsBucketAgg = new BucketAggType({
|
||||||
nestedSearchSource.setField('aggs', filterAgg);
|
nestedSearchSource.setField('aggs', filterAgg);
|
||||||
|
|
||||||
const request = inspectorAdapters.requests.start(
|
const request = inspectorAdapters.requests.start(
|
||||||
i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketTitle', { defaultMessage: 'Other bucket' }),
|
i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketTitle', {
|
||||||
|
defaultMessage: 'Other bucket',
|
||||||
|
}),
|
||||||
{
|
{
|
||||||
description: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketDescription', {
|
description: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketDescription', {
|
||||||
defaultMessage: 'This request counts the number of documents that fall ' +
|
defaultMessage:
|
||||||
'outside the criterion of the data buckets.'
|
'This request counts the number of documents that fall ' +
|
||||||
|
'outside the criterion of the data buckets.',
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
nestedSearchSource.getSearchRequestBody().then(body => {
|
nestedSearchSource.getSearchRequestBody().then((body: string) => {
|
||||||
request.json(body);
|
request.json(body);
|
||||||
});
|
});
|
||||||
request.stats(getRequestInspectorStats(nestedSearchSource));
|
request.stats(getRequestInspectorStats(nestedSearchSource));
|
||||||
|
|
||||||
const response = await nestedSearchSource.fetch();
|
const response = await nestedSearchSource.fetch();
|
||||||
request
|
request.stats(getResponseInspectorStats(nestedSearchSource, response)).ok({ json: response });
|
||||||
.stats(getResponseInspectorStats(nestedSearchSource, response))
|
|
||||||
.ok({ json: response });
|
|
||||||
resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg());
|
resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg());
|
||||||
}
|
}
|
||||||
if (aggConfig.params.missingBucket) {
|
if (aggConfig.params.missingBucket) {
|
||||||
|
@ -116,28 +147,34 @@ export const termsBucketAgg = new BucketAggType({
|
||||||
{
|
{
|
||||||
name: 'field',
|
name: 'field',
|
||||||
type: 'field',
|
type: 'field',
|
||||||
filterFieldTypes: ['number', 'boolean', 'date', 'ip', 'string']
|
filterFieldTypes: [
|
||||||
|
KBN_FIELD_TYPES.NUMBER,
|
||||||
|
KBN_FIELD_TYPES.BOOLEAN,
|
||||||
|
KBN_FIELD_TYPES.DATE,
|
||||||
|
KBN_FIELD_TYPES.IP,
|
||||||
|
KBN_FIELD_TYPES.STRING,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'orderBy',
|
name: 'orderBy',
|
||||||
editorComponent: OrderByParamEditor,
|
editorComponent: OrderByParamEditor,
|
||||||
write: () => {} // prevent default write, it's handled by orderAgg
|
write: noop, // prevent default write, it's handled by orderAgg
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'orderAgg',
|
name: 'orderAgg',
|
||||||
type: 'agg',
|
type: 'agg',
|
||||||
default: null,
|
default: null,
|
||||||
editorComponent: OrderAggParamEditor,
|
editorComponent: OrderAggParamEditor,
|
||||||
makeAgg: function (termsAgg, state) {
|
makeAgg(termsAgg: IBucketAggConfig, state: AggConfigOptions) {
|
||||||
state = state || {};
|
state = state || {};
|
||||||
state.schema = orderAggSchema;
|
state.schema = orderAggSchema;
|
||||||
const orderAgg = termsAgg.aggConfigs.createAggConfig(state, { addToAggConfigs: false });
|
const orderAgg = termsAgg.aggConfigs.createAggConfig(state, { addToAggConfigs: false });
|
||||||
orderAgg.id = termsAgg.id + '-orderAgg';
|
orderAgg.id = termsAgg.id + '-orderAgg';
|
||||||
return orderAgg;
|
return orderAgg;
|
||||||
},
|
},
|
||||||
write: function (agg, output, aggs) {
|
write(agg: IBucketAggConfig, output: Record<string, any>, aggs: AggConfigs) {
|
||||||
const dir = agg.params.order.value;
|
const dir = agg.params.order.value;
|
||||||
const order = output.params.order = {};
|
const order: Record<string, any> = (output.params.order = {});
|
||||||
|
|
||||||
let orderAgg = agg.params.orderAgg || aggs.getResponseAggById(agg.params.orderBy);
|
let orderAgg = agg.params.orderAgg || aggs.getResponseAggById(agg.params.orderBy);
|
||||||
|
|
||||||
|
@ -145,7 +182,8 @@ export const termsBucketAgg = new BucketAggType({
|
||||||
// thus causing issues with filtering. This probably causes other issues since float might not
|
// thus causing issues with filtering. This probably causes other issues since float might not
|
||||||
// be able to contain the number on the elasticsearch side
|
// be able to contain the number on the elasticsearch side
|
||||||
if (output.params.script) {
|
if (output.params.script) {
|
||||||
output.params.value_type = agg.getField().type === 'number' ? 'float' : agg.getField().type;
|
output.params.value_type =
|
||||||
|
agg.getField().type === 'number' ? 'float' : agg.getField().type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (agg.params.missingBucket && agg.params.field.type === 'string') {
|
if (agg.params.missingBucket && agg.params.field.type === 'string') {
|
||||||
|
@ -169,7 +207,7 @@ export const termsBucketAgg = new BucketAggType({
|
||||||
|
|
||||||
output.subAggs = (output.subAggs || []).concat(orderAgg);
|
output.subAggs = (output.subAggs || []).concat(orderAgg);
|
||||||
order[orderAggId] = dir;
|
order[orderAggId] = dir;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'order',
|
name: 'order',
|
||||||
|
@ -181,27 +219,27 @@ export const termsBucketAgg = new BucketAggType({
|
||||||
text: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', {
|
text: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', {
|
||||||
defaultMessage: 'Descending',
|
defaultMessage: 'Descending',
|
||||||
}),
|
}),
|
||||||
value: 'desc'
|
value: 'desc',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', {
|
text: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', {
|
||||||
defaultMessage: 'Ascending',
|
defaultMessage: 'Ascending',
|
||||||
}),
|
}),
|
||||||
value: 'asc'
|
value: 'asc',
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
write: () => {} // prevent default write, it's handled by orderAgg
|
write: noop, // prevent default write, it's handled by orderAgg
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'size',
|
name: 'size',
|
||||||
editorComponent: wrapWithInlineComp(SizeParamEditor),
|
editorComponent: wrapWithInlineComp(SizeParamEditor),
|
||||||
default: 5
|
default: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'otherBucket',
|
name: 'otherBucket',
|
||||||
default: false,
|
default: false,
|
||||||
editorComponent: OtherBucketParamEditor,
|
editorComponent: OtherBucketParamEditor,
|
||||||
write: () => {},
|
write: noop,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'otherBucketLabel',
|
name: 'otherBucketLabel',
|
||||||
|
@ -212,14 +250,14 @@ export const termsBucketAgg = new BucketAggType({
|
||||||
displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForOtherBucketLabel', {
|
displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForOtherBucketLabel', {
|
||||||
defaultMessage: 'Label for other bucket',
|
defaultMessage: 'Label for other bucket',
|
||||||
}),
|
}),
|
||||||
shouldShow: agg => agg.params.otherBucket,
|
shouldShow: (agg: IBucketAggConfig) => agg.getParam('otherBucket'),
|
||||||
write: () => {},
|
write: noop,
|
||||||
},
|
} as BucketAggParam,
|
||||||
{
|
{
|
||||||
name: 'missingBucket',
|
name: 'missingBucket',
|
||||||
default: false,
|
default: false,
|
||||||
editorComponent: MissingBucketParamEditor,
|
editorComponent: MissingBucketParamEditor,
|
||||||
write: () => {},
|
write: noop,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'missingBucketLabel',
|
name: 'missingBucketLabel',
|
||||||
|
@ -232,24 +270,28 @@ export const termsBucketAgg = new BucketAggType({
|
||||||
displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForMissingValuesLabel', {
|
displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForMissingValuesLabel', {
|
||||||
defaultMessage: 'Label for missing values',
|
defaultMessage: 'Label for missing values',
|
||||||
}),
|
}),
|
||||||
shouldShow: agg => agg.params.missingBucket,
|
shouldShow: (agg: IBucketAggConfig) => agg.getParam('missingBucket'),
|
||||||
write: () => {},
|
write: noop,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'exclude',
|
name: 'exclude',
|
||||||
displayName: i18n.translate('common.ui.aggTypes.buckets.terms.excludeLabel', { defaultMessage: 'Exclude' }),
|
displayName: i18n.translate('common.ui.aggTypes.buckets.terms.excludeLabel', {
|
||||||
|
defaultMessage: 'Exclude',
|
||||||
|
}),
|
||||||
type: 'string',
|
type: 'string',
|
||||||
advanced: true,
|
advanced: true,
|
||||||
shouldShow: isStringType,
|
shouldShow: isStringType,
|
||||||
...migrateIncludeExcludeFormat
|
...migrateIncludeExcludeFormat,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'include',
|
name: 'include',
|
||||||
displayName: i18n.translate('common.ui.aggTypes.buckets.terms.includeLabel', { defaultMessage: 'Include' }),
|
displayName: i18n.translate('common.ui.aggTypes.buckets.terms.includeLabel', {
|
||||||
|
defaultMessage: 'Include',
|
||||||
|
}),
|
||||||
type: 'string',
|
type: 'string',
|
||||||
advanced: true,
|
advanced: true,
|
||||||
shouldShow: isStringType,
|
shouldShow: isStringType,
|
||||||
...migrateIncludeExcludeFormat
|
...migrateIncludeExcludeFormat,
|
||||||
},
|
},
|
||||||
]
|
] as BucketAggParam[],
|
||||||
});
|
});
|
|
@ -17,73 +17,41 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
import { AggType } from './agg_type';
|
|
||||||
// @ts-ignore
|
|
||||||
import { countMetricAgg } from './metrics/count';
|
import { countMetricAgg } from './metrics/count';
|
||||||
// @ts-ignore
|
|
||||||
import { avgMetricAgg } from './metrics/avg';
|
import { avgMetricAgg } from './metrics/avg';
|
||||||
// @ts-ignore
|
|
||||||
import { sumMetricAgg } from './metrics/sum';
|
import { sumMetricAgg } from './metrics/sum';
|
||||||
// @ts-ignore
|
|
||||||
import { medianMetricAgg } from './metrics/median';
|
import { medianMetricAgg } from './metrics/median';
|
||||||
// @ts-ignore
|
|
||||||
import { minMetricAgg } from './metrics/min';
|
import { minMetricAgg } from './metrics/min';
|
||||||
// @ts-ignore
|
|
||||||
import { maxMetricAgg } from './metrics/max';
|
import { maxMetricAgg } from './metrics/max';
|
||||||
// @ts-ignore
|
|
||||||
import { topHitMetricAgg } from './metrics/top_hit';
|
import { topHitMetricAgg } from './metrics/top_hit';
|
||||||
// @ts-ignore
|
|
||||||
import { stdDeviationMetricAgg } from './metrics/std_deviation';
|
import { stdDeviationMetricAgg } from './metrics/std_deviation';
|
||||||
// @ts-ignore
|
|
||||||
import { cardinalityMetricAgg } from './metrics/cardinality';
|
import { cardinalityMetricAgg } from './metrics/cardinality';
|
||||||
// @ts-ignore
|
|
||||||
import { percentilesMetricAgg } from './metrics/percentiles';
|
import { percentilesMetricAgg } from './metrics/percentiles';
|
||||||
// @ts-ignore
|
|
||||||
import { geoBoundsMetricAgg } from './metrics/geo_bounds';
|
import { geoBoundsMetricAgg } from './metrics/geo_bounds';
|
||||||
// @ts-ignore
|
|
||||||
import { geoCentroidMetricAgg } from './metrics/geo_centroid';
|
import { geoCentroidMetricAgg } from './metrics/geo_centroid';
|
||||||
// @ts-ignore
|
|
||||||
import { percentileRanksMetricAgg } from './metrics/percentile_ranks';
|
import { percentileRanksMetricAgg } from './metrics/percentile_ranks';
|
||||||
// @ts-ignore
|
|
||||||
import { derivativeMetricAgg } from './metrics/derivative';
|
import { derivativeMetricAgg } from './metrics/derivative';
|
||||||
// @ts-ignore
|
|
||||||
import { cumulativeSumMetricAgg } from './metrics/cumulative_sum';
|
import { cumulativeSumMetricAgg } from './metrics/cumulative_sum';
|
||||||
// @ts-ignore
|
|
||||||
import { movingAvgMetricAgg } from './metrics/moving_avg';
|
import { movingAvgMetricAgg } from './metrics/moving_avg';
|
||||||
// @ts-ignore
|
|
||||||
import { serialDiffMetricAgg } from './metrics/serial_diff';
|
import { serialDiffMetricAgg } from './metrics/serial_diff';
|
||||||
// @ts-ignore
|
|
||||||
import { dateHistogramBucketAgg, setBounds } from './buckets/date_histogram';
|
import { dateHistogramBucketAgg, setBounds } from './buckets/date_histogram';
|
||||||
// @ts-ignore
|
|
||||||
import { histogramBucketAgg } from './buckets/histogram';
|
import { histogramBucketAgg } from './buckets/histogram';
|
||||||
// @ts-ignore
|
|
||||||
import { rangeBucketAgg } from './buckets/range';
|
import { rangeBucketAgg } from './buckets/range';
|
||||||
// @ts-ignore
|
|
||||||
import { dateRangeBucketAgg } from './buckets/date_range';
|
import { dateRangeBucketAgg } from './buckets/date_range';
|
||||||
// @ts-ignore
|
|
||||||
import { ipRangeBucketAgg } from './buckets/ip_range';
|
import { ipRangeBucketAgg } from './buckets/ip_range';
|
||||||
// @ts-ignore
|
|
||||||
import { termsBucketAgg } from './buckets/terms';
|
import { termsBucketAgg } from './buckets/terms';
|
||||||
// @ts-ignore
|
|
||||||
import { filterBucketAgg } from './buckets/filter';
|
import { filterBucketAgg } from './buckets/filter';
|
||||||
// @ts-ignore
|
|
||||||
import { filtersBucketAgg } from './buckets/filters';
|
import { filtersBucketAgg } from './buckets/filters';
|
||||||
// @ts-ignore
|
|
||||||
import { significantTermsBucketAgg } from './buckets/significant_terms';
|
import { significantTermsBucketAgg } from './buckets/significant_terms';
|
||||||
// @ts-ignore
|
|
||||||
import { geoHashBucketAgg } from './buckets/geo_hash';
|
import { geoHashBucketAgg } from './buckets/geo_hash';
|
||||||
// @ts-ignore
|
|
||||||
import { geoTileBucketAgg } from './buckets/geo_tile';
|
import { geoTileBucketAgg } from './buckets/geo_tile';
|
||||||
// @ts-ignore
|
|
||||||
import { bucketSumMetricAgg } from './metrics/bucket_sum';
|
import { bucketSumMetricAgg } from './metrics/bucket_sum';
|
||||||
// @ts-ignore
|
|
||||||
import { bucketAvgMetricAgg } from './metrics/bucket_avg';
|
import { bucketAvgMetricAgg } from './metrics/bucket_avg';
|
||||||
// @ts-ignore
|
|
||||||
import { bucketMinMetricAgg } from './metrics/bucket_min';
|
import { bucketMinMetricAgg } from './metrics/bucket_min';
|
||||||
// @ts-ignore
|
|
||||||
import { bucketMaxMetricAgg } from './metrics/bucket_max';
|
import { bucketMaxMetricAgg } from './metrics/bucket_max';
|
||||||
|
|
||||||
|
export { AggType } from './agg_type';
|
||||||
|
|
||||||
export const aggTypes = {
|
export const aggTypes = {
|
||||||
metrics: [
|
metrics: [
|
||||||
countMetricAgg,
|
countMetricAgg,
|
||||||
|
@ -123,13 +91,9 @@ export const aggTypes = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
aggTypes.metrics.forEach(aggType => (aggType.type = 'metrics'));
|
|
||||||
aggTypes.buckets.forEach(aggType => (aggType.type = 'buckets'));
|
|
||||||
|
|
||||||
export { AggParam } from './agg_params';
|
export { AggParam } from './agg_params';
|
||||||
export { AggType } from './agg_type';
|
|
||||||
export { AggConfig } from './agg_config';
|
export { AggConfig } from './agg_config';
|
||||||
export { AggConfigs } from './agg_configs';
|
export { AggConfigs } from './agg_configs';
|
||||||
export { FieldParamType } from './param_types';
|
export { FieldParamType } from './param_types';
|
||||||
export { BucketAggType } from './buckets/_bucket_agg_type';
|
|
||||||
export { setBounds };
|
export { setBounds };
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { MetricAggType } from './metric_agg_type';
|
import { IMetricAggConfig, MetricAggType } from './metric_agg_type';
|
||||||
import { METRIC_TYPES } from './metric_agg_types';
|
import { METRIC_TYPES } from './metric_agg_types';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -49,7 +49,7 @@ export const medianMetricAgg = new MetricAggType({
|
||||||
default: [50],
|
default: [50],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
write(agg, output) {
|
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||||
output.params.keyed = false;
|
output.params.keyed = false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,12 +27,10 @@ import { METRIC_TYPES } from './metric_agg_types';
|
||||||
import { fieldFormats } from '../../registry/field_formats';
|
import { fieldFormats } from '../../registry/field_formats';
|
||||||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
export interface IMetricAggConfig extends AggConfig {
|
export type IMetricAggConfig = AggConfig;
|
||||||
params: MetricAggParam[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MetricAggTypeConfig<TMetricAggConfig extends IMetricAggConfig>
|
export interface MetricAggTypeConfig<TMetricAggConfig extends IMetricAggConfig>
|
||||||
extends AggTypeConfig<TMetricAggConfig> {
|
extends AggTypeConfig<TMetricAggConfig, MetricAggParam> {
|
||||||
isScalable?: () => boolean;
|
isScalable?: () => boolean;
|
||||||
subtype?: string;
|
subtype?: string;
|
||||||
}
|
}
|
||||||
|
@ -42,11 +40,16 @@ export interface MetricAggParam extends AggParamType {
|
||||||
onlyAggregatable?: boolean;
|
onlyAggregatable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MetricAggType<TMetricAggConfig extends IMetricAggConfig> extends AggType<
|
const metricType = 'metrics';
|
||||||
TMetricAggConfig
|
|
||||||
> {
|
export class MetricAggType<
|
||||||
|
TMetricAggConfig extends IMetricAggConfig = IMetricAggConfig
|
||||||
|
> extends AggType<TMetricAggConfig, MetricAggParam> {
|
||||||
subtype: string;
|
subtype: string;
|
||||||
isScalable: () => boolean;
|
isScalable: () => boolean;
|
||||||
|
type = metricType;
|
||||||
|
|
||||||
|
getKey = () => {};
|
||||||
|
|
||||||
constructor(config: MetricAggTypeConfig<TMetricAggConfig>) {
|
constructor(config: MetricAggTypeConfig<TMetricAggConfig>) {
|
||||||
super(config);
|
super(config);
|
||||||
|
@ -81,3 +84,7 @@ export class MetricAggType<TMetricAggConfig extends IMetricAggConfig> extends Ag
|
||||||
this.isScalable = config.isScalable || (() => false);
|
this.isScalable = config.isScalable || (() => false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isMetricAggType(aggConfig: any): aggConfig is MetricAggType {
|
||||||
|
return aggConfig && aggConfig.type === metricType;
|
||||||
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { PercentileRanksEditor } from '../../vis/editors/default/controls/percentile_ranks';
|
import { PercentileRanksEditor } from '../../vis/editors/default/controls/percentile_ranks';
|
||||||
import { MetricAggType } from './metric_agg_type';
|
import { IMetricAggConfig, MetricAggType } from './metric_agg_type';
|
||||||
import { getResponseAggConfigClass, IResponseAggConfig } from './get_response_agg_config_class';
|
import { getResponseAggConfigClass, IResponseAggConfig } from './get_response_agg_config_class';
|
||||||
|
|
||||||
import { getPercentileValue } from './percentiles_get_value';
|
import { getPercentileValue } from './percentiles_get_value';
|
||||||
|
@ -69,7 +69,7 @@ export const percentileRanksMetricAgg = new MetricAggType<IPercentileRanksAggCon
|
||||||
default: [],
|
default: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
write(agg, output) {
|
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||||
output.params.keyed = false;
|
output.params.keyed = false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,8 +19,9 @@
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
|
||||||
import { MetricAggType } from './metric_agg_type';
|
import { IMetricAggConfig, MetricAggType } from './metric_agg_type';
|
||||||
import { METRIC_TYPES } from './metric_agg_types';
|
import { METRIC_TYPES } from './metric_agg_types';
|
||||||
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
import { getResponseAggConfigClass, IResponseAggConfig } from './get_response_agg_config_class';
|
import { getResponseAggConfigClass, IResponseAggConfig } from './get_response_agg_config_class';
|
||||||
import { getPercentileValue } from './percentiles_get_value';
|
import { getPercentileValue } from './percentiles_get_value';
|
||||||
|
@ -28,7 +29,6 @@ import { PercentilesEditor } from '../../vis/editors/default/controls/percentile
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { ordinalSuffix } from '../../utils/ordinal_suffix';
|
import { ordinalSuffix } from '../../utils/ordinal_suffix';
|
||||||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
|
||||||
|
|
||||||
type IPercentileAggConfig = IResponseAggConfig;
|
type IPercentileAggConfig = IResponseAggConfig;
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ export const percentilesMetricAgg = new MetricAggType<IPercentileAggConfig>({
|
||||||
default: [1, 5, 25, 50, 75, 95, 99],
|
default: [1, 5, 25, 50, 75, 95, 99],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
write(agg, output) {
|
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||||
output.params.keyed = false;
|
output.params.keyed = false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { METRIC_TYPES } from './metric_agg_types';
|
||||||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { wrapWithInlineComp } from '../buckets/_inline_comp_wrapper';
|
import { wrapWithInlineComp } from '../buckets/inline_comp_wrapper';
|
||||||
|
|
||||||
const isNumericFieldSelected = (agg: IMetricAggConfig) => {
|
const isNumericFieldSelected = (agg: IMetricAggConfig) => {
|
||||||
const field = agg.getParam('field');
|
const field = agg.getParam('field');
|
||||||
|
@ -46,7 +46,7 @@ aggTypeFieldFilters.addFilter((field, aggConfig: IMetricAggConfig) => {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return field.type === 'number';
|
return field.type === KBN_FIELD_TYPES.NUMBER;
|
||||||
});
|
});
|
||||||
|
|
||||||
export const topHitMetricAgg = new MetricAggType({
|
export const topHitMetricAgg = new MetricAggType({
|
||||||
|
@ -82,7 +82,7 @@ export const topHitMetricAgg = new MetricAggType({
|
||||||
editorComponent: TopFieldParamEditor,
|
editorComponent: TopFieldParamEditor,
|
||||||
onlyAggregatable: false,
|
onlyAggregatable: false,
|
||||||
filterFieldTypes: '*',
|
filterFieldTypes: '*',
|
||||||
write(agg, output) {
|
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||||
const field = agg.getParam('field');
|
const field = agg.getParam('field');
|
||||||
output.params = {};
|
output.params = {};
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ export const topHitMetricAgg = new MetricAggType({
|
||||||
value: 'asc',
|
value: 'asc',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
write(agg, output) {
|
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||||
const sortField = agg.params.sortField;
|
const sortField = agg.params.sortField;
|
||||||
const sortOrder = agg.params.sortOrder;
|
const sortOrder = agg.params.sortOrder;
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,8 @@ export class BaseParamType implements AggParam {
|
||||||
*/
|
*/
|
||||||
modifyAggConfigOnSearchRequestStart: (
|
modifyAggConfigOnSearchRequestStart: (
|
||||||
aggconfig: AggConfig,
|
aggconfig: AggConfig,
|
||||||
searchSource: SearchSource,
|
searchSource?: SearchSource,
|
||||||
searchRequest: any
|
searchRequest?: any
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
constructor(config: Record<string, any>) {
|
constructor(config: Record<string, any>) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ import { AggParamEditorProps } from '..';
|
||||||
const generateId = htmlIdGenerator();
|
const generateId = htmlIdGenerator();
|
||||||
const config = chrome.getUiSettingsClient();
|
const config = chrome.getUiSettingsClient();
|
||||||
|
|
||||||
interface FilterValue {
|
export interface FilterValue {
|
||||||
input: Query;
|
input: Query;
|
||||||
label: string;
|
label: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -34,6 +34,7 @@ jest.mock('ui/new_platform');
|
||||||
jest.mock('ui/agg_types/buckets/date_histogram', () => ({
|
jest.mock('ui/agg_types/buckets/date_histogram', () => ({
|
||||||
setBounds: () => {},
|
setBounds: () => {},
|
||||||
dateHistogramBucketAgg: () => {},
|
dateHistogramBucketAgg: () => {},
|
||||||
|
isDateHistogramBucketAggConfig: () => true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('visualize loader pipeline helpers: build pipeline', () => {
|
describe('visualize loader pipeline helpers: build pipeline', () => {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { cloneDeep, get } from 'lodash';
|
||||||
import { setBounds } from 'ui/agg_types';
|
import { setBounds } from 'ui/agg_types';
|
||||||
import { SearchSource } from 'ui/courier';
|
import { SearchSource } from 'ui/courier';
|
||||||
import { AggConfig, Vis, VisParams, VisState } from 'ui/vis';
|
import { AggConfig, Vis, VisParams, VisState } from 'ui/vis';
|
||||||
|
import { isDateHistogramBucketAggConfig } from 'ui/agg_types/buckets/date_histogram';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { SerializedFieldFormat } from 'src/plugins/expressions/common/expressions/types/common';
|
import { SerializedFieldFormat } from 'src/plugins/expressions/common/expressions/types/common';
|
||||||
import { createFormat } from './utilities';
|
import { createFormat } from './utilities';
|
||||||
|
@ -76,7 +77,7 @@ const vislibCharts: string[] = [
|
||||||
|
|
||||||
export const getSchemas = (vis: Vis, timeRange?: any): Schemas => {
|
export const getSchemas = (vis: Vis, timeRange?: any): Schemas => {
|
||||||
const createSchemaConfig = (accessor: number, agg: AggConfig): SchemaConfig => {
|
const createSchemaConfig = (accessor: number, agg: AggConfig): SchemaConfig => {
|
||||||
if (agg.type.name === 'date_histogram') {
|
if (isDateHistogramBucketAggConfig(agg)) {
|
||||||
agg.params.timeRange = timeRange;
|
agg.params.timeRange = timeRange;
|
||||||
setBounds(agg, true);
|
setBounds(agg, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
],
|
],
|
||||||
"monitoring/common/*": [
|
"monitoring/common/*": [
|
||||||
"x-pack/monitoring/common/*"
|
"x-pack/monitoring/common/*"
|
||||||
]
|
],
|
||||||
|
"plugins/*": ["src/legacy/core_plugins/*/public/"]
|
||||||
},
|
},
|
||||||
"types": [
|
"types": [
|
||||||
"node",
|
"node",
|
||||||
|
|
Loading…
Reference in a new issue