mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Convert ui/agg_types/buckets
to TypeScript / Jest (#47730)
* 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
0d0b38ad02
commit
8837faebde
45 changed files with 875 additions and 601 deletions
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
|
||||
): PhrasesFilter;
|
||||
|
||||
export function buildQueryFilter(query: any, index: string): CustomFilter;
|
||||
export function buildQueryFilter(query: any, index: string, alias?: string): CustomFilter;
|
||||
|
||||
export function buildRangeFilter(
|
||||
field: Field,
|
||||
|
|
|
@ -28,7 +28,12 @@ import { GeoPolygonFilter, isGeoPolygonFilter } from './geo_polygon_filter';
|
|||
import { PhraseFilter, isPhraseFilter, isScriptedPhraseFilter } from './phrase_filter';
|
||||
import { PhrasesFilter, isPhrasesFilter } from './phrases_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 { MissingFilter, isMissingFilter } from './missing_filter';
|
||||
|
||||
|
@ -50,6 +55,7 @@ export {
|
|||
RangeFilter,
|
||||
isRangeFilter,
|
||||
isScriptedRangeFilter,
|
||||
RangeFilterParams,
|
||||
MatchAllFilter,
|
||||
isMatchAllFilter,
|
||||
MissingFilter,
|
||||
|
|
|
@ -19,23 +19,16 @@
|
|||
import { get, keys } from 'lodash';
|
||||
import { Filter, FilterMeta } from './meta_filter';
|
||||
|
||||
interface FilterRange {
|
||||
export interface RangeFilterParams {
|
||||
from?: number | string;
|
||||
to?: number | string;
|
||||
}
|
||||
|
||||
interface FilterRangeGt {
|
||||
gt?: number | string;
|
||||
lt?: number | string;
|
||||
}
|
||||
|
||||
interface FilterRangeGte {
|
||||
gte?: number | string;
|
||||
lte?: number | string;
|
||||
format?: string;
|
||||
}
|
||||
|
||||
export type RangeFilterParams = FilterRange & FilterRangeGt & FilterRangeGte;
|
||||
|
||||
export type RangeFilterMeta = FilterMeta & {
|
||||
params: RangeFilterParams;
|
||||
field?: any;
|
||||
|
|
|
@ -38,7 +38,8 @@ describe('Significant Terms Agg', function () {
|
|||
$rootScope.agg = {
|
||||
id: 'test',
|
||||
params: aggParams,
|
||||
type: significantTerms
|
||||
type: significantTerms,
|
||||
getParam: key => aggParams[key],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@ describe('Terms Agg', function () {
|
|||
type: terms,
|
||||
vis: {
|
||||
aggs: []
|
||||
}
|
||||
},
|
||||
getParam: key => aggParams[key],
|
||||
};
|
||||
$rootScope.metricAggs = metricAggs;
|
||||
$controller(orderAggController, { $scope: $rootScope });
|
||||
|
|
|
@ -26,20 +26,23 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
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';
|
||||
// @ts-ignore
|
||||
import { fieldFormats } from '../registry/field_formats';
|
||||
import { writeParams } from './agg_params';
|
||||
import { AggConfigs } from './agg_configs';
|
||||
import { Schema } from '../vis/editors/default/schemas';
|
||||
import { ContentType } from '../../../../plugins/data/common';
|
||||
|
||||
// @ts-ignore
|
||||
import { fieldFormats } from '../registry/field_formats';
|
||||
|
||||
export interface AggConfigOptions {
|
||||
id: string;
|
||||
enabled: boolean;
|
||||
type: string;
|
||||
schema: string;
|
||||
params: any;
|
||||
id?: string;
|
||||
schema?: string;
|
||||
}
|
||||
|
||||
const unknownSchema: Schema = {
|
||||
|
@ -139,7 +142,10 @@ export class AggConfig {
|
|||
|
||||
// setters
|
||||
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
|
||||
this.setParams(opts.params || {});
|
||||
|
@ -253,7 +259,7 @@ export class AggConfig {
|
|||
* @return {void|Object} - if the config has a dsl representation, it is
|
||||
* returned, else undefined is returned
|
||||
*/
|
||||
toDsl(aggConfigs: AggConfigs) {
|
||||
toDsl(aggConfigs?: AggConfigs) {
|
||||
if (this.type.hasNoDsl) return;
|
||||
const output = this.write(aggConfigs) as any;
|
||||
|
||||
|
@ -327,8 +333,8 @@ export class AggConfig {
|
|||
}
|
||||
|
||||
getKey(bucket: any, key: string) {
|
||||
if (this.type instanceof BucketAggType) {
|
||||
return (this.type as BucketAggType).getKey(bucket, key, this);
|
||||
if (this.type.getKey) {
|
||||
return this.type.getKey(bucket, key, this);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
@ -336,6 +342,7 @@ export class AggConfig {
|
|||
|
||||
getFieldDisplayName() {
|
||||
const field = this.getField();
|
||||
|
||||
return field ? field.displayName || this.fieldName() : '';
|
||||
}
|
||||
|
||||
|
@ -365,13 +372,16 @@ export class AggConfig {
|
|||
return this.aggConfigs.timeRange;
|
||||
}
|
||||
|
||||
fieldFormatter(contentType: string, defaultFormat: any) {
|
||||
fieldFormatter(contentType?: ContentType, defaultFormat?: any) {
|
||||
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);
|
||||
}
|
||||
|
||||
fieldOwnFormatter(contentType: string, defaultFormat: any) {
|
||||
fieldOwnFormatter(contentType?: ContentType, defaultFormat?: any) {
|
||||
const field = this.getField();
|
||||
let format = field && field.format;
|
||||
if (!format) format = defaultFormat;
|
||||
|
|
|
@ -20,17 +20,19 @@
|
|||
import { constant, noop, identity } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AggParam, initParams } from './agg_params';
|
||||
// @ts-ignore
|
||||
import { FieldFormat, fieldFormats } from '../registry/field_formats';
|
||||
|
||||
import { AggConfig } from '../vis';
|
||||
import { AggConfigs } from './agg_configs';
|
||||
import { SearchSource } from '../courier';
|
||||
import { Adapters } from '../inspector';
|
||||
import { BaseParamType } from './param_types/base';
|
||||
|
||||
// @ts-ignore
|
||||
import { FieldFormat, fieldFormats } from '../registry/field_formats';
|
||||
|
||||
export interface AggTypeConfig<
|
||||
TAggConfig extends AggConfig = AggConfig,
|
||||
TParam extends AggParam = TAggConfig['params'][number]
|
||||
TParam extends AggParam = AggParam
|
||||
> {
|
||||
name: string;
|
||||
title: string;
|
||||
|
@ -50,7 +52,8 @@ export interface AggTypeConfig<
|
|||
aggConfigs: AggConfigs,
|
||||
aggConfig: TAggConfig,
|
||||
searchSource: SearchSource,
|
||||
inspectorAdapters: Adapters
|
||||
inspectorAdapters: Adapters,
|
||||
abortSignal?: AbortSignal
|
||||
) => Promise<any>;
|
||||
getFormat?: (agg: TAggConfig) => FieldFormat;
|
||||
getValue?: (agg: TAggConfig, bucket: any) => any;
|
||||
|
@ -62,7 +65,7 @@ const getFormat = (agg: AggConfig) => {
|
|||
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
|
||||
*
|
||||
|
@ -131,7 +134,7 @@ export class AggType<TAggConfig extends AggConfig = AggConfig> {
|
|||
* @property params
|
||||
* @type {AggParams}
|
||||
*/
|
||||
params: TAggConfig['params'];
|
||||
params: TParam[];
|
||||
/**
|
||||
* Designed for multi-value metric aggs, this method can return a
|
||||
* 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;
|
||||
|
||||
getKey?: (bucket: any, key: any, agg: TAggConfig) => any;
|
||||
|
||||
paramByName = (name: string) => {
|
||||
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) {
|
||||
this.params = config.params as TAggConfig['params'];
|
||||
this.params = config.params as TParam[];
|
||||
} else {
|
||||
// always append the raw JSON param
|
||||
const params: any[] = config.params ? [...config.params] : [];
|
||||
|
|
|
@ -17,13 +17,32 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { AggType, AggTypeConfig } from '../agg_type';
|
||||
import { AggParamType } from '../param_types/agg';
|
||||
import { AggConfig } from '../../vis';
|
||||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||
import { AggType, AggTypeConfig } from '../agg_type';
|
||||
|
||||
export class BucketAggType extends AggType {
|
||||
getKey: (bucket: any, key: any, agg: AggConfig) => any;
|
||||
export type IBucketAggConfig = AggConfig;
|
||||
|
||||
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);
|
||||
|
||||
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.
|
||||
*/
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { IBucketAggConfig } from './_bucket_agg_type';
|
||||
|
||||
export const intervalOptions = [
|
||||
{
|
||||
|
@ -24,58 +25,58 @@ export const intervalOptions = [
|
|||
defaultMessage: 'Auto',
|
||||
}),
|
||||
val: 'auto',
|
||||
enabled: function (agg) {
|
||||
enabled(agg: IBucketAggConfig) {
|
||||
// not only do we need a time field, but the selected field needs
|
||||
// to be the time field. (see #3028)
|
||||
return agg.fieldIsTimeField();
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName', {
|
||||
defaultMessage: 'Millisecond',
|
||||
}),
|
||||
val: 'ms'
|
||||
val: 'ms',
|
||||
},
|
||||
{
|
||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.secondDisplayName', {
|
||||
defaultMessage: 'Second',
|
||||
}),
|
||||
val: 's'
|
||||
val: 's',
|
||||
},
|
||||
{
|
||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName', {
|
||||
defaultMessage: 'Minute',
|
||||
}),
|
||||
val: 'm'
|
||||
val: 'm',
|
||||
},
|
||||
{
|
||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName', {
|
||||
defaultMessage: 'Hourly',
|
||||
}),
|
||||
val: 'h'
|
||||
val: 'h',
|
||||
},
|
||||
{
|
||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName', {
|
||||
defaultMessage: 'Daily',
|
||||
}),
|
||||
val: 'd'
|
||||
val: 'd',
|
||||
},
|
||||
{
|
||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName', {
|
||||
defaultMessage: 'Weekly',
|
||||
}),
|
||||
val: 'w'
|
||||
val: 'w',
|
||||
},
|
||||
{
|
||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName', {
|
||||
defaultMessage: 'Monthly',
|
||||
}),
|
||||
val: 'M'
|
||||
val: 'M',
|
||||
},
|
||||
{
|
||||
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName', {
|
||||
defaultMessage: 'Yearly',
|
||||
}),
|
||||
val: 'y'
|
||||
}
|
||||
val: 'y',
|
||||
},
|
||||
];
|
|
@ -59,7 +59,9 @@ const getAggResultBuckets = (aggConfigs, response, aggWithOtherBucket, key) => {
|
|||
const aggKey = _.keys(responseAgg)[aggId];
|
||||
const aggConfig = _.find(aggConfigs.aggs, agg => agg.id === aggKey);
|
||||
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];
|
||||
});
|
||||
if (bucket) {
|
||||
|
@ -93,7 +95,7 @@ const getAggConfigResultMissingBuckets = (responseAggs, aggId) => {
|
|||
_.each(agg.buckets, bucket => {
|
||||
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
|
||||
*/
|
||||
const getOtherAggTerms = (requestAgg, key, otherAgg) => {
|
||||
return requestAgg['other-filter'].filters.filters[key].bool.must_not.filter(filter =>
|
||||
filter.match_phrase && filter.match_phrase[otherAgg.params.field.name]
|
||||
).map(filter =>
|
||||
filter.match_phrase[otherAgg.params.field.name].query
|
||||
);
|
||||
return requestAgg['other-filter'].filters.filters[key].bool.must_not
|
||||
.filter(filter => filter.match_phrase && filter.match_phrase[otherAgg.params.field.name])
|
||||
.map(filter => filter.match_phrase[otherAgg.params.field.name].query);
|
||||
};
|
||||
|
||||
|
||||
export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) => {
|
||||
const bucketAggs = aggConfigs.aggs.filter(agg => agg.type.type === AggGroupNames.Buckets);
|
||||
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;
|
||||
|
||||
// create filters aggregation
|
||||
const filterAgg = aggConfigs.createAggConfig({
|
||||
type: 'filters',
|
||||
id: 'other',
|
||||
params: {
|
||||
filters: [],
|
||||
const filterAgg = aggConfigs.createAggConfig(
|
||||
{
|
||||
type: 'filters',
|
||||
id: 'other',
|
||||
params: {
|
||||
filters: [],
|
||||
},
|
||||
},
|
||||
}, {
|
||||
addToAggConfigs: false,
|
||||
});
|
||||
{
|
||||
addToAggConfigs: false,
|
||||
}
|
||||
);
|
||||
|
||||
// nest all the child aggregations of aggWithOtherBucket
|
||||
const resultAgg = {
|
||||
|
@ -156,16 +158,33 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) =>
|
|||
const currentAgg = bucketAggs[aggIndex];
|
||||
if (aggIndex < index) {
|
||||
_.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 newFilters = _.flatten([...filters, filter]);
|
||||
walkBucketTree(newAggIndex, bucket, newAgg.id, newFilters, `${key}-${bucketKey.toString()}`);
|
||||
walkBucketTree(
|
||||
newAggIndex,
|
||||
bucket,
|
||||
newAgg.id,
|
||||
newFilters,
|
||||
`${key}-${bucketKey.toString()}`
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aggWithOtherBucket.params.missingBucket || agg.buckets.some(bucket => bucket.key === '__missing__')) {
|
||||
filters.push(buildExistsFilter(aggWithOtherBucket.params.field, aggWithOtherBucket.params.field.indexPattern));
|
||||
if (
|
||||
!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
|
||||
|
@ -177,7 +196,7 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) =>
|
|||
});
|
||||
|
||||
resultAgg.filters.filters[key] = {
|
||||
bool: buildQueryFromFilters(filters, indexPattern)
|
||||
bool: buildQueryFromFilters(filters, indexPattern),
|
||||
};
|
||||
};
|
||||
walkBucketTree(0, response.aggregations, bucketAggs[0].id, [], '');
|
||||
|
@ -189,26 +208,43 @@ export const buildOtherBucketAgg = (aggConfigs, aggWithOtherBucket, response) =>
|
|||
|
||||
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);
|
||||
_.each(otherResponse.aggregations['other-filter'].buckets, (bucket, key) => {
|
||||
if (!bucket.doc_count) return;
|
||||
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 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;
|
||||
bucket.filters = [ phraseFilter ];
|
||||
bucket.filters = [phraseFilter];
|
||||
bucket.key = '__other__';
|
||||
|
||||
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);
|
||||
});
|
||||
|
|
|
@ -17,7 +17,15 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { AggConfig } from 'ui/agg_types/agg_config';
|
||||
|
||||
export function isStringType(type: AggConfig): boolean;
|
||||
export function isType(type: string): (agg: AggConfig) => boolean;
|
||||
export enum BUCKET_TYPES {
|
||||
FILTER = 'filter',
|
||||
HISTOGRAM = 'histogram',
|
||||
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 { 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 interval = agg.buckets.getInterval();
|
||||
|
||||
return buildRangeFilter(agg.params.field, {
|
||||
gte: start.toISOString(),
|
||||
lt: start.add(interval).toISOString(),
|
||||
format: 'strict_date_optional_time'
|
||||
}, agg.getIndexPattern());
|
||||
}
|
||||
return buildRangeFilter(
|
||||
agg.params.field,
|
||||
{
|
||||
gte: start.toISOString(),
|
||||
lt: start.add(interval).toISOString(),
|
||||
format: 'strict_date_optional_time',
|
||||
},
|
||||
agg.getIndexPattern()
|
||||
);
|
||||
};
|
|
@ -17,19 +17,20 @@
|
|||
* 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 { 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 range = dateRange.parse(key, config.get('dateFormat'));
|
||||
|
||||
const filter = {};
|
||||
const filter: RangeFilterParams = {};
|
||||
if (range.from) filter.gte = range.from.toISOString();
|
||||
if (range.to) filter.lt = range.to.toISOString();
|
||||
if (range.to && range.from) filter.format = 'strict_date_optional_time';
|
||||
|
||||
return buildRangeFilter(agg.params.field, filter, agg.getIndexPattern());
|
||||
}
|
||||
};
|
|
@ -17,15 +17,17 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
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
|
||||
const dslFilters = _.get(aggConfig.toDsl(), 'filters.filters');
|
||||
const dslFilters: any = get(aggConfig.toDsl(), 'filters.filters');
|
||||
const filter = dslFilters[key];
|
||||
const indexPattern = aggConfig.getIndexPattern();
|
||||
|
||||
if (filter) {
|
||||
return buildQueryFilter(filter.query, aggConfig.getIndexPattern().id, key);
|
||||
if (filter && indexPattern && indexPattern.id) {
|
||||
return buildQueryFilter(filter.query, indexPattern.id, key);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -17,15 +17,17 @@
|
|||
* 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 params: RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval };
|
||||
|
||||
return buildRangeFilter(
|
||||
aggConfig.params.field,
|
||||
{ gte: value, lt: value + aggConfig.params.interval },
|
||||
params,
|
||||
aggConfig.getIndexPattern(),
|
||||
aggConfig.fieldFormatter()(key)
|
||||
);
|
||||
}
|
||||
};
|
|
@ -17,20 +17,27 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { buildRangeFilter, RangeFilterParams } from '@kbn/es-query';
|
||||
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') {
|
||||
range = new CidrMask(key).getRange();
|
||||
} else {
|
||||
const [from, to] = key.split(/\s+to\s+/);
|
||||
|
||||
range = {
|
||||
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 { IBucketAggConfig } from '../_bucket_agg_type';
|
||||
|
||||
export function createFilterRange(aggConfig, key) {
|
||||
export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => {
|
||||
return buildRangeFilter(
|
||||
aggConfig.params.field,
|
||||
key,
|
||||
params,
|
||||
aggConfig.getIndexPattern(),
|
||||
aggConfig.fieldFormatter()(key)
|
||||
aggConfig.fieldFormatter()(params)
|
||||
);
|
||||
}
|
||||
};
|
|
@ -17,9 +17,10 @@
|
|||
* 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 indexPattern = field.indexPattern;
|
||||
|
||||
|
@ -29,9 +30,9 @@ export function createFilterTerms(aggConfig, key, params) {
|
|||
const phraseFilter = buildPhrasesFilter(field, terms, indexPattern);
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -42,4 +43,4 @@ export function createFilterTerms(aggConfig, key, params) {
|
|||
return existsFilter;
|
||||
}
|
||||
return buildPhraseFilter(field, key, indexPattern);
|
||||
}
|
||||
};
|
|
@ -18,10 +18,11 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import chrome from '../../chrome';
|
||||
import moment from 'moment-timezone';
|
||||
import { BucketAggType } from './_bucket_agg_type';
|
||||
import { TimeBuckets } from '../../time_buckets';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
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 { intervalOptions } from './_interval_options';
|
||||
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 { ScaleMetricsParamEditor } from '../../vis/editors/default/controls/scale_metrics';
|
||||
import { dateHistogramInterval } from '../../../../core_plugins/data/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
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 detectedTimezone = moment.tz.guess();
|
||||
const tzOffset = moment().format('Z');
|
||||
|
||||
function getInterval(agg) {
|
||||
return _.get(agg, ['params', 'interval']);
|
||||
}
|
||||
const getInterval = (agg: IBucketAggConfig): string => _.get(agg, ['params', 'interval']);
|
||||
|
||||
export function setBounds(agg, force) {
|
||||
export const setBounds = (agg: IBucketDateHistogramAggConfig, force?: boolean) => {
|
||||
if (agg.buckets._alreadySet && !force) return;
|
||||
agg.buckets._alreadySet = true;
|
||||
const bounds = agg.params.timeRange ? timefilter.calculateBounds(agg.params.timeRange) : null;
|
||||
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({
|
||||
name: 'date_histogram',
|
||||
export function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHistogramAggConfig {
|
||||
return Boolean(agg.buckets);
|
||||
}
|
||||
|
||||
export const dateHistogramBucketAgg = new BucketAggType<IBucketDateHistogramAggConfig>({
|
||||
name: BUCKET_TYPES.DATE_HISTOGRAM,
|
||||
title: i18n.translate('common.ui.aggTypes.buckets.dateHistogramTitle', {
|
||||
defaultMessage: 'Date Histogram',
|
||||
}),
|
||||
ordered: {
|
||||
date: true
|
||||
date: true,
|
||||
},
|
||||
makeLabel: function (agg) {
|
||||
const output = writeParams(this.params, agg);
|
||||
makeLabel(agg) {
|
||||
const output: Record<string, any> = writeParams(this.params as BucketAggParam[], agg);
|
||||
const field = agg.getFieldDisplayName();
|
||||
return i18n.translate('common.ui.aggTypes.buckets.dateHistogramLabel', {
|
||||
defaultMessage: '{fieldName} per {intervalDescription}',
|
||||
values: {
|
||||
fieldName: field,
|
||||
intervalDescription: output.metricScaleText || output.bucketInterval.description,
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
createFilter: createFilterDateHistogram,
|
||||
decorateAggConfig: function () {
|
||||
let buckets;
|
||||
decorateAggConfig() {
|
||||
let buckets: any;
|
||||
return {
|
||||
buckets: {
|
||||
configurable: true,
|
||||
get: function () {
|
||||
get() {
|
||||
if (buckets) return buckets;
|
||||
|
||||
buckets = new TimeBuckets();
|
||||
|
@ -81,28 +103,28 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
|||
setBounds(this);
|
||||
|
||||
return buckets;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
getFormat: function (agg) {
|
||||
getFormat(agg) {
|
||||
return agg.buckets.getScaledDateFormatter();
|
||||
},
|
||||
params: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'field',
|
||||
filterFieldTypes: 'date',
|
||||
default: function (agg) {
|
||||
filterFieldTypes: KBN_FIELD_TYPES.DATE,
|
||||
default(agg: IBucketDateHistogramAggConfig) {
|
||||
return agg.getIndexPattern().timeFieldName;
|
||||
},
|
||||
onChange: function (agg) {
|
||||
onChange(agg: IBucketDateHistogramAggConfig) {
|
||||
if (_.get(agg, 'params.interval') === 'auto' && !agg.fieldIsTimeField()) {
|
||||
delete agg.params.interval;
|
||||
}
|
||||
|
||||
setBounds(agg, true);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'timeRange',
|
||||
|
@ -124,7 +146,7 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
|||
{
|
||||
name: 'interval',
|
||||
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
|
||||
if (state === 'custom') {
|
||||
return _.get(agg, 'params.customInterval');
|
||||
|
@ -141,10 +163,10 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
|||
},
|
||||
default: 'auto',
|
||||
options: intervalOptions,
|
||||
modifyAggConfigOnSearchRequestStart: function (agg) {
|
||||
modifyAggConfigOnSearchRequestStart(agg: IBucketDateHistogramAggConfig) {
|
||||
setBounds(agg, true);
|
||||
},
|
||||
write: function (agg, output, aggs) {
|
||||
write(agg: IBucketDateHistogramAggConfig, output: Record<string, any>, aggs: AggConfigs) {
|
||||
setBounds(agg, true);
|
||||
agg.buckets.setInterval(getInterval(agg));
|
||||
const { useNormalizedEsInterval, scaleMetricValues } = agg.params;
|
||||
|
@ -166,31 +188,41 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
|||
|
||||
const scaleMetrics = scaleMetricValues && interval.scaled && interval.scale < 1;
|
||||
if (scaleMetrics && aggs) {
|
||||
const metrics = aggs.aggs.filter(agg => agg.type && agg.type.type === 'metrics');
|
||||
const all = _.every(metrics, function (agg) {
|
||||
return agg.type.isScalable();
|
||||
const metrics = aggs.aggs.filter(a => isMetricAggType(a.type));
|
||||
const all = _.every(metrics, (a: AggConfig) => {
|
||||
const { type } = a;
|
||||
|
||||
if (isMetricAggType(type)) {
|
||||
return type.isScalable();
|
||||
}
|
||||
});
|
||||
if (all) {
|
||||
output.metricScale = interval.scale;
|
||||
output.metricScaleText = interval.preScaled.description;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
} as BucketAggParam,
|
||||
{
|
||||
name: 'time_zone',
|
||||
default: undefined,
|
||||
// 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
|
||||
// time_zones being persisted into saved_objects
|
||||
serialize: () => undefined,
|
||||
write: (agg, output) => {
|
||||
serialize: _.noop,
|
||||
write(agg: IBucketDateHistogramAggConfig, output: Record<string, any>) {
|
||||
// If a time_zone has been set explicitly always prefer this.
|
||||
let tz = agg.params.time_zone;
|
||||
if (!tz && agg.params.field) {
|
||||
// If a field has been configured check the index pattern's typeMeta if a date_histogram on that
|
||||
// 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 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;
|
||||
},
|
||||
},
|
||||
} as BucketAggParam,
|
||||
{
|
||||
name: 'drop_partials',
|
||||
default: false,
|
||||
|
@ -211,29 +243,27 @@ export const dateHistogramBucketAgg = new BucketAggType({
|
|||
},
|
||||
},
|
||||
{
|
||||
name: 'format'
|
||||
name: 'format',
|
||||
},
|
||||
|
||||
{
|
||||
name: 'min_doc_count',
|
||||
default: 1
|
||||
default: 1,
|
||||
},
|
||||
|
||||
{
|
||||
name: 'extended_bounds',
|
||||
default: {},
|
||||
write: function (agg, output) {
|
||||
write(agg: IBucketDateHistogramAggConfig, output: Record<string, any>) {
|
||||
const val = agg.params.extended_bounds;
|
||||
|
||||
if (val.min != null || val.max != null) {
|
||||
output.params.extended_bounds = {
|
||||
min: moment(val.min).valueOf(),
|
||||
max: moment(val.max).valueOf()
|
||||
max: moment(val.max).valueOf(),
|
||||
};
|
||||
|
||||
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
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { BucketAggType } from './_bucket_agg_type';
|
||||
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({
|
||||
name: 'filter',
|
||||
title: i18n.translate('common.ui.aggTypes.buckets.filterTitle', {
|
||||
defaultMessage: 'Filter',
|
||||
}),
|
||||
name: BUCKET_TYPES.FILTER,
|
||||
title: filterTitle,
|
||||
params: [
|
||||
{
|
||||
name: 'geo_bounding_box'
|
||||
}
|
||||
]
|
||||
name: 'geo_bounding_box',
|
||||
},
|
||||
],
|
||||
});
|
|
@ -20,69 +20,79 @@
|
|||
import _ from 'lodash';
|
||||
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 { Storage } from 'ui/storage';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
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';
|
||||
|
||||
const { getQueryLog } = data.query.helpers;
|
||||
const config = chrome.getUiSettingsClient();
|
||||
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({
|
||||
name: 'filters',
|
||||
title: 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.'
|
||||
}),
|
||||
title: filtersTitle,
|
||||
createFilter: createFilterFilters,
|
||||
customLabels: false,
|
||||
params: [
|
||||
{
|
||||
name: 'filters',
|
||||
editorComponent: FiltersParamEditor,
|
||||
default: [ { input: { query: '', language: config.get('search:queryLanguage') }, label: '' } ],
|
||||
write: function (aggConfig, output) {
|
||||
const inFilters = aggConfig.params.filters;
|
||||
default: [{ input: { query: '', language: config.get('search:queryLanguage') }, label: '' }],
|
||||
write(aggConfig: IBucketAggConfig, output: Record<string, any>) {
|
||||
const inFilters: FilterValue[] = aggConfig.params.filters;
|
||||
if (!_.size(inFilters)) return;
|
||||
|
||||
inFilters.forEach((filter) => {
|
||||
inFilters.forEach(filter => {
|
||||
const persistedLog = getQueryLog(config, storage, 'filtersAgg', filter.input.language);
|
||||
persistedLog.add(filter.input.query);
|
||||
});
|
||||
|
||||
const outFilters = _.transform(inFilters, function (filters, filter) {
|
||||
const input = _.cloneDeep(filter.input);
|
||||
const outFilters = _.transform(
|
||||
inFilters,
|
||||
function(filters, filter) {
|
||||
const input = _.cloneDeep(filter.input);
|
||||
|
||||
if (!input) {
|
||||
console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console
|
||||
return;
|
||||
}
|
||||
if (!input) {
|
||||
console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console
|
||||
return;
|
||||
}
|
||||
|
||||
const query = buildEsQuery(aggConfig.getIndexPattern(), [input], [], config);
|
||||
const query = buildEsQuery(aggConfig.getIndexPattern(), [input], [], config);
|
||||
|
||||
if (!query) {
|
||||
console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console
|
||||
return;
|
||||
}
|
||||
if (!query) {
|
||||
console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console
|
||||
return;
|
||||
}
|
||||
|
||||
const matchAllLabel = filter.input.query === '' ? '*' : '';
|
||||
const label = filter.label
|
||||
|| matchAllLabel
|
||||
|| (typeof filter.input.query === 'string' ? filter.input.query : angular.toJson(filter.input.query));
|
||||
filters[label] = { query };
|
||||
}, {});
|
||||
const matchAllLabel = filter.input.query === '' ? '*' : '';
|
||||
const label =
|
||||
filter.label ||
|
||||
matchAllLabel ||
|
||||
(typeof filter.input.query === 'string'
|
||||
? filter.input.query
|
||||
: angular.toJson(filter.input.query));
|
||||
filters[label] = { query };
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
if (!_.size(outFilters)) return;
|
||||
|
||||
const params = output.params || (output.params = {});
|
||||
params.filters = outFilters;
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
|
@ -17,16 +17,21 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
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 { UseGeocentroidParamEditor } from '../../vis/editors/default/controls/use_geocentroid';
|
||||
import { IsFilteredByCollarParamEditor } from '../../vis/editors/default/controls/is_filtered_by_collar';
|
||||
import { PrecisionParamEditor } from '../../vis/editors/default/controls/precision';
|
||||
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 { 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();
|
||||
|
||||
|
@ -36,14 +41,15 @@ const maxPrecision = parseInt(config.get('visualization:tileMap:maxPrecision'),
|
|||
* 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.
|
||||
*/
|
||||
const zoomPrecision = {};
|
||||
const zoomPrecision: any = {};
|
||||
const minGeohashPixels = 16;
|
||||
|
||||
for (let zoom = 0; zoom <= 21; zoom += 1) {
|
||||
const worldPixels = 256 * Math.pow(2, zoom);
|
||||
zoomPrecision[zoom] = 1;
|
||||
for (let precision = 2; precision <= maxPrecision; precision += 1) {
|
||||
const columns = geohashColumns(precision);
|
||||
if ((worldPixels / columns) >= minGeohashPixels) {
|
||||
if (worldPixels / columns >= minGeohashPixels) {
|
||||
zoomPrecision[zoom] = precision;
|
||||
} else {
|
||||
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 (isNaN(precision)) {
|
||||
if (Number.isNaN(precision)) {
|
||||
precision = defaultPrecision;
|
||||
}
|
||||
|
||||
|
@ -66,20 +71,29 @@ function getPrecision(precision) {
|
|||
return precision;
|
||||
}
|
||||
|
||||
function isOutsideCollar(bounds, collar) {
|
||||
return bounds && collar && !geoContains(collar, bounds);
|
||||
const isOutsideCollar = (bounds: unknown, collar: MapCollar) =>
|
||||
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({
|
||||
name: 'geohash_grid',
|
||||
title: i18n.translate('common.ui.aggTypes.buckets.geohashGridTitle', {
|
||||
defaultMessage: 'Geohash',
|
||||
}),
|
||||
export interface IBucketGeoHashGridAggConfig extends IBucketAggConfig {
|
||||
lastMapCollar: MapCollar;
|
||||
}
|
||||
|
||||
export const geoHashBucketAgg = new BucketAggType<IBucketGeoHashGridAggConfig>({
|
||||
name: BUCKET_TYPES.GEOHASH_GRID,
|
||||
title: geohashGridTitle,
|
||||
params: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'field',
|
||||
filterFieldTypes: 'geo_point'
|
||||
filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
|
||||
},
|
||||
{
|
||||
name: 'autoPrecision',
|
||||
|
@ -92,12 +106,13 @@ export const geoHashBucketAgg = new BucketAggType({
|
|||
editorComponent: PrecisionParamEditor,
|
||||
default: defaultPrecision,
|
||||
deserialize: getPrecision,
|
||||
write: function (aggConfig, output) {
|
||||
write(aggConfig, output) {
|
||||
const currZoom = aggConfig.params.mapZoom;
|
||||
const autoPrecisionVal = zoomPrecision[currZoom];
|
||||
output.params.precision = aggConfig.params.autoPrecision ?
|
||||
autoPrecisionVal : getPrecision(aggConfig.params.precision);
|
||||
}
|
||||
output.params.precision = aggConfig.params.autoPrecision
|
||||
? autoPrecisionVal
|
||||
: getPrecision(aggConfig.params.precision);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'useGeocentroid',
|
||||
|
@ -125,17 +140,21 @@ export const geoHashBucketAgg = new BucketAggType({
|
|||
name: 'mapBounds',
|
||||
default: null,
|
||||
write: () => {},
|
||||
}
|
||||
},
|
||||
],
|
||||
getRequestAggs: function (agg) {
|
||||
const aggs = [];
|
||||
getRequestAggs(agg) {
|
||||
const aggs: AggConfig[] = [];
|
||||
const params = agg.params;
|
||||
|
||||
if (params.isFilteredByCollar && agg.getField()) {
|
||||
const { mapBounds, mapZoom } = params;
|
||||
if (mapBounds) {
|
||||
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.zoom = mapZoom;
|
||||
agg.lastMapCollar = mapCollar;
|
||||
|
@ -146,35 +165,45 @@ export const geoHashBucketAgg = new BucketAggType({
|
|||
ignore_unmapped: true,
|
||||
[agg.getField().name]: {
|
||||
top_left: mapCollar.top_left,
|
||||
bottom_right: mapCollar.bottom_right
|
||||
}
|
||||
};
|
||||
aggs.push(agg.aggConfigs.createAggConfig({
|
||||
type: 'filter',
|
||||
id: 'filter_agg',
|
||||
enabled: true,
|
||||
params: {
|
||||
geo_bounding_box: boundingBox
|
||||
bottom_right: mapCollar.bottom_right,
|
||||
},
|
||||
schema: {
|
||||
group: AggGroupNames.Buckets
|
||||
}
|
||||
}, { addToAggConfigs: false }));
|
||||
};
|
||||
aggs.push(
|
||||
agg.aggConfigs.createAggConfig(
|
||||
{
|
||||
type: 'filter',
|
||||
id: 'filter_agg',
|
||||
enabled: true,
|
||||
params: {
|
||||
geo_bounding_box: boundingBox,
|
||||
},
|
||||
schema: {
|
||||
group: AggGroupNames.Buckets,
|
||||
},
|
||||
} as any,
|
||||
{ addToAggConfigs: false }
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
aggs.push(agg);
|
||||
|
||||
if (params.useGeocentroid) {
|
||||
aggs.push(agg.aggConfigs.createAggConfig({
|
||||
type: 'geo_centroid',
|
||||
enabled: true,
|
||||
params: {
|
||||
field: agg.getField()
|
||||
}
|
||||
}, { addToAggConfigs: false }));
|
||||
aggs.push(
|
||||
agg.aggConfigs.createAggConfig(
|
||||
{
|
||||
type: 'geo_centroid',
|
||||
enabled: true,
|
||||
params: {
|
||||
field: agg.getField(),
|
||||
},
|
||||
},
|
||||
{ addToAggConfigs: false }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return aggs;
|
||||
}
|
||||
return aggs as IBucketGeoHashGridAggConfig[];
|
||||
},
|
||||
});
|
|
@ -17,47 +17,56 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { BucketAggType } from './_bucket_agg_type';
|
||||
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({
|
||||
name: 'geotile_grid',
|
||||
title: i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', {
|
||||
defaultMessage: 'Geotile',
|
||||
}),
|
||||
name: BUCKET_TYPES.GEOTILE_GRID,
|
||||
title: geotileGridTitle,
|
||||
params: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'field',
|
||||
filterFieldTypes: 'geo_point'
|
||||
filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
|
||||
},
|
||||
{
|
||||
name: 'useGeocentroid',
|
||||
default: true,
|
||||
write: _.noop
|
||||
write: noop,
|
||||
},
|
||||
{
|
||||
name: 'precision',
|
||||
default: 0,
|
||||
}
|
||||
},
|
||||
],
|
||||
getRequestAggs: function (agg) {
|
||||
getRequestAggs(agg) {
|
||||
const aggs = [];
|
||||
const params = agg.params;
|
||||
const useGeocentroid = agg.getParam('useGeocentroid');
|
||||
|
||||
aggs.push(agg);
|
||||
|
||||
if (params.useGeocentroid) {
|
||||
aggs.push(agg.aggConfigs.createAggConfig({
|
||||
type: 'geo_centroid',
|
||||
if (useGeocentroid) {
|
||||
const aggConfig: AggConfigOptions = {
|
||||
type: METRIC_TYPES.GEO_CENTROID,
|
||||
enabled: true,
|
||||
params: {
|
||||
field: agg.getField()
|
||||
}
|
||||
}, { addToAggConfigs: false }));
|
||||
field: agg.getField(),
|
||||
},
|
||||
};
|
||||
|
||||
aggs.push(agg.aggConfigs.createAggConfig(aggConfig, { addToAggConfigs: false }));
|
||||
}
|
||||
|
||||
return aggs;
|
||||
}
|
||||
},
|
||||
});
|
|
@ -18,51 +18,64 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
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 { NumberIntervalParamEditor } from '../../vis/editors/default/controls/number_interval';
|
||||
import { MinDocCountParamEditor } from '../../vis/editors/default/controls/min_doc_count';
|
||||
import { HasExtendedBoundsParamEditor } from '../../vis/editors/default/controls/has_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();
|
||||
export const histogramBucketAgg = new BucketAggType({
|
||||
name: 'histogram',
|
||||
export const histogramBucketAgg = new BucketAggType<IBucketHistogramAggConfig>({
|
||||
name: BUCKET_TYPES.HISTOGRAM,
|
||||
title: i18n.translate('common.ui.aggTypes.buckets.histogramTitle', {
|
||||
defaultMessage: 'Histogram',
|
||||
}),
|
||||
ordered: {},
|
||||
makeLabel: function (aggConfig) {
|
||||
makeLabel(aggConfig) {
|
||||
return aggConfig.getFieldDisplayName();
|
||||
},
|
||||
createFilter: createFilterHistogram,
|
||||
decorateAggConfig: function () {
|
||||
let autoBounds;
|
||||
decorateAggConfig() {
|
||||
let autoBounds: AutoBounds;
|
||||
|
||||
return {
|
||||
setAutoBounds: {
|
||||
configurable: true,
|
||||
value(newValue) {
|
||||
value(newValue: AutoBounds) {
|
||||
autoBounds = newValue;
|
||||
}
|
||||
},
|
||||
},
|
||||
getAutoBounds: {
|
||||
configurable: true,
|
||||
value() {
|
||||
return autoBounds;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
params: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'field',
|
||||
filterFieldTypes: 'number'
|
||||
filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
|
||||
},
|
||||
{
|
||||
/*
|
||||
|
@ -76,7 +89,11 @@ export const histogramBucketAgg = new BucketAggType({
|
|||
{
|
||||
name: 'interval',
|
||||
editorComponent: NumberIntervalParamEditor,
|
||||
modifyAggConfigOnSearchRequestStart(aggConfig, searchSource, searchRequest) {
|
||||
modifyAggConfigOnSearchRequestStart(
|
||||
aggConfig: IBucketHistogramAggConfig,
|
||||
searchSource: any,
|
||||
searchRequest: any
|
||||
) {
|
||||
const field = aggConfig.getField();
|
||||
const aggBody = field.scripted
|
||||
? { script: { source: field.script, lang: field.lang } }
|
||||
|
@ -87,31 +104,35 @@ export const histogramBucketAgg = new BucketAggType({
|
|||
.setField('size', 0)
|
||||
.setField('aggs', {
|
||||
maxAgg: {
|
||||
max: aggBody
|
||||
max: aggBody,
|
||||
},
|
||||
minAgg: {
|
||||
min: aggBody
|
||||
}
|
||||
min: aggBody,
|
||||
},
|
||||
});
|
||||
|
||||
searchRequest.whenAborted(() => childSearchSource.cancelQueued());
|
||||
|
||||
return childSearchSource.fetch()
|
||||
.then((resp) => {
|
||||
return childSearchSource
|
||||
.fetch()
|
||||
.then((resp: any) => {
|
||||
aggConfig.setAutoBounds({
|
||||
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;
|
||||
toastNotifications.addWarning(i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', {
|
||||
// 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.'
|
||||
}));
|
||||
toastNotifications.addWarning(
|
||||
i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', {
|
||||
// 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);
|
||||
if (interval <= 0) {
|
||||
interval = 1;
|
||||
|
@ -146,29 +167,26 @@ export const histogramBucketAgg = new BucketAggType({
|
|||
}
|
||||
|
||||
output.params.interval = interval;
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
} as BucketAggParam,
|
||||
{
|
||||
name: 'min_doc_count',
|
||||
default: false,
|
||||
editorComponent: MinDocCountParamEditor,
|
||||
write: function (aggConfig, output) {
|
||||
write(aggConfig: AggConfig, output: Record<string, any>) {
|
||||
if (aggConfig.params.min_doc_count) {
|
||||
output.params.min_doc_count = 0;
|
||||
} else {
|
||||
output.params.min_doc_count = 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'has_extended_bounds',
|
||||
default: false,
|
||||
editorComponent: HasExtendedBoundsParamEditor,
|
||||
write: () => {},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'extended_bounds',
|
||||
default: {
|
||||
|
@ -176,16 +194,14 @@ export const histogramBucketAgg = new BucketAggType({
|
|||
max: '',
|
||||
},
|
||||
editorComponent: ExtendedBoundsParamEditor,
|
||||
write: function (aggConfig, output) {
|
||||
write(aggConfig: AggConfig, output: Record<string, any>) {
|
||||
const { min, max } = aggConfig.params.extended_bounds;
|
||||
|
||||
if (aggConfig.params.has_extended_bounds &&
|
||||
(min || min === 0) &&
|
||||
(max || max === 0)) {
|
||||
if (aggConfig.params.has_extended_bounds && (min || min === 0) && (max || max === 0)) {
|
||||
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.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { BucketAggType } from './_bucket_agg_type';
|
||||
import { createFilterIpRange } from './create_filter/ip_range';
|
||||
import { get, noop, map, omit, isNull } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
|
||||
import { IpRangeTypeParamEditor } from '../../vis/editors/default/controls/ip_range_type';
|
||||
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({
|
||||
name: 'ip_range',
|
||||
title: i18n.translate('common.ui.aggTypes.buckets.ipRangeTitle', {
|
||||
defaultMessage: 'IPv4 Range',
|
||||
}),
|
||||
name: BUCKET_TYPES.IP_RANGE,
|
||||
title: ipRangeTitle,
|
||||
createFilter: createFilterIpRange,
|
||||
getKey: function (bucket, key) {
|
||||
getKey(bucket, key) {
|
||||
if (key) return key;
|
||||
const from = _.get(bucket, 'from', '-Infinity');
|
||||
const to = _.get(bucket, 'to', 'Infinity');
|
||||
const from = get(bucket, 'from', '-Infinity');
|
||||
const to = get(bucket, 'to', 'Infinity');
|
||||
|
||||
return `${from} to ${to}`;
|
||||
},
|
||||
makeLabel: function (aggConfig) {
|
||||
makeLabel(aggConfig) {
|
||||
return i18n.translate('common.ui.aggTypes.buckets.ipRangeLabel', {
|
||||
defaultMessage: '{fieldName} IP ranges',
|
||||
values: {
|
||||
fieldName: aggConfig.getFieldDisplayName()
|
||||
}
|
||||
fieldName: aggConfig.getFieldDisplayName(),
|
||||
},
|
||||
});
|
||||
},
|
||||
params: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'field',
|
||||
filterFieldTypes: 'ip'
|
||||
}, {
|
||||
filterFieldTypes: KBN_FIELD_TYPES.IP,
|
||||
},
|
||||
{
|
||||
name: 'ipRangeType',
|
||||
editorComponent: IpRangeTypeParamEditor,
|
||||
default: 'fromTo',
|
||||
write: _.noop
|
||||
}, {
|
||||
write: noop,
|
||||
},
|
||||
{
|
||||
name: 'ranges',
|
||||
default: {
|
||||
fromTo: [
|
||||
{ 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: '0.0.0.0/1' },
|
||||
{ mask: '128.0.0.0/2' }
|
||||
]
|
||||
mask: [{ mask: '0.0.0.0/1' }, { mask: '128.0.0.0/2' }],
|
||||
},
|
||||
editorComponent: IpRangesParamEditor,
|
||||
write: function (aggConfig, output) {
|
||||
write(aggConfig: IBucketAggConfig, output: Record<string, any>) {
|
||||
const ipRangeType = aggConfig.params.ipRangeType;
|
||||
let ranges = aggConfig.params.ranges[ipRangeType];
|
||||
|
||||
if (ipRangeType === 'fromTo') {
|
||||
ranges = _.map(ranges, (range) => {
|
||||
return _.omit(range, _.isNull);
|
||||
});
|
||||
ranges = map(ranges, (range: any) => omit(range, isNull));
|
||||
}
|
||||
|
||||
output.params.ranges = ranges;
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
|
@ -18,35 +18,32 @@
|
|||
*/
|
||||
|
||||
import { isString, isObject } from 'lodash';
|
||||
import { AggConfig } from 'ui/agg_types';
|
||||
import { IBucketAggConfig, BucketAggType, BucketAggParam } from './_bucket_agg_type';
|
||||
|
||||
function isType(type) {
|
||||
return function (agg) {
|
||||
export const isType = (type: string) => {
|
||||
return (agg: IBucketAggConfig): boolean => {
|
||||
const field = agg.params.field;
|
||||
|
||||
return field && field.type === type;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const isStringType = isType('string');
|
||||
export const isStringType = isType('string');
|
||||
|
||||
const migrateIncludeExcludeFormat = {
|
||||
serialize: function (value, agg) {
|
||||
export const migrateIncludeExcludeFormat = {
|
||||
serialize(this: BucketAggParam, value: any, agg: AggConfig) {
|
||||
if (this.shouldShow && !this.shouldShow(agg)) return;
|
||||
if (!value || isString(value)) return value;
|
||||
else return value.pattern;
|
||||
},
|
||||
write: function (aggConfig, output) {
|
||||
const value = aggConfig.params[this.name];
|
||||
write(this: BucketAggType<IBucketAggConfig>, aggConfig: AggConfig, output: Record<string, any>) {
|
||||
const value = aggConfig.getParam(this.name);
|
||||
|
||||
if (isObject(value)) {
|
||||
output.params[this.name] = value.pattern;
|
||||
} else if (value && isStringType(aggConfig)) {
|
||||
output.params[this.name] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
isType,
|
||||
isStringType,
|
||||
migrateIncludeExcludeFormat
|
||||
},
|
||||
};
|
|
@ -17,32 +17,38 @@
|
|||
* 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 { createFilterRange } from './create_filter/range';
|
||||
import { FieldFormat } from '../../../../../plugins/data/common/field_formats';
|
||||
import { RangeKey } from './range_key';
|
||||
import { RangesParamEditor } from '../../vis/editors/default/controls/ranges';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { RangesEditor } from './range_editor';
|
||||
|
||||
// @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 formats = new WeakMap();
|
||||
|
||||
const rangeTitle = i18n.translate('common.ui.aggTypes.buckets.rangeTitle', {
|
||||
defaultMessage: 'Range',
|
||||
});
|
||||
|
||||
export const rangeBucketAgg = new BucketAggType({
|
||||
name: 'range',
|
||||
title: i18n.translate('common.ui.aggTypes.buckets.rangeTitle', {
|
||||
defaultMessage: 'Range',
|
||||
}),
|
||||
name: BUCKET_TYPES.RANGE,
|
||||
title: rangeTitle,
|
||||
createFilter: createFilterRange,
|
||||
makeLabel: function (aggConfig) {
|
||||
makeLabel(aggConfig) {
|
||||
return i18n.translate('common.ui.aggTypes.buckets.rangesLabel', {
|
||||
defaultMessage: '{fieldName} ranges',
|
||||
values: {
|
||||
fieldName: aggConfig.getFieldDisplayName()
|
||||
}
|
||||
fieldName: aggConfig.getFieldDisplayName(),
|
||||
},
|
||||
});
|
||||
},
|
||||
getKey: function (bucket, key, agg) {
|
||||
getKey(bucket, key, agg) {
|
||||
let keys = keyCaches.get(agg);
|
||||
|
||||
if (!keys) {
|
||||
|
@ -60,11 +66,11 @@ export const rangeBucketAgg = new BucketAggType({
|
|||
|
||||
return key;
|
||||
},
|
||||
getFormat: function (agg) {
|
||||
let format = formats.get(agg);
|
||||
if (format) return format;
|
||||
getFormat(agg) {
|
||||
let aggFormat = formats.get(agg);
|
||||
if (aggFormat) return aggFormat;
|
||||
|
||||
const RangeFormat = FieldFormat.from(function (range) {
|
||||
const RangeFormat = FieldFormat.from((range: any) => {
|
||||
const format = agg.fieldOwnFormatter();
|
||||
const gte = '\u2265';
|
||||
const lt = '\u003c';
|
||||
|
@ -79,28 +85,25 @@ export const rangeBucketAgg = new BucketAggType({
|
|||
});
|
||||
});
|
||||
|
||||
format = new RangeFormat();
|
||||
aggFormat = new RangeFormat();
|
||||
|
||||
formats.set(agg, format);
|
||||
return format;
|
||||
formats.set(agg, aggFormat);
|
||||
return aggFormat;
|
||||
},
|
||||
params: [
|
||||
{
|
||||
name: 'field',
|
||||
type: 'field',
|
||||
filterFieldTypes: ['number']
|
||||
filterFieldTypes: [KBN_FIELD_TYPES.NUMBER],
|
||||
},
|
||||
{
|
||||
name: 'ranges',
|
||||
default: [
|
||||
{ from: 0, to: 1000 },
|
||||
{ from: 1000, to: 2000 }
|
||||
],
|
||||
editorComponent: ({ value, setValue }) => <RangesParamEditor value={value} setValue={setValue}/>,
|
||||
write: function (aggConfig, output) {
|
||||
default: [{ from: 0, to: 1000 }, { from: 1000, to: 2000 }],
|
||||
editorComponent: RangesEditor,
|
||||
write(aggConfig: IBucketAggConfig, output: Record<string, any>) {
|
||||
output.params.ranges = aggConfig.params.ranges;
|
||||
output.params.keyed = true;
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
|
@ -18,10 +18,9 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { AggParamEditorProps } from 'ui/vis/editors/default';
|
||||
import { RangesParamEditor } from '../../vis/editors/default/controls/ranges';
|
||||
|
||||
const wrapWithInlineComp = Component => props => (
|
||||
<div className={`visEditorAggParam--half visEditorAggParam--half-${props.aggParam.name}`}>
|
||||
<Component {...props}/>
|
||||
</div>);
|
||||
|
||||
export { wrapWithInlineComp };
|
||||
export const RangesEditor = (props: AggParamEditorProps<any>) => (
|
||||
<RangesParamEditor value={props.value} setValue={props.setValue} />
|
||||
);
|
|
@ -19,16 +19,19 @@
|
|||
|
||||
const id = Symbol('id');
|
||||
|
||||
class RangeKey {
|
||||
constructor(bucket) {
|
||||
export class RangeKey {
|
||||
[id]: string;
|
||||
gte: string | number;
|
||||
lt: string | number;
|
||||
|
||||
constructor(bucket: any) {
|
||||
this.gte = bucket.from == null ? -Infinity : bucket.from;
|
||||
this.lt = bucket.to == null ? +Infinity : bucket.to;
|
||||
|
||||
this[id] = RangeKey.idBucket(bucket);
|
||||
}
|
||||
|
||||
|
||||
static idBucket(bucket) {
|
||||
static idBucket(bucket: any) {
|
||||
return `from:${bucket.from},to:${bucket.to}`;
|
||||
}
|
||||
|
||||
|
@ -36,5 +39,3 @@ class RangeKey {
|
|||
return this[id];
|
||||
}
|
||||
}
|
||||
|
||||
export { RangeKey };
|
|
@ -19,22 +19,26 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
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 { 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({
|
||||
name: 'significant_terms',
|
||||
title: i18n.translate('common.ui.aggTypes.buckets.significantTermsTitle', {
|
||||
defaultMessage: 'Significant Terms',
|
||||
}),
|
||||
makeLabel: function (aggConfig) {
|
||||
name: BUCKET_TYPES.SIGNIFICANT_TERMS,
|
||||
title: significantTermsTitle,
|
||||
makeLabel(aggConfig) {
|
||||
return i18n.translate('common.ui.aggTypes.buckets.significantTermsLabel', {
|
||||
defaultMessage: 'Top {size} unusual terms in {fieldName}',
|
||||
values: {
|
||||
size: aggConfig.params.size,
|
||||
fieldName: aggConfig.getFieldDisplayName(),
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
createFilter: createFilterTerms,
|
||||
|
@ -43,7 +47,7 @@ export const significantTermsBucketAgg = new BucketAggType({
|
|||
name: 'field',
|
||||
type: 'field',
|
||||
scriptable: false,
|
||||
filterFieldTypes: 'string'
|
||||
filterFieldTypes: KBN_FIELD_TYPES.STRING,
|
||||
},
|
||||
{
|
||||
name: 'size',
|
||||
|
@ -53,22 +57,22 @@ export const significantTermsBucketAgg = new BucketAggType({
|
|||
{
|
||||
name: 'exclude',
|
||||
displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.excludeLabel', {
|
||||
defaultMessage: 'Exclude'
|
||||
defaultMessage: 'Exclude',
|
||||
}),
|
||||
type: 'string',
|
||||
advanced: true,
|
||||
shouldShow: isStringType,
|
||||
...migrateIncludeExcludeFormat
|
||||
},
|
||||
...migrateIncludeExcludeFormat,
|
||||
} as BucketAggParam,
|
||||
{
|
||||
name: 'include',
|
||||
displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.includeLabel', {
|
||||
defaultMessage: 'Include'
|
||||
defaultMessage: 'Include',
|
||||
}),
|
||||
type: 'string',
|
||||
advanced: true,
|
||||
shouldShow: isStringType,
|
||||
...migrateIncludeExcludeFormat
|
||||
}
|
||||
]
|
||||
...migrateIncludeExcludeFormat,
|
||||
} as BucketAggParam,
|
||||
],
|
||||
});
|
|
@ -18,13 +18,20 @@
|
|||
*/
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { noop } from 'lodash';
|
||||
import { SearchSource } from 'ui/courier';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { BucketAggType } from './_bucket_agg_type';
|
||||
import { Schemas } from '../../vis/editors/default/schemas';
|
||||
import { getRequestInspectorStats, getResponseInspectorStats } from '../../courier/utils/courier_inspector_utils';
|
||||
import { BucketAggType, BucketAggParam } from './_bucket_agg_type';
|
||||
import { BUCKET_TYPES } from './bucket_agg_types';
|
||||
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 { wrapWithInlineComp } from './_inline_comp_wrapper';
|
||||
import { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket } from './_terms_other_bucket_helper';
|
||||
import { wrapWithInlineComp } from './inline_comp_wrapper';
|
||||
import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format';
|
||||
import { OrderAggParamEditor } from '../../vis/editors/default/controls/order_agg';
|
||||
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 { MissingBucketParamEditor } from '../../vis/editors/default/controls/missing_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',
|
||||
name: 'orderAgg',
|
||||
// This string is never visible to the user so it doesn't need to be translated
|
||||
title: 'Order Agg',
|
||||
hideCustomLabel: true,
|
||||
aggFilter: aggFilter
|
||||
}
|
||||
])).all[0];
|
||||
aggFilter,
|
||||
},
|
||||
]).all;
|
||||
|
||||
const termsTitle = i18n.translate('common.ui.aggTypes.buckets.termsTitle', {
|
||||
defaultMessage: 'Terms',
|
||||
});
|
||||
|
||||
export const termsBucketAgg = new BucketAggType({
|
||||
name: 'terms',
|
||||
title: i18n.translate('common.ui.aggTypes.buckets.termsTitle', {
|
||||
defaultMessage: 'Terms',
|
||||
}),
|
||||
makeLabel: function (agg) {
|
||||
name: BUCKET_TYPES.TERMS,
|
||||
title: termsTitle,
|
||||
makeLabel(agg) {
|
||||
const params = agg.params;
|
||||
return agg.getFieldDisplayName() + ': ' + params.order.text;
|
||||
},
|
||||
getFormat: function (bucket) {
|
||||
getFormat(bucket) {
|
||||
return {
|
||||
getConverterFor: (type) => {
|
||||
return (val) => {
|
||||
getConverterFor: (type: ContentType) => {
|
||||
return (val: any) => {
|
||||
if (val === '__other__') {
|
||||
return bucket.params.otherBucketLabel;
|
||||
}
|
||||
|
@ -71,11 +94,18 @@ export const termsBucketAgg = new BucketAggType({
|
|||
const converter = bucket.params.field.format.getConverterFor(type);
|
||||
return converter(val, undefined, undefined, parsedUrl);
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
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;
|
||||
const nestedSearchSource = searchSource.createChild();
|
||||
if (aggConfig.params.otherBucket) {
|
||||
|
@ -88,23 +118,24 @@ export const termsBucketAgg = new BucketAggType({
|
|||
nestedSearchSource.setField('aggs', filterAgg);
|
||||
|
||||
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', {
|
||||
defaultMessage: 'This request counts the number of documents that fall ' +
|
||||
'outside the criterion of the data buckets.'
|
||||
defaultMessage:
|
||||
'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.stats(getRequestInspectorStats(nestedSearchSource));
|
||||
|
||||
const response = await nestedSearchSource.fetch();
|
||||
request
|
||||
.stats(getResponseInspectorStats(nestedSearchSource, response))
|
||||
.ok({ json: response });
|
||||
request.stats(getResponseInspectorStats(nestedSearchSource, response)).ok({ json: response });
|
||||
resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg());
|
||||
}
|
||||
if (aggConfig.params.missingBucket) {
|
||||
|
@ -116,28 +147,34 @@ export const termsBucketAgg = new BucketAggType({
|
|||
{
|
||||
name: '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',
|
||||
editorComponent: OrderByParamEditor,
|
||||
write: () => {} // prevent default write, it's handled by orderAgg
|
||||
write: noop, // prevent default write, it's handled by orderAgg
|
||||
},
|
||||
{
|
||||
name: 'orderAgg',
|
||||
type: 'agg',
|
||||
default: null,
|
||||
editorComponent: OrderAggParamEditor,
|
||||
makeAgg: function (termsAgg, state) {
|
||||
makeAgg(termsAgg: IBucketAggConfig, state: AggConfigOptions) {
|
||||
state = state || {};
|
||||
state.schema = orderAggSchema;
|
||||
const orderAgg = termsAgg.aggConfigs.createAggConfig(state, { addToAggConfigs: false });
|
||||
orderAgg.id = termsAgg.id + '-orderAgg';
|
||||
return orderAgg;
|
||||
},
|
||||
write: function (agg, output, aggs) {
|
||||
write(agg: IBucketAggConfig, output: Record<string, any>, aggs: AggConfigs) {
|
||||
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);
|
||||
|
||||
|
@ -145,7 +182,8 @@ export const termsBucketAgg = new BucketAggType({
|
|||
// thus causing issues with filtering. This probably causes other issues since float might not
|
||||
// be able to contain the number on the elasticsearch side
|
||||
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') {
|
||||
|
@ -169,7 +207,7 @@ export const termsBucketAgg = new BucketAggType({
|
|||
|
||||
output.subAggs = (output.subAggs || []).concat(orderAgg);
|
||||
order[orderAggId] = dir;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'order',
|
||||
|
@ -181,27 +219,27 @@ export const termsBucketAgg = new BucketAggType({
|
|||
text: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', {
|
||||
defaultMessage: 'Descending',
|
||||
}),
|
||||
value: 'desc'
|
||||
value: 'desc',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', {
|
||||
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',
|
||||
editorComponent: wrapWithInlineComp(SizeParamEditor),
|
||||
default: 5
|
||||
default: 5,
|
||||
},
|
||||
{
|
||||
name: 'otherBucket',
|
||||
default: false,
|
||||
editorComponent: OtherBucketParamEditor,
|
||||
write: () => {},
|
||||
write: noop,
|
||||
},
|
||||
{
|
||||
name: 'otherBucketLabel',
|
||||
|
@ -212,14 +250,14 @@ export const termsBucketAgg = new BucketAggType({
|
|||
displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForOtherBucketLabel', {
|
||||
defaultMessage: 'Label for other bucket',
|
||||
}),
|
||||
shouldShow: agg => agg.params.otherBucket,
|
||||
write: () => {},
|
||||
},
|
||||
shouldShow: (agg: IBucketAggConfig) => agg.getParam('otherBucket'),
|
||||
write: noop,
|
||||
} as BucketAggParam,
|
||||
{
|
||||
name: 'missingBucket',
|
||||
default: false,
|
||||
editorComponent: MissingBucketParamEditor,
|
||||
write: () => {},
|
||||
write: noop,
|
||||
},
|
||||
{
|
||||
name: 'missingBucketLabel',
|
||||
|
@ -232,24 +270,28 @@ export const termsBucketAgg = new BucketAggType({
|
|||
displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForMissingValuesLabel', {
|
||||
defaultMessage: 'Label for missing values',
|
||||
}),
|
||||
shouldShow: agg => agg.params.missingBucket,
|
||||
write: () => {},
|
||||
shouldShow: (agg: IBucketAggConfig) => agg.getParam('missingBucket'),
|
||||
write: noop,
|
||||
},
|
||||
{
|
||||
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',
|
||||
advanced: true,
|
||||
shouldShow: isStringType,
|
||||
...migrateIncludeExcludeFormat
|
||||
...migrateIncludeExcludeFormat,
|
||||
},
|
||||
{
|
||||
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',
|
||||
advanced: true,
|
||||
shouldShow: isStringType,
|
||||
...migrateIncludeExcludeFormat
|
||||
...migrateIncludeExcludeFormat,
|
||||
},
|
||||
]
|
||||
] as BucketAggParam[],
|
||||
});
|
|
@ -17,73 +17,41 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
import { AggType } from './agg_type';
|
||||
// @ts-ignore
|
||||
import { countMetricAgg } from './metrics/count';
|
||||
// @ts-ignore
|
||||
import { avgMetricAgg } from './metrics/avg';
|
||||
// @ts-ignore
|
||||
import { sumMetricAgg } from './metrics/sum';
|
||||
// @ts-ignore
|
||||
import { medianMetricAgg } from './metrics/median';
|
||||
// @ts-ignore
|
||||
import { minMetricAgg } from './metrics/min';
|
||||
// @ts-ignore
|
||||
import { maxMetricAgg } from './metrics/max';
|
||||
// @ts-ignore
|
||||
import { topHitMetricAgg } from './metrics/top_hit';
|
||||
// @ts-ignore
|
||||
import { stdDeviationMetricAgg } from './metrics/std_deviation';
|
||||
// @ts-ignore
|
||||
import { cardinalityMetricAgg } from './metrics/cardinality';
|
||||
// @ts-ignore
|
||||
import { percentilesMetricAgg } from './metrics/percentiles';
|
||||
// @ts-ignore
|
||||
import { geoBoundsMetricAgg } from './metrics/geo_bounds';
|
||||
// @ts-ignore
|
||||
import { geoCentroidMetricAgg } from './metrics/geo_centroid';
|
||||
// @ts-ignore
|
||||
import { percentileRanksMetricAgg } from './metrics/percentile_ranks';
|
||||
// @ts-ignore
|
||||
import { derivativeMetricAgg } from './metrics/derivative';
|
||||
// @ts-ignore
|
||||
import { cumulativeSumMetricAgg } from './metrics/cumulative_sum';
|
||||
// @ts-ignore
|
||||
import { movingAvgMetricAgg } from './metrics/moving_avg';
|
||||
// @ts-ignore
|
||||
import { serialDiffMetricAgg } from './metrics/serial_diff';
|
||||
// @ts-ignore
|
||||
import { dateHistogramBucketAgg, setBounds } from './buckets/date_histogram';
|
||||
// @ts-ignore
|
||||
import { histogramBucketAgg } from './buckets/histogram';
|
||||
// @ts-ignore
|
||||
import { rangeBucketAgg } from './buckets/range';
|
||||
// @ts-ignore
|
||||
import { dateRangeBucketAgg } from './buckets/date_range';
|
||||
// @ts-ignore
|
||||
import { ipRangeBucketAgg } from './buckets/ip_range';
|
||||
// @ts-ignore
|
||||
import { termsBucketAgg } from './buckets/terms';
|
||||
// @ts-ignore
|
||||
import { filterBucketAgg } from './buckets/filter';
|
||||
// @ts-ignore
|
||||
import { filtersBucketAgg } from './buckets/filters';
|
||||
// @ts-ignore
|
||||
import { significantTermsBucketAgg } from './buckets/significant_terms';
|
||||
// @ts-ignore
|
||||
import { geoHashBucketAgg } from './buckets/geo_hash';
|
||||
// @ts-ignore
|
||||
import { geoTileBucketAgg } from './buckets/geo_tile';
|
||||
// @ts-ignore
|
||||
import { bucketSumMetricAgg } from './metrics/bucket_sum';
|
||||
// @ts-ignore
|
||||
import { bucketAvgMetricAgg } from './metrics/bucket_avg';
|
||||
// @ts-ignore
|
||||
import { bucketMinMetricAgg } from './metrics/bucket_min';
|
||||
// @ts-ignore
|
||||
import { bucketMaxMetricAgg } from './metrics/bucket_max';
|
||||
|
||||
export { AggType } from './agg_type';
|
||||
|
||||
export const aggTypes = {
|
||||
metrics: [
|
||||
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 { AggType } from './agg_type';
|
||||
export { AggConfig } from './agg_config';
|
||||
export { AggConfigs } from './agg_configs';
|
||||
export { FieldParamType } from './param_types';
|
||||
export { BucketAggType } from './buckets/_bucket_agg_type';
|
||||
|
||||
export { setBounds };
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
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';
|
||||
|
||||
// @ts-ignore
|
||||
|
@ -49,7 +49,7 @@ export const medianMetricAgg = new MetricAggType({
|
|||
default: [50],
|
||||
},
|
||||
{
|
||||
write(agg, output) {
|
||||
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||
output.params.keyed = false;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -27,12 +27,10 @@ import { METRIC_TYPES } from './metric_agg_types';
|
|||
import { fieldFormats } from '../../registry/field_formats';
|
||||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||
|
||||
export interface IMetricAggConfig extends AggConfig {
|
||||
params: MetricAggParam[];
|
||||
}
|
||||
export type IMetricAggConfig = AggConfig;
|
||||
|
||||
export interface MetricAggTypeConfig<TMetricAggConfig extends IMetricAggConfig>
|
||||
extends AggTypeConfig<TMetricAggConfig> {
|
||||
extends AggTypeConfig<TMetricAggConfig, MetricAggParam> {
|
||||
isScalable?: () => boolean;
|
||||
subtype?: string;
|
||||
}
|
||||
|
@ -42,11 +40,16 @@ export interface MetricAggParam extends AggParamType {
|
|||
onlyAggregatable?: boolean;
|
||||
}
|
||||
|
||||
export class MetricAggType<TMetricAggConfig extends IMetricAggConfig> extends AggType<
|
||||
TMetricAggConfig
|
||||
> {
|
||||
const metricType = 'metrics';
|
||||
|
||||
export class MetricAggType<
|
||||
TMetricAggConfig extends IMetricAggConfig = IMetricAggConfig
|
||||
> extends AggType<TMetricAggConfig, MetricAggParam> {
|
||||
subtype: string;
|
||||
isScalable: () => boolean;
|
||||
type = metricType;
|
||||
|
||||
getKey = () => {};
|
||||
|
||||
constructor(config: MetricAggTypeConfig<TMetricAggConfig>) {
|
||||
super(config);
|
||||
|
@ -81,3 +84,7 @@ export class MetricAggType<TMetricAggConfig extends IMetricAggConfig> extends Ag
|
|||
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 { 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 { getPercentileValue } from './percentiles_get_value';
|
||||
|
@ -69,7 +69,7 @@ export const percentileRanksMetricAgg = new MetricAggType<IPercentileRanksAggCon
|
|||
default: [],
|
||||
},
|
||||
{
|
||||
write(agg, output) {
|
||||
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||
output.params.keyed = false;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
|
||||
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 { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||
|
||||
import { getResponseAggConfigClass, IResponseAggConfig } from './get_response_agg_config_class';
|
||||
import { getPercentileValue } from './percentiles_get_value';
|
||||
|
@ -28,7 +29,6 @@ import { PercentilesEditor } from '../../vis/editors/default/controls/percentile
|
|||
|
||||
// @ts-ignore
|
||||
import { ordinalSuffix } from '../../utils/ordinal_suffix';
|
||||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||
|
||||
type IPercentileAggConfig = IResponseAggConfig;
|
||||
|
||||
|
@ -67,7 +67,7 @@ export const percentilesMetricAgg = new MetricAggType<IPercentileAggConfig>({
|
|||
default: [1, 5, 25, 50, 75, 95, 99],
|
||||
},
|
||||
{
|
||||
write(agg, output) {
|
||||
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||
output.params.keyed = false;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -30,7 +30,7 @@ import { METRIC_TYPES } from './metric_agg_types';
|
|||
import { KBN_FIELD_TYPES } from '../../../../../plugins/data/common';
|
||||
|
||||
// @ts-ignore
|
||||
import { wrapWithInlineComp } from '../buckets/_inline_comp_wrapper';
|
||||
import { wrapWithInlineComp } from '../buckets/inline_comp_wrapper';
|
||||
|
||||
const isNumericFieldSelected = (agg: IMetricAggConfig) => {
|
||||
const field = agg.getParam('field');
|
||||
|
@ -46,7 +46,7 @@ aggTypeFieldFilters.addFilter((field, aggConfig: IMetricAggConfig) => {
|
|||
return true;
|
||||
}
|
||||
|
||||
return field.type === 'number';
|
||||
return field.type === KBN_FIELD_TYPES.NUMBER;
|
||||
});
|
||||
|
||||
export const topHitMetricAgg = new MetricAggType({
|
||||
|
@ -82,7 +82,7 @@ export const topHitMetricAgg = new MetricAggType({
|
|||
editorComponent: TopFieldParamEditor,
|
||||
onlyAggregatable: false,
|
||||
filterFieldTypes: '*',
|
||||
write(agg, output) {
|
||||
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||
const field = agg.getParam('field');
|
||||
output.params = {};
|
||||
|
||||
|
@ -196,7 +196,7 @@ export const topHitMetricAgg = new MetricAggType({
|
|||
value: 'asc',
|
||||
},
|
||||
],
|
||||
write(agg, output) {
|
||||
write(agg: IMetricAggConfig, output: Record<string, any>) {
|
||||
const sortField = agg.params.sortField;
|
||||
const sortOrder = agg.params.sortOrder;
|
||||
|
||||
|
|
|
@ -56,8 +56,8 @@ export class BaseParamType implements AggParam {
|
|||
*/
|
||||
modifyAggConfigOnSearchRequestStart: (
|
||||
aggconfig: AggConfig,
|
||||
searchSource: SearchSource,
|
||||
searchRequest: any
|
||||
searchSource?: SearchSource,
|
||||
searchRequest?: any
|
||||
) => void;
|
||||
|
||||
constructor(config: Record<string, any>) {
|
||||
|
|
|
@ -29,7 +29,7 @@ import { AggParamEditorProps } from '..';
|
|||
const generateId = htmlIdGenerator();
|
||||
const config = chrome.getUiSettingsClient();
|
||||
|
||||
interface FilterValue {
|
||||
export interface FilterValue {
|
||||
input: Query;
|
||||
label: string;
|
||||
id: string;
|
||||
|
|
|
@ -34,6 +34,7 @@ jest.mock('ui/new_platform');
|
|||
jest.mock('ui/agg_types/buckets/date_histogram', () => ({
|
||||
setBounds: () => {},
|
||||
dateHistogramBucketAgg: () => {},
|
||||
isDateHistogramBucketAggConfig: () => true,
|
||||
}));
|
||||
|
||||
describe('visualize loader pipeline helpers: build pipeline', () => {
|
||||
|
|
|
@ -22,6 +22,7 @@ import { cloneDeep, get } from 'lodash';
|
|||
import { setBounds } from 'ui/agg_types';
|
||||
import { SearchSource } from 'ui/courier';
|
||||
import { AggConfig, Vis, VisParams, VisState } from 'ui/vis';
|
||||
import { isDateHistogramBucketAggConfig } from 'ui/agg_types/buckets/date_histogram';
|
||||
import moment from 'moment';
|
||||
import { SerializedFieldFormat } from 'src/plugins/expressions/common/expressions/types/common';
|
||||
import { createFormat } from './utilities';
|
||||
|
@ -76,7 +77,7 @@ const vislibCharts: string[] = [
|
|||
|
||||
export const getSchemas = (vis: Vis, timeRange?: any): Schemas => {
|
||||
const createSchemaConfig = (accessor: number, agg: AggConfig): SchemaConfig => {
|
||||
if (agg.type.name === 'date_histogram') {
|
||||
if (isDateHistogramBucketAggConfig(agg)) {
|
||||
agg.params.timeRange = timeRange;
|
||||
setBounds(agg, true);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
],
|
||||
"monitoring/common/*": [
|
||||
"x-pack/monitoring/common/*"
|
||||
]
|
||||
],
|
||||
"plugins/*": ["src/legacy/core_plugins/*/public/"]
|
||||
},
|
||||
"types": [
|
||||
"node",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue