diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index 481349463fc56..cb2c9d02e84d1 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -31,6 +31,20 @@ export { DataStart }; export { Field, FieldType, IFieldList, IndexPattern } from './index_patterns'; export { SearchBar, SearchBarProps } from './search'; +export { + // agg_types + AggParam, + AggParamOption, + DateRangeKey, + IpRangeKey, + OptionedParamEditorProps, + OptionedValueProp, + // search_source + EsQuerySortValue, + FetchOptions, + ISearchSource, + SortDirection, +} from './search/types'; export { SavedQueryAttributes, SavedQuery, @@ -41,3 +55,22 @@ export { export * from '../common'; export { FilterStateManager } from './filter/filter_manager'; export { getFromSavedObject, getRoutes, flattenHitWrapper } from './index_patterns'; +export { + // agg_types + AggParamType, + aggTypeFilters, + CidrMask, + convertDateRangeToString, + convertIPRangeToString, + intervalOptions, // only used in Discover + isDateHistogramBucketAggConfig, + isStringType, + isType, + isValidInterval, + isValidJson, + OptionedParamType, + propFilter, + // search_source + getRequestInspectorStats, + getResponseInspectorStats, +} from './search'; diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index a4fdfd7482f74..73cfe17183cd1 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -18,7 +18,7 @@ */ import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; -import { createSearchBar, StatetfulSearchBarProps } from './search'; +import { createSearchBar, StatetfulSearchBarProps, SearchService, SearchStart } from './search'; import { Storage, IStorageWrapper } from '../../../../../src/plugins/kibana_utils/public'; import { DataPublicPluginStart } from '../../../../plugins/data/public'; import { initLegacyModule } from './shim/legacy_module'; @@ -36,6 +36,7 @@ export interface DataPluginStartDependencies { * @public */ export interface DataStart { + search: SearchStart; ui: { SearchBar: React.ComponentType; }; @@ -54,6 +55,7 @@ export interface DataStart { */ export class DataPlugin implements Plugin { + private readonly search: SearchService = new SearchService(); private storage!: IStorageWrapper; public setup(core: CoreSetup) { @@ -72,11 +74,14 @@ export class DataPlugin implements Plugin { + // We need to inline require here, since we're having a cyclic dependency + // from somewhere inside agg_types back to AggConfig. + const aggTypes = require('../agg_types').aggTypes; + const registeredType = + aggTypes.metrics.find((agg: AggType) => agg.name === type) || + aggTypes.buckets.find((agg: AggType) => agg.name === type); + + if (!registeredType) { + throw new Error('unknown type'); + } + + return registeredType; +}; + +const getSchemaFromRegistry = (schemas: any, schema: string): Schema => { + let registeredSchema = schemas ? schemas.byName[schema] : null; + if (!registeredSchema) { + registeredSchema = Object.assign({}, unknownSchema); + registeredSchema.name = schema; + } + + return registeredSchema; +}; + +export class AggConfig { + /** + * Ensure that all of the objects in the list have ids, the objects + * and list are modified by reference. + * + * @param {array[object]} list - a list of objects, objects can be anything really + * @return {array} - the list that was passed in + */ + static ensureIds(list: AggConfig[]) { + const have: AggConfig[] = []; + const haveNot: AggConfig[] = []; + list.forEach(function(obj) { + (obj.id ? have : haveNot).push(obj); + }); + + let nextId = AggConfig.nextId(have); + haveNot.forEach(function(obj) { + obj.id = String(nextId++); + }); + + return list; + } + + /** + * Calculate the next id based on the ids in this list + * + * @return {array} list - a list of objects with id properties + */ + static nextId(list: AggConfig[]) { + return ( + 1 + + list.reduce(function(max, obj) { + return Math.max(max, +obj.id || 0); + }, 0) + ); + } + + public aggConfigs: AggConfigs; + public id: string; + public enabled: boolean; + public params: any; + public parent?: AggConfigs; + + private __schema: Schema; + private __type: AggType; + private __typeDecorations: any; + private subAggs: AggConfig[] = []; + + constructor(aggConfigs: AggConfigs, opts: AggConfigOptions) { + this.aggConfigs = aggConfigs; + this.id = String(opts.id || AggConfig.nextId(aggConfigs.aggs as any)); + this.enabled = typeof opts.enabled === 'boolean' ? opts.enabled : true; + + // start with empty params so that checks in type/schema setters don't freak + // because this.params is undefined + this.params = {}; + + // setters + this.setType(opts.type); + + if (opts.schema) { + this.setSchema(opts.schema); + } + + // set the params to the values from opts, or just to the defaults + this.setParams(opts.params || {}); + + // @ts-ignore + this.__type = this.__type; + // @ts-ignore + this.__schema = this.__schema; + } + + /** + * Write the current values to this.params, filling in the defaults as we go + * + * @param {object} [from] - optional object to read values from, + * used when initializing + * @return {undefined} + */ + setParams(from: any) { + from = from || this.params || {}; + const to = (this.params = {} as any); + + this.getAggParams().forEach(aggParam => { + let val = from[aggParam.name]; + + if (val == null) { + if (aggParam.default == null) return; + + if (!_.isFunction(aggParam.default)) { + val = aggParam.default; + } else { + val = aggParam.default(this); + if (val == null) return; + } + } + + if (aggParam.deserialize) { + const isTyped = _.isFunction(aggParam.valueType); + + const isType = isTyped && val instanceof aggParam.valueType; + const isObject = !isTyped && _.isObject(val); + const isDeserialized = isType || isObject; + + if (!isDeserialized) { + val = aggParam.deserialize(val, this); + } + + to[aggParam.name] = val; + return; + } + + to[aggParam.name] = _.cloneDeep(val); + }); + } + + getParam(key: string): any { + return _.get(this.params, key); + } + + write(aggs?: AggConfigs) { + return writeParams(this.type.params, this, aggs); + } + + isFilterable() { + return _.isFunction(this.type.createFilter); + } + + createFilter(key: string, params = {}) { + const createFilter = this.type.createFilter; + + if (!createFilter) { + throw new TypeError(`The "${this.type.title}" aggregation does not support filtering.`); + } + + const field = this.getField(); + const label = this.getFieldDisplayName(); + if (field && !field.filterable) { + let message = `The "${label}" field can not be used for filtering.`; + if (field.scripted) { + message = `The "${label}" field is scripted and can not be used for filtering.`; + } + throw new TypeError(message); + } + + return createFilter(this, key, params); + } + + /** + * Hook for pre-flight logic, see AggType#onSearchRequestStart + * @param {Courier.SearchSource} searchSource + * @param {Courier.FetchOptions} options + * @return {Promise} + */ + onSearchRequestStart(searchSource: ISearchSource, options?: FetchOptions) { + if (!this.type) { + return Promise.resolve(); + } + + return Promise.all( + this.type.params.map((param: any) => + param.modifyAggConfigOnSearchRequestStart(this, searchSource, options) + ) + ); + } + + /** + * Convert this aggConfig to its dsl syntax. + * + * Adds params and adhoc subaggs to a pojo, then returns it + * + * @param {AggConfigs} aggConfigs - the config object to convert + * @return {void|Object} - if the config has a dsl representation, it is + * returned, else undefined is returned + */ + toDsl(aggConfigs?: AggConfigs) { + if (this.type.hasNoDsl) return; + const output = this.write(aggConfigs) as any; + + const configDsl = {} as any; + configDsl[this.type.dslName || this.type.name] = output.params; + + // if the config requires subAggs, write them to the dsl as well + if (this.subAggs.length && !output.subAggs) output.subAggs = this.subAggs; + if (output.subAggs) { + const subDslLvl = configDsl.aggs || (configDsl.aggs = {}); + output.subAggs.forEach(function nestAdhocSubAggs(subAggConfig: any) { + subDslLvl[subAggConfig.id] = subAggConfig.toDsl(aggConfigs); + }); + } + + if (output.parentAggs) { + const subDslLvl = configDsl.parentAggs || (configDsl.parentAggs = {}); + output.parentAggs.forEach(function nestAdhocSubAggs(subAggConfig: any) { + subDslLvl[subAggConfig.id] = subAggConfig.toDsl(aggConfigs); + }); + } + + return configDsl; + } + + toJSON() { + const params = this.params; + + const outParams = _.transform( + this.getAggParams(), + (out, aggParam) => { + let val = params[aggParam.name]; + + // don't serialize undefined/null values + if (val == null) return; + if (aggParam.serialize) val = aggParam.serialize(val, this); + if (val == null) return; + + // to prevent accidental leaking, we will clone all complex values + out[aggParam.name] = _.cloneDeep(val); + }, + {} + ); + + return { + id: this.id, + enabled: this.enabled, + type: this.type && this.type.name, + schema: _.get(this, 'schema.name', this.schema), + params: outParams, + }; + } + + getAggParams() { + return [ + ...(_.has(this, 'type.params') ? this.type.params : []), + ...(_.has(this, 'schema.params') ? (this.schema as Schema).params : []), + ]; + } + + getRequestAggs() { + return (this.type && this.type.getRequestAggs(this)) || [this]; + } + + getResponseAggs() { + return (this.type && this.type.getResponseAggs(this)) || [this]; + } + + getValue(bucket: any) { + return this.type.getValue(this, bucket); + } + + getKey(bucket: any, key?: string) { + if (this.type.getKey) { + return this.type.getKey(bucket, key, this); + } else { + return ''; + } + } + + getFieldDisplayName() { + const field = this.getField(); + + return field ? field.displayName || this.fieldName() : ''; + } + + getField() { + return this.params.field; + } + + makeLabel(percentageMode = false) { + if (this.params.customLabel) { + return this.params.customLabel; + } + + if (!this.type) return ''; + return percentageMode + ? i18n.translate('common.ui.vis.aggConfig.percentageOfLabel', { + defaultMessage: 'Percentage of {label}', + values: { label: this.type.makeLabel(this) }, + }) + : `${this.type.makeLabel(this)}`; + } + + getIndexPattern() { + return this.aggConfigs.indexPattern; + } + + getTimeRange() { + return this.aggConfigs.timeRange; + } + + fieldFormatter(contentType?: ContentType, defaultFormat?: any) { + const format = this.type && this.type.getFormat(this); + + if (format) { + return format.getConverterFor(contentType); + } + + return this.fieldOwnFormatter(contentType, defaultFormat); + } + + fieldOwnFormatter(contentType?: ContentType, defaultFormat?: any) { + const fieldFormats = npStart.plugins.data.fieldFormats; + const field = this.getField(); + let format = field && field.format; + if (!format) format = defaultFormat; + if (!format) format = fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.STRING); + return format.getConverterFor(contentType); + } + + fieldName() { + const field = this.getField(); + return field ? field.name : ''; + } + + fieldIsTimeField() { + const indexPattern = this.getIndexPattern(); + if (!indexPattern) return false; + // @ts-ignore + const timeFieldName = indexPattern.timeFieldName; + return timeFieldName && this.fieldName() === timeFieldName; + } + + public get type() { + return this.__type; + } + + public set type(type) { + if (this.__typeDecorations) { + _.forOwn( + this.__typeDecorations, + function(prop, name: string | undefined) { + // @ts-ignore + delete this[name]; + }, + this + ); + } + + if (type && _.isFunction(type.decorateAggConfig)) { + this.__typeDecorations = type.decorateAggConfig(); + Object.defineProperties(this, this.__typeDecorations); + } + + this.__type = type; + let availableFields = []; + + const fieldParam = this.type && this.type.params.find((p: any) => p.type === 'field'); + + if (fieldParam) { + // @ts-ignore + availableFields = fieldParam.getAvailableFields(this.getIndexPattern().fields); + } + + // clear out the previous params except for a few special ones + this.setParams({ + // split row/columns is "outside" of the agg, so don't reset it + row: this.params.row, + + // almost every agg has fields, so we try to persist that when type changes + field: availableFields.find((field: any) => field.name === this.getField()), + }); + } + + public setType(type: string | AggType) { + this.type = typeof type === 'string' ? getTypeFromRegistry(type) : type; + } + + public get schema() { + return this.__schema; + } + + public set schema(schema) { + this.__schema = schema; + } + + public setSchema(schema: string | Schema) { + this.schema = + typeof schema === 'string' ? getSchemaFromRegistry(this.aggConfigs.schemas, schema) : schema; + } +} diff --git a/src/legacy/core_plugins/data/public/search/agg_types/agg_configs.ts b/src/legacy/core_plugins/data/public/search/agg_types/agg_configs.ts new file mode 100644 index 0000000000000..3ba5dca3ba3ff --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/agg_configs.ts @@ -0,0 +1,315 @@ +/* + * 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. + */ + +/** + * @name AggConfig + * + * @extends IndexedArray + * + * @description A "data structure"-like class with methods for indexing and + * accessing instances of AggConfig. + */ + +import _ from 'lodash'; +import { TimeRange } from 'src/plugins/data/public'; +import { AggGroupNames } from 'ui/vis/editors/default/agg_groups'; +import { Schema } from 'ui/vis/editors/default/schemas'; +import { IndexPattern } from '../../../../../core_plugins/data/public'; +import { FetchOptions, ISearchSource } from '../types'; +import { AggConfig, AggConfigOptions } from './agg_config'; + +type Schemas = Record; + +function removeParentAggs(obj: any) { + for (const prop in obj) { + if (prop === 'parentAggs') delete obj[prop]; + else if (typeof obj[prop] === 'object') removeParentAggs(obj[prop]); + } +} + +function parseParentAggs(dslLvlCursor: any, dsl: any) { + if (dsl.parentAggs) { + _.each(dsl.parentAggs, (agg, key) => { + dslLvlCursor[key as string] = agg; + parseParentAggs(dslLvlCursor, agg); + }); + } +} + +export class AggConfigs { + public indexPattern: IndexPattern; + public schemas: any; + public timeRange?: TimeRange; + + aggs: AggConfig[]; + + constructor(indexPattern: IndexPattern, configStates = [] as any, schemas?: any) { + configStates = AggConfig.ensureIds(configStates); + + this.aggs = []; + this.indexPattern = indexPattern; + this.schemas = schemas; + + configStates.forEach((params: any) => this.createAggConfig(params)); + + if (this.schemas) { + this.initializeDefaultsFromSchemas(schemas); + } + } + + initializeDefaultsFromSchemas(schemas: Schemas) { + // Set the defaults for any schema which has them. If the defaults + // for some reason has more then the max only set the max number + // of defaults (not sure why a someone define more... + // but whatever). Also if a schema.name is already set then don't + // set anything. + _(schemas) + .filter((schema: Schema) => { + return Array.isArray(schema.defaults) && schema.defaults.length > 0; + }) + .each((schema: any) => { + if (!this.aggs.find((agg: AggConfig) => agg.schema && agg.schema.name === schema.name)) { + const defaults = schema.defaults.slice(0, schema.max); + _.each(defaults, defaultState => { + const state = _.defaults({ id: AggConfig.nextId(this.aggs) }, defaultState); + this.aggs.push(new AggConfig(this, state as AggConfigOptions)); + }); + } + }) + .commit(); + } + + setTimeRange(timeRange: TimeRange) { + this.timeRange = timeRange; + + const updateAggTimeRange = (agg: AggConfig) => { + _.each(agg.params, param => { + if (param instanceof AggConfig) { + updateAggTimeRange(param); + } + }); + if (_.get(agg, 'type.name') === 'date_histogram') { + agg.params.timeRange = timeRange; + } + }; + + this.aggs.forEach(updateAggTimeRange); + } + + // clone method will reuse existing AggConfig in the list (will not create new instances) + clone({ enabledOnly = true } = {}) { + const filterAggs = (agg: AggConfig) => { + if (!enabledOnly) return true; + return agg.enabled; + }; + const aggConfigs = new AggConfigs( + this.indexPattern, + this.aggs.filter(filterAggs), + this.schemas + ); + return aggConfigs; + } + + createAggConfig( + params: AggConfig | AggConfigOptions, + { addToAggConfigs = true } = {} + ) { + let aggConfig; + if (params instanceof AggConfig) { + aggConfig = params; + params.parent = this; + } else { + aggConfig = new AggConfig(this, params); + } + if (addToAggConfigs) { + this.aggs.push(aggConfig); + } + return aggConfig as T; + } + + /** + * Data-by-data comparison of this Aggregation + * Ignores the non-array indexes + * @param aggConfigs an AggConfigs instance + */ + jsonDataEquals(aggConfigs: AggConfig[]) { + if (aggConfigs.length !== this.aggs.length) { + return false; + } + for (let i = 0; i < this.aggs.length; i += 1) { + if (!_.isEqual(aggConfigs[i].toJSON(), this.aggs[i].toJSON())) { + return false; + } + } + return true; + } + + toDsl(hierarchical: boolean = false) { + const dslTopLvl = {}; + let dslLvlCursor: Record; + let nestedMetrics: Array<{ config: AggConfig; dsl: any }> | []; + + if (hierarchical) { + // collect all metrics, and filter out the ones that we won't be copying + nestedMetrics = this.aggs + .filter(function(agg) { + return agg.type.type === 'metrics' && agg.type.name !== 'count'; + }) + .map(agg => { + return { + config: agg, + dsl: agg.toDsl(this), + }; + }); + } + this.getRequestAggs() + .filter((config: AggConfig) => !config.type.hasNoDsl) + .forEach((config: AggConfig, i: number, list) => { + if (!dslLvlCursor) { + // start at the top level + dslLvlCursor = dslTopLvl; + } else { + const prevConfig: AggConfig = list[i - 1]; + const prevDsl = dslLvlCursor[prevConfig.id]; + + // advance the cursor and nest under the previous agg, or + // put it on the same level if the previous agg doesn't accept + // sub aggs + dslLvlCursor = prevDsl.aggs || dslLvlCursor; + } + + const dsl = (dslLvlCursor[config.id] = config.toDsl(this)); + let subAggs: any; + + parseParentAggs(dslLvlCursor, dsl); + + if (config.type.type === AggGroupNames.Buckets && i < list.length - 1) { + // buckets that are not the last item in the list accept sub-aggs + subAggs = dsl.aggs || (dsl.aggs = {}); + } + + if (subAggs && nestedMetrics) { + nestedMetrics.forEach((agg: any) => { + subAggs[agg.config.id] = agg.dsl; + // if a nested metric agg has parent aggs, we have to add them to every level of the tree + // to make sure "bucket_path" references in the nested metric agg itself are still working + if (agg.dsl.parentAggs) { + Object.entries(agg.dsl.parentAggs).forEach(([parentAggId, parentAgg]) => { + subAggs[parentAggId] = parentAgg; + }); + } + }); + } + }); + + removeParentAggs(dslTopLvl); + return dslTopLvl; + } + + getAll() { + return [...this.aggs]; + } + + byIndex(index: number) { + return this.aggs[index]; + } + + byId(id: string) { + return this.aggs.find(agg => agg.id === id); + } + + byName(name: string) { + return this.aggs.filter(agg => agg.type.name === name); + } + + byType(type: string) { + return this.aggs.filter(agg => agg.type.type === type); + } + + byTypeName(type: string) { + return this.aggs.filter(agg => agg.type.name === type); + } + + bySchemaName(schema: string) { + return this.aggs.filter(agg => agg.schema && agg.schema.name === schema); + } + + bySchemaGroup(group: string) { + return this.aggs.filter(agg => agg.schema && agg.schema.group === group); + } + + getRequestAggs(): AggConfig[] { + // collect all the aggregations + const aggregations = this.aggs + .filter(agg => agg.enabled && agg.type) + .reduce((requestValuesAggs, agg: AggConfig) => { + const aggs = agg.getRequestAggs(); + return aggs ? requestValuesAggs.concat(aggs) : requestValuesAggs; + }, [] as AggConfig[]); + // move metrics to the end + return _.sortBy(aggregations, (agg: AggConfig) => + agg.type.type === AggGroupNames.Metrics ? 1 : 0 + ); + } + + getRequestAggById(id: string) { + return this.aggs.find((agg: AggConfig) => agg.id === id); + } + + /** + * Gets the AggConfigs (and possibly ResponseAggConfigs) that + * represent the values that will be produced when all aggs + * are run. + * + * With multi-value metric aggs it is possible for a single agg + * request to result in multiple agg values, which is why the length + * of a vis' responseValuesAggs may be different than the vis' aggs + * + * @return {array[AggConfig]} + */ + getResponseAggs(): AggConfig[] { + return this.getRequestAggs().reduce(function(responseValuesAggs, agg: AggConfig) { + const aggs = agg.getResponseAggs(); + return aggs ? responseValuesAggs.concat(aggs) : responseValuesAggs; + }, [] as AggConfig[]); + } + + /** + * Find a response agg by it's id. This may be an agg in the aggConfigs, or one + * created specifically for a response value + * + * @param {string} id - the id of the agg to find + * @return {AggConfig} + */ + getResponseAggById(id: string): AggConfig | undefined { + id = String(id); + const reqAgg = _.find(this.getRequestAggs(), function(agg: AggConfig) { + return id.substr(0, String(agg.id).length) === agg.id; + }); + if (!reqAgg) return; + return _.find(reqAgg.getResponseAggs(), { id }); + } + + onSearchRequestStart(searchSource: ISearchSource, options?: FetchOptions) { + return Promise.all( + // @ts-ignore + this.getRequestAggs().map((agg: AggConfig) => agg.onSearchRequestStart(searchSource, options)) + ); + } +} diff --git a/src/legacy/ui/public/agg_types/agg_params.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/agg_params.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/agg_params.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/agg_params.test.ts diff --git a/src/legacy/core_plugins/data/public/search/agg_types/agg_params.ts b/src/legacy/core_plugins/data/public/search/agg_types/agg_params.ts new file mode 100644 index 0000000000000..262a57f4a5aa3 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/agg_params.ts @@ -0,0 +1,93 @@ +/* + * 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 { AggParamType } from './param_types/agg'; +import { FieldParamType } from './param_types/field'; +import { OptionedParamType } from './param_types/optioned'; +import { StringParamType } from './param_types/string'; +import { JsonParamType } from './param_types/json'; +import { BaseParamType } from './param_types/base'; + +import { AggConfig } from './agg_config'; +import { AggConfigs } from './agg_configs'; + +const paramTypeMap = { + field: FieldParamType, + optioned: OptionedParamType, + string: StringParamType, + json: JsonParamType, + agg: AggParamType, + _default: BaseParamType, +} as Record; + +export type AggParam = BaseParamType; + +export interface AggParamOption { + val: string; + display: string; + enabled?(agg: AggConfig): boolean; +} + +export const initParams = ( + params: TAggParam[] +): TAggParam[] => + params.map((config: TAggParam) => { + const Class = paramTypeMap[config.type] || paramTypeMap._default; + + return new Class(config); + }) as TAggParam[]; + +/** + * Reads an aggConfigs + * + * @method write + * @param {AggConfig} aggConfig + * the AggConfig object who's type owns these aggParams and contains the param values for our param defs + * @param {object} [locals] + * an array of locals that will be available to the write function (can be used to enhance + * the quality of things like date_histogram's "auto" interval) + * @return {object} output + * output of the write calls, reduced into a single object. A `params: {}` property is exposed on the + * output object which is used to create the agg dsl for the search request. All other properties + * are dependent on the AggParam#write methods which should be studied for each AggType. + */ +export const writeParams = < + TAggConfig extends AggConfig = AggConfig, + TAggParam extends AggParamType = AggParamType +>( + params: Array> = [], + aggConfig: TAggConfig, + aggs?: AggConfigs, + locals?: Record +) => { + const output = { params: {} as Record }; + locals = locals || {}; + + params.forEach(param => { + if (param.write) { + param.write(aggConfig, output, aggs, locals); + } else { + if (param && param.name) { + output.params[param.name] = aggConfig.params[param.name]; + } + } + }); + + return output; +}; diff --git a/src/legacy/ui/public/agg_types/agg_type.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/agg_type.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/agg_type.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/agg_type.test.ts diff --git a/src/legacy/core_plugins/data/public/search/agg_types/agg_type.ts b/src/legacy/core_plugins/data/public/search/agg_types/agg_type.ts new file mode 100644 index 0000000000000..dcaeb5f0f01b8 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/agg_type.ts @@ -0,0 +1,260 @@ +/* + * 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 { constant, noop, identity } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { npStart } from 'ui/new_platform'; +import { Adapters } from 'ui/inspector'; +import { AggConfig } from 'ui/vis'; + +import { initParams } from './agg_params'; +import { AggConfigs } from './agg_configs'; +import { ISearchSource } from '../types'; +import { BaseParamType } from './param_types/base'; +import { AggParamType } from '../agg_types/param_types/agg'; +import { KBN_FIELD_TYPES, FieldFormat } from '../../../../../../plugins/data/public'; + +export interface AggTypeConfig< + TAggConfig extends AggConfig = AggConfig, + TParam extends AggParamType = AggParamType +> { + name: string; + title: string; + createFilter?: (aggConfig: TAggConfig, key: any, params?: any) => any; + type?: string; + dslName?: string; + makeLabel?: ((aggConfig: TAggConfig) => string) | (() => string); + ordered?: any; + hasNoDsl?: boolean; + params?: Array>; + getRequestAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); + getResponseAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); + customLabels?: boolean; + decorateAggConfig?: () => any; + postFlightRequest?: ( + resp: any, + aggConfigs: AggConfigs, + aggConfig: TAggConfig, + searchSource: ISearchSource, + inspectorAdapters: Adapters, + abortSignal?: AbortSignal + ) => Promise; + getFormat?: (agg: TAggConfig) => FieldFormat; + getValue?: (agg: TAggConfig, bucket: any) => any; + getKey?: (bucket: any, key: any, agg: TAggConfig) => any; +} + +const getFormat = (agg: AggConfig) => { + const field = agg.getField(); + const fieldFormats = npStart.plugins.data.fieldFormats; + + return field ? field.format : fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.STRING); +}; + +export class AggType< + TAggConfig extends AggConfig = AggConfig, + TParam extends AggParamType = AggParamType +> { + /** + * the unique, unchanging, name that we have assigned this aggType + * + * @property name + * @type {string} + */ + name: string; + + type: string; + /** + * the name of the elasticsearch aggregation that this aggType represents. Usually just this.name + * + * @property name + * @type {string} + */ + dslName: string; + /** + * the user friendly name that will be shown in the ui for this aggType + * + * @property title + * @type {string} + */ + title: string; + /** + * a function that will be called when this aggType is assigned to + * an aggConfig, and that aggConfig is being rendered (in a form, chart, etc.). + * + * @method makeLabel + * @param {AggConfig} aggConfig - an agg config of this type + * @returns {string} - label that can be used in the ui to describe the aggConfig + */ + makeLabel: ((aggConfig: TAggConfig) => string) | (() => string); + /** + * Describes if this aggType creates data that is ordered, and if that ordered data + * is some sort of time series. + * + * If the aggType does not create ordered data, set this to something "falsy". + * + * If this does create orderedData, then the value should be an object. + * + * If the orderdata is some sort of time series, `this.ordered` should be an object + * with the property `date: true` + * + * @property ordered + * @type {object|undefined} + */ + ordered: any; + /** + * Flag that prevents this aggregation from being included in the dsl. This is only + * used by the count aggregation (currently) since it doesn't really exist and it's output + * is available on every bucket. + * + * @type {Boolean} + */ + hasNoDsl: boolean; + /** + * The method to create a filter representation of the bucket + * @param {object} aggConfig The instance of the aggConfig + * @param {mixed} key The key for the bucket + * @returns {object} The filter + */ + createFilter: ((aggConfig: TAggConfig, key: any, params?: any) => any) | undefined; + /** + * An instance of {{#crossLink "AggParams"}}{{/crossLink}}. + * + * @property params + * @type {AggParams} + */ + params: TParam[]; + /** + * Designed for multi-value metric aggs, this method can return a + * set of AggConfigs that should replace this aggConfig in requests + * + * @method getRequestAggs + * @returns {array[AggConfig]} - an array of aggConfig objects + * that should replace this one, + * or undefined + */ + getRequestAggs: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); + /** + * Designed for multi-value metric aggs, this method can return a + * set of AggConfigs that should replace this aggConfig in result sets + * that walk the AggConfig set. + * + * @method getResponseAggs + * @returns {array[AggConfig]|undefined} - an array of aggConfig objects + * that should replace this one, + * or undefined + */ + getResponseAggs: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); + /** + * A function that will be called each time an aggConfig of this type + * is created, giving the agg type a chance to modify the agg config + */ + decorateAggConfig: () => any; + /** + * A function that needs to be called after the main request has been made + * and should return an updated response + * @param aggConfigs - agg config array used to produce main request + * @param aggConfig - AggConfig that requested the post flight request + * @param searchSourceAggs - SearchSource aggregation configuration + * @param resp - Response to the main request + * @param nestedSearchSource - the new SearchSource that will be used to make post flight request + * @return {Promise} + */ + postFlightRequest: ( + resp: any, + aggConfigs: AggConfigs, + aggConfig: TAggConfig, + searchSource: ISearchSource, + inspectorAdapters: Adapters, + abortSignal?: AbortSignal + ) => Promise; + /** + * Pick a format for the values produced by this agg type, + * overridden by several metrics that always output a simple + * number + * + * @param {agg} agg - the agg to pick a format for + * @return {FieldFormat} + */ + getFormat: (agg: TAggConfig) => FieldFormat; + + getValue: (agg: TAggConfig, bucket: any) => any; + + getKey?: (bucket: any, key: any, agg: TAggConfig) => any; + + paramByName = (name: string) => { + return this.params.find((p: TParam) => p.name === name); + }; + + /** + * Generic AggType Constructor + * + * Used to create the values exposed by the agg_types module. + * + * @class AggType + * @private + * @param {object} config - used to set the properties of the AggType + */ + constructor(config: AggTypeConfig) { + this.name = config.name; + this.type = config.type || 'metrics'; + this.dslName = config.dslName || config.name; + this.title = config.title; + this.makeLabel = config.makeLabel || constant(this.name); + this.ordered = config.ordered; + this.hasNoDsl = !!config.hasNoDsl; + + if (config.createFilter) { + this.createFilter = config.createFilter; + } + + if (config.params && config.params.length && config.params[0] instanceof BaseParamType) { + this.params = config.params as TParam[]; + } else { + // always append the raw JSON param + const params: any[] = config.params ? [...config.params] : []; + params.push({ + name: 'json', + type: 'json', + advanced: true, + }); + // always append custom label + + if (config.customLabels !== false) { + params.push({ + name: 'customLabel', + displayName: i18n.translate('data.search.aggs.string.customLabel', { + defaultMessage: 'Custom label', + }), + type: 'string', + write: noop, + }); + } + + this.params = initParams(params); + } + + this.getRequestAggs = config.getRequestAggs || noop; + this.getResponseAggs = config.getResponseAggs || (() => {}); + this.decorateAggConfig = config.decorateAggConfig || (() => ({})); + this.postFlightRequest = config.postFlightRequest || identity; + this.getFormat = config.getFormat || getFormat; + this.getValue = config.getValue || ((agg: TAggConfig, bucket: any) => {}); + } +} diff --git a/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/_bucket_agg_type.ts similarity index 94% rename from src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/_bucket_agg_type.ts index ed332ea420bcc..6a5509541ee70 100644 --- a/src/legacy/ui/public/agg_types/buckets/_bucket_agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/_bucket_agg_type.ts @@ -17,8 +17,8 @@ * under the License. */ -import { AggConfig } from '../../vis'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { AggConfig } from 'ui/vis'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { AggType, AggTypeConfig } from '../agg_type'; import { AggParamType } from '../param_types/agg'; diff --git a/src/legacy/core_plugins/data/public/search/agg_types/buckets/_interval_options.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/_interval_options.ts new file mode 100644 index 0000000000000..e196687607d19 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/_interval_options.ts @@ -0,0 +1,82 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { IBucketAggConfig } from './_bucket_agg_type'; + +export const intervalOptions = [ + { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.autoDisplayName', { + defaultMessage: 'Auto', + }), + val: 'auto', + 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('data.search.aggs.buckets.intervalOptions.millisecondDisplayName', { + defaultMessage: 'Millisecond', + }), + val: 'ms', + }, + { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.secondDisplayName', { + defaultMessage: 'Second', + }), + val: 's', + }, + { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.minuteDisplayName', { + defaultMessage: 'Minute', + }), + val: 'm', + }, + { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.hourlyDisplayName', { + defaultMessage: 'Hourly', + }), + val: 'h', + }, + { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.dailyDisplayName', { + defaultMessage: 'Daily', + }), + val: 'd', + }, + { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.weeklyDisplayName', { + defaultMessage: 'Weekly', + }), + val: 'w', + }, + { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.monthlyDisplayName', { + defaultMessage: 'Monthly', + }), + val: 'M', + }, + { + display: i18n.translate('data.search.aggs.buckets.intervalOptions.yearlyDisplayName', { + defaultMessage: 'Yearly', + }), + val: 'y', + }, +]; diff --git a/src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js b/src/legacy/core_plugins/data/public/search/agg_types/buckets/_terms_other_bucket_helper.js similarity index 98% rename from src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/_terms_other_bucket_helper.js index d0d712704964b..4963205a3654d 100644 --- a/src/legacy/ui/public/agg_types/buckets/_terms_other_bucket_helper.js +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/_terms_other_bucket_helper.js @@ -18,8 +18,8 @@ */ import _ from 'lodash'; -import { AggGroupNames } from '../../vis/editors/default/agg_groups'; -import { esFilters, esQuery } from '../../../../../plugins/data/public'; +import { AggGroupNames } from 'ui/vis/editors/default/agg_groups'; +import { esFilters, esQuery } from '../../../../../../../plugins/data/public'; /** * walks the aggregation DSL and returns DSL starting at aggregation with id of startFromAggId diff --git a/src/legacy/ui/public/agg_types/buckets/bucket_agg_types.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/bucket_agg_types.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/bucket_agg_types.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/bucket_agg_types.ts diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_histogram.test.ts similarity index 98% rename from src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_histogram.test.ts index 9426df7d34c29..e212132257ef6 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_histogram.test.ts @@ -23,7 +23,7 @@ import { intervalOptions } from '../_interval_options'; import { AggConfigs } from '../../agg_configs'; import { IBucketDateHistogramAggConfig } from '../date_histogram'; import { BUCKET_TYPES } from '../bucket_agg_types'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_histogram.ts similarity index 94% rename from src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_histogram.ts index f91a92eab1c33..e634b5daf0ac3 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_histogram.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_histogram.ts @@ -19,7 +19,7 @@ import moment from 'moment'; import { IBucketDateHistogramAggConfig } from '../date_histogram'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterDateHistogram = ( agg: IBucketDateHistogramAggConfig, diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_range.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_range.test.ts index ddb4102563a7c..af0b633b5896d 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_range.test.ts @@ -19,7 +19,7 @@ import moment from 'moment'; import { createFilterDateRange } from './date_range'; -import { DateFormat } from '../../../../../../plugins/data/public'; +import { DateFormat } from '../../../../../../../../plugins/data/public'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_range.ts similarity index 94% rename from src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_range.ts index 01689d954a072..f7f2cfdb7bb61 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/date_range.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/date_range.ts @@ -20,7 +20,7 @@ import moment from 'moment'; import { IBucketAggConfig } from '../_bucket_agg_type'; import { DateRangeKey } from '../date_range'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterDateRange = (agg: IBucketAggConfig, { from, to }: DateRangeKey) => { const filter: esFilters.RangeFilterParams = {}; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/filters.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/create_filter/filters.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/filters.test.ts diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/filters.ts similarity index 94% rename from src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/filters.ts index 6b614514580b6..715f6895374e6 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/filters.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/filters.ts @@ -19,7 +19,7 @@ import { get } from 'lodash'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => { // have the aggConfig write agg dsl params diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/histogram.test.ts similarity index 96% rename from src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/histogram.test.ts index d07cf84aef4d9..6b874ba3c4a5e 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/histogram.test.ts @@ -20,7 +20,7 @@ import { createFilterHistogram } from './histogram'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { BytesFormat } from '../../../../../../plugins/data/public'; +import { BytesFormat } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/histogram.ts similarity index 94% rename from src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/histogram.ts index fc587fa9ecdb6..820f3de5ae9f0 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/histogram.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/histogram.ts @@ -18,7 +18,7 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => { const value = parseInt(key, 10); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/ip_range.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/ip_range.test.ts index bf6b437f17cf2..c1327fd8539ea 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/ip_range.test.ts @@ -19,7 +19,7 @@ import { createFilterIpRange } from './ip_range'; import { AggConfigs } from '../../agg_configs'; -import { IpFormat } from '../../../../../../plugins/data/public'; +import { IpFormat } from '../../../../../../../../plugins/data/public'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/ip_range.ts similarity index 95% rename from src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/ip_range.ts index a513b8c782739..d78f4579cd713 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/ip_range.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/ip_range.ts @@ -20,7 +20,7 @@ import { CidrMask } from '../lib/cidr_mask'; import { IBucketAggConfig } from '../_bucket_agg_type'; import { IpRangeKey } from '../ip_range'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: IpRangeKey) => { let range: esFilters.RangeFilterParams; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/range.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/range.test.ts index dc02b773edc42..41921d740595a 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/range.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/range.test.ts @@ -18,7 +18,7 @@ */ import { createFilterRange } from './range'; -import { BytesFormat } from '../../../../../../plugins/data/public'; +import { BytesFormat } from '../../../../../../../../plugins/data/public'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/range.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/range.ts similarity index 93% rename from src/legacy/ui/public/agg_types/buckets/create_filter/range.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/range.ts index 929827c6e3fec..125a30a1ab1dd 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/range.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/range.ts @@ -18,7 +18,7 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => { return esFilters.buildRangeFilter( diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/terms.test.ts similarity index 98% rename from src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/terms.test.ts index 86c0aa24f529a..d5fd1337f2cb2 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/terms.test.ts @@ -21,7 +21,7 @@ import { createFilterTerms } from './terms'; import { AggConfigs } from '../../agg_configs'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/terms.ts similarity index 95% rename from src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/terms.ts index 5bd770e672786..e0d1f91c1e16a 100644 --- a/src/legacy/ui/public/agg_types/buckets/create_filter/terms.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/create_filter/terms.ts @@ -18,7 +18,7 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../../../plugins/data/public'; export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, params: any) => { const field = aggConfig.params.field; diff --git a/src/legacy/core_plugins/data/public/search/agg_types/buckets/date_histogram.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/date_histogram.ts new file mode 100644 index 0000000000000..72c5c4e0f53ec --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/date_histogram.ts @@ -0,0 +1,269 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import _ from 'lodash'; +import moment from 'moment-timezone'; +import { npStart } from 'ui/new_platform'; +import { timefilter } from 'ui/timefilter'; +import { TimeBuckets } from 'ui/time_buckets'; +import { DropPartialsParamEditor } from 'ui/vis/editors/default/controls/drop_partials'; +import { ScaleMetricsParamEditor } from 'ui/vis/editors/default/controls/scale_metrics'; +import { TimeIntervalParamEditor } from 'ui/vis/editors/default/controls/time_interval'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { dateHistogramInterval } from '../../../../common'; +import { writeParams } from '../agg_params'; +import { isMetricAggType } from '../metrics/metric_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { createFilterDateHistogram } from './create_filter/date_histogram'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; +import { intervalOptions } from './_interval_options'; + +const detectedTimezone = moment.tz.guess(); +const tzOffset = moment().format('Z'); + +const getInterval = (agg: IBucketAggConfig): string => _.get(agg, ['params', 'interval']); + +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 function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHistogramAggConfig { + return Boolean(agg.buckets); +} + +export const dateHistogramBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.DATE_HISTOGRAM, + title: i18n.translate('data.search.aggs.buckets.dateHistogramTitle', { + defaultMessage: 'Date Histogram', + }), + ordered: { + date: true, + }, + makeLabel(agg) { + let output: Record = {}; + + if (this.params) { + output = writeParams(this.params, agg); + } + + const field = agg.getFieldDisplayName(); + return i18n.translate('data.search.aggs.buckets.dateHistogramLabel', { + defaultMessage: '{fieldName} per {intervalDescription}', + values: { + fieldName: field, + intervalDescription: output.metricScaleText || output.bucketInterval.description, + }, + }); + }, + createFilter: createFilterDateHistogram, + decorateAggConfig() { + let buckets: any; + return { + buckets: { + configurable: true, + get() { + if (buckets) return buckets; + + buckets = new TimeBuckets(); + buckets.setInterval(getInterval(this)); + setBounds(this); + + return buckets; + }, + } as any, + }; + }, + getFormat(agg) { + return agg.buckets.getScaledDateFormatter(); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.DATE, + default(agg: IBucketDateHistogramAggConfig) { + return agg.getIndexPattern().timeFieldName; + }, + onChange(agg: IBucketDateHistogramAggConfig) { + if (_.get(agg, 'params.interval') === 'auto' && !agg.fieldIsTimeField()) { + delete agg.params.interval; + } + + setBounds(agg, true); + }, + }, + { + name: 'timeRange', + default: null, + write: _.noop, + }, + { + name: 'useNormalizedEsInterval', + default: true, + write: _.noop, + }, + { + name: 'scaleMetricValues', + default: false, + write: _.noop, + advanced: true, + editorComponent: ScaleMetricsParamEditor, + }, + { + name: 'interval', + editorComponent: TimeIntervalParamEditor, + deserialize(state: any, agg) { + // 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'); + } + + const interval = _.find(intervalOptions, { val: state }); + + // For upgrading from 4.0.x to 4.1.x - intervals are now stored as 'y' instead of 'year', + // but this maps the old values to the new values + if (!interval && state === 'year') { + return 'y'; + } + return state; + }, + default: 'auto', + options: intervalOptions, + modifyAggConfigOnSearchRequestStart(agg: IBucketDateHistogramAggConfig) { + setBounds(agg, true); + }, + write(agg, output, aggs) { + setBounds(agg, true); + agg.buckets.setInterval(getInterval(agg)); + const { useNormalizedEsInterval, scaleMetricValues } = agg.params; + const interval = agg.buckets.getInterval(useNormalizedEsInterval); + output.bucketInterval = interval; + if (interval.expression === '0ms') { + // We are hitting this code a couple of times while configuring in editor + // with an interval of 0ms because the overall time range has not yet been + // set. Since 0ms is not a valid ES interval, we cannot pass it through dateHistogramInterval + // below, since it would throw an exception. So in the cases we still have an interval of 0ms + // here we simply skip the rest of the method and never write an interval into the DSL, since + // this DSL will anyway not be used before we're passing this code with an actual interval. + return; + } + output.params = { + ...output.params, + ...dateHistogramInterval(interval.expression), + }; + + const scaleMetrics = scaleMetricValues && interval.scaled && interval.scale < 1; + if (scaleMetrics && aggs) { + const metrics = aggs.aggs.filter(a => isMetricAggType(a.type)); + const all = _.every(metrics, (a: IBucketAggConfig) => { + const { type } = a; + + if (isMetricAggType(type)) { + return type.isScalable(); + } + }); + if (all) { + output.metricScale = interval.scale; + output.metricScaleText = interval.preScaled.description; + } + } + }, + }, + { + 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: _.noop, + write(agg, output) { + // 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', + ]); + } + if (!tz) { + const config = npStart.core.uiSettings; + // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz + const isDefaultTimezone = config.isDefault('dateFormat:tz'); + tz = isDefaultTimezone ? detectedTimezone || tzOffset : config.get('dateFormat:tz'); + } + output.params.time_zone = tz; + }, + }, + { + name: 'drop_partials', + default: false, + write: _.noop, + editorComponent: DropPartialsParamEditor, + shouldShow: agg => { + const field = agg.params.field; + return field && field.name && field.name === agg.getIndexPattern().timeFieldName; + }, + }, + { + name: 'format', + }, + { + name: 'min_doc_count', + default: 1, + }, + { + name: 'extended_bounds', + default: {}, + write(agg, output) { + 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(), + }; + + return; + } + }, + }, + ], +}); diff --git a/src/legacy/ui/public/agg_types/buckets/date_range.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/date_range.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/date_range.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/date_range.test.ts diff --git a/src/legacy/core_plugins/data/public/search/agg_types/buckets/date_range.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/date_range.ts new file mode 100644 index 0000000000000..61a85d3f244b3 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/date_range.ts @@ -0,0 +1,128 @@ +/* + * 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 { DateRangesParamEditor } from 'ui/vis/editors/default/controls/date_ranges'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { createFilterDateRange } from './create_filter/date_range'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; + +import { + FieldFormat, + KBN_FIELD_TYPES, + TEXT_CONTEXT_TYPE, +} from '../../../../../../../plugins/data/public'; + +const dateRangeTitle = i18n.translate('data.search.aggs.buckets.dateRangeTitle', { + defaultMessage: 'Date Range', +}); + +export interface DateRangeKey { + from: number; + to: number; +} + +export const dateRangeBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.DATE_RANGE, + title: dateRangeTitle, + createFilter: createFilterDateRange, + getKey({ from, to }): DateRangeKey { + return { from, to }; + }, + getFormat(agg) { + const fieldFormats = npStart.plugins.data.fieldFormats; + + const formatter = agg.fieldOwnFormatter( + TEXT_CONTEXT_TYPE, + fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.DATE) + ); + const DateRangeFormat = FieldFormat.from(function(range: DateRangeKey) { + return convertDateRangeToString(range, formatter); + }); + return new DateRangeFormat(); + }, + makeLabel(aggConfig) { + return aggConfig.getFieldDisplayName() + ' date ranges'; + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.DATE, + default(agg: IBucketAggConfig) { + 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) => { + 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; + }, + }, + ], +}); + +export const convertDateRangeToString = ( + { from, to }: DateRangeKey, + format: (val: any) => string +) => { + if (!from) { + return 'Before ' + format(to); + } else if (!to) { + return 'After ' + format(from); + } else { + return format(from) + ' to ' + format(to); + } +}; diff --git a/src/legacy/ui/public/agg_types/buckets/filter.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/filter.ts similarity index 93% rename from src/legacy/ui/public/agg_types/buckets/filter.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/filter.ts index 3f8a898f4c963..b52e2d6cfd4df 100644 --- a/src/legacy/ui/public/agg_types/buckets/filter.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/filter.ts @@ -20,7 +20,7 @@ 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', { +const filterTitle = i18n.translate('data.search.aggs.buckets.filterTitle', { defaultMessage: 'Filter', }); diff --git a/src/legacy/ui/public/agg_types/buckets/filters.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/filters.ts similarity index 90% rename from src/legacy/ui/public/agg_types/buckets/filters.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/filters.ts index 6e7f4e27b9e90..77dfe7e046679 100644 --- a/src/legacy/ui/public/agg_types/buckets/filters.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/filters.ts @@ -23,16 +23,16 @@ import angular from 'angular'; import { i18n } from '@kbn/i18n'; import chrome from 'ui/chrome'; -import { FiltersParamEditor, FilterValue } from '../../vis/editors/default/controls/filters'; +import { FiltersParamEditor, FilterValue } from 'ui/vis/editors/default/controls/filters'; import { createFilterFilters } from './create_filter/filters'; import { BucketAggType } from './_bucket_agg_type'; -import { Storage } from '../../../../../plugins/kibana_utils/public'; -import { getQueryLog, esQuery } from '../../../../../plugins/data/public'; +import { Storage } from '../../../../../../../plugins/kibana_utils/public'; +import { getQueryLog, esQuery } from '../../../../../../../plugins/data/public'; const config = chrome.getUiSettingsClient(); const storage = new Storage(window.localStorage); -const filtersTitle = i18n.translate('common.ui.aggTypes.buckets.filtersTitle', { +const filtersTitle = i18n.translate('data.search.aggs.buckets.filtersTitle', { defaultMessage: 'Filters', description: 'The name of an aggregation, that allows to specify multiple individual filters to group data by.', diff --git a/src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/geo_hash.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/geo_hash.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/geo_hash.test.ts diff --git a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/geo_hash.ts similarity index 88% rename from src/legacy/ui/public/agg_types/buckets/geo_hash.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/geo_hash.ts index 8e39a464b9adf..e957ab652f01d 100644 --- a/src/legacy/ui/public/agg_types/buckets/geo_hash.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/geo_hash.ts @@ -18,18 +18,17 @@ */ import { i18n } from '@kbn/i18n'; +import chrome from 'ui/chrome'; +import { AggGroupNames } from 'ui/vis/editors/default/agg_groups'; +import { AutoPrecisionParamEditor } from 'ui/vis/editors/default/controls/auto_precision'; +import { IsFilteredByCollarParamEditor } from 'ui/vis/editors/default/controls/is_filtered_by_collar'; +import { PrecisionParamEditor } from 'ui/vis/editors/default/controls/precision'; +import { UseGeocentroidParamEditor } from 'ui/vis/editors/default/controls/use_geocentroid'; import { geohashColumns } from 'ui/vis/map/decode_geo_hash'; -import chrome from '../../chrome'; -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 { AggGroupNames } from '../../vis/editors/default/agg_groups'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -import { geoContains, scaleBounds, GeoBoundingBox } from './lib/geo_utils'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { BUCKET_TYPES } from './bucket_agg_types'; +import { GeoBoundingBox, geoContains, scaleBounds } from './lib/geo_utils'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; const config = chrome.getUiSettingsClient(); @@ -72,7 +71,7 @@ function getPrecision(val: string) { const isOutsideCollar = (bounds: GeoBoundingBox, collar: MapCollar) => bounds && collar && !geoContains(collar, bounds); -const geohashGridTitle = i18n.translate('common.ui.aggTypes.buckets.geohashGridTitle', { +const geohashGridTitle = i18n.translate('data.search.aggs.buckets.geohashGridTitle', { defaultMessage: 'Geohash', }); diff --git a/src/legacy/ui/public/agg_types/buckets/geo_tile.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/geo_tile.ts similarity index 92% rename from src/legacy/ui/public/agg_types/buckets/geo_tile.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/geo_tile.ts index ef71e3947566a..57e8f6e8c5ded 100644 --- a/src/legacy/ui/public/agg_types/buckets/geo_tile.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/geo_tile.ts @@ -23,11 +23,11 @@ import { AggConfigOptions } from '../agg_config'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { IBucketAggConfig } from './_bucket_agg_type'; import { METRIC_TYPES } from '../metrics/metric_agg_types'; -const geotileGridTitle = i18n.translate('common.ui.aggTypes.buckets.geotileGridTitle', { +const geotileGridTitle = i18n.translate('data.search.aggs.buckets.geotileGridTitle', { defaultMessage: 'Geotile', }); diff --git a/src/legacy/ui/public/agg_types/buckets/histogram.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/histogram.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/histogram.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/histogram.test.ts diff --git a/src/legacy/ui/public/agg_types/buckets/histogram.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/histogram.ts similarity index 91% rename from src/legacy/ui/public/agg_types/buckets/histogram.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/histogram.ts index d287cbddb7834..b9dd535657062 100644 --- a/src/legacy/ui/public/agg_types/buckets/histogram.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/histogram.ts @@ -20,16 +20,16 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { toastNotifications } from 'ui/notify'; - import { npStart } from 'ui/new_platform'; -import { BucketAggType, IBucketAggConfig } 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 { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; + +import { ExtendedBoundsParamEditor } from 'ui/vis/editors/default/controls/extended_bounds'; +import { HasExtendedBoundsParamEditor } from 'ui/vis/editors/default/controls/has_extended_bounds'; +import { MinDocCountParamEditor } from 'ui/vis/editors/default/controls/min_doc_count'; +import { NumberIntervalParamEditor } from 'ui/vis/editors/default/controls/number_interval'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { BUCKET_TYPES } from './bucket_agg_types'; +import { createFilterHistogram } from './create_filter/histogram'; +import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; export interface AutoBounds { min: number; @@ -45,7 +45,7 @@ const getUIConfig = () => npStart.core.uiSettings; export const histogramBucketAgg = new BucketAggType({ name: BUCKET_TYPES.HISTOGRAM, - title: i18n.translate('common.ui.aggTypes.buckets.histogramTitle', { + title: i18n.translate('data.search.aggs.buckets.histogramTitle', { defaultMessage: 'Histogram', }), ordered: {}, @@ -122,7 +122,7 @@ export const histogramBucketAgg = new BucketAggType({ .catch((e: Error) => { if (e.name === 'AbortError') return; toastNotifications.addWarning( - i18n.translate('common.ui.aggTypes.histogram.missingMaxMinValuesWarning', { + i18n.translate('data.search.aggs.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.', diff --git a/src/legacy/ui/public/agg_types/buckets/inline_comp_wrapper.tsx b/src/legacy/core_plugins/data/public/search/agg_types/buckets/inline_comp_wrapper.tsx similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/inline_comp_wrapper.tsx rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/inline_comp_wrapper.tsx diff --git a/src/legacy/core_plugins/data/public/search/agg_types/buckets/ip_range.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/ip_range.ts new file mode 100644 index 0000000000000..8173aafd63978 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/ip_range.ts @@ -0,0 +1,117 @@ +/* + * 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 { isNull, map, noop, omit } from 'lodash'; +import { i18n } from '@kbn/i18n'; + +import { npStart } from 'ui/new_platform'; +import { IpRangesParamEditor } from 'ui/vis/editors/default/controls/ip_ranges'; +import { IpRangeTypeParamEditor } from 'ui/vis/editors/default/controls/ip_range_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { createFilterIpRange } from './create_filter/ip_range'; +import { BucketAggType } from './_bucket_agg_type'; + +import { + FieldFormat, + KBN_FIELD_TYPES, + TEXT_CONTEXT_TYPE, +} from '../../../../../../../plugins/data/public'; + +const ipRangeTitle = i18n.translate('data.search.aggs.buckets.ipRangeTitle', { + defaultMessage: 'IPv4 Range', +}); + +export type IpRangeKey = + | { type: 'mask'; mask: string } + | { type: 'range'; from: string; to: string }; + +export const ipRangeBucketAgg = new BucketAggType({ + name: BUCKET_TYPES.IP_RANGE, + title: ipRangeTitle, + createFilter: createFilterIpRange, + getKey(bucket, key, agg): IpRangeKey { + if (agg.params.ipRangeType === 'mask') { + return { type: 'mask', mask: key }; + } + return { type: 'range', from: bucket.from, to: bucket.to }; + }, + getFormat(agg) { + const fieldFormats = npStart.plugins.data.fieldFormats; + const formatter = agg.fieldOwnFormatter( + TEXT_CONTEXT_TYPE, + fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.IP) + ); + const IpRangeFormat = FieldFormat.from(function(range: IpRangeKey) { + return convertIPRangeToString(range, formatter); + }); + return new IpRangeFormat(); + }, + makeLabel(aggConfig) { + return i18n.translate('data.search.aggs.buckets.ipRangeLabel', { + defaultMessage: '{fieldName} IP ranges', + values: { + fieldName: aggConfig.getFieldDisplayName(), + }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.IP, + }, + { + name: 'ipRangeType', + editorComponent: IpRangeTypeParamEditor, + default: 'fromTo', + 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' }, + ], + mask: [{ mask: '0.0.0.0/1' }, { mask: '128.0.0.0/2' }], + }, + editorComponent: IpRangesParamEditor, + write(aggConfig, output) { + const ipRangeType = aggConfig.params.ipRangeType; + let ranges = aggConfig.params.ranges[ipRangeType]; + + if (ipRangeType === 'fromTo') { + ranges = map(ranges, (range: any) => omit(range, isNull)); + } + + output.params.ranges = ranges; + }, + }, + ], +}); + +export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { + if (range.type === 'mask') { + return format(range.mask); + } + const from = range.from ? format(range.from) : '-Infinity'; + const to = range.to ? format(range.to) : 'Infinity'; + + return `${from} to ${to}`; +}; diff --git a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/lib/cidr_mask.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/lib/cidr_mask.test.ts diff --git a/src/legacy/core_plugins/data/public/search/agg_types/buckets/lib/cidr_mask.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/lib/cidr_mask.ts new file mode 100644 index 0000000000000..30c4e400fb806 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/lib/cidr_mask.ts @@ -0,0 +1,58 @@ +/* + * 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 { Ipv4Address } from '../../../../../../../../plugins/kibana_utils/public'; + +const NUM_BITS = 32; + +function throwError(mask: string) { + throw Error('Invalid CIDR mask: ' + mask); +} + +export class CidrMask { + public readonly initialAddress: Ipv4Address; + public readonly prefixLength: number; + + constructor(mask: string) { + const splits = mask.split('/'); + if (splits.length !== 2) { + throwError(mask); + } + this.initialAddress = new Ipv4Address(splits[0]); + this.prefixLength = Number(splits[1]); + if (isNaN(this.prefixLength) || this.prefixLength < 1 || this.prefixLength > NUM_BITS) { + throwError(mask); + } + } + + public getRange() { + const variableBits = NUM_BITS - this.prefixLength; + // eslint-disable-next-line no-bitwise + const fromAddress = ((this.initialAddress.valueOf() >> variableBits) << variableBits) >>> 0; // >>> 0 coerces to unsigned + const numAddresses = Math.pow(2, variableBits); + return { + from: new Ipv4Address(fromAddress).toString(), + to: new Ipv4Address(fromAddress + numAddresses - 1).toString(), + }; + } + + public toString() { + return this.initialAddress.toString() + '/' + this.prefixLength; + } +} diff --git a/src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/lib/geo_utils.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/lib/geo_utils.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/lib/geo_utils.ts diff --git a/src/legacy/core_plugins/data/public/search/agg_types/buckets/migrate_include_exclude_format.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/migrate_include_exclude_format.ts new file mode 100644 index 0000000000000..77e84e044de55 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/migrate_include_exclude_format.ts @@ -0,0 +1,53 @@ +/* + * 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 { isString, isObject } from 'lodash'; +import { IBucketAggConfig, BucketAggType, BucketAggParam } from './_bucket_agg_type'; +import { AggConfig } from '../agg_config'; + +export const isType = (type: string) => { + return (agg: AggConfig): boolean => { + const field = agg.params.field; + + return field && field.type === type; + }; +}; + +export const isStringType = isType('string'); + +export const migrateIncludeExcludeFormat = { + serialize(this: BucketAggParam, value: any, agg: IBucketAggConfig) { + if (this.shouldShow && !this.shouldShow(agg)) return; + if (!value || isString(value)) return value; + else return value.pattern; + }, + write( + this: BucketAggType, + aggConfig: IBucketAggConfig, + output: Record + ) { + 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; + } + }, +} as Partial>; diff --git a/src/legacy/ui/public/agg_types/buckets/range.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/range.test.ts similarity index 97% rename from src/legacy/ui/public/agg_types/buckets/range.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/range.test.ts index 5db7eb3c2d8e9..5cd10cb60e5ab 100644 --- a/src/legacy/ui/public/agg_types/buckets/range.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/range.test.ts @@ -19,7 +19,7 @@ import { AggConfigs } from '../agg_configs'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { NumberFormat } from '../../../../../plugins/data/public'; +import { NumberFormat } from '../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/buckets/range.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/range.ts similarity index 89% rename from src/legacy/ui/public/agg_types/buckets/range.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/range.ts index 24757a607e005..33e74a41b6d49 100644 --- a/src/legacy/ui/public/agg_types/buckets/range.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/range.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType } from './_bucket_agg_type'; -import { FieldFormat, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { FieldFormat, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { RangeKey } from './range_key'; import { RangesEditor } from './range_editor'; @@ -30,7 +30,7 @@ import { BUCKET_TYPES } from './bucket_agg_types'; const keyCaches = new WeakMap(); const formats = new WeakMap(); -const rangeTitle = i18n.translate('common.ui.aggTypes.buckets.rangeTitle', { +const rangeTitle = i18n.translate('data.search.aggs.buckets.rangeTitle', { defaultMessage: 'Range', }); @@ -39,7 +39,7 @@ export const rangeBucketAgg = new BucketAggType({ title: rangeTitle, createFilter: createFilterRange, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.rangesLabel', { + return i18n.translate('data.search.aggs.buckets.rangesLabel', { defaultMessage: '{fieldName} ranges', values: { fieldName: aggConfig.getFieldDisplayName(), @@ -72,7 +72,7 @@ export const rangeBucketAgg = new BucketAggType({ const format = agg.fieldOwnFormatter(); const gte = '\u2265'; const lt = '\u003c'; - return i18n.translate('common.ui.aggTypes.buckets.ranges.rangesFormatMessage', { + return i18n.translate('data.search.aggs.buckets.ranges.rangesFormatMessage', { defaultMessage: '{gte} {from} and {lt} {to}', values: { gte, diff --git a/src/legacy/ui/public/agg_types/buckets/range_editor.tsx b/src/legacy/core_plugins/data/public/search/agg_types/buckets/range_editor.tsx similarity index 92% rename from src/legacy/ui/public/agg_types/buckets/range_editor.tsx rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/range_editor.tsx index 967a4a7d7cc40..179028206702a 100644 --- a/src/legacy/ui/public/agg_types/buckets/range_editor.tsx +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/range_editor.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { AggParamEditorProps } from 'ui/vis/editors/default'; -import { RangesParamEditor } from '../../vis/editors/default/controls/ranges'; +import { RangesParamEditor } from 'ui/vis/editors/default/controls/ranges'; export const RangesEditor = (props: AggParamEditorProps) => ( diff --git a/src/legacy/ui/public/agg_types/buckets/range_key.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/range_key.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/range_key.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/range_key.ts diff --git a/src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/significant_terms.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/significant_terms.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/significant_terms.test.ts diff --git a/src/legacy/ui/public/agg_types/buckets/significant_terms.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/significant_terms.ts similarity index 80% rename from src/legacy/ui/public/agg_types/buckets/significant_terms.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/significant_terms.ts index 128fd9e83e6fd..0c41d204afb47 100644 --- a/src/legacy/ui/public/agg_types/buckets/significant_terms.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/significant_terms.ts @@ -18,14 +18,14 @@ */ import { i18n } from '@kbn/i18n'; -import { SizeParamEditor } from '../../vis/editors/default/controls/size'; +import { SizeParamEditor } from 'ui/vis/editors/default/controls/size'; import { BucketAggType } 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/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const significantTermsTitle = i18n.translate('common.ui.aggTypes.buckets.significantTermsTitle', { +const significantTermsTitle = i18n.translate('data.search.aggs.buckets.significantTermsTitle', { defaultMessage: 'Significant Terms', }); @@ -33,7 +33,7 @@ export const significantTermsBucketAgg = new BucketAggType({ name: BUCKET_TYPES.SIGNIFICANT_TERMS, title: significantTermsTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.significantTermsLabel', { + return i18n.translate('data.search.aggs.buckets.significantTermsLabel', { defaultMessage: 'Top {size} unusual terms in {fieldName}', values: { size: aggConfig.params.size, @@ -56,7 +56,7 @@ export const significantTermsBucketAgg = new BucketAggType({ }, { name: 'exclude', - displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.excludeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.significantTerms.excludeLabel', { defaultMessage: 'Exclude', }), type: 'string', @@ -66,7 +66,7 @@ export const significantTermsBucketAgg = new BucketAggType({ }, { name: 'include', - displayName: i18n.translate('common.ui.aggTypes.buckets.significantTerms.includeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.significantTerms.includeLabel', { defaultMessage: 'Include', }), type: 'string', diff --git a/src/legacy/ui/public/agg_types/buckets/terms.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/terms.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/buckets/terms.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/terms.test.ts diff --git a/src/legacy/ui/public/agg_types/buckets/terms.ts b/src/legacy/core_plugins/data/public/search/agg_types/buckets/terms.ts similarity index 81% rename from src/legacy/ui/public/agg_types/buckets/terms.ts rename to src/legacy/core_plugins/data/public/search/agg_types/buckets/terms.ts index e38f7ca4cc038..41e2055fa67eb 100644 --- a/src/legacy/ui/public/agg_types/buckets/terms.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/buckets/terms.ts @@ -20,23 +20,30 @@ import chrome from 'ui/chrome'; import { noop } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { SearchSource, getRequestInspectorStats, getResponseInspectorStats } from '../../courier'; + +import { OrderAggParamEditor } from 'ui/vis/editors/default/controls/order_agg'; +import { OrderParamEditor } from 'ui/vis/editors/default/controls/order'; +import { OrderByParamEditor, aggFilter } from 'ui/vis/editors/default/controls/order_by'; +import { SizeParamEditor } from 'ui/vis/editors/default/controls/size'; +import { MissingBucketParamEditor } from 'ui/vis/editors/default/controls/missing_bucket'; +import { OtherBucketParamEditor } from 'ui/vis/editors/default/controls/other_bucket'; + +import { ISearchSource } from '../../search_source'; +import { getRequestInspectorStats, getResponseInspectorStats } from '../../utils'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketAggConfig } from './_bucket_agg_type'; import { createFilterTerms } from './create_filter/terms'; 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'; -import { OrderByParamEditor, aggFilter } from '../../vis/editors/default/controls/order_by'; -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 { AggConfigs } from '../agg_configs'; -import { Adapters } from '../../../../../plugins/inspector/public'; -import { ContentType, FieldFormat, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { Adapters } from '../../../../../../../plugins/inspector/public'; +import { + ContentType, + FieldFormat, + KBN_FIELD_TYPES, +} from '../../../../../../../plugins/data/public'; // @ts-ignore import { Schemas } from '../../vis/editors/default/schemas'; @@ -59,7 +66,7 @@ const [orderAggSchema] = new Schemas([ }, ]).all; -const termsTitle = i18n.translate('common.ui.aggTypes.buckets.termsTitle', { +const termsTitle = i18n.translate('data.search.aggs.buckets.termsTitle', { defaultMessage: 'Terms', }); @@ -97,7 +104,7 @@ export const termsBucketAgg = new BucketAggType({ resp: any, aggConfigs: AggConfigs, aggConfig: IBucketAggConfig, - searchSource: SearchSource, + searchSource: ISearchSource, inspectorAdapters: Adapters, abortSignal?: AbortSignal ) => { @@ -110,11 +117,11 @@ export const termsBucketAgg = new BucketAggType({ nestedSearchSource.setField('aggs', filterAgg); const request = inspectorAdapters.requests.start( - i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketTitle', { + i18n.translate('data.search.aggs.buckets.terms.otherBucketTitle', { defaultMessage: 'Other bucket', }), { - description: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketDescription', { + description: i18n.translate('data.search.aggs.buckets.terms.otherBucketDescription', { defaultMessage: 'This request counts the number of documents that fall ' + 'outside the criterion of the data buckets.', @@ -212,13 +219,13 @@ export const termsBucketAgg = new BucketAggType({ editorComponent: wrapWithInlineComp(OrderParamEditor), options: [ { - text: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', { + text: i18n.translate('data.search.aggs.buckets.terms.orderDescendingTitle', { defaultMessage: 'Descending', }), value: 'desc', }, { - text: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', { + text: i18n.translate('data.search.aggs.buckets.terms.orderAscendingTitle', { defaultMessage: 'Ascending', }), value: 'asc', @@ -240,10 +247,10 @@ export const termsBucketAgg = new BucketAggType({ { name: 'otherBucketLabel', type: 'string', - default: i18n.translate('common.ui.aggTypes.buckets.terms.otherBucketLabel', { + default: i18n.translate('data.search.aggs.buckets.terms.otherBucketLabel', { defaultMessage: 'Other', }), - displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForOtherBucketLabel', { + displayName: i18n.translate('data.search.aggs.otherBucket.labelForOtherBucketLabel', { defaultMessage: 'Label for other bucket', }), shouldShow: agg => agg.getParam('otherBucket'), @@ -257,13 +264,13 @@ export const termsBucketAgg = new BucketAggType({ }, { name: 'missingBucketLabel', - default: i18n.translate('common.ui.aggTypes.buckets.terms.missingBucketLabel', { + default: i18n.translate('data.search.aggs.buckets.terms.missingBucketLabel', { defaultMessage: 'Missing', description: `Default label used in charts when documents are missing a field. Visible when you create a chart with a terms aggregation and enable "Show missing values"`, }), type: 'string', - displayName: i18n.translate('common.ui.aggTypes.otherBucket.labelForMissingValuesLabel', { + displayName: i18n.translate('data.search.aggs.otherBucket.labelForMissingValuesLabel', { defaultMessage: 'Label for missing values', }), shouldShow: agg => agg.getParam('missingBucket'), @@ -271,7 +278,7 @@ export const termsBucketAgg = new BucketAggType({ }, { name: 'exclude', - displayName: i18n.translate('common.ui.aggTypes.buckets.terms.excludeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.terms.excludeLabel', { defaultMessage: 'Exclude', }), type: 'string', @@ -281,7 +288,7 @@ export const termsBucketAgg = new BucketAggType({ }, { name: 'include', - displayName: i18n.translate('common.ui.aggTypes.buckets.terms.includeLabel', { + displayName: i18n.translate('data.search.aggs.buckets.terms.includeLabel', { defaultMessage: 'Include', }), type: 'string', diff --git a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/filter/agg_type_filters.test.ts similarity index 98% rename from src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/filter/agg_type_filters.test.ts index f470ebbc90b48..e898fdcb58def 100644 --- a/src/legacy/ui/public/agg_types/filter/agg_type_filters.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/filter/agg_type_filters.test.ts @@ -20,7 +20,7 @@ import { IndexPattern } from 'ui/index_patterns'; import { AggTypeFilters } from './agg_type_filters'; import { AggType } from '..'; -import { AggConfig } from '../../vis'; +import { AggConfig } from 'ui/vis'; describe('AggTypeFilters', () => { let registry: AggTypeFilters; diff --git a/src/legacy/ui/public/agg_types/filter/agg_type_filters.ts b/src/legacy/core_plugins/data/public/search/agg_types/filter/agg_type_filters.ts similarity index 90% rename from src/legacy/ui/public/agg_types/filter/agg_type_filters.ts rename to src/legacy/core_plugins/data/public/search/agg_types/filter/agg_type_filters.ts index 4d99575e4ae38..ef79eaa4acb40 100644 --- a/src/legacy/ui/public/agg_types/filter/agg_type_filters.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/filter/agg_type_filters.ts @@ -16,13 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -import { IndexPattern } from '../../index_patterns'; -import { AggConfig } from '../../vis'; + +import { AggConfig } from 'ui/vis'; +import { IIndexPattern } from '../../../../../../../plugins/data/public'; import { AggType } from '..'; type AggTypeFilter = ( aggType: AggType, - indexPattern: IndexPattern, + indexPattern: IIndexPattern, aggConfig: AggConfig ) => boolean; @@ -50,7 +51,7 @@ class AggTypeFilters { * @param aggConfig The aggConfig for which the returning list will be used. * @return A filtered list of the passed aggTypes. */ - public filter(aggTypes: AggType[], indexPattern: IndexPattern, aggConfig: AggConfig) { + public filter(aggTypes: AggType[], indexPattern: IIndexPattern, aggConfig: AggConfig) { const allFilters = Array.from(this.filters); const allowedAggTypes = aggTypes.filter(aggType => { const isAggTypeAllowed = allFilters.every(filter => filter(aggType, indexPattern, aggConfig)); diff --git a/src/legacy/core_plugins/data/public/search/agg_types/filter/index.ts b/src/legacy/core_plugins/data/public/search/agg_types/filter/index.ts new file mode 100644 index 0000000000000..3fc577e7e9a23 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/filter/index.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +export { aggTypeFilters } from './agg_type_filters'; +export { propFilter } from './prop_filter'; diff --git a/src/legacy/ui/public/agg_types/filter/prop_filter.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/filter/prop_filter.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/filter/prop_filter.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/filter/prop_filter.test.ts diff --git a/src/legacy/ui/public/agg_types/filter/prop_filter.ts b/src/legacy/core_plugins/data/public/search/agg_types/filter/prop_filter.ts similarity index 100% rename from src/legacy/ui/public/agg_types/filter/prop_filter.ts rename to src/legacy/core_plugins/data/public/search/agg_types/filter/prop_filter.ts diff --git a/src/legacy/ui/public/agg_types/index.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/index.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/index.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/index.test.ts diff --git a/src/legacy/core_plugins/data/public/search/agg_types/index.ts b/src/legacy/core_plugins/data/public/search/agg_types/index.ts new file mode 100644 index 0000000000000..e0704080fa444 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/index.ts @@ -0,0 +1,110 @@ +/* + * 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 { countMetricAgg } from './metrics/count'; +import { avgMetricAgg } from './metrics/avg'; +import { sumMetricAgg } from './metrics/sum'; +import { medianMetricAgg } from './metrics/median'; +import { minMetricAgg } from './metrics/min'; +import { maxMetricAgg } from './metrics/max'; +import { topHitMetricAgg } from './metrics/top_hit'; +import { stdDeviationMetricAgg } from './metrics/std_deviation'; +import { cardinalityMetricAgg } from './metrics/cardinality'; +import { percentilesMetricAgg } from './metrics/percentiles'; +import { geoBoundsMetricAgg } from './metrics/geo_bounds'; +import { geoCentroidMetricAgg } from './metrics/geo_centroid'; +import { percentileRanksMetricAgg } from './metrics/percentile_ranks'; +import { derivativeMetricAgg } from './metrics/derivative'; +import { cumulativeSumMetricAgg } from './metrics/cumulative_sum'; +import { movingAvgMetricAgg } from './metrics/moving_avg'; +import { serialDiffMetricAgg } from './metrics/serial_diff'; +import { dateHistogramBucketAgg } from './buckets/date_histogram'; +import { histogramBucketAgg } from './buckets/histogram'; +import { rangeBucketAgg } from './buckets/range'; +import { dateRangeBucketAgg } from './buckets/date_range'; +import { ipRangeBucketAgg } from './buckets/ip_range'; +import { termsBucketAgg } from './buckets/terms'; +import { filterBucketAgg } from './buckets/filter'; +import { filtersBucketAgg } from './buckets/filters'; +import { significantTermsBucketAgg } from './buckets/significant_terms'; +import { geoHashBucketAgg } from './buckets/geo_hash'; +import { geoTileBucketAgg } from './buckets/geo_tile'; +import { bucketSumMetricAgg } from './metrics/bucket_sum'; +import { bucketAvgMetricAgg } from './metrics/bucket_avg'; +import { bucketMinMetricAgg } from './metrics/bucket_min'; +import { bucketMaxMetricAgg } from './metrics/bucket_max'; + +export const aggTypes = { + metrics: [ + countMetricAgg, + avgMetricAgg, + sumMetricAgg, + medianMetricAgg, + minMetricAgg, + maxMetricAgg, + stdDeviationMetricAgg, + cardinalityMetricAgg, + percentilesMetricAgg, + percentileRanksMetricAgg, + topHitMetricAgg, + derivativeMetricAgg, + cumulativeSumMetricAgg, + movingAvgMetricAgg, + serialDiffMetricAgg, + bucketAvgMetricAgg, + bucketSumMetricAgg, + bucketMinMetricAgg, + bucketMaxMetricAgg, + geoBoundsMetricAgg, + geoCentroidMetricAgg, + ], + buckets: [ + dateHistogramBucketAgg, + histogramBucketAgg, + rangeBucketAgg, + dateRangeBucketAgg, + ipRangeBucketAgg, + termsBucketAgg, + filterBucketAgg, + filtersBucketAgg, + significantTermsBucketAgg, + geoHashBucketAgg, + geoTileBucketAgg, + ], +}; + +export { AggType } from './agg_type'; +export { AggConfig } from './agg_config'; +export { AggConfigs } from './agg_configs'; +export { FieldParamType } from './param_types'; +export { aggTypeFieldFilters } from './param_types/filter'; +export { setBounds } from './buckets/date_histogram'; +export { parentPipelineAggHelper } from './metrics/lib/parent_pipeline_agg_helper'; + +// static code +export { AggParamType } from './param_types/agg'; +export { intervalOptions } from './buckets/_interval_options'; // only used in Discover +export { isDateHistogramBucketAggConfig } from './buckets/date_histogram'; +export { isType, isStringType } from './buckets/migrate_include_exclude_format'; +export { CidrMask } from './buckets/lib/cidr_mask'; +export { convertDateRangeToString } from './buckets/date_range'; +export { convertIPRangeToString } from './buckets/ip_range'; +export { aggTypeFilters, propFilter } from './filter'; +export { OptionedParamType } from './param_types/optioned'; +export { isValidJson, isValidInterval } from './utils'; diff --git a/src/legacy/ui/public/agg_types/metrics/avg.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/avg.ts similarity index 85% rename from src/legacy/ui/public/agg_types/metrics/avg.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/avg.ts index 0222a8e543223..b80671a43d2af 100644 --- a/src/legacy/ui/public/agg_types/metrics/avg.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/avg.ts @@ -20,9 +20,9 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const averageTitle = i18n.translate('common.ui.aggTypes.metrics.averageTitle', { +const averageTitle = i18n.translate('data.search.aggs.metrics.averageTitle', { defaultMessage: 'Average', }); @@ -30,7 +30,7 @@ export const avgMetricAgg = new MetricAggType({ name: METRIC_TYPES.AVG, title: averageTitle, makeLabel: aggConfig => { - return i18n.translate('common.ui.aggTypes.metrics.averageLabel', { + return i18n.translate('data.search.aggs.metrics.averageLabel', { defaultMessage: 'Average {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_avg.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_avg.ts similarity index 91% rename from src/legacy/ui/public/agg_types/metrics/bucket_avg.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_avg.ts index 7142546dbd494..9fb28f8631bc6 100644 --- a/src/legacy/ui/public/agg_types/metrics/bucket_avg.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_avg.ts @@ -25,11 +25,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallAverageLabel = i18n.translate('common.ui.aggTypes.metrics.overallAverageLabel', { +const overallAverageLabel = i18n.translate('data.search.aggs.metrics.overallAverageLabel', { defaultMessage: 'overall average', }); -const averageBucketTitle = i18n.translate('common.ui.aggTypes.metrics.averageBucketTitle', { +const averageBucketTitle = i18n.translate('data.search.aggs.metrics.averageBucketTitle', { defaultMessage: 'Average Bucket', }); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_max.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_max.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/bucket_max.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_max.ts index aa5b0521709a5..83837f0de5114 100644 --- a/src/legacy/ui/public/agg_types/metrics/bucket_max.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_max.ts @@ -24,11 +24,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallMaxLabel = i18n.translate('common.ui.aggTypes.metrics.overallMaxLabel', { +const overallMaxLabel = i18n.translate('data.search.aggs.metrics.overallMaxLabel', { defaultMessage: 'overall max', }); -const maxBucketTitle = i18n.translate('common.ui.aggTypes.metrics.maxBucketTitle', { +const maxBucketTitle = i18n.translate('data.search.aggs.metrics.maxBucketTitle', { defaultMessage: 'Max Bucket', }); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_min.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_min.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/bucket_min.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_min.ts index b5c0b8865e106..d96197693dc2e 100644 --- a/src/legacy/ui/public/agg_types/metrics/bucket_min.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_min.ts @@ -22,11 +22,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallMinLabel = i18n.translate('common.ui.aggTypes.metrics.overallMinLabel', { +const overallMinLabel = i18n.translate('data.search.aggs.metrics.overallMinLabel', { defaultMessage: 'overall min', }); -const minBucketTitle = i18n.translate('common.ui.aggTypes.metrics.minBucketTitle', { +const minBucketTitle = i18n.translate('data.search.aggs.metrics.minBucketTitle', { defaultMessage: 'Min Bucket', }); diff --git a/src/legacy/ui/public/agg_types/metrics/bucket_sum.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_sum.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/bucket_sum.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_sum.ts index d4faa81c4041c..1f9392c5bec35 100644 --- a/src/legacy/ui/public/agg_types/metrics/bucket_sum.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/bucket_sum.ts @@ -23,11 +23,11 @@ import { makeNestedLabel } from './lib/make_nested_label'; import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper'; import { METRIC_TYPES } from './metric_agg_types'; -const overallSumLabel = i18n.translate('common.ui.aggTypes.metrics.overallSumLabel', { +const overallSumLabel = i18n.translate('data.search.aggs.metrics.overallSumLabel', { defaultMessage: 'overall sum', }); -const sumBucketTitle = i18n.translate('common.ui.aggTypes.metrics.sumBucketTitle', { +const sumBucketTitle = i18n.translate('data.search.aggs.metrics.sumBucketTitle', { defaultMessage: 'Sum Bucket', }); diff --git a/src/legacy/ui/public/agg_types/metrics/cardinality.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/cardinality.ts similarity index 86% rename from src/legacy/ui/public/agg_types/metrics/cardinality.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/cardinality.ts index 301ae2c80116c..e024a62319bc6 100644 --- a/src/legacy/ui/public/agg_types/metrics/cardinality.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/cardinality.ts @@ -21,9 +21,9 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const uniqueCountTitle = i18n.translate('common.ui.aggTypes.metrics.uniqueCountTitle', { +const uniqueCountTitle = i18n.translate('data.search.aggs.metrics.uniqueCountTitle', { defaultMessage: 'Unique Count', }); @@ -31,7 +31,7 @@ export const cardinalityMetricAgg = new MetricAggType({ name: METRIC_TYPES.CARDINALITY, title: uniqueCountTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.uniqueCountLabel', { + return i18n.translate('data.search.aggs.metrics.uniqueCountLabel', { defaultMessage: 'Unique count of {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/count.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/count.ts similarity index 87% rename from src/legacy/ui/public/agg_types/metrics/count.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/count.ts index b5b844e8658d6..b46c7f9137e3d 100644 --- a/src/legacy/ui/public/agg_types/metrics/count.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/count.ts @@ -19,18 +19,18 @@ import { i18n } from '@kbn/i18n'; import { npStart } from 'ui/new_platform'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; export const countMetricAgg = new MetricAggType({ name: METRIC_TYPES.COUNT, - title: i18n.translate('common.ui.aggTypes.metrics.countTitle', { + title: i18n.translate('data.search.aggs.metrics.countTitle', { defaultMessage: 'Count', }), hasNoDsl: true, makeLabel() { - return i18n.translate('common.ui.aggTypes.metrics.countLabel', { + return i18n.translate('data.search.aggs.metrics.countLabel', { defaultMessage: 'Count', }); }, diff --git a/src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/cumulative_sum.ts similarity index 88% rename from src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/cumulative_sum.ts index bad2de8cb16dc..a5d02459900bb 100644 --- a/src/legacy/ui/public/agg_types/metrics/cumulative_sum.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/cumulative_sum.ts @@ -23,11 +23,11 @@ import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; import { makeNestedLabel } from './lib/make_nested_label'; import { METRIC_TYPES } from './metric_agg_types'; -const cumulativeSumLabel = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumLabel', { +const cumulativeSumLabel = i18n.translate('data.search.aggs.metrics.cumulativeSumLabel', { defaultMessage: 'cumulative sum', }); -const cumulativeSumTitle = i18n.translate('common.ui.aggTypes.metrics.cumulativeSumTitle', { +const cumulativeSumTitle = i18n.translate('data.search.aggs.metrics.cumulativeSumTitle', { defaultMessage: 'Cumulative Sum', }); diff --git a/src/legacy/ui/public/agg_types/metrics/derivative.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/derivative.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/derivative.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/derivative.ts index 42921621a2933..1169a527b0668 100644 --- a/src/legacy/ui/public/agg_types/metrics/derivative.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/derivative.ts @@ -23,11 +23,11 @@ import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; import { makeNestedLabel } from './lib/make_nested_label'; import { METRIC_TYPES } from './metric_agg_types'; -const derivativeLabel = i18n.translate('common.ui.aggTypes.metrics.derivativeLabel', { +const derivativeLabel = i18n.translate('data.search.aggs.metrics.derivativeLabel', { defaultMessage: 'derivative', }); -const derivativeTitle = i18n.translate('common.ui.aggTypes.metrics.derivativeTitle', { +const derivativeTitle = i18n.translate('data.search.aggs.metrics.derivativeTitle', { defaultMessage: 'Derivative', }); diff --git a/src/legacy/ui/public/agg_types/metrics/geo_bounds.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/geo_bounds.ts similarity index 84% rename from src/legacy/ui/public/agg_types/metrics/geo_bounds.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/geo_bounds.ts index b8ce03cdf11ec..53bc72f9ce1da 100644 --- a/src/legacy/ui/public/agg_types/metrics/geo_bounds.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/geo_bounds.ts @@ -20,13 +20,13 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const geoBoundsTitle = i18n.translate('common.ui.aggTypes.metrics.geoBoundsTitle', { +const geoBoundsTitle = i18n.translate('data.search.aggs.metrics.geoBoundsTitle', { defaultMessage: 'Geo Bounds', }); -const geoBoundsLabel = i18n.translate('common.ui.aggTypes.metrics.geoBoundsLabel', { +const geoBoundsLabel = i18n.translate('data.search.aggs.metrics.geoBoundsLabel', { defaultMessage: 'Geo Bounds', }); diff --git a/src/legacy/ui/public/agg_types/metrics/geo_centroid.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/geo_centroid.ts similarity index 84% rename from src/legacy/ui/public/agg_types/metrics/geo_centroid.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/geo_centroid.ts index 5313e31796a5b..a79b2b34ad1ca 100644 --- a/src/legacy/ui/public/agg_types/metrics/geo_centroid.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/geo_centroid.ts @@ -20,13 +20,13 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const geoCentroidTitle = i18n.translate('common.ui.aggTypes.metrics.geoCentroidTitle', { +const geoCentroidTitle = i18n.translate('data.search.aggs.metrics.geoCentroidTitle', { defaultMessage: 'Geo Centroid', }); -const geoCentroidLabel = i18n.translate('common.ui.aggTypes.metrics.geoCentroidLabel', { +const geoCentroidLabel = i18n.translate('data.search.aggs.metrics.geoCentroidLabel', { defaultMessage: 'Geo Centroid', }); diff --git a/src/legacy/ui/public/agg_types/metrics/lib/get_response_agg_config_class.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/get_response_agg_config_class.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/get_response_agg_config_class.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/get_response_agg_config_class.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/make_nested_label.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/make_nested_label.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/make_nested_label.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/make_nested_label.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/make_nested_label.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/nested_agg_helpers.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/nested_agg_helpers.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/nested_agg_helpers.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/ordinal_suffix.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/ordinal_suffix.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/ordinal_suffix.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/ordinal_suffix.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/ordinal_suffix.ts diff --git a/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/parent_pipeline_agg_helper.ts new file mode 100644 index 0000000000000..0c88627f14abd --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/parent_pipeline_agg_helper.ts @@ -0,0 +1,111 @@ +/* + * 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 { noop } from 'lodash'; +import { i18n } from '@kbn/i18n'; + +// @ts-ignore +import { Schemas } from 'ui/vis/editors/default/schemas'; +import { MetricAggParamEditor } from 'ui/vis/editors/default/controls/metric_agg'; +import { SubAggParamEditor } from 'ui/vis/editors/default/controls/sub_agg'; + +import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; +import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; +import { parentPipelineAggWriter } from './parent_pipeline_agg_writer'; + +const metricAggFilter = [ + '!top_hits', + '!percentiles', + '!percentile_ranks', + '!median', + '!std_dev', + '!geo_bounds', + '!geo_centroid', +]; + +const metricAggTitle = i18n.translate('data.search.aggs.metrics.metricAggTitle', { + defaultMessage: 'Metric agg', +}); + +const subtypeLabel = i18n.translate( + 'data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle', + { + defaultMessage: 'Parent Pipeline Aggregations', + } +); + +const [metricAggSchema] = new Schemas([ + { + group: 'none', + name: 'metricAgg', + title: metricAggTitle, + hideCustomLabel: true, + aggFilter: metricAggFilter, + }, +]).all; + +export const parentPipelineAggHelper = { + subtype: subtypeLabel, + + params() { + return [ + { + name: 'metricAgg', + editorComponent: MetricAggParamEditor, + default: 'custom', + write: parentPipelineAggWriter, + }, + { + name: 'customMetric', + editorComponent: SubAggParamEditor, + type: 'agg', + makeAgg(termsAgg, state: any) { + state = state || { type: 'count' }; + state.schema = metricAggSchema; + + const metricAgg = termsAgg.aggConfigs.createAggConfig(state, { addToAggConfigs: false }); + + metricAgg.id = termsAgg.id + '-metric'; + + return metricAgg; + }, + modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart( + 'customMetric' + ), + write: noop, + }, + { + name: 'buckets_path', + write: noop, + }, + ] as Array>; + }, + + getFormat(agg: IMetricAggConfig) { + let subAgg; + const customMetric = agg.getParam('customMetric'); + + if (customMetric) { + subAgg = customMetric; + } else { + subAgg = agg.aggConfigs.byId(agg.getParam('metricAgg')); + } + return subAgg.type.getFormat(subAgg); + }, +}; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_writer.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/parent_pipeline_agg_writer.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_writer.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/parent_pipeline_agg_writer.ts diff --git a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts index e75ebf366a27e..07ea7410246bd 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/sibling_pipeline_agg_helper.ts @@ -18,15 +18,14 @@ */ import { i18n } from '@kbn/i18n'; +// @ts-ignore +import { Schemas } from 'ui/vis/editors/default/schemas'; +import { SubMetricParamEditor } from 'ui/vis/editors/default/controls/sub_metric'; import { siblingPipelineAggWriter } from './sibling_pipeline_agg_writer'; -import { SubMetricParamEditor } from '../../../vis/editors/default/controls/sub_metric'; import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; -// @ts-ignore -import { Schemas } from '../../../vis/editors/default/schemas'; - const metricAggFilter: string[] = [ '!top_hits', '!percentiles', @@ -50,7 +49,7 @@ const [metricAggSchema] = new Schemas([ { group: 'none', name: 'metricAgg', - title: i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { + title: i18n.translate('data.search.aggs.metrics.metricAggTitle', { defaultMessage: 'Metric agg', }), aggFilter: metricAggFilter, @@ -60,7 +59,7 @@ const [metricAggSchema] = new Schemas([ const [bucketAggSchema] = new Schemas([ { group: 'none', - title: i18n.translate('common.ui.aggTypes.metrics.bucketAggTitle', { + title: i18n.translate('data.search.aggs.metrics.bucketAggTitle', { defaultMessage: 'Bucket agg', }), name: 'bucketAgg', @@ -69,7 +68,7 @@ const [bucketAggSchema] = new Schemas([ ]).all; const siblingPipelineAggHelper = { - subtype: i18n.translate('common.ui.aggTypes.metrics.siblingPipelineAggregationsSubtypeTitle', { + subtype: i18n.translate('data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle', { defaultMessage: 'Sibling pipeline aggregations', }), params() { diff --git a/src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/lib/sibling_pipeline_agg_writer.ts diff --git a/src/legacy/ui/public/agg_types/metrics/max.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/max.ts similarity index 86% rename from src/legacy/ui/public/agg_types/metrics/max.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/max.ts index 5c43511acee72..d561788936b51 100644 --- a/src/legacy/ui/public/agg_types/metrics/max.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/max.ts @@ -20,9 +20,9 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const maxTitle = i18n.translate('common.ui.aggTypes.metrics.maxTitle', { +const maxTitle = i18n.translate('data.search.aggs.metrics.maxTitle', { defaultMessage: 'Max', }); @@ -30,7 +30,7 @@ export const maxMetricAgg = new MetricAggType({ name: METRIC_TYPES.MAX, title: maxTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.maxLabel', { + return i18n.translate('data.search.aggs.metrics.maxLabel', { defaultMessage: 'Max {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/median.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/median.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/median.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/median.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/median.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/median.ts similarity index 88% rename from src/legacy/ui/public/agg_types/metrics/median.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/median.ts index 5792d4a7c2ba3..be080aaa5ee6f 100644 --- a/src/legacy/ui/public/agg_types/metrics/median.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/median.ts @@ -22,9 +22,9 @@ import { METRIC_TYPES } from './metric_agg_types'; // @ts-ignore import { percentilesMetricAgg } from './percentiles'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const medianTitle = i18n.translate('common.ui.aggTypes.metrics.medianTitle', { +const medianTitle = i18n.translate('data.search.aggs.metrics.medianTitle', { defaultMessage: 'Median', }); @@ -33,7 +33,7 @@ export const medianMetricAgg = new MetricAggType({ dslName: 'percentiles', title: medianTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.medianLabel', { + return i18n.translate('data.search.aggs.metrics.medianLabel', { defaultMessage: 'Median {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/metric_agg_type.ts similarity index 95% rename from src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/metric_agg_type.ts index 29499c5be84b8..45617a87f0199 100644 --- a/src/legacy/ui/public/agg_types/metrics/metric_agg_type.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/metric_agg_type.ts @@ -23,7 +23,7 @@ import { AggType, AggTypeConfig } from '../agg_type'; import { AggParamType } from '../param_types/agg'; import { AggConfig } from '../agg_config'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; export interface IMetricAggConfig extends AggConfig { type: InstanceType; @@ -81,7 +81,7 @@ export class MetricAggType({ name: METRIC_TYPES.PERCENTILE_RANKS, - title: i18n.translate('common.ui.aggTypes.metrics.percentileRanksTitle', { + title: i18n.translate('data.search.aggs.metrics.percentileRanksTitle', { defaultMessage: 'Percentile Ranks', }), makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.percentileRanksLabel', { + return i18n.translate('data.search.aggs.metrics.percentileRanksLabel', { defaultMessage: 'Percentile ranks of {field}', values: { field: agg.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/percentiles.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/percentiles.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/percentiles.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/percentiles.ts similarity index 86% rename from src/legacy/ui/public/agg_types/metrics/percentiles.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/percentiles.ts index 9b8205425b4a4..b9f108b44c4cf 100644 --- a/src/legacy/ui/public/agg_types/metrics/percentiles.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/percentiles.ts @@ -19,13 +19,14 @@ import { i18n } from '@kbn/i18n'; +import { PercentilesEditor } from 'ui/vis/editors/default/controls/percentiles'; + import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; import { getPercentileValue } from './percentiles_get_value'; -import { PercentilesEditor } from '../../vis/editors/default/controls/percentiles'; // @ts-ignore import { ordinalSuffix } from './lib/ordinal_suffix'; @@ -37,7 +38,7 @@ const valueProps = { const customLabel = this.getParam('customLabel'); const label = customLabel || this.getFieldDisplayName(); - return i18n.translate('common.ui.aggTypes.metrics.percentiles.valuePropsLabel', { + return i18n.translate('data.search.aggs.metrics.percentiles.valuePropsLabel', { defaultMessage: '{percentile} percentile of {label}', values: { percentile: ordinalSuffix(this.key), label }, }); @@ -46,11 +47,11 @@ const valueProps = { export const percentilesMetricAgg = new MetricAggType({ name: METRIC_TYPES.PERCENTILES, - title: i18n.translate('common.ui.aggTypes.metrics.percentilesTitle', { + title: i18n.translate('data.search.aggs.metrics.percentilesTitle', { defaultMessage: 'Percentiles', }), makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.percentilesLabel', { + return i18n.translate('data.search.aggs.metrics.percentilesLabel', { defaultMessage: 'Percentiles of {field}', values: { field: agg.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/percentiles_get_value.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/percentiles_get_value.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/percentiles_get_value.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/percentiles_get_value.ts diff --git a/src/legacy/ui/public/agg_types/metrics/serial_diff.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/serial_diff.ts similarity index 89% rename from src/legacy/ui/public/agg_types/metrics/serial_diff.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/serial_diff.ts index bb5431fbbefd9..5af6e1952d135 100644 --- a/src/legacy/ui/public/agg_types/metrics/serial_diff.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/serial_diff.ts @@ -23,11 +23,11 @@ import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper'; import { makeNestedLabel } from './lib/make_nested_label'; import { METRIC_TYPES } from './metric_agg_types'; -const serialDiffTitle = i18n.translate('common.ui.aggTypes.metrics.serialDiffTitle', { +const serialDiffTitle = i18n.translate('data.search.aggs.metrics.serialDiffTitle', { defaultMessage: 'Serial Diff', }); -const serialDiffLabel = i18n.translate('common.ui.aggTypes.metrics.serialDiffLabel', { +const serialDiffLabel = i18n.translate('data.search.aggs.metrics.serialDiffLabel', { defaultMessage: 'serial diff', }); diff --git a/src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/sibling_pipeline.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/sibling_pipeline.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/sibling_pipeline.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/std_deviation.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/metrics/std_deviation.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/std_deviation.test.ts diff --git a/src/legacy/ui/public/agg_types/metrics/std_deviation.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/std_deviation.ts similarity index 85% rename from src/legacy/ui/public/agg_types/metrics/std_deviation.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/std_deviation.ts index b2e6d3b3ca4d0..caf3bb71dd89a 100644 --- a/src/legacy/ui/public/agg_types/metrics/std_deviation.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/std_deviation.ts @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; interface ValProp { valProp: string[]; @@ -51,7 +51,7 @@ const responseAggConfigProps = { keyedDetails(this: IStdDevAggConfig, customLabel: string, fieldDisplayName: string) { const label = customLabel || - i18n.translate('common.ui.aggTypes.metrics.standardDeviation.keyDetailsLabel', { + i18n.translate('data.search.aggs.metrics.standardDeviation.keyDetailsLabel', { defaultMessage: 'Standard Deviation of {fieldDisplayName}', values: { fieldDisplayName }, }); @@ -59,14 +59,14 @@ const responseAggConfigProps = { return { std_lower: { valProp: ['std_deviation_bounds', 'lower'], - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.lowerKeyDetailsTitle', { + title: i18n.translate('data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle', { defaultMessage: 'Lower {label}', values: { label }, }), }, std_upper: { valProp: ['std_deviation_bounds', 'upper'], - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviation.upperKeyDetailsTitle', { + title: i18n.translate('data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle', { defaultMessage: 'Upper {label}', values: { label }, }), @@ -78,11 +78,11 @@ const responseAggConfigProps = { export const stdDeviationMetricAgg = new MetricAggType({ name: METRIC_TYPES.STD_DEV, dslName: 'extended_stats', - title: i18n.translate('common.ui.aggTypes.metrics.standardDeviationTitle', { + title: i18n.translate('data.search.aggs.metrics.standardDeviationTitle', { defaultMessage: 'Standard Deviation', }), makeLabel(agg) { - return i18n.translate('common.ui.aggTypes.metrics.standardDeviationLabel', { + return i18n.translate('data.search.aggs.metrics.standardDeviationLabel', { defaultMessage: 'Standard Deviation of {field}', values: { field: agg.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/sum.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/sum.ts similarity index 86% rename from src/legacy/ui/public/agg_types/metrics/sum.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/sum.ts index ce79c761ce799..f3450ba1700c8 100644 --- a/src/legacy/ui/public/agg_types/metrics/sum.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/sum.ts @@ -20,9 +20,9 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -const sumTitle = i18n.translate('common.ui.aggTypes.metrics.sumTitle', { +const sumTitle = i18n.translate('data.search.aggs.metrics.sumTitle', { defaultMessage: 'Sum', }); @@ -30,7 +30,7 @@ export const sumMetricAgg = new MetricAggType({ name: METRIC_TYPES.SUM, title: sumTitle, makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.metrics.sumLabel', { + return i18n.translate('data.search.aggs.metrics.sumLabel', { defaultMessage: 'Sum of {field}', values: { field: aggConfig.getFieldDisplayName() }, }); diff --git a/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/top_hit.test.ts similarity index 99% rename from src/legacy/ui/public/agg_types/metrics/top_hit.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/top_hit.test.ts index 3e861c052d367..a973de4fe8659 100644 --- a/src/legacy/ui/public/agg_types/metrics/top_hit.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/top_hit.test.ts @@ -21,7 +21,7 @@ import { dropRight, last } from 'lodash'; import { topHitMetricAgg } from './top_hit'; import { AggConfigs } from '../agg_configs'; import { IMetricAggConfig } from './metric_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/metrics/top_hit.ts b/src/legacy/core_plugins/data/public/search/agg_types/metrics/top_hit.ts similarity index 83% rename from src/legacy/ui/public/agg_types/metrics/top_hit.ts rename to src/legacy/core_plugins/data/public/search/agg_types/metrics/top_hit.ts index 4b07c997f11e0..84c86d14707f7 100644 --- a/src/legacy/ui/public/agg_types/metrics/top_hit.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/metrics/top_hit.ts @@ -19,15 +19,17 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; + +import { TopSortFieldParamEditor } from 'ui/vis/editors/default/controls/top_sort_field'; +import { OrderParamEditor } from 'ui/vis/editors/default/controls/order'; +import { TopFieldParamEditor } from 'ui/vis/editors/default/controls/top_field'; +import { TopSizeParamEditor } from 'ui/vis/editors/default/controls/top_size'; +import { TopAggregateParamEditor } from 'ui/vis/editors/default/controls/top_aggregate'; + import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; -import { TopSortFieldParamEditor } from '../../vis/editors/default/controls/top_sort_field'; -import { OrderParamEditor } from '../../vis/editors/default/controls/order'; -import { TopFieldParamEditor } from '../../vis/editors/default/controls/top_field'; -import { TopSizeParamEditor } from '../../vis/editors/default/controls/top_size'; -import { TopAggregateParamEditor } from '../../vis/editors/default/controls/top_aggregate'; import { aggTypeFieldFilters } from '../param_types/filter'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; // @ts-ignore import { wrapWithInlineComp } from '../buckets/inline_comp_wrapper'; @@ -51,14 +53,14 @@ aggTypeFieldFilters.addFilter((field, aggConfig) => { export const topHitMetricAgg = new MetricAggType({ name: METRIC_TYPES.TOP_HITS, - title: i18n.translate('common.ui.aggTypes.metrics.topHitTitle', { + title: i18n.translate('data.search.aggs.metrics.topHitTitle', { defaultMessage: 'Top Hit', }), makeLabel(aggConfig) { - const lastPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.lastPrefixLabel', { + const lastPrefixLabel = i18n.translate('data.search.aggs.metrics.topHit.lastPrefixLabel', { defaultMessage: 'Last', }); - const firstPrefixLabel = i18n.translate('common.ui.aggTypes.metrics.topHit.firstPrefixLabel', { + const firstPrefixLabel = i18n.translate('data.search.aggs.metrics.topHit.firstPrefixLabel', { defaultMessage: 'First', }); @@ -113,7 +115,7 @@ export const topHitMetricAgg = new MetricAggType({ editorComponent: wrapWithInlineComp(TopAggregateParamEditor), options: [ { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.minLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.minLabel', { defaultMessage: 'Min', }), isCompatible: isNumericFieldSelected, @@ -121,7 +123,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'min', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.maxLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.maxLabel', { defaultMessage: 'Max', }), isCompatible: isNumericFieldSelected, @@ -129,7 +131,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'max', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.sumLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.sumLabel', { defaultMessage: 'Sum', }), isCompatible: isNumericFieldSelected, @@ -137,7 +139,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'sum', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.averageLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.averageLabel', { defaultMessage: 'Average', }), isCompatible: isNumericFieldSelected, @@ -145,7 +147,7 @@ export const topHitMetricAgg = new MetricAggType({ value: 'average', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.concatenateLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.concatenateLabel', { defaultMessage: 'Concatenate', }), isCompatible(aggConfig: IMetricAggConfig) { @@ -184,13 +186,13 @@ export const topHitMetricAgg = new MetricAggType({ editorComponent: OrderParamEditor, options: [ { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.descendingLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.descendingLabel', { defaultMessage: 'Descending', }), value: 'desc', }, { - text: i18n.translate('common.ui.aggTypes.metrics.topHit.ascendingLabel', { + text: i18n.translate('data.search.aggs.metrics.topHit.ascendingLabel', { defaultMessage: 'Ascending', }), value: 'asc', diff --git a/src/legacy/core_plugins/data/public/search/agg_types/param_types/agg.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/agg.ts new file mode 100644 index 0000000000000..0a83805c8c44c --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/param_types/agg.ts @@ -0,0 +1,57 @@ +/* + * 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 { AggConfig } from '../agg_config'; +import { BaseParamType } from './base'; + +export class AggParamType extends BaseParamType< + TAggConfig +> { + makeAgg: (agg: TAggConfig, state?: any) => TAggConfig; + + constructor(config: Record) { + super(config); + + if (!config.write) { + this.write = (aggConfig: TAggConfig, output: Record) => { + if (aggConfig.params[this.name] && aggConfig.params[this.name].length) { + output.params[this.name] = aggConfig.params[this.name]; + } + }; + } + if (!config.serialize) { + this.serialize = (agg: TAggConfig) => { + return agg.toJSON(); + }; + } + if (!config.deserialize) { + this.deserialize = (state: unknown, agg?: TAggConfig): TAggConfig => { + if (!agg) { + throw new Error('aggConfig was not provided to AggParamType deserialize function'); + } + return this.makeAgg(agg, state); + }; + } + if (!config.editorComponent) { + this.editorComponent = require('../../vis/editors/default/controls/sub_agg'); + } + this.makeAgg = config.makeAgg; + this.valueType = AggConfig; + } +} diff --git a/src/legacy/ui/public/agg_types/param_types/base.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/base.ts similarity index 95% rename from src/legacy/ui/public/agg_types/param_types/base.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/base.ts index bc8fd30e6324e..5060672de06bb 100644 --- a/src/legacy/ui/public/agg_types/param_types/base.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/param_types/base.ts @@ -17,9 +17,9 @@ * under the License. */ +import { AggConfig } from 'ui/vis'; import { AggConfigs } from '../agg_configs'; -import { AggConfig } from '../../vis'; -import { SearchSourceContract, FetchOptions } from '../../courier/types'; +import { ISearchSource, FetchOptions } from '../../types'; export class BaseParamType { name: string; @@ -54,7 +54,7 @@ export class BaseParamType { */ modifyAggConfigOnSearchRequestStart: ( aggConfig: TAggConfig, - searchSource?: SearchSourceContract, + searchSource?: ISearchSource, options?: FetchOptions ) => void; diff --git a/src/legacy/ui/public/agg_types/param_types/field.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/field.test.ts similarity index 98% rename from src/legacy/ui/public/agg_types/param_types/field.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/field.test.ts index 9cea2934d7459..d0fa711d89c70 100644 --- a/src/legacy/ui/public/agg_types/param_types/field.test.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/param_types/field.test.ts @@ -19,7 +19,7 @@ import { BaseParamType } from './base'; import { FieldParamType } from './field'; -import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; +import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); diff --git a/src/legacy/ui/public/agg_types/param_types/field.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/field.ts similarity index 82% rename from src/legacy/ui/public/agg_types/param_types/field.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/field.ts index 4fda86bd1379f..f7c5148d9b4f6 100644 --- a/src/legacy/ui/public/agg_types/param_types/field.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/param_types/field.ts @@ -19,13 +19,13 @@ // @ts-ignore import { i18n } from '@kbn/i18n'; -import { AggConfig } from '../../vis'; -import { SavedObjectNotFound } from '../../../../../plugins/kibana_utils/public'; -import { FieldParamEditor } from '../../vis/editors/default/controls/field'; +import { AggConfig } from 'ui/vis'; +import { toastNotifications } from 'ui/notify'; +import { FieldParamEditor } from 'ui/vis/editors/default/controls/field'; +import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public'; import { BaseParamType } from './base'; -import { toastNotifications } from '../../notify'; import { propFilter } from '../filter'; -import { Field, IFieldList } from '../../index_patterns'; +import { Field, IFieldList } from '../../../../../../../plugins/data/public'; const filterByType = propFilter('type'); @@ -48,15 +48,12 @@ export class FieldParamType extends BaseParamType { if (!field) { throw new TypeError( - i18n.translate( - 'common.ui.aggTypes.paramTypes.field.requiredFieldParameterErrorMessage', - { - defaultMessage: '{fieldParameter} is a required parameter', - values: { - fieldParameter: '"field"', - }, - } - ) + i18n.translate('data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage', { + defaultMessage: '{fieldParameter} is a required parameter', + values: { + fieldParameter: '"field"', + }, + }) ); } @@ -92,7 +89,7 @@ export class FieldParamType extends BaseParamType { if (!validField) { toastNotifications.addDanger( i18n.translate( - 'common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage', + 'data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage', { defaultMessage: 'Saved {fieldParameter} parameter is now invalid. Please select a new field.', diff --git a/src/legacy/ui/public/agg_types/param_types/filter/field_filters.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/filter/field_filters.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/filter/field_filters.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/filter/field_filters.test.ts diff --git a/src/legacy/ui/public/agg_types/param_types/filter/field_filters.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/filter/field_filters.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/filter/field_filters.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/filter/field_filters.ts diff --git a/src/legacy/core_plugins/data/public/search/agg_types/param_types/filter/index.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/filter/index.ts new file mode 100644 index 0000000000000..ce5c7c4f9fea5 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/param_types/filter/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export { aggTypeFieldFilters } from './field_filters'; diff --git a/src/legacy/core_plugins/data/public/search/agg_types/param_types/index.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/index.ts new file mode 100644 index 0000000000000..3414e6a71ecdc --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/param_types/index.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +export * from './base'; +export * from './field'; +export * from './json'; +export * from './optioned'; +export * from './string'; diff --git a/src/legacy/ui/public/agg_types/param_types/json.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/json.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/json.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/json.test.ts diff --git a/src/legacy/ui/public/agg_types/param_types/json.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/json.ts similarity index 96% rename from src/legacy/ui/public/agg_types/param_types/json.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/json.ts index e2878aac3af27..7573d749d3890 100644 --- a/src/legacy/ui/public/agg_types/param_types/json.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/param_types/json.ts @@ -19,7 +19,7 @@ import _ from 'lodash'; import { AggConfig } from 'ui/vis'; -import { RawJsonParamEditor } from '../../vis/editors/default/controls/raw_json'; +import { RawJsonParamEditor } from 'ui/vis/editors/default/controls/raw_json'; import { BaseParamType } from './base'; export class JsonParamType extends BaseParamType { diff --git a/src/legacy/ui/public/agg_types/param_types/optioned.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/optioned.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/optioned.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/optioned.test.ts diff --git a/src/legacy/core_plugins/data/public/search/agg_types/param_types/optioned.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/optioned.ts new file mode 100644 index 0000000000000..a38a4ebbe5e6e --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/param_types/optioned.ts @@ -0,0 +1,59 @@ +/* + * 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 { AggConfig } from 'ui/vis'; +import { BaseParamType } from './base'; + +export interface OptionedValueProp { + value: string; + text: string; + disabled?: boolean; + isCompatible: (agg: AggConfig) => boolean; +} + +export interface OptionedParamEditorProps { + aggParam: { + options: T[]; + }; +} + +export class OptionedParamType extends BaseParamType { + options: OptionedValueProp[]; + + constructor(config: Record) { + super(config); + + if (!config.write) { + this.write = (aggConfig: AggConfig, output: Record) => { + output.params[this.name] = aggConfig.params[this.name].value; + }; + } + if (!config.serialize) { + this.serialize = (selected: OptionedValueProp) => { + return selected.value; + }; + } + if (!config.deserialize) { + this.deserialize = (value: any) => { + return this.options.find((option: OptionedValueProp) => option.value === value); + }; + } + this.options = config.options || []; + } +} diff --git a/src/legacy/ui/public/agg_types/param_types/string.test.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/string.test.ts similarity index 100% rename from src/legacy/ui/public/agg_types/param_types/string.test.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/string.test.ts diff --git a/src/legacy/ui/public/agg_types/param_types/string.ts b/src/legacy/core_plugins/data/public/search/agg_types/param_types/string.ts similarity index 94% rename from src/legacy/ui/public/agg_types/param_types/string.ts rename to src/legacy/core_plugins/data/public/search/agg_types/param_types/string.ts index f87bbb46ec0ee..e13784899ff1b 100644 --- a/src/legacy/ui/public/agg_types/param_types/string.ts +++ b/src/legacy/core_plugins/data/public/search/agg_types/param_types/string.ts @@ -18,7 +18,7 @@ */ import { AggConfig } from 'ui/vis'; -import { StringParamEditor } from '../../vis/editors/default/controls/string'; +import { StringParamEditor } from 'ui/vis/editors/default/controls/string'; import { BaseParamType } from './base'; export class StringParamType extends BaseParamType { diff --git a/src/legacy/core_plugins/data/public/search/agg_types/types.ts b/src/legacy/core_plugins/data/public/search/agg_types/types.ts new file mode 100644 index 0000000000000..3fa2b20485aa8 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/types.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +export { AggParam, AggParamOption } from './agg_params'; +export { DateRangeKey } from './buckets/date_range'; +export { IpRangeKey } from './buckets/ip_range'; +export { OptionedValueProp, OptionedParamEditorProps } from './param_types/optioned'; diff --git a/src/legacy/ui/public/agg_types/utils.test.tsx b/src/legacy/core_plugins/data/public/search/agg_types/utils.test.tsx similarity index 100% rename from src/legacy/ui/public/agg_types/utils.test.tsx rename to src/legacy/core_plugins/data/public/search/agg_types/utils.test.tsx diff --git a/src/legacy/core_plugins/data/public/search/agg_types/utils.ts b/src/legacy/core_plugins/data/public/search/agg_types/utils.ts new file mode 100644 index 0000000000000..64c14fed4ec0f --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/agg_types/utils.ts @@ -0,0 +1,70 @@ +/* + * 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 { leastCommonInterval } from 'ui/vis/lib/least_common_interval'; +import { isValidEsInterval } from '../../../common'; + +/** + * Check a string if it's a valid JSON. + * + * @param {string} value a string that should be validated + * @returns {boolean} true if value is a valid JSON or if value is an empty string, or a string with whitespaces, otherwise false + */ +export function isValidJson(value: string): boolean { + if (!value || value.length === 0) { + return true; + } + + const trimmedValue = value.trim(); + + if (trimmedValue.length === 0) { + return true; + } + + if (trimmedValue[0] === '{' || trimmedValue[0] === '[') { + try { + JSON.parse(trimmedValue); + return true; + } catch (e) { + return false; + } + } else { + return false; + } +} + +export function isValidInterval(value: string, baseInterval?: string) { + if (baseInterval) { + return _parseWithBase(value, baseInterval); + } else { + return isValidEsInterval(value); + } +} + +// When base interval is set, check for least common interval and allow +// input the value is the same. This means that the input interval is a +// multiple of the base interval. +function _parseWithBase(value: string, baseInterval: string) { + try { + const interval = leastCommonInterval(baseInterval, value); + return interval === value.replace(/\s/g, ''); + } catch (e) { + return false; + } +} diff --git a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts index c94d35d1f7f2a..a14e2c8492648 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts +++ b/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts @@ -32,7 +32,7 @@ import { import { npStart } from 'ui/new_platform'; import { SearchSource, - SearchSourceContract, + ISearchSource, getRequestInspectorStats, getResponseInspectorStats, } from '../../../../../ui/public/courier'; @@ -51,7 +51,7 @@ import { PersistedState } from '../../../../../ui/public/persisted_state'; import { Adapters } from '../../../../../../plugins/inspector/public'; export interface RequestHandlerParams { - searchSource: SearchSourceContract; + searchSource: ISearchSource; aggs: AggConfigs; timeRange?: TimeRange; query?: Query; diff --git a/src/legacy/ui/public/courier/fetch/call_client.test.ts b/src/legacy/core_plugins/data/public/search/fetch/call_client.test.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/call_client.test.ts rename to src/legacy/core_plugins/data/public/search/fetch/call_client.test.ts diff --git a/src/legacy/ui/public/courier/fetch/call_client.ts b/src/legacy/core_plugins/data/public/search/fetch/call_client.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/call_client.ts rename to src/legacy/core_plugins/data/public/search/fetch/call_client.ts diff --git a/src/legacy/ui/public/courier/fetch/components/__mocks__/shard_failure_request.ts b/src/legacy/core_plugins/data/public/search/fetch/components/__mocks__/shard_failure_request.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/__mocks__/shard_failure_request.ts rename to src/legacy/core_plugins/data/public/search/fetch/components/__mocks__/shard_failure_request.ts diff --git a/src/legacy/ui/public/courier/fetch/components/__mocks__/shard_failure_response.ts b/src/legacy/core_plugins/data/public/search/fetch/components/__mocks__/shard_failure_response.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/__mocks__/shard_failure_response.ts rename to src/legacy/core_plugins/data/public/search/fetch/components/__mocks__/shard_failure_response.ts diff --git a/src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_description.test.tsx.snap b/src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_description.test.tsx.snap similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_description.test.tsx.snap rename to src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_description.test.tsx.snap diff --git a/src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap b/src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap similarity index 98% rename from src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap rename to src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap index 9a47fff2745c3..f7f3d1c1fbd0c 100644 --- a/src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap +++ b/src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_modal.test.tsx.snap @@ -181,7 +181,7 @@ exports[`ShardFailureModal renders matching snapshot given valid properties 1`] diff --git a/src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_table.test.tsx.snap b/src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_table.test.tsx.snap similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/__snapshots__/shard_failure_table.test.tsx.snap rename to src/legacy/core_plugins/data/public/search/fetch/components/__snapshots__/shard_failure_table.test.tsx.snap diff --git a/src/legacy/ui/public/courier/fetch/components/_shard_failure_modal.scss b/src/legacy/core_plugins/data/public/search/fetch/components/_shard_failure_modal.scss similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/_shard_failure_modal.scss rename to src/legacy/core_plugins/data/public/search/fetch/components/_shard_failure_modal.scss diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_description.test.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.test.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_description.test.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.test.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_description.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.tsx similarity index 96% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_description.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.tsx index 6028a50cf9c3e..60e0e35a0f152 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_description.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { EuiCodeBlock, EuiDescriptionList, EuiSpacer } from '@elastic/eui'; import { ShardFailure } from './shard_failure_types'; -import { getFlattenedObject } from '../../../../../../legacy/utils/get_flattened_object'; +import { getFlattenedObject } from '../../../../../../../legacy/utils/get_flattened_object'; import { ShardFailureDescriptionHeader } from './shard_failure_description_header'; /** diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_description_header.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description_header.tsx similarity index 96% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_description_header.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description_header.tsx index ea4f33f9e914e..947f33efa242c 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_description_header.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_description_header.tsx @@ -35,7 +35,7 @@ export function getFailureSummaryText(failure: ShardFailure, failureDetails?: st const displayDetails = typeof failureDetails === 'string' ? failureDetails : getFailureSummaryDetailsText(failure); - return i18n.translate('common.ui.courier.fetch.shardsFailedModal.failureHeader', { + return i18n.translate('data.search.searchSource.fetch.shardsFailedModal.failureHeader', { defaultMessage: '{failureName} at {failureDetails}', values: { failureName, failureDetails: displayDetails }, description: 'Summary of shard failures, e.g. "IllegalArgumentException at shard 0 node xyz"', diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_modal.test.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.test.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_modal.test.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.test.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_modal.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.tsx similarity index 85% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_modal.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.tsx index d028a831a6e39..65cb49c611575 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_modal.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_modal.tsx @@ -59,15 +59,18 @@ export function ShardFailureModal({ request, response, title, onClose }: Props) const tabs = [ { id: 'table', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tabHeaderShardFailures', { - defaultMessage: 'Shard failures', - description: 'Name of the tab displaying shard failures', - }), + name: i18n.translate( + 'data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures', + { + defaultMessage: 'Shard failures', + description: 'Name of the tab displaying shard failures', + } + ), content: , }, { id: 'json-request', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tabHeaderRequest', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest', { defaultMessage: 'Request', description: 'Name of the tab displaying the JSON request', }), @@ -79,7 +82,7 @@ export function ShardFailureModal({ request, response, title, onClose }: Props) }, { id: 'json-response', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tabHeaderResponse', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse', { defaultMessage: 'Response', description: 'Name of the tab displaying the JSON response', }), @@ -104,7 +107,7 @@ export function ShardFailureModal({ request, response, title, onClose }: Props) {copy => ( @@ -112,7 +115,7 @@ export function ShardFailureModal({ request, response, title, onClose }: Props) onClose()} fill data-test-sub="closeShardFailureModal"> diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.test.mocks.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.test.mocks.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.test.mocks.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.test.mocks.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.test.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.test.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.test.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.test.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.tsx similarity index 92% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.tsx index b02344ce6dd72..d81ee70a4611c 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_open_modal_button.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_open_modal_button.tsx @@ -22,7 +22,7 @@ import { npStart } from 'ui/new_platform'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiTextAlign } from '@elastic/eui'; -import { toMountPoint } from '../../../../../../plugins/kibana_react/public'; +import { toMountPoint } from '../../../../../../../plugins/kibana_react/public'; import { ShardFailureModal } from './shard_failure_modal'; import { ResponseWithShardFailure, Request } from './shard_failure_types'; @@ -57,7 +57,7 @@ export function ShardFailureOpenModalButton({ request, response, title }: Props) data-test-subj="openShardFailureModalBtn" > diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_table.test.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.test.tsx similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_table.test.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.test.tsx diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_table.tsx b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.tsx similarity index 87% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_table.tsx rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.tsx index 7b19102647701..2599177749a9b 100644 --- a/src/legacy/ui/public/courier/fetch/components/shard_failure_table.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_table.tsx @@ -44,7 +44,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { render: (item: ListItem) => { const failureSummeryText = getFailureSummaryText(item); const collapseLabel = i18n.translate( - 'common.ui.courier.fetch.shardsFailedModal.tableRowCollapse', + 'data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse', { defaultMessage: 'Collapse {rowDescription}', description: 'Collapse a row of a table with failures', @@ -53,7 +53,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { ); const expandLabel = i18n.translate( - 'common.ui.courier.fetch.shardsFailedModal.tableRowExpand', + 'data.search.searchSource.fetch.shardsFailedModal.tableRowExpand', { defaultMessage: 'Expand {rowDescription}', description: 'Expand a row of a table with failures', @@ -81,7 +81,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { }, { field: 'shard', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tableColShard', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColShard', { defaultMessage: 'Shard', }), sortable: true, @@ -90,7 +90,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { }, { field: 'index', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tableColIndex', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColIndex', { defaultMessage: 'Index', }), sortable: true, @@ -98,7 +98,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { }, { field: 'node', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tableColNode', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColNode', { defaultMessage: 'Node', }), sortable: true, @@ -106,7 +106,7 @@ export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { }, { field: 'reason.type', - name: i18n.translate('common.ui.courier.fetch.shardsFailedModal.tableColReason', { + name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tableColReason', { defaultMessage: 'Reason', }), truncateText: true, diff --git a/src/legacy/ui/public/courier/fetch/components/shard_failure_types.ts b/src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_types.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/components/shard_failure_types.ts rename to src/legacy/core_plugins/data/public/search/fetch/components/shard_failure_types.ts diff --git a/src/legacy/ui/public/courier/fetch/errors.ts b/src/legacy/core_plugins/data/public/search/fetch/errors.ts similarity index 91% rename from src/legacy/ui/public/courier/fetch/errors.ts rename to src/legacy/core_plugins/data/public/search/fetch/errors.ts index a2ac013915b4b..5f5dc0452df51 100644 --- a/src/legacy/ui/public/courier/fetch/errors.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/errors.ts @@ -17,9 +17,10 @@ * under the License. */ -import { SearchError } from '../../courier'; -import { KbnError } from '../../../../../plugins/kibana_utils/public'; +import { SearchError } from '../search_strategy'; +import { KbnError } from '../../../../../../plugins/kibana_utils/public'; import { SearchResponse } from '../types'; + /** * Request Failure - When an entire multi request fails * @param {Error} err - the Error that came back diff --git a/src/legacy/ui/public/courier/fetch/fetch_soon.test.ts b/src/legacy/core_plugins/data/public/search/fetch/fetch_soon.test.ts similarity index 98% rename from src/legacy/ui/public/courier/fetch/fetch_soon.test.ts rename to src/legacy/core_plugins/data/public/search/fetch/fetch_soon.test.ts index d96fb536985da..69a343c78b1e1 100644 --- a/src/legacy/ui/public/courier/fetch/fetch_soon.test.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/fetch_soon.test.ts @@ -19,7 +19,7 @@ import { fetchSoon } from './fetch_soon'; import { callClient } from './call_client'; -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; import { FetchHandlers, FetchOptions } from './types'; import { SearchRequest, SearchResponse } from '../types'; diff --git a/src/legacy/ui/public/courier/fetch/fetch_soon.ts b/src/legacy/core_plugins/data/public/search/fetch/fetch_soon.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/fetch_soon.ts rename to src/legacy/core_plugins/data/public/search/fetch/fetch_soon.ts diff --git a/src/legacy/ui/public/courier/fetch/get_search_params.test.ts b/src/legacy/core_plugins/data/public/search/fetch/get_search_params.test.ts similarity index 98% rename from src/legacy/ui/public/courier/fetch/get_search_params.test.ts rename to src/legacy/core_plugins/data/public/search/fetch/get_search_params.test.ts index 76f3105d7f942..f856aa77bf1f8 100644 --- a/src/legacy/ui/public/courier/fetch/get_search_params.test.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/get_search_params.test.ts @@ -18,7 +18,7 @@ */ import { getMSearchParams, getSearchParams } from './get_search_params'; -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; function getConfigStub(config: any = {}) { return { diff --git a/src/legacy/ui/public/courier/fetch/get_search_params.ts b/src/legacy/core_plugins/data/public/search/fetch/get_search_params.ts similarity index 97% rename from src/legacy/ui/public/courier/fetch/get_search_params.ts rename to src/legacy/core_plugins/data/public/search/fetch/get_search_params.ts index 9fb8f2c728c6f..de9ec4cb920e8 100644 --- a/src/legacy/ui/public/courier/fetch/get_search_params.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/get_search_params.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; const sessionId = Date.now(); diff --git a/src/legacy/ui/public/courier/fetch/handle_response.test.ts b/src/legacy/core_plugins/data/public/search/fetch/handle_response.test.ts similarity index 95% rename from src/legacy/ui/public/courier/fetch/handle_response.test.ts rename to src/legacy/core_plugins/data/public/search/fetch/handle_response.test.ts index 0163aca777161..f8763a71d840e 100644 --- a/src/legacy/ui/public/courier/fetch/handle_response.test.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/handle_response.test.ts @@ -18,9 +18,9 @@ */ import { handleResponse } from './handle_response'; -import { toastNotifications } from '../../notify/toasts'; +import { toastNotifications } from 'ui/notify/toasts'; -jest.mock('../../notify/toasts', () => { +jest.mock('ui/notify/toasts', () => { return { toastNotifications: { addWarning: jest.fn(), diff --git a/src/legacy/ui/public/courier/fetch/handle_response.tsx b/src/legacy/core_plugins/data/public/search/fetch/handle_response.tsx similarity index 84% rename from src/legacy/ui/public/courier/fetch/handle_response.tsx rename to src/legacy/core_plugins/data/public/search/fetch/handle_response.tsx index d7f2263268f8c..e3fd5ad15242d 100644 --- a/src/legacy/ui/public/courier/fetch/handle_response.tsx +++ b/src/legacy/core_plugins/data/public/search/fetch/handle_response.tsx @@ -20,23 +20,23 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiSpacer } from '@elastic/eui'; -import { toastNotifications } from '../../notify/toasts'; +import { toastNotifications } from 'ui/notify/toasts'; import { ShardFailureOpenModalButton } from './components/shard_failure_open_modal_button'; import { Request, ResponseWithShardFailure } from './components/shard_failure_types'; import { SearchRequest, SearchResponse } from '../types'; -import { toMountPoint } from '../../../../../plugins/kibana_react/public'; +import { toMountPoint } from '../../../../../../plugins/kibana_react/public'; export function handleResponse(request: SearchRequest, response: SearchResponse) { if (response.timed_out) { toastNotifications.addWarning({ - title: i18n.translate('common.ui.courier.fetch.requestTimedOutNotificationMessage', { + title: i18n.translate('data.search.searchSource.fetch.requestTimedOutNotificationMessage', { defaultMessage: 'Data might be incomplete because your request timed out', }), }); } if (response._shards && response._shards.failed) { - const title = i18n.translate('common.ui.courier.fetch.shardsFailedNotificationMessage', { + const title = i18n.translate('data.search.searchSource.fetch.shardsFailedNotificationMessage', { defaultMessage: '{shardsFailed} of {shardsTotal} shards failed', values: { shardsFailed: response._shards.failed, @@ -44,7 +44,7 @@ export function handleResponse(request: SearchRequest, response: SearchResponse) }, }); const description = i18n.translate( - 'common.ui.courier.fetch.shardsFailedNotificationDescription', + 'data.search.searchSource.fetch.shardsFailedNotificationDescription', { defaultMessage: 'The data you are seeing might be incomplete or wrong.', } diff --git a/src/legacy/ui/public/courier/fetch/index.ts b/src/legacy/core_plugins/data/public/search/fetch/index.ts similarity index 100% rename from src/legacy/ui/public/courier/fetch/index.ts rename to src/legacy/core_plugins/data/public/search/fetch/index.ts diff --git a/src/legacy/ui/public/courier/fetch/types.ts b/src/legacy/core_plugins/data/public/search/fetch/types.ts similarity index 95% rename from src/legacy/ui/public/courier/fetch/types.ts rename to src/legacy/core_plugins/data/public/search/fetch/types.ts index 03bf51ae15d45..0887a1f84c7c8 100644 --- a/src/legacy/ui/public/courier/fetch/types.ts +++ b/src/legacy/core_plugins/data/public/search/fetch/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; import { SearchRequest, SearchResponse } from '../types'; export interface ApiCaller { diff --git a/src/legacy/core_plugins/data/public/search/index.ts b/src/legacy/core_plugins/data/public/search/index.ts index 24ffa939a746e..038599e5571e8 100644 --- a/src/legacy/core_plugins/data/public/search/index.ts +++ b/src/legacy/core_plugins/data/public/search/index.ts @@ -17,4 +17,7 @@ * under the License. */ +export * from './agg_types'; export * from './search_bar'; +export * from './search_service'; +export * from './utils'; diff --git a/src/legacy/core_plugins/data/public/search/search_service.ts b/src/legacy/core_plugins/data/public/search/search_service.ts new file mode 100644 index 0000000000000..f616f0c9c7b30 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_service.ts @@ -0,0 +1,83 @@ +/* + * 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 { Plugin, CoreSetup, CoreStart } from '../../../../../core/public'; +import { + aggTypes, + AggType, + AggConfig, + AggConfigs, + FieldParamType, + aggTypeFieldFilters, + setBounds, + parentPipelineAggHelper, +} from './agg_types'; +import { SearchSource } from './search_source'; +import { defaultSearchStrategy } from './search_strategy'; +import { SearchStrategyProvider } from './search_strategy/types'; + +interface AggTypesStart { + types: typeof aggTypes; + AggConfig: typeof AggConfig; + AggConfigs: typeof AggConfigs; + AggType: typeof AggType; + aggTypeFieldFilters: typeof aggTypeFieldFilters; + FieldParamType: typeof FieldParamType; + parentPipelineAggHelper: typeof parentPipelineAggHelper; + setBounds: typeof setBounds; +} + +export interface SearchSetup {} // eslint-disable-line @typescript-eslint/no-empty-interface + +export interface SearchStart { + aggs: AggTypesStart; + defaultSearchStrategy: SearchStrategyProvider; + SearchSource: typeof SearchSource; +} + +/** + * The contract provided here is a new platform shim for ui/courier and ui/agg_types. + * + * Once it has been refactored to work with new platform services, + * it will move into the existing search service in src/plugins/data/public/search + */ +export class SearchService implements Plugin { + public setup(core: CoreSetup): SearchSetup { + return {}; + } + + public start(core: CoreStart): SearchStart { + return { + aggs: { + types: aggTypes, + AggConfig, + AggConfigs, + AggType, + aggTypeFieldFilters, + FieldParamType, + parentPipelineAggHelper, + setBounds, + }, + defaultSearchStrategy, + SearchSource, + }; + } + + public stop() {} +} diff --git a/src/legacy/ui/public/courier/search_source/filter_docvalue_fields.test.ts b/src/legacy/core_plugins/data/public/search/search_source/filter_docvalue_fields.test.ts similarity index 100% rename from src/legacy/ui/public/courier/search_source/filter_docvalue_fields.test.ts rename to src/legacy/core_plugins/data/public/search/search_source/filter_docvalue_fields.test.ts diff --git a/src/legacy/ui/public/courier/search_source/filter_docvalue_fields.ts b/src/legacy/core_plugins/data/public/search/search_source/filter_docvalue_fields.ts similarity index 100% rename from src/legacy/ui/public/courier/search_source/filter_docvalue_fields.ts rename to src/legacy/core_plugins/data/public/search/search_source/filter_docvalue_fields.ts diff --git a/src/legacy/core_plugins/data/public/search/search_source/index.ts b/src/legacy/core_plugins/data/public/search/search_source/index.ts new file mode 100644 index 0000000000000..72170adc2b129 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_source/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export * from './search_source'; diff --git a/src/legacy/core_plugins/data/public/search/search_source/mocks.ts b/src/legacy/core_plugins/data/public/search/search_source/mocks.ts new file mode 100644 index 0000000000000..fd72158012de6 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_source/mocks.ts @@ -0,0 +1,59 @@ +/* + * 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. + */ + +/* + * 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 { ISearchSource } from './search_source'; + +export const searchSourceMock: MockedKeys = { + setPreferredSearchStrategyId: jest.fn(), + setFields: jest.fn().mockReturnThis(), + setField: jest.fn().mockReturnThis(), + getId: jest.fn(), + getFields: jest.fn(), + getField: jest.fn(), + getOwnField: jest.fn(), + create: jest.fn().mockReturnThis(), + createCopy: jest.fn().mockReturnThis(), + createChild: jest.fn().mockReturnThis(), + setParent: jest.fn(), + getParent: jest.fn().mockReturnThis(), + fetch: jest.fn().mockResolvedValue({}), + onRequestStart: jest.fn(), + getSearchRequestBody: jest.fn(), + destroy: jest.fn(), + history: [], +}; diff --git a/src/legacy/ui/public/courier/search_source/normalize_sort_request.test.ts b/src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.test.ts similarity index 97% rename from src/legacy/ui/public/courier/search_source/normalize_sort_request.test.ts rename to src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.test.ts index d27b01eb5cf7c..22d1d931a9d09 100644 --- a/src/legacy/ui/public/courier/search_source/normalize_sort_request.test.ts +++ b/src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.test.ts @@ -19,7 +19,7 @@ import { normalizeSortRequest } from './normalize_sort_request'; import { SortDirection } from './types'; -import { IndexPattern } from '../../../../core_plugins/data/public/index_patterns'; +import { IIndexPattern } from '../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); @@ -40,7 +40,7 @@ describe('SearchSource#normalizeSortRequest', function() { }; const indexPattern = { fields: [scriptedField, murmurScriptedField], - } as IndexPattern; + } as IIndexPattern; it('should return an array', function() { const sortable = { someField: SortDirection.desc }; diff --git a/src/legacy/ui/public/courier/search_source/normalize_sort_request.ts b/src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.ts similarity index 93% rename from src/legacy/ui/public/courier/search_source/normalize_sort_request.ts rename to src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.ts index 0f8fc8076caa0..93834c95514dc 100644 --- a/src/legacy/ui/public/courier/search_source/normalize_sort_request.ts +++ b/src/legacy/core_plugins/data/public/search/search_source/normalize_sort_request.ts @@ -17,12 +17,12 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IIndexPattern } from '../../../../../../plugins/data/public'; import { EsQuerySortValue, SortOptions } from './types'; export function normalizeSortRequest( sortObject: EsQuerySortValue | EsQuerySortValue[], - indexPattern: IndexPattern | string | undefined, + indexPattern: IIndexPattern | string | undefined, defaultSortOptions: SortOptions = {} ) { const sortArray: EsQuerySortValue[] = Array.isArray(sortObject) ? sortObject : [sortObject]; @@ -38,7 +38,7 @@ export function normalizeSortRequest( */ function normalize( sortable: EsQuerySortValue, - indexPattern: IndexPattern | string | undefined, + indexPattern: IIndexPattern | string | undefined, defaultSortOptions: any ) { const [[sortField, sortOrder]] = Object.entries(sortable); diff --git a/src/legacy/ui/public/courier/search_source/search_source.test.ts b/src/legacy/core_plugins/data/public/search/search_source/search_source.test.ts similarity index 98% rename from src/legacy/ui/public/courier/search_source/search_source.test.ts rename to src/legacy/core_plugins/data/public/search/search_source/search_source.test.ts index ddd3717f55e29..28f8dba9a75de 100644 --- a/src/legacy/ui/public/courier/search_source/search_source.test.ts +++ b/src/legacy/core_plugins/data/public/search/search_source/search_source.test.ts @@ -18,7 +18,7 @@ */ import { SearchSource } from '../search_source'; -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; jest.mock('ui/new_platform'); @@ -26,7 +26,7 @@ jest.mock('../fetch', () => ({ fetchSoon: jest.fn().mockResolvedValue({}), })); -jest.mock('../../chrome', () => ({ +jest.mock('ui/chrome', () => ({ dangerouslyGetActiveInjector: () => ({ get: jest.fn(), }), diff --git a/src/legacy/core_plugins/data/public/search/search_source/search_source.ts b/src/legacy/core_plugins/data/public/search/search_source/search_source.ts new file mode 100644 index 0000000000000..01fc34e230a31 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_source/search_source.ts @@ -0,0 +1,410 @@ +/* + * 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. + */ + +/** + * @name SearchSource + * + * @description A promise-based stream of search results that can inherit from other search sources. + * + * Because filters/queries in Kibana have different levels of persistence and come from different + * places, it is important to keep track of where filters come from for when they are saved back to + * the savedObject store in the Kibana index. To do this, we create trees of searchSource objects + * that can have associated query parameters (index, query, filter, etc) which can also inherit from + * other searchSource objects. + * + * At query time, all of the searchSource objects that have subscribers are "flattened", at which + * point the query params from the searchSource are collected while traversing up the inheritance + * chain. At each link in the chain a decision about how to merge the query params is made until a + * single set of query parameters is created for each active searchSource (a searchSource with + * subscribers). + * + * That set of query parameters is then sent to elasticsearch. This is how the filter hierarchy + * works in Kibana. + * + * Visualize, starting from a new search: + * + * - the `savedVis.searchSource` is set as the `appSearchSource`. + * - The `savedVis.searchSource` would normally inherit from the `appSearchSource`, but now it is + * upgraded to inherit from the `rootSearchSource`. + * - Any interaction with the visualization will still apply filters to the `appSearchSource`, so + * they will be stored directly on the `savedVis.searchSource`. + * - Any interaction with the time filter will be written to the `rootSearchSource`, so those + * filters will not be saved by the `savedVis`. + * - When the `savedVis` is saved to elasticsearch, it takes with it all the filters that are + * defined on it directly, but none of the ones that it inherits from other places. + * + * Visualize, starting from an existing search: + * + * - The `savedVis` loads the `savedSearch` on which it is built. + * - The `savedVis.searchSource` is set to inherit from the `saveSearch.searchSource` and set as + * the `appSearchSource`. + * - The `savedSearch.searchSource`, is set to inherit from the `rootSearchSource`. + * - Then the `savedVis` is written to elasticsearch it will be flattened and only include the + * filters created in the visualize application and will reconnect the filters from the + * `savedSearch` at runtime to prevent losing the relationship + * + * Dashboard search sources: + * + * - Each panel in a dashboard has a search source. + * - The `savedDashboard` also has a searchsource, and it is set as the `appSearchSource`. + * - Each panel's search source inherits from the `appSearchSource`, meaning that they inherit from + * the dashboard search source. + * - When a filter is added to the search box, or via a visualization, it is written to the + * `appSearchSource`. + */ + +import _ from 'lodash'; +import { npSetup } from 'ui/new_platform'; +import chrome from 'ui/chrome'; +import { fieldWildcardFilter } from 'ui/field_wildcard'; +import { normalizeSortRequest } from './normalize_sort_request'; +import { fetchSoon } from '../fetch'; +import { getHighlightRequest, esFilters, esQuery } from '../../../../../../plugins/data/public'; +import { RequestFailure } from '../fetch/errors'; +import { filterDocvalueFields } from './filter_docvalue_fields'; +import { SearchSourceOptions, SearchSourceFields, SearchRequest } from './types'; +import { FetchOptions, ApiCaller } from '../fetch/types'; + +const esShardTimeout = npSetup.core.injectedMetadata.getInjectedVar('esShardTimeout') as number; +const config = npSetup.core.uiSettings; + +export type ISearchSource = Pick; + +export class SearchSource { + private id: string = _.uniqueId('data_source'); + private searchStrategyId?: string; + private parent?: SearchSource; + private requestStartHandlers: Array< + (searchSource: ISearchSource, options?: FetchOptions) => Promise + > = []; + private inheritOptions: SearchSourceOptions = {}; + public history: SearchRequest[] = []; + + constructor(private fields: SearchSourceFields = {}) {} + + /** *** + * PUBLIC API + *****/ + + setPreferredSearchStrategyId(searchStrategyId: string) { + this.searchStrategyId = searchStrategyId; + } + + setFields(newFields: SearchSourceFields) { + this.fields = newFields; + return this; + } + + setField(field: K, value: SearchSourceFields[K]) { + if (value == null) { + delete this.fields[field]; + } else { + this.fields[field] = value; + } + return this; + } + + getId() { + return this.id; + } + + getFields() { + return { ...this.fields }; + } + + /** + * Get fields from the fields + */ + getField(field: K, recurse = true): SearchSourceFields[K] { + if (!recurse || this.fields[field] !== void 0) { + return this.fields[field]; + } + const parent = this.getParent(); + return parent && parent.getField(field); + } + + /** + * Get the field from our own fields, don't traverse up the chain + */ + getOwnField(field: K): SearchSourceFields[K] { + return this.getField(field, false); + } + + create() { + return new SearchSource(); + } + + createCopy() { + const newSearchSource = new SearchSource(); + newSearchSource.setFields({ ...this.fields }); + // when serializing the internal fields we lose the internal classes used in the index + // pattern, so we have to set it again to workaround this behavior + newSearchSource.setField('index', this.getField('index')); + newSearchSource.setParent(this.getParent()); + return newSearchSource; + } + + createChild(options = {}) { + const childSearchSource = new SearchSource(); + childSearchSource.setParent(this, options); + return childSearchSource; + } + + /** + * Set a searchSource that this source should inherit from + * @param {SearchSource} parent - the parent searchSource + * @param {SearchSourceOptions} options - the inherit options + * @return {this} - chainable + */ + setParent(parent?: ISearchSource, options: SearchSourceOptions = {}) { + this.parent = parent as SearchSource; + this.inheritOptions = options; + return this; + } + + /** + * Get the parent of this SearchSource + * @return {undefined|searchSource} + */ + getParent() { + return this.parent; + } + + /** + * Fetch this source and reject the returned Promise on error + * + * @async + */ + async fetch(options: FetchOptions = {}) { + const $injector = await chrome.dangerouslyGetActiveInjector(); + const es = $injector.get('es') as ApiCaller; + + await this.requestIsStarting(options); + + const searchRequest = await this.flatten(); + this.history = [searchRequest]; + + const response = await fetchSoon( + searchRequest, + { + ...(this.searchStrategyId && { searchStrategyId: this.searchStrategyId }), + ...options, + }, + { es, config, esShardTimeout } + ); + + if (response.error) { + throw new RequestFailure(null, response); + } + + return response; + } + + /** + * Add a handler that will be notified whenever requests start + * @param {Function} handler + * @return {undefined} + */ + onRequestStart( + handler: (searchSource: ISearchSource, options?: FetchOptions) => Promise + ) { + this.requestStartHandlers.push(handler); + } + + async getSearchRequestBody() { + const searchRequest = await this.flatten(); + return searchRequest.body; + } + + /** + * Completely destroy the SearchSource. + * @return {undefined} + */ + destroy() { + this.requestStartHandlers.length = 0; + } + + /** **** + * PRIVATE APIS + ******/ + + /** + * Called by requests of this search source when they are started + * @param {Courier.Request} request + * @param options + * @return {Promise} + */ + private requestIsStarting(options: FetchOptions = {}) { + const handlers = [...this.requestStartHandlers]; + // If callParentStartHandlers has been set to true, we also call all + // handlers of parent search sources. + if (this.inheritOptions.callParentStartHandlers) { + let searchSource = this.getParent(); + while (searchSource) { + handlers.push(...searchSource.requestStartHandlers); + searchSource = searchSource.getParent(); + } + } + + return Promise.all(handlers.map(fn => fn(this, options))); + } + + /** + * Used to merge properties into the data within ._flatten(). + * The data is passed in and modified by the function + * + * @param {object} data - the current merged data + * @param {*} val - the value at `key` + * @param {*} key - The key of `val` + * @return {undefined} + */ + private mergeProp( + data: SearchRequest, + val: SearchSourceFields[K], + key: K + ) { + val = typeof val === 'function' ? val(this) : val; + if (val == null || !key) return; + + const addToRoot = (rootKey: string, value: any) => { + data[rootKey] = value; + }; + + /** + * Add the key and val to the body of the request + */ + const addToBody = (bodyKey: string, value: any) => { + // ignore if we already have a value + if (data.body[bodyKey] == null) { + data.body[bodyKey] = value; + } + }; + + switch (key) { + case 'filter': + return addToRoot('filters', (data.filters || []).concat(val)); + case 'query': + return addToRoot(key, (data[key] || []).concat(val)); + case 'fields': + const fields = _.uniq((data[key] || []).concat(val)); + return addToRoot(key, fields); + case 'index': + case 'type': + case 'highlightAll': + return key && data[key] == null && addToRoot(key, val); + case 'searchAfter': + return addToBody('search_after', val); + case 'source': + return addToBody('_source', val); + case 'sort': + const sort = normalizeSortRequest(val, this.getField('index'), config.get('sort:options')); + return addToBody(key, sort); + default: + return addToBody(key, val); + } + } + + /** + * Walk the inheritance chain of a source and return its + * flat representation (taking into account merging rules) + * @returns {Promise} + * @resolved {Object|null} - the flat data of the SearchSource + */ + private mergeProps(root = this, searchRequest: SearchRequest = { body: {} }) { + Object.entries(this.fields).forEach(([key, value]) => { + this.mergeProp(searchRequest, value, key as keyof SearchSourceFields); + }); + if (this.parent) { + this.parent.mergeProps(root, searchRequest); + } + return searchRequest; + } + + private flatten() { + const searchRequest = this.mergeProps(); + + searchRequest.body = searchRequest.body || {}; + const { body, index, fields, query, filters, highlightAll } = searchRequest; + + const computedFields = index ? index.getComputedFields() : {}; + + body.stored_fields = computedFields.storedFields; + body.script_fields = body.script_fields || {}; + _.extend(body.script_fields, computedFields.scriptFields); + + const defaultDocValueFields = computedFields.docvalueFields + ? computedFields.docvalueFields + : []; + body.docvalue_fields = body.docvalue_fields || defaultDocValueFields; + + if (!body.hasOwnProperty('_source') && index) { + body._source = index.getSourceFiltering(); + } + + if (body._source) { + // exclude source fields for this index pattern specified by the user + const filter = fieldWildcardFilter(body._source.excludes, config.get('metaFields')); + body.docvalue_fields = body.docvalue_fields.filter((docvalueField: any) => + filter(docvalueField.field) + ); + } + + // if we only want to search for certain fields + if (fields) { + // filter out the docvalue_fields, and script_fields to only include those that we are concerned with + body.docvalue_fields = filterDocvalueFields(body.docvalue_fields, fields); + body.script_fields = _.pick(body.script_fields, fields); + + // request the remaining fields from both stored_fields and _source + const remainingFields = _.difference(fields, _.keys(body.script_fields)); + body.stored_fields = remainingFields; + _.set(body, '_source.includes', remainingFields); + } + + const esQueryConfigs = esQuery.getEsQueryConfig(config); + body.query = esQuery.buildEsQuery(index, query, filters, esQueryConfigs); + + if (highlightAll && body.query) { + body.highlight = getHighlightRequest(body.query, config.get('doc_table:highlight')); + delete searchRequest.highlightAll; + } + + const translateToQuery = (filter: esFilters.Filter) => filter && (filter.query || filter); + + // re-write filters within filter aggregations + (function recurse(aggBranch) { + if (!aggBranch) return; + Object.keys(aggBranch).forEach(function(id) { + const agg = aggBranch[id]; + + if (agg.filters) { + // translate filters aggregations + const { filters: aggFilters } = agg.filters; + Object.keys(aggFilters).forEach(filterId => { + aggFilters[filterId] = translateToQuery(aggFilters[filterId]); + }); + } + + recurse(agg.aggs || agg.aggregations); + }); + })(body.aggs || body.aggregations); + + return searchRequest; + } +} diff --git a/src/legacy/ui/public/courier/search_source/types.ts b/src/legacy/core_plugins/data/public/search/search_source/types.ts similarity index 92% rename from src/legacy/ui/public/courier/search_source/types.ts rename to src/legacy/core_plugins/data/public/search/search_source/types.ts index 293f3d49596c3..41235e47071ca 100644 --- a/src/legacy/ui/public/courier/search_source/types.ts +++ b/src/legacy/core_plugins/data/public/search/search_source/types.ts @@ -17,8 +17,7 @@ * under the License. */ import { NameList } from 'elasticsearch'; -import { esFilters, Query } from '../../../../../plugins/data/public'; -import { IndexPattern } from '../../../../core_plugins/data/public/index_patterns'; +import { esFilters, IndexPattern, Query } from '../../../../../../plugins/data/public'; export type EsQuerySearchAfter = [string | number, string | number]; @@ -53,7 +52,7 @@ export interface SearchSourceOptions { callParentStartHandlers?: boolean; } -export { SearchSourceContract } from './search_source'; +export { ISearchSource } from './search_source'; export interface SortOptions { mode?: 'min' | 'max' | 'sum' | 'avg' | 'median'; diff --git a/src/legacy/ui/public/courier/search_strategy/default_search_strategy.test.ts b/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.test.ts similarity index 98% rename from src/legacy/ui/public/courier/search_strategy/default_search_strategy.test.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.test.ts index 53a857a72c1a3..0ec6a6c2e143e 100644 --- a/src/legacy/ui/public/courier/search_strategy/default_search_strategy.test.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.test.ts @@ -18,7 +18,7 @@ */ import { defaultSearchStrategy } from './default_search_strategy'; -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from '../../../../../../core/public'; import { SearchStrategySearchParams } from './types'; const { search } = defaultSearchStrategy; diff --git a/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.ts b/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.ts new file mode 100644 index 0000000000000..9bfa1df71aa81 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_strategy/default_search_strategy.ts @@ -0,0 +1,78 @@ +/* + * 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 { SearchStrategyProvider, SearchStrategySearchParams } from './types'; +import { isDefaultTypeIndexPattern } from './is_default_type_index_pattern'; +import { + getSearchParams, + getMSearchParams, + getPreference, + getTimeout, +} from '../fetch/get_search_params'; + +export const defaultSearchStrategy: SearchStrategyProvider = { + id: 'default', + + search: params => { + return params.config.get('courier:batchSearches') ? msearch(params) : search(params); + }, + + isViable: indexPattern => { + return indexPattern && isDefaultTypeIndexPattern(indexPattern); + }, +}; + +function msearch({ searchRequests, es, config, esShardTimeout }: SearchStrategySearchParams) { + const inlineRequests = searchRequests.map(({ index, body, search_type: searchType }) => { + const inlineHeader = { + index: index.title || index, + search_type: searchType, + ignore_unavailable: true, + preference: getPreference(config), + }; + const inlineBody = { + ...body, + timeout: getTimeout(esShardTimeout), + }; + return `${JSON.stringify(inlineHeader)}\n${JSON.stringify(inlineBody)}`; + }); + + const searching = es.msearch({ + ...getMSearchParams(config), + body: `${inlineRequests.join('\n')}\n`, + }); + return { + searching: searching.then(({ responses }) => responses), + abort: searching.abort, + }; +} + +function search({ searchRequests, es, config, esShardTimeout }: SearchStrategySearchParams) { + const abortController = new AbortController(); + const searchParams = getSearchParams(config, esShardTimeout); + const promises = searchRequests.map(({ index, body }) => { + const searching = es.search({ index: index.title || index, body, ...searchParams }); + abortController.signal.addEventListener('abort', searching.abort); + return searching.catch(({ response }) => JSON.parse(response)); + }); + return { + searching: Promise.all(promises), + abort: () => abortController.abort(), + }; +} diff --git a/src/legacy/core_plugins/data/public/search/search_strategy/index.ts b/src/legacy/core_plugins/data/public/search/search_strategy/index.ts new file mode 100644 index 0000000000000..1584baa4faade --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_strategy/index.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + +export { + addSearchStrategy, + hasSearchStategyForIndexPattern, + getSearchStrategyById, + getSearchStrategyForSearchRequest, +} from './search_strategy_registry'; + +export { defaultSearchStrategy } from './default_search_strategy'; + +export { isDefaultTypeIndexPattern } from './is_default_type_index_pattern'; + +export { SearchError, getSearchErrorType } from './search_error'; diff --git a/src/legacy/ui/public/courier/search_strategy/is_default_type_index_pattern.ts b/src/legacy/core_plugins/data/public/search/search_strategy/is_default_type_index_pattern.ts similarity index 93% rename from src/legacy/ui/public/courier/search_strategy/is_default_type_index_pattern.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/is_default_type_index_pattern.ts index 3785ce6341078..7d03b1dc9e0b1 100644 --- a/src/legacy/ui/public/courier/search_strategy/is_default_type_index_pattern.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/is_default_type_index_pattern.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; export const isDefaultTypeIndexPattern = (indexPattern: IndexPattern) => { // Default index patterns don't have `type` defined. diff --git a/src/legacy/ui/public/courier/search_strategy/no_op_search_strategy.ts b/src/legacy/core_plugins/data/public/search/search_strategy/no_op_search_strategy.ts similarity index 83% rename from src/legacy/ui/public/courier/search_strategy/no_op_search_strategy.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/no_op_search_strategy.ts index 24c3876cfcc05..dc7331e614a0e 100644 --- a/src/legacy/ui/public/courier/search_strategy/no_op_search_strategy.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/no_op_search_strategy.ts @@ -27,11 +27,14 @@ export const noOpSearchStrategy: SearchStrategyProvider = { search: () => { const searchError = new SearchError({ status: '418', // "I'm a teapot" error - title: i18n.translate('common.ui.courier.noSearchStrategyRegisteredErrorMessageTitle', { - defaultMessage: 'No search strategy registered', - }), + title: i18n.translate( + 'data.search.searchSource.noSearchStrategyRegisteredErrorMessageTitle', + { + defaultMessage: 'No search strategy registered', + } + ), message: i18n.translate( - 'common.ui.courier.noSearchStrategyRegisteredErrorMessageDescription', + 'data.search.searchSource.noSearchStrategyRegisteredErrorMessageDescription', { defaultMessage: `Couldn't find a search strategy for the search request`, } diff --git a/src/legacy/core_plugins/data/public/search/search_strategy/search_error.ts b/src/legacy/core_plugins/data/public/search/search_strategy/search_error.ts new file mode 100644 index 0000000000000..d4042fb17499c --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_strategy/search_error.ts @@ -0,0 +1,62 @@ +/* + * 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. + */ + +interface SearchErrorOptions { + status: string; + title: string; + message: string; + path: string; + type: string; +} + +export class SearchError extends Error { + public name: string; + public status: string; + public title: string; + public message: string; + public path: string; + public type: string; + + constructor({ status, title, message, path, type }: SearchErrorOptions) { + super(message); + this.name = 'SearchError'; + this.status = status; + this.title = title; + this.message = message; + this.path = path; + this.type = type; + + // captureStackTrace is only available in the V8 engine, so any browser using + // a different JS engine won't have access to this method. + if (Error.captureStackTrace) { + Error.captureStackTrace(this, SearchError); + } + + // Babel doesn't support traditional `extends` syntax for built-in classes. + // https://babeljs.io/docs/en/caveats/#classes + Object.setPrototypeOf(this, SearchError.prototype); + } +} + +export function getSearchErrorType({ message }: Pick) { + const msg = message.toLowerCase(); + if (msg.indexOf('unsupported query') > -1) { + return 'UNSUPPORTED_QUERY'; + } +} diff --git a/src/legacy/ui/public/courier/search_strategy/search_strategy_registry.test.ts b/src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.test.ts similarity index 98% rename from src/legacy/ui/public/courier/search_strategy/search_strategy_registry.test.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.test.ts index ae2ed6128c8ea..73b011896a97d 100644 --- a/src/legacy/ui/public/courier/search_strategy/search_strategy_registry.test.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; import { noOpSearchStrategy } from './no_op_search_strategy'; import { searchStrategies, diff --git a/src/legacy/ui/public/courier/search_strategy/search_strategy_registry.ts b/src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.ts similarity index 97% rename from src/legacy/ui/public/courier/search_strategy/search_strategy_registry.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.ts index 9ef007f97531e..d814a04737f75 100644 --- a/src/legacy/ui/public/courier/search_strategy/search_strategy_registry.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/search_strategy_registry.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; import { SearchStrategyProvider } from './types'; import { noOpSearchStrategy } from './no_op_search_strategy'; import { SearchResponse } from '../types'; diff --git a/src/legacy/ui/public/courier/search_strategy/types.ts b/src/legacy/core_plugins/data/public/search/search_strategy/types.ts similarity index 94% rename from src/legacy/ui/public/courier/search_strategy/types.ts rename to src/legacy/core_plugins/data/public/search/search_strategy/types.ts index 1542f9824a5b1..ad8576589e4e3 100644 --- a/src/legacy/ui/public/courier/search_strategy/types.ts +++ b/src/legacy/core_plugins/data/public/search/search_strategy/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../core_plugins/data/public'; +import { IndexPattern } from '../../../../../../plugins/data/public'; import { FetchHandlers } from '../fetch/types'; import { SearchRequest, SearchResponse } from '../types'; diff --git a/src/legacy/core_plugins/data/public/search/types.ts b/src/legacy/core_plugins/data/public/search/types.ts new file mode 100644 index 0000000000000..94cb2814607af --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/types.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +export * from './agg_types/types'; +export * from './fetch/types'; +export * from './search_source/types'; +export * from './search_strategy/types'; +export * from './utils/types'; diff --git a/src/legacy/ui/public/courier/utils/courier_inspector_utils.ts b/src/legacy/core_plugins/data/public/search/utils/courier_inspector_utils.ts similarity index 72% rename from src/legacy/ui/public/courier/utils/courier_inspector_utils.ts rename to src/legacy/core_plugins/data/public/search/utils/courier_inspector_utils.ts index b4d5d5537333e..7f7d216d8f0f3 100644 --- a/src/legacy/ui/public/courier/utils/courier_inspector_utils.ts +++ b/src/legacy/core_plugins/data/public/search/utils/courier_inspector_utils.ts @@ -26,28 +26,28 @@ import { i18n } from '@kbn/i18n'; import { SearchResponse } from 'elasticsearch'; -import { SearchSourceContract, RequestInspectorStats } from '../types'; +import { ISearchSource, RequestInspectorStats } from '../types'; -export function getRequestInspectorStats(searchSource: SearchSourceContract) { +export function getRequestInspectorStats(searchSource: ISearchSource) { const stats: RequestInspectorStats = {}; const index = searchSource.getField('index'); if (index) { stats.indexPattern = { - label: i18n.translate('common.ui.courier.indexPatternLabel', { + label: i18n.translate('data.search.searchSource.indexPatternLabel', { defaultMessage: 'Index pattern', }), value: index.title, - description: i18n.translate('common.ui.courier.indexPatternDescription', { + description: i18n.translate('data.search.searchSource.indexPatternDescription', { defaultMessage: 'The index pattern that connected to the Elasticsearch indices.', }), }; stats.indexPatternId = { - label: i18n.translate('common.ui.courier.indexPatternIdLabel', { + label: i18n.translate('data.search.searchSource.indexPatternIdLabel', { defaultMessage: 'Index pattern ID', }), value: index.id!, - description: i18n.translate('common.ui.courier.indexPatternIdDescription', { + description: i18n.translate('data.search.searchSource.indexPatternIdDescription', { defaultMessage: 'The ID in the {kibanaIndexPattern} index.', values: { kibanaIndexPattern: '.kibana' }, }), @@ -58,7 +58,7 @@ export function getRequestInspectorStats(searchSource: SearchSourceContract) { } export function getResponseInspectorStats( - searchSource: SearchSourceContract, + searchSource: ISearchSource, resp: SearchResponse ) { const lastRequest = searchSource.history && searchSource.history[searchSource.history.length - 1]; @@ -66,14 +66,14 @@ export function getResponseInspectorStats( if (resp && resp.took) { stats.queryTime = { - label: i18n.translate('common.ui.courier.queryTimeLabel', { + label: i18n.translate('data.search.searchSource.queryTimeLabel', { defaultMessage: 'Query time', }), - value: i18n.translate('common.ui.courier.queryTimeValue', { + value: i18n.translate('data.search.searchSource.queryTimeValue', { defaultMessage: '{queryTime}ms', values: { queryTime: resp.took }, }), - description: i18n.translate('common.ui.courier.queryTimeDescription', { + description: i18n.translate('data.search.searchSource.queryTimeDescription', { defaultMessage: 'The time it took to process the query. ' + 'Does not include the time to send the request or parse it in the browser.', @@ -83,21 +83,21 @@ export function getResponseInspectorStats( if (resp && resp.hits) { stats.hitsTotal = { - label: i18n.translate('common.ui.courier.hitsTotalLabel', { + label: i18n.translate('data.search.searchSource.hitsTotalLabel', { defaultMessage: 'Hits (total)', }), value: `${resp.hits.total}`, - description: i18n.translate('common.ui.courier.hitsTotalDescription', { + description: i18n.translate('data.search.searchSource.hitsTotalDescription', { defaultMessage: 'The number of documents that match the query.', }), }; stats.hits = { - label: i18n.translate('common.ui.courier.hitsLabel', { + label: i18n.translate('data.search.searchSource.hitsLabel', { defaultMessage: 'Hits', }), value: `${resp.hits.hits.length}`, - description: i18n.translate('common.ui.courier.hitsDescription', { + description: i18n.translate('data.search.searchSource.hitsDescription', { defaultMessage: 'The number of documents returned by the query.', }), }; @@ -105,14 +105,14 @@ export function getResponseInspectorStats( if (lastRequest && (lastRequest.ms === 0 || lastRequest.ms)) { stats.requestTime = { - label: i18n.translate('common.ui.courier.requestTimeLabel', { + label: i18n.translate('data.search.searchSource.requestTimeLabel', { defaultMessage: 'Request time', }), - value: i18n.translate('common.ui.courier.requestTimeValue', { + value: i18n.translate('data.search.searchSource.requestTimeValue', { defaultMessage: '{requestTime}ms', values: { requestTime: lastRequest.ms }, }), - description: i18n.translate('common.ui.courier.requestTimeDescription', { + description: i18n.translate('data.search.searchSource.requestTimeDescription', { defaultMessage: 'The time of the request from the browser to Elasticsearch and back. ' + 'Does not include the time the requested waited in the queue.', diff --git a/src/legacy/core_plugins/data/public/search/utils/index.ts b/src/legacy/core_plugins/data/public/search/utils/index.ts new file mode 100644 index 0000000000000..021ece8701e98 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/utils/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export * from './courier_inspector_utils'; diff --git a/src/legacy/ui/public/courier/utils/types.ts b/src/legacy/core_plugins/data/public/search/utils/types.ts similarity index 100% rename from src/legacy/ui/public/courier/utils/types.ts rename to src/legacy/core_plugins/data/public/search/utils/types.ts diff --git a/src/legacy/core_plugins/kbn_doc_views/public/views/table/table.test.tsx b/src/legacy/core_plugins/kbn_doc_views/public/views/table/table.test.tsx index bad006aa8c7d5..24efbc2d41f4f 100644 --- a/src/legacy/core_plugins/kbn_doc_views/public/views/table/table.test.tsx +++ b/src/legacy/core_plugins/kbn_doc_views/public/views/table/table.test.tsx @@ -24,6 +24,8 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { flattenHitWrapper } from '../../../../data/public/'; import { DocViewTable } from './table'; +jest.mock('ui/new_platform'); + // @ts-ignore const indexPattern = { fields: { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts index 20544fa97fdb0..30e5a9c95a4a4 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/saved_dashboard/saved_dashboard.d.ts @@ -18,7 +18,7 @@ */ import { SavedObject } from 'ui/saved_objects/types'; -import { SearchSourceContract } from '../../../../../ui/public/courier'; +import { ISearchSource } from '../../../../../ui/public/courier'; import { esFilters, Query, RefreshInterval } from '../../../../../../plugins/data/public'; export interface SavedObjectDashboard extends SavedObject { @@ -34,7 +34,7 @@ export interface SavedObjectDashboard extends SavedObject { // TODO: write a migration to rid of this, it's only around for bwc. uiStateJSON?: string; lastSavedTitle: string; - searchSource: SearchSourceContract; + searchSource: ISearchSource; destroy: () => void; refreshInterval?: RefreshInterval; getQuery(): Query; diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/context/api/utils/fetch_hits_in_interval.ts b/src/legacy/core_plugins/kibana/public/discover/angular/context/api/utils/fetch_hits_in_interval.ts index 19c2ee2cdfe10..5de936f4c17de 100644 --- a/src/legacy/core_plugins/kibana/public/discover/angular/context/api/utils/fetch_hits_in_interval.ts +++ b/src/legacy/core_plugins/kibana/public/discover/angular/context/api/utils/fetch_hits_in_interval.ts @@ -19,7 +19,7 @@ import { EsQuerySortValue, SortDirection, - SearchSourceContract, + ISearchSource, } from '../../../../../../../../ui/public/courier'; import { convertTimeValueToIso } from './date_conversion'; import { EsHitRecordList } from '../context'; @@ -40,7 +40,7 @@ interface RangeQuery { * and filters set. */ export async function fetchHitsInInterval( - searchSource: SearchSourceContract, + searchSource: ISearchSource, timeField: string, sort: [EsQuerySortValue, EsQuerySortValue], sortDir: SortDirection, diff --git a/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts b/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts index 273c7d80f216c..c73b3eeadfd71 100644 --- a/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts @@ -21,7 +21,7 @@ import * as Rx from 'rxjs'; import { Subscription } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { TExecuteTriggerActions } from 'src/plugins/ui_actions/public'; -import { SearchSourceContract } from '../../../../../ui/public/courier'; +import { ISearchSource } from '../../../../../ui/public/courier'; import { esFilters, TimeRange, @@ -89,7 +89,7 @@ export class SearchEmbeddable extends Embeddable private inspectorAdaptors: Adapters; private searchScope?: SearchScope; private panelTitle: string = ''; - private filtersSearchSource?: SearchSourceContract; + private filtersSearchSource?: ISearchSource; private searchInstance?: JQLite; private autoRefreshFetchSubscription?: Subscription; private subscription?: Subscription; diff --git a/src/legacy/core_plugins/kibana/public/discover/types.d.ts b/src/legacy/core_plugins/kibana/public/discover/types.d.ts index 6cdd802fa2800..cf7b552e8d171 100644 --- a/src/legacy/core_plugins/kibana/public/discover/types.d.ts +++ b/src/legacy/core_plugins/kibana/public/discover/types.d.ts @@ -17,14 +17,14 @@ * under the License. */ -import { SearchSourceContract } from '../../../../ui/public/courier'; +import { ISearchSource } from '../../../../ui/public/courier'; import { SortOrder } from './angular/doc_table/components/table_header/helpers'; export { SortOrder } from './angular/doc_table/components/table_header/helpers'; export interface SavedSearch { readonly id: string; title: string; - searchSource: SearchSourceContract; + searchSource: ISearchSource; description?: string; columns: string[]; sort: SortOrder[]; diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts index 8e414984a0c08..081865424a1a3 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts @@ -29,7 +29,7 @@ import { getTableAggs } from 'ui/visualize/loader/pipeline_helpers/utilities'; import { AppState } from 'ui/state_management/app_state'; import { npStart } from 'ui/new_platform'; import { IExpressionLoaderParams } from 'src/plugins/expressions/public'; -import { SearchSourceContract } from '../../../../../ui/public/courier'; +import { ISearchSource } from '../../../../../ui/public/courier'; import { VISUALIZE_EMBEDDABLE_TYPE } from './constants'; import { IIndexPattern, @@ -53,7 +53,7 @@ const getKeys = (o: T): Array => Object.keys(o) as Array< export interface VisSavedObject extends SavedObject { vis: Vis; description?: string; - searchSource: SearchSourceContract; + searchSource: ISearchSource; title: string; uiStateJSON?: string; destroy: () => void; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts index 0f9e9c11a9dbc..59c6bddb64521 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts @@ -28,7 +28,7 @@ import { createFormat, } from '../../../legacy_imports'; // eslint-disable-next-line -import { SearchSourceContract } from '../../../../../../ui/public/courier/search_source/search_source'; +import { ISearchSource } from '../../../../../../ui/public/courier/search_source/search_source'; import { Vis, VisParams, VisState } from '..'; interface SchemaConfigParams { @@ -466,7 +466,7 @@ export const buildVislibDimensions = async ( // take a Vis object and decorate it with the necessary params (dimensions, bucket, metric, etc) export const getVisParams = async ( vis: Vis, - params: { searchSource: SearchSourceContract; timeRange?: any; abortSignal?: AbortSignal } + params: { searchSource: ISearchSource; timeRange?: any; abortSignal?: AbortSignal } ) => { const schemas = getSchemas(vis, params.timeRange); let visConfig = cloneDeep(vis.params); @@ -484,7 +484,7 @@ export const getVisParams = async ( export const buildPipeline = async ( vis: Vis, params: { - searchSource: SearchSourceContract; + searchSource: ISearchSource; timeRange?: any; } ) => { diff --git a/src/legacy/ui/public/agg_types/agg_config.ts b/src/legacy/ui/public/agg_types/agg_config.ts index 9306ffcaff9fd..489751a83724d 100644 --- a/src/legacy/ui/public/agg_types/agg_config.ts +++ b/src/legacy/ui/public/agg_types/agg_config.ts @@ -17,446 +17,4 @@ * under the License. */ -/** - * @name AggConfig - * - * @description This class represents an aggregation, which is displayed in the left-hand nav of - * the Visualize app. - */ - -import _ from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { SearchSourceContract, FetchOptions } from '../courier/types'; -import { AggType } from './agg_type'; -import { AggGroupNames } from '../vis/editors/default/agg_groups'; -import { writeParams } from './agg_params'; -import { AggConfigs } from './agg_configs'; -import { Schema } from '../vis/editors/default/schemas'; -import { ContentType, KBN_FIELD_TYPES } from '../../../../plugins/data/public'; - -export interface AggConfigOptions { - enabled: boolean; - type: string; - params: any; - id?: string; - schema?: string; -} - -const unknownSchema: Schema = { - name: 'unknown', - title: 'Unknown', - hideCustomLabel: true, - aggFilter: [], - min: 1, - max: 1, - params: [], - defaults: {}, - editor: false, - group: AggGroupNames.Metrics, -}; - -const getTypeFromRegistry = (type: string): AggType => { - // We need to inline require here, since we're having a cyclic dependency - // from somewhere inside agg_types back to AggConfig. - const aggTypes = require('../agg_types').aggTypes; - const registeredType = - aggTypes.metrics.find((agg: AggType) => agg.name === type) || - aggTypes.buckets.find((agg: AggType) => agg.name === type); - - if (!registeredType) { - throw new Error('unknown type'); - } - - return registeredType; -}; - -const getSchemaFromRegistry = (schemas: any, schema: string): Schema => { - let registeredSchema = schemas ? schemas.byName[schema] : null; - if (!registeredSchema) { - registeredSchema = Object.assign({}, unknownSchema); - registeredSchema.name = schema; - } - - return registeredSchema; -}; - -export class AggConfig { - /** - * Ensure that all of the objects in the list have ids, the objects - * and list are modified by reference. - * - * @param {array[object]} list - a list of objects, objects can be anything really - * @return {array} - the list that was passed in - */ - static ensureIds(list: AggConfig[]) { - const have: AggConfig[] = []; - const haveNot: AggConfig[] = []; - list.forEach(function(obj) { - (obj.id ? have : haveNot).push(obj); - }); - - let nextId = AggConfig.nextId(have); - haveNot.forEach(function(obj) { - obj.id = String(nextId++); - }); - - return list; - } - - /** - * Calculate the next id based on the ids in this list - * - * @return {array} list - a list of objects with id properties - */ - static nextId(list: AggConfig[]) { - return ( - 1 + - list.reduce(function(max, obj) { - return Math.max(max, +obj.id || 0); - }, 0) - ); - } - - public aggConfigs: AggConfigs; - public id: string; - public enabled: boolean; - public params: any; - public parent?: AggConfigs; - - private __schema: Schema; - private __type: AggType; - private __typeDecorations: any; - private subAggs: AggConfig[] = []; - - constructor(aggConfigs: AggConfigs, opts: AggConfigOptions) { - this.aggConfigs = aggConfigs; - this.id = String(opts.id || AggConfig.nextId(aggConfigs.aggs as any)); - this.enabled = typeof opts.enabled === 'boolean' ? opts.enabled : true; - - // start with empty params so that checks in type/schema setters don't freak - // because this.params is undefined - this.params = {}; - - // setters - this.setType(opts.type); - - if (opts.schema) { - this.setSchema(opts.schema); - } - - // set the params to the values from opts, or just to the defaults - this.setParams(opts.params || {}); - - // @ts-ignore - this.__type = this.__type; - // @ts-ignore - this.__schema = this.__schema; - } - - /** - * Write the current values to this.params, filling in the defaults as we go - * - * @param {object} [from] - optional object to read values from, - * used when initializing - * @return {undefined} - */ - setParams(from: any) { - from = from || this.params || {}; - const to = (this.params = {} as any); - - this.getAggParams().forEach(aggParam => { - let val = from[aggParam.name]; - - if (val == null) { - if (aggParam.default == null) return; - - if (!_.isFunction(aggParam.default)) { - val = aggParam.default; - } else { - val = aggParam.default(this); - if (val == null) return; - } - } - - if (aggParam.deserialize) { - const isTyped = _.isFunction(aggParam.valueType); - - const isType = isTyped && val instanceof aggParam.valueType; - const isObject = !isTyped && _.isObject(val); - const isDeserialized = isType || isObject; - - if (!isDeserialized) { - val = aggParam.deserialize(val, this); - } - - to[aggParam.name] = val; - return; - } - - to[aggParam.name] = _.cloneDeep(val); - }); - } - - getParam(key: string): any { - return _.get(this.params, key); - } - - write(aggs?: AggConfigs) { - return writeParams(this.type.params, this, aggs); - } - - isFilterable() { - return _.isFunction(this.type.createFilter); - } - - createFilter(key: string, params = {}) { - const createFilter = this.type.createFilter; - - if (!createFilter) { - throw new TypeError(`The "${this.type.title}" aggregation does not support filtering.`); - } - - const field = this.getField(); - const label = this.getFieldDisplayName(); - if (field && !field.filterable) { - let message = `The "${label}" field can not be used for filtering.`; - if (field.scripted) { - message = `The "${label}" field is scripted and can not be used for filtering.`; - } - throw new TypeError(message); - } - - return createFilter(this, key, params); - } - - /** - * Hook for pre-flight logic, see AggType#onSearchRequestStart - * @param {Courier.SearchSource} searchSource - * @param {Courier.FetchOptions} options - * @return {Promise} - */ - onSearchRequestStart(searchSource: SearchSourceContract, options?: FetchOptions) { - if (!this.type) { - return Promise.resolve(); - } - - return Promise.all( - this.type.params.map((param: any) => - param.modifyAggConfigOnSearchRequestStart(this, searchSource, options) - ) - ); - } - - /** - * Convert this aggConfig to its dsl syntax. - * - * Adds params and adhoc subaggs to a pojo, then returns it - * - * @param {AggConfigs} aggConfigs - the config object to convert - * @return {void|Object} - if the config has a dsl representation, it is - * returned, else undefined is returned - */ - toDsl(aggConfigs?: AggConfigs) { - if (this.type.hasNoDsl) return; - const output = this.write(aggConfigs) as any; - - const configDsl = {} as any; - configDsl[this.type.dslName || this.type.name] = output.params; - - // if the config requires subAggs, write them to the dsl as well - if (this.subAggs.length && !output.subAggs) output.subAggs = this.subAggs; - if (output.subAggs) { - const subDslLvl = configDsl.aggs || (configDsl.aggs = {}); - output.subAggs.forEach(function nestAdhocSubAggs(subAggConfig: any) { - subDslLvl[subAggConfig.id] = subAggConfig.toDsl(aggConfigs); - }); - } - - if (output.parentAggs) { - const subDslLvl = configDsl.parentAggs || (configDsl.parentAggs = {}); - output.parentAggs.forEach(function nestAdhocSubAggs(subAggConfig: any) { - subDslLvl[subAggConfig.id] = subAggConfig.toDsl(aggConfigs); - }); - } - - return configDsl; - } - - toJSON() { - const params = this.params; - - const outParams = _.transform( - this.getAggParams(), - (out, aggParam) => { - let val = params[aggParam.name]; - - // don't serialize undefined/null values - if (val == null) return; - if (aggParam.serialize) val = aggParam.serialize(val, this); - if (val == null) return; - - // to prevent accidental leaking, we will clone all complex values - out[aggParam.name] = _.cloneDeep(val); - }, - {} - ); - - return { - id: this.id, - enabled: this.enabled, - type: this.type && this.type.name, - schema: _.get(this, 'schema.name', this.schema), - params: outParams, - }; - } - - getAggParams() { - return [ - ...(_.has(this, 'type.params') ? this.type.params : []), - ...(_.has(this, 'schema.params') ? (this.schema as Schema).params : []), - ]; - } - - getRequestAggs() { - return (this.type && this.type.getRequestAggs(this)) || [this]; - } - - getResponseAggs() { - return (this.type && this.type.getResponseAggs(this)) || [this]; - } - - getValue(bucket: any) { - return this.type.getValue(this, bucket); - } - - getKey(bucket: any, key?: string) { - if (this.type.getKey) { - return this.type.getKey(bucket, key, this); - } else { - return ''; - } - } - - getFieldDisplayName() { - const field = this.getField(); - - return field ? field.displayName || this.fieldName() : ''; - } - - getField() { - return this.params.field; - } - - makeLabel(percentageMode = false) { - if (this.params.customLabel) { - return this.params.customLabel; - } - - if (!this.type) return ''; - return percentageMode - ? i18n.translate('common.ui.vis.aggConfig.percentageOfLabel', { - defaultMessage: 'Percentage of {label}', - values: { label: this.type.makeLabel(this) }, - }) - : `${this.type.makeLabel(this)}`; - } - - getIndexPattern() { - return this.aggConfigs.indexPattern; - } - - getTimeRange() { - return this.aggConfigs.timeRange; - } - - fieldFormatter(contentType?: ContentType, defaultFormat?: any) { - const format = this.type && this.type.getFormat(this); - - if (format) { - return format.getConverterFor(contentType); - } - - return this.fieldOwnFormatter(contentType, defaultFormat); - } - - fieldOwnFormatter(contentType?: ContentType, defaultFormat?: any) { - const fieldFormats = npStart.plugins.data.fieldFormats; - const field = this.getField(); - let format = field && field.format; - if (!format) format = defaultFormat; - if (!format) format = fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.STRING); - return format.getConverterFor(contentType); - } - - fieldName() { - const field = this.getField(); - return field ? field.name : ''; - } - - fieldIsTimeField() { - const indexPattern = this.getIndexPattern(); - if (!indexPattern) return false; - // @ts-ignore - const timeFieldName = indexPattern.timeFieldName; - return timeFieldName && this.fieldName() === timeFieldName; - } - - public get type() { - return this.__type; - } - - public set type(type) { - if (this.__typeDecorations) { - _.forOwn( - this.__typeDecorations, - function(prop, name: string | undefined) { - // @ts-ignore - delete this[name]; - }, - this - ); - } - - if (type && _.isFunction(type.decorateAggConfig)) { - this.__typeDecorations = type.decorateAggConfig(); - Object.defineProperties(this, this.__typeDecorations); - } - - this.__type = type; - let availableFields = []; - - const fieldParam = this.type && this.type.params.find((p: any) => p.type === 'field'); - - if (fieldParam) { - // @ts-ignore - availableFields = fieldParam.getAvailableFields(this.getIndexPattern().fields); - } - - // clear out the previous params except for a few special ones - this.setParams({ - // split row/columns is "outside" of the agg, so don't reset it - row: this.params.row, - - // almost every agg has fields, so we try to persist that when type changes - field: availableFields.find((field: any) => field.name === this.getField()), - }); - } - - public setType(type: string | AggType) { - this.type = typeof type === 'string' ? getTypeFromRegistry(type) : type; - } - - public get schema() { - return this.__schema; - } - - public set schema(schema) { - this.__schema = schema; - } - - public setSchema(schema: string | Schema) { - this.schema = - typeof schema === 'string' ? getSchemaFromRegistry(this.aggConfigs.schemas, schema) : schema; - } -} +export { AggConfig } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_configs.ts b/src/legacy/ui/public/agg_types/agg_configs.ts index b5a7474c99b0e..a04585dd82bdc 100644 --- a/src/legacy/ui/public/agg_types/agg_configs.ts +++ b/src/legacy/ui/public/agg_types/agg_configs.ts @@ -17,299 +17,4 @@ * under the License. */ -/** - * @name AggConfig - * - * @extends IndexedArray - * - * @description A "data structure"-like class with methods for indexing and - * accessing instances of AggConfig. - */ - -import _ from 'lodash'; -import { TimeRange } from 'src/plugins/data/public'; -import { Schema } from '../vis/editors/default/schemas'; -import { AggConfig, AggConfigOptions } from './agg_config'; -import { AggGroupNames } from '../vis/editors/default/agg_groups'; -import { IndexPattern } from '../../../core_plugins/data/public'; -import { SearchSourceContract, FetchOptions } from '../courier/types'; - -type Schemas = Record; - -function removeParentAggs(obj: any) { - for (const prop in obj) { - if (prop === 'parentAggs') delete obj[prop]; - else if (typeof obj[prop] === 'object') removeParentAggs(obj[prop]); - } -} - -function parseParentAggs(dslLvlCursor: any, dsl: any) { - if (dsl.parentAggs) { - _.each(dsl.parentAggs, (agg, key) => { - dslLvlCursor[key as string] = agg; - parseParentAggs(dslLvlCursor, agg); - }); - } -} - -export class AggConfigs { - public indexPattern: IndexPattern; - public schemas: any; - public timeRange?: TimeRange; - - aggs: AggConfig[]; - - constructor(indexPattern: IndexPattern, configStates = [] as any, schemas?: any) { - configStates = AggConfig.ensureIds(configStates); - - this.aggs = []; - this.indexPattern = indexPattern; - this.schemas = schemas; - - configStates.forEach((params: any) => this.createAggConfig(params)); - - if (this.schemas) { - this.initializeDefaultsFromSchemas(schemas); - } - } - - initializeDefaultsFromSchemas(schemas: Schemas) { - // Set the defaults for any schema which has them. If the defaults - // for some reason has more then the max only set the max number - // of defaults (not sure why a someone define more... - // but whatever). Also if a schema.name is already set then don't - // set anything. - _(schemas) - .filter((schema: Schema) => { - return Array.isArray(schema.defaults) && schema.defaults.length > 0; - }) - .each((schema: any) => { - if (!this.aggs.find((agg: AggConfig) => agg.schema && agg.schema.name === schema.name)) { - const defaults = schema.defaults.slice(0, schema.max); - _.each(defaults, defaultState => { - const state = _.defaults({ id: AggConfig.nextId(this.aggs) }, defaultState); - this.aggs.push(new AggConfig(this, state as AggConfigOptions)); - }); - } - }) - .commit(); - } - - setTimeRange(timeRange: TimeRange) { - this.timeRange = timeRange; - - const updateAggTimeRange = (agg: AggConfig) => { - _.each(agg.params, param => { - if (param instanceof AggConfig) { - updateAggTimeRange(param); - } - }); - if (_.get(agg, 'type.name') === 'date_histogram') { - agg.params.timeRange = timeRange; - } - }; - - this.aggs.forEach(updateAggTimeRange); - } - - // clone method will reuse existing AggConfig in the list (will not create new instances) - clone({ enabledOnly = true } = {}) { - const filterAggs = (agg: AggConfig) => { - if (!enabledOnly) return true; - return agg.enabled; - }; - const aggConfigs = new AggConfigs( - this.indexPattern, - this.aggs.filter(filterAggs), - this.schemas - ); - return aggConfigs; - } - - createAggConfig( - params: AggConfig | AggConfigOptions, - { addToAggConfigs = true } = {} - ) { - let aggConfig; - if (params instanceof AggConfig) { - aggConfig = params; - params.parent = this; - } else { - aggConfig = new AggConfig(this, params); - } - if (addToAggConfigs) { - this.aggs.push(aggConfig); - } - return aggConfig as T; - } - - /** - * Data-by-data comparison of this Aggregation - * Ignores the non-array indexes - * @param aggConfigs an AggConfigs instance - */ - jsonDataEquals(aggConfigs: AggConfig[]) { - if (aggConfigs.length !== this.aggs.length) { - return false; - } - for (let i = 0; i < this.aggs.length; i += 1) { - if (!_.isEqual(aggConfigs[i].toJSON(), this.aggs[i].toJSON())) { - return false; - } - } - return true; - } - - toDsl(hierarchical: boolean = false) { - const dslTopLvl = {}; - let dslLvlCursor: Record; - let nestedMetrics: Array<{ config: AggConfig; dsl: any }> | []; - - if (hierarchical) { - // collect all metrics, and filter out the ones that we won't be copying - nestedMetrics = this.aggs - .filter(function(agg) { - return agg.type.type === 'metrics' && agg.type.name !== 'count'; - }) - .map(agg => { - return { - config: agg, - dsl: agg.toDsl(this), - }; - }); - } - this.getRequestAggs() - .filter((config: AggConfig) => !config.type.hasNoDsl) - .forEach((config: AggConfig, i: number, list) => { - if (!dslLvlCursor) { - // start at the top level - dslLvlCursor = dslTopLvl; - } else { - const prevConfig: AggConfig = list[i - 1]; - const prevDsl = dslLvlCursor[prevConfig.id]; - - // advance the cursor and nest under the previous agg, or - // put it on the same level if the previous agg doesn't accept - // sub aggs - dslLvlCursor = prevDsl.aggs || dslLvlCursor; - } - - const dsl = (dslLvlCursor[config.id] = config.toDsl(this)); - let subAggs: any; - - parseParentAggs(dslLvlCursor, dsl); - - if (config.type.type === AggGroupNames.Buckets && i < list.length - 1) { - // buckets that are not the last item in the list accept sub-aggs - subAggs = dsl.aggs || (dsl.aggs = {}); - } - - if (subAggs && nestedMetrics) { - nestedMetrics.forEach((agg: any) => { - subAggs[agg.config.id] = agg.dsl; - // if a nested metric agg has parent aggs, we have to add them to every level of the tree - // to make sure "bucket_path" references in the nested metric agg itself are still working - if (agg.dsl.parentAggs) { - Object.entries(agg.dsl.parentAggs).forEach(([parentAggId, parentAgg]) => { - subAggs[parentAggId] = parentAgg; - }); - } - }); - } - }); - - removeParentAggs(dslTopLvl); - return dslTopLvl; - } - - getAll() { - return [...this.aggs]; - } - - byIndex(index: number) { - return this.aggs[index]; - } - - byId(id: string) { - return this.aggs.find(agg => agg.id === id); - } - - byName(name: string) { - return this.aggs.filter(agg => agg.type.name === name); - } - - byType(type: string) { - return this.aggs.filter(agg => agg.type.type === type); - } - - byTypeName(type: string) { - return this.aggs.filter(agg => agg.type.name === type); - } - - bySchemaName(schema: string) { - return this.aggs.filter(agg => agg.schema && agg.schema.name === schema); - } - - bySchemaGroup(group: string) { - return this.aggs.filter(agg => agg.schema && agg.schema.group === group); - } - - getRequestAggs(): AggConfig[] { - // collect all the aggregations - const aggregations = this.aggs - .filter(agg => agg.enabled && agg.type) - .reduce((requestValuesAggs, agg: AggConfig) => { - const aggs = agg.getRequestAggs(); - return aggs ? requestValuesAggs.concat(aggs) : requestValuesAggs; - }, [] as AggConfig[]); - // move metrics to the end - return _.sortBy(aggregations, (agg: AggConfig) => - agg.type.type === AggGroupNames.Metrics ? 1 : 0 - ); - } - - getRequestAggById(id: string) { - return this.aggs.find((agg: AggConfig) => agg.id === id); - } - - /** - * Gets the AggConfigs (and possibly ResponseAggConfigs) that - * represent the values that will be produced when all aggs - * are run. - * - * With multi-value metric aggs it is possible for a single agg - * request to result in multiple agg values, which is why the length - * of a vis' responseValuesAggs may be different than the vis' aggs - * - * @return {array[AggConfig]} - */ - getResponseAggs(): AggConfig[] { - return this.getRequestAggs().reduce(function(responseValuesAggs, agg: AggConfig) { - const aggs = agg.getResponseAggs(); - return aggs ? responseValuesAggs.concat(aggs) : responseValuesAggs; - }, [] as AggConfig[]); - } - - /** - * Find a response agg by it's id. This may be an agg in the aggConfigs, or one - * created specifically for a response value - * - * @param {string} id - the id of the agg to find - * @return {AggConfig} - */ - getResponseAggById(id: string): AggConfig | undefined { - id = String(id); - const reqAgg = _.find(this.getRequestAggs(), function(agg: AggConfig) { - return id.substr(0, String(agg.id).length) === agg.id; - }); - if (!reqAgg) return; - return _.find(reqAgg.getResponseAggs(), { id }); - } - - onSearchRequestStart(searchSource: SearchSourceContract, options?: FetchOptions) { - return Promise.all( - // @ts-ignore - this.getRequestAggs().map((agg: AggConfig) => agg.onSearchRequestStart(searchSource, options)) - ); - } -} +export { AggConfigs } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_params.ts b/src/legacy/ui/public/agg_types/agg_params.ts index 262a57f4a5aa3..d850be8039025 100644 --- a/src/legacy/ui/public/agg_types/agg_params.ts +++ b/src/legacy/ui/public/agg_types/agg_params.ts @@ -17,77 +17,4 @@ * under the License. */ -import { AggParamType } from './param_types/agg'; -import { FieldParamType } from './param_types/field'; -import { OptionedParamType } from './param_types/optioned'; -import { StringParamType } from './param_types/string'; -import { JsonParamType } from './param_types/json'; -import { BaseParamType } from './param_types/base'; - -import { AggConfig } from './agg_config'; -import { AggConfigs } from './agg_configs'; - -const paramTypeMap = { - field: FieldParamType, - optioned: OptionedParamType, - string: StringParamType, - json: JsonParamType, - agg: AggParamType, - _default: BaseParamType, -} as Record; - -export type AggParam = BaseParamType; - -export interface AggParamOption { - val: string; - display: string; - enabled?(agg: AggConfig): boolean; -} - -export const initParams = ( - params: TAggParam[] -): TAggParam[] => - params.map((config: TAggParam) => { - const Class = paramTypeMap[config.type] || paramTypeMap._default; - - return new Class(config); - }) as TAggParam[]; - -/** - * Reads an aggConfigs - * - * @method write - * @param {AggConfig} aggConfig - * the AggConfig object who's type owns these aggParams and contains the param values for our param defs - * @param {object} [locals] - * an array of locals that will be available to the write function (can be used to enhance - * the quality of things like date_histogram's "auto" interval) - * @return {object} output - * output of the write calls, reduced into a single object. A `params: {}` property is exposed on the - * output object which is used to create the agg dsl for the search request. All other properties - * are dependent on the AggParam#write methods which should be studied for each AggType. - */ -export const writeParams = < - TAggConfig extends AggConfig = AggConfig, - TAggParam extends AggParamType = AggParamType ->( - params: Array> = [], - aggConfig: TAggConfig, - aggs?: AggConfigs, - locals?: Record -) => { - const output = { params: {} as Record }; - locals = locals || {}; - - params.forEach(param => { - if (param.write) { - param.write(aggConfig, output, aggs, locals); - } else { - if (param && param.name) { - output.params[param.name] = aggConfig.params[param.name]; - } - } - }); - - return output; -}; +export { AggParam, AggParamOption } from './index'; diff --git a/src/legacy/ui/public/agg_types/agg_type.ts b/src/legacy/ui/public/agg_types/agg_type.ts index ff4c6875ec6c0..5a74495dd815b 100644 --- a/src/legacy/ui/public/agg_types/agg_type.ts +++ b/src/legacy/ui/public/agg_types/agg_type.ts @@ -17,244 +17,4 @@ * under the License. */ -import { constant, noop, identity } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { initParams } from './agg_params'; - -import { AggConfig } from '../vis'; -import { AggConfigs } from './agg_configs'; -import { SearchSource } from '../courier'; -import { Adapters } from '../inspector'; -import { BaseParamType } from './param_types/base'; -import { AggParamType } from '../agg_types/param_types/agg'; -import { KBN_FIELD_TYPES, FieldFormat } from '../../../../plugins/data/public'; - -export interface AggTypeConfig< - TAggConfig extends AggConfig = AggConfig, - TParam extends AggParamType = AggParamType -> { - name: string; - title: string; - createFilter?: (aggConfig: TAggConfig, key: any, params?: any) => any; - type?: string; - dslName?: string; - makeLabel?: ((aggConfig: TAggConfig) => string) | (() => string); - ordered?: any; - hasNoDsl?: boolean; - params?: Array>; - getRequestAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); - getResponseAggs?: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); - customLabels?: boolean; - decorateAggConfig?: () => any; - postFlightRequest?: ( - resp: any, - aggConfigs: AggConfigs, - aggConfig: TAggConfig, - searchSource: SearchSource, - inspectorAdapters: Adapters, - abortSignal?: AbortSignal - ) => Promise; - getFormat?: (agg: TAggConfig) => FieldFormat; - getValue?: (agg: TAggConfig, bucket: any) => any; - getKey?: (bucket: any, key: any, agg: TAggConfig) => any; -} - -const getFormat = (agg: AggConfig) => { - const field = agg.getField(); - const fieldFormats = npStart.plugins.data.fieldFormats; - - return field ? field.format : fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.STRING); -}; - -export class AggType< - TAggConfig extends AggConfig = AggConfig, - TParam extends AggParamType = AggParamType -> { - /** - * the unique, unchanging, name that we have assigned this aggType - * - * @property name - * @type {string} - */ - name: string; - - type: string; - /** - * the name of the elasticsearch aggregation that this aggType represents. Usually just this.name - * - * @property name - * @type {string} - */ - dslName: string; - /** - * the user friendly name that will be shown in the ui for this aggType - * - * @property title - * @type {string} - */ - title: string; - /** - * a function that will be called when this aggType is assigned to - * an aggConfig, and that aggConfig is being rendered (in a form, chart, etc.). - * - * @method makeLabel - * @param {AggConfig} aggConfig - an agg config of this type - * @returns {string} - label that can be used in the ui to describe the aggConfig - */ - makeLabel: ((aggConfig: TAggConfig) => string) | (() => string); - /** - * Describes if this aggType creates data that is ordered, and if that ordered data - * is some sort of time series. - * - * If the aggType does not create ordered data, set this to something "falsy". - * - * If this does create orderedData, then the value should be an object. - * - * If the orderdata is some sort of time series, `this.ordered` should be an object - * with the property `date: true` - * - * @property ordered - * @type {object|undefined} - */ - ordered: any; - /** - * Flag that prevents this aggregation from being included in the dsl. This is only - * used by the count aggregation (currently) since it doesn't really exist and it's output - * is available on every bucket. - * - * @type {Boolean} - */ - hasNoDsl: boolean; - /** - * The method to create a filter representation of the bucket - * @param {object} aggConfig The instance of the aggConfig - * @param {mixed} key The key for the bucket - * @returns {object} The filter - */ - createFilter: ((aggConfig: TAggConfig, key: any, params?: any) => any) | undefined; - /** - * An instance of {{#crossLink "AggParams"}}{{/crossLink}}. - * - * @property params - * @type {AggParams} - */ - params: TParam[]; - /** - * Designed for multi-value metric aggs, this method can return a - * set of AggConfigs that should replace this aggConfig in requests - * - * @method getRequestAggs - * @returns {array[AggConfig]} - an array of aggConfig objects - * that should replace this one, - * or undefined - */ - getRequestAggs: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); - /** - * Designed for multi-value metric aggs, this method can return a - * set of AggConfigs that should replace this aggConfig in result sets - * that walk the AggConfig set. - * - * @method getResponseAggs - * @returns {array[AggConfig]|undefined} - an array of aggConfig objects - * that should replace this one, - * or undefined - */ - getResponseAggs: ((aggConfig: TAggConfig) => TAggConfig[]) | (() => TAggConfig[] | void); - /** - * A function that will be called each time an aggConfig of this type - * is created, giving the agg type a chance to modify the agg config - */ - decorateAggConfig: () => any; - /** - * A function that needs to be called after the main request has been made - * and should return an updated response - * @param aggConfigs - agg config array used to produce main request - * @param aggConfig - AggConfig that requested the post flight request - * @param searchSourceAggs - SearchSource aggregation configuration - * @param resp - Response to the main request - * @param nestedSearchSource - the new SearchSource that will be used to make post flight request - * @return {Promise} - */ - postFlightRequest: ( - resp: any, - aggConfigs: AggConfigs, - aggConfig: TAggConfig, - searchSource: SearchSource, - inspectorAdapters: Adapters, - abortSignal?: AbortSignal - ) => Promise; - /** - * Pick a format for the values produced by this agg type, - * overridden by several metrics that always output a simple - * number - * - * @param {agg} agg - the agg to pick a format for - * @return {FieldFormat} - */ - getFormat: (agg: TAggConfig) => FieldFormat; - - getValue: (agg: TAggConfig, bucket: any) => any; - - getKey?: (bucket: any, key: any, agg: TAggConfig) => any; - - paramByName = (name: string) => { - return this.params.find((p: TParam) => p.name === name); - }; - - /** - * Generic AggType Constructor - * - * Used to create the values exposed by the agg_types module. - * - * @class AggType - * @private - * @param {object} config - used to set the properties of the AggType - */ - constructor(config: AggTypeConfig) { - this.name = config.name; - this.type = config.type || 'metrics'; - this.dslName = config.dslName || config.name; - this.title = config.title; - this.makeLabel = config.makeLabel || constant(this.name); - this.ordered = config.ordered; - this.hasNoDsl = !!config.hasNoDsl; - - if (config.createFilter) { - this.createFilter = config.createFilter; - } - - if (config.params && config.params.length && config.params[0] instanceof BaseParamType) { - this.params = config.params as TParam[]; - } else { - // always append the raw JSON param - const params: any[] = config.params ? [...config.params] : []; - params.push({ - name: 'json', - type: 'json', - advanced: true, - }); - // always append custom label - - if (config.customLabels !== false) { - params.push({ - name: 'customLabel', - displayName: i18n.translate('common.ui.aggTypes.string.customLabel', { - defaultMessage: 'Custom label', - }), - type: 'string', - write: noop, - }); - } - - this.params = initParams(params); - } - - this.getRequestAggs = config.getRequestAggs || noop; - this.getResponseAggs = config.getResponseAggs || (() => {}); - this.decorateAggConfig = config.decorateAggConfig || (() => ({})); - this.postFlightRequest = config.postFlightRequest || identity; - this.getFormat = config.getFormat || getFormat; - this.getValue = config.getValue || ((agg: TAggConfig, bucket: any) => {}); - } -} +export { AggType } from './index'; diff --git a/src/legacy/ui/public/agg_types/buckets/_interval_options.ts b/src/legacy/ui/public/agg_types/buckets/_interval_options.ts index 01d0abb7a366c..d3838e280f873 100644 --- a/src/legacy/ui/public/agg_types/buckets/_interval_options.ts +++ b/src/legacy/ui/public/agg_types/buckets/_interval_options.ts @@ -16,67 +16,5 @@ * specific language governing permissions and limitations * under the License. */ -import { i18n } from '@kbn/i18n'; -import { IBucketAggConfig } from './_bucket_agg_type'; -export const intervalOptions = [ - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.autoDisplayName', { - defaultMessage: 'Auto', - }), - val: 'auto', - 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', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.secondDisplayName', { - defaultMessage: 'Second', - }), - val: 's', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName', { - defaultMessage: 'Minute', - }), - val: 'm', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName', { - defaultMessage: 'Hourly', - }), - val: 'h', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName', { - defaultMessage: 'Daily', - }), - val: 'd', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName', { - defaultMessage: 'Weekly', - }), - val: 'w', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName', { - defaultMessage: 'Monthly', - }), - val: 'M', - }, - { - display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName', { - defaultMessage: 'Yearly', - }), - val: 'y', - }, -]; +export { intervalOptions } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts b/src/legacy/ui/public/agg_types/buckets/date_histogram.ts index 45122a24c8184..35b14f620bdae 100644 --- a/src/legacy/ui/public/agg_types/buckets/date_histogram.ts +++ b/src/legacy/ui/public/agg_types/buckets/date_histogram.ts @@ -17,257 +17,4 @@ * under the License. */ -import _ from 'lodash'; -import moment from 'moment-timezone'; -import { i18n } from '@kbn/i18n'; - -import { npStart } from 'ui/new_platform'; -import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { createFilterDateHistogram } from './create_filter/date_histogram'; -import { intervalOptions } from './_interval_options'; -import { TimeIntervalParamEditor } from '../../vis/editors/default/controls/time_interval'; -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 { writeParams } from '../agg_params'; -import { isMetricAggType } from '../metrics/metric_agg_type'; - -import { KBN_FIELD_TYPES } from '../../../../../plugins/data/public'; - -// @ts-ignore -import { TimeBuckets } from '../../time_buckets'; - -const detectedTimezone = moment.tz.guess(); -const tzOffset = moment().format('Z'); - -const getInterval = (agg: IBucketAggConfig): string => _.get(agg, ['params', 'interval']); - -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 function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHistogramAggConfig { - return Boolean(agg.buckets); -} - -export const dateHistogramBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.DATE_HISTOGRAM, - title: i18n.translate('common.ui.aggTypes.buckets.dateHistogramTitle', { - defaultMessage: 'Date Histogram', - }), - ordered: { - date: true, - }, - makeLabel(agg) { - let output: Record = {}; - - if (this.params) { - output = writeParams(this.params, 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() { - let buckets: any; - return { - buckets: { - configurable: true, - get() { - if (buckets) return buckets; - - buckets = new TimeBuckets(); - buckets.setInterval(getInterval(this)); - setBounds(this); - - return buckets; - }, - } as any, - }; - }, - getFormat(agg) { - return agg.buckets.getScaledDateFormatter(); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.DATE, - default(agg: IBucketDateHistogramAggConfig) { - return agg.getIndexPattern().timeFieldName; - }, - onChange(agg: IBucketDateHistogramAggConfig) { - if (_.get(agg, 'params.interval') === 'auto' && !agg.fieldIsTimeField()) { - delete agg.params.interval; - } - - setBounds(agg, true); - }, - }, - { - name: 'timeRange', - default: null, - write: _.noop, - }, - { - name: 'useNormalizedEsInterval', - default: true, - write: _.noop, - }, - { - name: 'scaleMetricValues', - default: false, - write: _.noop, - advanced: true, - editorComponent: ScaleMetricsParamEditor, - }, - { - name: 'interval', - editorComponent: TimeIntervalParamEditor, - deserialize(state: any, agg) { - // 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'); - } - - const interval = _.find(intervalOptions, { val: state }); - - // For upgrading from 4.0.x to 4.1.x - intervals are now stored as 'y' instead of 'year', - // but this maps the old values to the new values - if (!interval && state === 'year') { - return 'y'; - } - return state; - }, - default: 'auto', - options: intervalOptions, - modifyAggConfigOnSearchRequestStart(agg: IBucketDateHistogramAggConfig) { - setBounds(agg, true); - }, - write(agg, output, aggs) { - setBounds(agg, true); - agg.buckets.setInterval(getInterval(agg)); - const { useNormalizedEsInterval, scaleMetricValues } = agg.params; - const interval = agg.buckets.getInterval(useNormalizedEsInterval); - output.bucketInterval = interval; - if (interval.expression === '0ms') { - // We are hitting this code a couple of times while configuring in editor - // with an interval of 0ms because the overall time range has not yet been - // set. Since 0ms is not a valid ES interval, we cannot pass it through dateHistogramInterval - // below, since it would throw an exception. So in the cases we still have an interval of 0ms - // here we simply skip the rest of the method and never write an interval into the DSL, since - // this DSL will anyway not be used before we're passing this code with an actual interval. - return; - } - output.params = { - ...output.params, - ...dateHistogramInterval(interval.expression), - }; - - const scaleMetrics = scaleMetricValues && interval.scaled && interval.scale < 1; - if (scaleMetrics && aggs) { - const metrics = aggs.aggs.filter(a => isMetricAggType(a.type)); - const all = _.every(metrics, (a: IBucketAggConfig) => { - const { type } = a; - - if (isMetricAggType(type)) { - return type.isScalable(); - } - }); - if (all) { - output.metricScale = interval.scale; - output.metricScaleText = interval.preScaled.description; - } - } - }, - }, - { - 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: _.noop, - write(agg, output) { - // 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', - ]); - } - if (!tz) { - const config = npStart.core.uiSettings; - // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz - const isDefaultTimezone = config.isDefault('dateFormat:tz'); - tz = isDefaultTimezone ? detectedTimezone || tzOffset : config.get('dateFormat:tz'); - } - output.params.time_zone = tz; - }, - }, - { - name: 'drop_partials', - default: false, - write: _.noop, - editorComponent: DropPartialsParamEditor, - shouldShow: agg => { - const field = agg.params.field; - return field && field.name && field.name === agg.getIndexPattern().timeFieldName; - }, - }, - { - name: 'format', - }, - { - name: 'min_doc_count', - default: 1, - }, - { - name: 'extended_bounds', - default: {}, - write(agg, output) { - 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(), - }; - - return; - } - }, - }, - ], -}); +export { isDateHistogramBucketAggConfig, setBounds } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/date_range.ts b/src/legacy/ui/public/agg_types/buckets/date_range.ts index ad54e95ffb7b1..34eae58375a06 100644 --- a/src/legacy/ui/public/agg_types/buckets/date_range.ts +++ b/src/legacy/ui/public/agg_types/buckets/date_range.ts @@ -16,112 +16,5 @@ * 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, IBucketAggConfig } from './_bucket_agg_type'; -import { createFilterDateRange } from './create_filter/date_range'; -import { DateRangesParamEditor } from '../../vis/editors/default/controls/date_ranges'; -import { - KBN_FIELD_TYPES, - TEXT_CONTEXT_TYPE, - FieldFormat, -} from '../../../../../plugins/data/public'; - -const dateRangeTitle = i18n.translate('common.ui.aggTypes.buckets.dateRangeTitle', { - defaultMessage: 'Date Range', -}); - -export interface DateRangeKey { - from: number; - to: number; -} - -export const dateRangeBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.DATE_RANGE, - title: dateRangeTitle, - createFilter: createFilterDateRange, - getKey({ from, to }): DateRangeKey { - return { from, to }; - }, - getFormat(agg) { - const fieldFormats = npStart.plugins.data.fieldFormats; - - const formatter = agg.fieldOwnFormatter( - TEXT_CONTEXT_TYPE, - fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.DATE) - ); - const DateRangeFormat = FieldFormat.from(function(range: DateRangeKey) { - return convertDateRangeToString(range, formatter); - }); - return new DateRangeFormat(); - }, - makeLabel(aggConfig) { - return aggConfig.getFieldDisplayName() + ' date ranges'; - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.DATE, - default(agg: IBucketAggConfig) { - 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) => { - 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; - }, - }, - ], -}); - -export const convertDateRangeToString = ( - { from, to }: DateRangeKey, - format: (val: any) => string -) => { - if (!from) { - return 'Before ' + format(to); - } else if (!to) { - return 'After ' + format(from); - } else { - return format(from) + ' to ' + format(to); - } -}; +export { DateRangeKey, convertDateRangeToString } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/ip_range.ts b/src/legacy/ui/public/agg_types/buckets/ip_range.ts index 609cd8adb5c39..7a8fd4f89b1ff 100644 --- a/src/legacy/ui/public/agg_types/buckets/ip_range.ts +++ b/src/legacy/ui/public/agg_types/buckets/ip_range.ts @@ -17,101 +17,4 @@ * under the License. */ -import { noop, map, omit, isNull } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { npStart } from 'ui/new_platform'; -import { BucketAggType } from './_bucket_agg_type'; -import { IpRangeTypeParamEditor } from '../../vis/editors/default/controls/ip_range_type'; -import { IpRangesParamEditor } from '../../vis/editors/default/controls/ip_ranges'; -import { BUCKET_TYPES } from './bucket_agg_types'; - -// @ts-ignore -import { createFilterIpRange } from './create_filter/ip_range'; -import { - KBN_FIELD_TYPES, - TEXT_CONTEXT_TYPE, - FieldFormat, -} from '../../../../../plugins/data/public'; - -const ipRangeTitle = i18n.translate('common.ui.aggTypes.buckets.ipRangeTitle', { - defaultMessage: 'IPv4 Range', -}); - -export type IpRangeKey = - | { type: 'mask'; mask: string } - | { type: 'range'; from: string; to: string }; - -export const ipRangeBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.IP_RANGE, - title: ipRangeTitle, - createFilter: createFilterIpRange, - getKey(bucket, key, agg): IpRangeKey { - if (agg.params.ipRangeType === 'mask') { - return { type: 'mask', mask: key }; - } - return { type: 'range', from: bucket.from, to: bucket.to }; - }, - getFormat(agg) { - const fieldFormats = npStart.plugins.data.fieldFormats; - const formatter = agg.fieldOwnFormatter( - TEXT_CONTEXT_TYPE, - fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.IP) - ); - const IpRangeFormat = FieldFormat.from(function(range: IpRangeKey) { - return convertIPRangeToString(range, formatter); - }); - return new IpRangeFormat(); - }, - makeLabel(aggConfig) { - return i18n.translate('common.ui.aggTypes.buckets.ipRangeLabel', { - defaultMessage: '{fieldName} IP ranges', - values: { - fieldName: aggConfig.getFieldDisplayName(), - }, - }); - }, - params: [ - { - name: 'field', - type: 'field', - filterFieldTypes: KBN_FIELD_TYPES.IP, - }, - { - name: 'ipRangeType', - editorComponent: IpRangeTypeParamEditor, - default: 'fromTo', - 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' }, - ], - mask: [{ mask: '0.0.0.0/1' }, { mask: '128.0.0.0/2' }], - }, - editorComponent: IpRangesParamEditor, - write(aggConfig, output) { - const ipRangeType = aggConfig.params.ipRangeType; - let ranges = aggConfig.params.ranges[ipRangeType]; - - if (ipRangeType === 'fromTo') { - ranges = map(ranges, (range: any) => omit(range, isNull)); - } - - output.params.ranges = ranges; - }, - }, - ], -}); - -export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { - if (range.type === 'mask') { - return format(range.mask); - } - const from = range.from ? format(range.from) : '-Infinity'; - const to = range.to ? format(range.to) : 'Infinity'; - - return `${from} to ${to}`; -}; +export { IpRangeKey, convertIPRangeToString } from '../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts index aadbbc8c82276..0774a89ee3f03 100644 --- a/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts +++ b/src/legacy/ui/public/agg_types/buckets/lib/cidr_mask.ts @@ -17,42 +17,4 @@ * under the License. */ -import { Ipv4Address } from '../../../../../../plugins/kibana_utils/public'; - -const NUM_BITS = 32; - -function throwError(mask: string) { - throw Error('Invalid CIDR mask: ' + mask); -} - -export class CidrMask { - public readonly initialAddress: Ipv4Address; - public readonly prefixLength: number; - - constructor(mask: string) { - const splits = mask.split('/'); - if (splits.length !== 2) { - throwError(mask); - } - this.initialAddress = new Ipv4Address(splits[0]); - this.prefixLength = Number(splits[1]); - if (isNaN(this.prefixLength) || this.prefixLength < 1 || this.prefixLength > NUM_BITS) { - throwError(mask); - } - } - - public getRange() { - const variableBits = NUM_BITS - this.prefixLength; - // eslint-disable-next-line no-bitwise - const fromAddress = ((this.initialAddress.valueOf() >> variableBits) << variableBits) >>> 0; // >>> 0 coerces to unsigned - const numAddresses = Math.pow(2, variableBits); - return { - from: new Ipv4Address(fromAddress).toString(), - to: new Ipv4Address(fromAddress + numAddresses - 1).toString(), - }; - } - - public toString() { - return this.initialAddress.toString() + '/' + this.prefixLength; - } -} +export { CidrMask } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts b/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts index 77e84e044de55..f86cc2b6a294b 100644 --- a/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts +++ b/src/legacy/ui/public/agg_types/buckets/migrate_include_exclude_format.ts @@ -17,37 +17,4 @@ * under the License. */ -import { isString, isObject } from 'lodash'; -import { IBucketAggConfig, BucketAggType, BucketAggParam } from './_bucket_agg_type'; -import { AggConfig } from '../agg_config'; - -export const isType = (type: string) => { - return (agg: AggConfig): boolean => { - const field = agg.params.field; - - return field && field.type === type; - }; -}; - -export const isStringType = isType('string'); - -export const migrateIncludeExcludeFormat = { - serialize(this: BucketAggParam, value: any, agg: IBucketAggConfig) { - if (this.shouldShow && !this.shouldShow(agg)) return; - if (!value || isString(value)) return value; - else return value.pattern; - }, - write( - this: BucketAggType, - aggConfig: IBucketAggConfig, - output: Record - ) { - 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; - } - }, -} as Partial>; +export { isType, isStringType } from '../index'; diff --git a/src/legacy/ui/public/agg_types/filter/index.ts b/src/legacy/ui/public/agg_types/filter/index.ts index 3fc577e7e9a23..6fa298438824e 100644 --- a/src/legacy/ui/public/agg_types/filter/index.ts +++ b/src/legacy/ui/public/agg_types/filter/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export { aggTypeFilters } from './agg_type_filters'; -export { propFilter } from './prop_filter'; +export { aggTypeFilters, propFilter } from '../index'; diff --git a/src/legacy/ui/public/agg_types/index.ts b/src/legacy/ui/public/agg_types/index.ts index e52640743a25b..9df019e98d227 100644 --- a/src/legacy/ui/public/agg_types/index.ts +++ b/src/legacy/ui/public/agg_types/index.ts @@ -17,83 +17,52 @@ * under the License. */ -import { countMetricAgg } from './metrics/count'; -import { avgMetricAgg } from './metrics/avg'; -import { sumMetricAgg } from './metrics/sum'; -import { medianMetricAgg } from './metrics/median'; -import { minMetricAgg } from './metrics/min'; -import { maxMetricAgg } from './metrics/max'; -import { topHitMetricAgg } from './metrics/top_hit'; -import { stdDeviationMetricAgg } from './metrics/std_deviation'; -import { cardinalityMetricAgg } from './metrics/cardinality'; -import { percentilesMetricAgg } from './metrics/percentiles'; -import { geoBoundsMetricAgg } from './metrics/geo_bounds'; -import { geoCentroidMetricAgg } from './metrics/geo_centroid'; -import { percentileRanksMetricAgg } from './metrics/percentile_ranks'; -import { derivativeMetricAgg } from './metrics/derivative'; -import { cumulativeSumMetricAgg } from './metrics/cumulative_sum'; -import { movingAvgMetricAgg } from './metrics/moving_avg'; -import { serialDiffMetricAgg } from './metrics/serial_diff'; -import { dateHistogramBucketAgg, setBounds } from './buckets/date_histogram'; -import { histogramBucketAgg } from './buckets/histogram'; -import { rangeBucketAgg } from './buckets/range'; -import { dateRangeBucketAgg } from './buckets/date_range'; -import { ipRangeBucketAgg } from './buckets/ip_range'; -import { termsBucketAgg } from './buckets/terms'; -import { filterBucketAgg } from './buckets/filter'; -import { filtersBucketAgg } from './buckets/filters'; -import { significantTermsBucketAgg } from './buckets/significant_terms'; -import { geoHashBucketAgg } from './buckets/geo_hash'; -import { geoTileBucketAgg } from './buckets/geo_tile'; -import { bucketSumMetricAgg } from './metrics/bucket_sum'; -import { bucketAvgMetricAgg } from './metrics/bucket_avg'; -import { bucketMinMetricAgg } from './metrics/bucket_min'; -import { bucketMaxMetricAgg } from './metrics/bucket_max'; +/** + * Nothing to see here! + * + * Agg Types have moved to the data plugin, and are being + * re-exported from ui/agg_types for backwards compatibility. + */ -export { AggType } from './agg_type'; +import { start as dataStart } from '../../../core_plugins/data/public/legacy'; -export const aggTypes = { - metrics: [ - countMetricAgg, - avgMetricAgg, - sumMetricAgg, - medianMetricAgg, - minMetricAgg, - maxMetricAgg, - stdDeviationMetricAgg, - cardinalityMetricAgg, - percentilesMetricAgg, - percentileRanksMetricAgg, - topHitMetricAgg, - derivativeMetricAgg, - cumulativeSumMetricAgg, - movingAvgMetricAgg, - serialDiffMetricAgg, - bucketAvgMetricAgg, - bucketSumMetricAgg, - bucketMinMetricAgg, - bucketMaxMetricAgg, - geoBoundsMetricAgg, - geoCentroidMetricAgg, - ], - buckets: [ - dateHistogramBucketAgg, - histogramBucketAgg, - rangeBucketAgg, - dateRangeBucketAgg, - ipRangeBucketAgg, - termsBucketAgg, - filterBucketAgg, - filtersBucketAgg, - significantTermsBucketAgg, - geoHashBucketAgg, - geoTileBucketAgg, - ], -}; +// runtime contracts +export const { + types: aggTypes, + AggConfig, + AggConfigs, + AggType, + aggTypeFieldFilters, + FieldParamType, + parentPipelineAggHelper, + setBounds, +} = dataStart.search.aggs; -export { AggParam } from './agg_params'; -export { AggConfig } from './agg_config'; -export { AggConfigs } from './agg_configs'; -export { FieldParamType } from './param_types'; +// types +export { + // agg_types + AggParam, + AggParamOption, + DateRangeKey, + IpRangeKey, + OptionedParamEditorProps, + OptionedValueProp, +} from '../../../core_plugins/data/public'; -export { setBounds }; +// static code +export { + // agg_types + AggParamType, + aggTypeFilters, + CidrMask, + convertDateRangeToString, + convertIPRangeToString, + intervalOptions, // only used in Discover + isDateHistogramBucketAggConfig, + isStringType, + isType, + isValidInterval, + isValidJson, + OptionedParamType, + propFilter, +} from '../../../core_plugins/data/public'; diff --git a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts index d177a62649d13..26acf3c024592 100644 --- a/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts +++ b/src/legacy/ui/public/agg_types/metrics/lib/parent_pipeline_agg_helper.ts @@ -17,94 +17,4 @@ * under the License. */ -import { i18n } from '@kbn/i18n'; -import { noop } from 'lodash'; -import { MetricAggParamEditor } from '../../../vis/editors/default/controls/metric_agg'; -import { SubAggParamEditor } from '../../../vis/editors/default/controls/sub_agg'; -import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; -import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; -import { parentPipelineAggWriter } from './parent_pipeline_agg_writer'; - -// @ts-ignore -import { Schemas } from '../../../vis/editors/default/schemas'; - -const metricAggFilter = [ - '!top_hits', - '!percentiles', - '!percentile_ranks', - '!median', - '!std_dev', - '!geo_bounds', - '!geo_centroid', -]; - -const metricAggTitle = i18n.translate('common.ui.aggTypes.metrics.metricAggTitle', { - defaultMessage: 'Metric agg', -}); - -const subtypeLabel = i18n.translate( - 'common.ui.aggTypes.metrics.parentPipelineAggregationsSubtypeTitle', - { - defaultMessage: 'Parent Pipeline Aggregations', - } -); - -const [metricAggSchema] = new Schemas([ - { - group: 'none', - name: 'metricAgg', - title: metricAggTitle, - hideCustomLabel: true, - aggFilter: metricAggFilter, - }, -]).all; - -export const parentPipelineAggHelper = { - subtype: subtypeLabel, - - params() { - return [ - { - name: 'metricAgg', - editorComponent: MetricAggParamEditor, - default: 'custom', - write: parentPipelineAggWriter, - }, - { - name: 'customMetric', - editorComponent: SubAggParamEditor, - type: 'agg', - makeAgg(termsAgg, state: any) { - state = state || { type: 'count' }; - state.schema = metricAggSchema; - - const metricAgg = termsAgg.aggConfigs.createAggConfig(state, { addToAggConfigs: false }); - - metricAgg.id = termsAgg.id + '-metric'; - - return metricAgg; - }, - modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart( - 'customMetric' - ), - write: noop, - }, - { - name: 'buckets_path', - write: noop, - }, - ] as Array>; - }, - - getFormat(agg: IMetricAggConfig) { - let subAgg; - const customMetric = agg.getParam('customMetric'); - - if (customMetric) { - subAgg = customMetric; - } else { - subAgg = agg.aggConfigs.byId(agg.getParam('metricAgg')); - } - return subAgg.type.getFormat(subAgg); - }, -}; +export { parentPipelineAggHelper } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/param_types/agg.ts b/src/legacy/ui/public/agg_types/param_types/agg.ts index 0a83805c8c44c..68c58e1dd7e07 100644 --- a/src/legacy/ui/public/agg_types/param_types/agg.ts +++ b/src/legacy/ui/public/agg_types/param_types/agg.ts @@ -17,41 +17,4 @@ * under the License. */ -import { AggConfig } from '../agg_config'; -import { BaseParamType } from './base'; - -export class AggParamType extends BaseParamType< - TAggConfig -> { - makeAgg: (agg: TAggConfig, state?: any) => TAggConfig; - - constructor(config: Record) { - super(config); - - if (!config.write) { - this.write = (aggConfig: TAggConfig, output: Record) => { - if (aggConfig.params[this.name] && aggConfig.params[this.name].length) { - output.params[this.name] = aggConfig.params[this.name]; - } - }; - } - if (!config.serialize) { - this.serialize = (agg: TAggConfig) => { - return agg.toJSON(); - }; - } - if (!config.deserialize) { - this.deserialize = (state: unknown, agg?: TAggConfig): TAggConfig => { - if (!agg) { - throw new Error('aggConfig was not provided to AggParamType deserialize function'); - } - return this.makeAgg(agg, state); - }; - } - if (!config.editorComponent) { - this.editorComponent = require('../../vis/editors/default/controls/sub_agg'); - } - this.makeAgg = config.makeAgg; - this.valueType = AggConfig; - } -} +export { AggParamType } from '../index'; diff --git a/src/legacy/ui/public/agg_types/param_types/filter/index.ts b/src/legacy/ui/public/agg_types/param_types/filter/index.ts index ce5c7c4f9fea5..1ea49dfbd0fe2 100644 --- a/src/legacy/ui/public/agg_types/param_types/filter/index.ts +++ b/src/legacy/ui/public/agg_types/param_types/filter/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { aggTypeFieldFilters } from './field_filters'; +export { aggTypeFieldFilters } from '../../index'; diff --git a/src/legacy/ui/public/agg_types/param_types/index.ts b/src/legacy/ui/public/agg_types/param_types/index.ts index 3414e6a71ecdc..5f085e498c788 100644 --- a/src/legacy/ui/public/agg_types/param_types/index.ts +++ b/src/legacy/ui/public/agg_types/param_types/index.ts @@ -17,8 +17,4 @@ * under the License. */ -export * from './base'; -export * from './field'; -export * from './json'; export * from './optioned'; -export * from './string'; diff --git a/src/legacy/ui/public/agg_types/param_types/optioned.ts b/src/legacy/ui/public/agg_types/param_types/optioned.ts index 6ac892e232bfb..d6ce116b996c6 100644 --- a/src/legacy/ui/public/agg_types/param_types/optioned.ts +++ b/src/legacy/ui/public/agg_types/param_types/optioned.ts @@ -17,43 +17,4 @@ * under the License. */ -import { AggConfig } from '../../vis'; -import { BaseParamType } from './base'; - -export interface OptionedValueProp { - value: string; - text: string; - disabled?: boolean; - isCompatible: (agg: AggConfig) => boolean; -} - -export interface OptionedParamEditorProps { - aggParam: { - options: T[]; - }; -} - -export class OptionedParamType extends BaseParamType { - options: OptionedValueProp[]; - - constructor(config: Record) { - super(config); - - if (!config.write) { - this.write = (aggConfig: AggConfig, output: Record) => { - output.params[this.name] = aggConfig.params[this.name].value; - }; - } - if (!config.serialize) { - this.serialize = (selected: OptionedValueProp) => { - return selected.value; - }; - } - if (!config.deserialize) { - this.deserialize = (value: any) => { - return this.options.find((option: OptionedValueProp) => option.value === value); - }; - } - this.options = config.options || []; - } -} +export { OptionedParamEditorProps, OptionedParamType, OptionedValueProp } from '../index'; diff --git a/src/legacy/ui/public/agg_types/utils.ts b/src/legacy/ui/public/agg_types/utils.ts index fd405d49625ed..ec1eab7e4b115 100644 --- a/src/legacy/ui/public/agg_types/utils.ts +++ b/src/legacy/ui/public/agg_types/utils.ts @@ -17,56 +17,4 @@ * under the License. */ -import { isValidEsInterval } from '../../../core_plugins/data/public'; -import { leastCommonInterval } from '../vis/lib/least_common_interval'; - -/** - * Check a string if it's a valid JSON. - * - * @param {string} value a string that should be validated - * @returns {boolean} true if value is a valid JSON or if value is an empty string, or a string with whitespaces, otherwise false - */ -function isValidJson(value: string): boolean { - if (!value || value.length === 0) { - return true; - } - - const trimmedValue = value.trim(); - - if (trimmedValue.length === 0) { - return true; - } - - if (trimmedValue[0] === '{' || trimmedValue[0] === '[') { - try { - JSON.parse(trimmedValue); - return true; - } catch (e) { - return false; - } - } else { - return false; - } -} - -function isValidInterval(value: string, baseInterval?: string) { - if (baseInterval) { - return _parseWithBase(value, baseInterval); - } else { - return isValidEsInterval(value); - } -} - -// When base interval is set, check for least common interval and allow -// input the value is the same. This means that the input interval is a -// multiple of the base interval. -function _parseWithBase(value: string, baseInterval: string) { - try { - const interval = leastCommonInterval(baseInterval, value); - return interval === value.replace(/\s/g, ''); - } catch (e) { - return false; - } -} - -export { isValidJson, isValidInterval }; +export { isValidJson, isValidInterval } from './index'; diff --git a/src/legacy/ui/public/courier/_index.scss b/src/legacy/ui/public/courier/_index.scss index a5b3911b1d53c..17382cfa30ce5 100644 --- a/src/legacy/ui/public/courier/_index.scss +++ b/src/legacy/ui/public/courier/_index.scss @@ -1 +1 @@ -@import './fetch/components/shard_failure_modal'; \ No newline at end of file +@import '../../../core_plugins/data/public/search/fetch/components/shard_failure_modal'; \ No newline at end of file diff --git a/src/legacy/ui/public/courier/index.ts b/src/legacy/ui/public/courier/index.ts index c8a06ec2a5518..709ff1c11e901 100644 --- a/src/legacy/ui/public/courier/index.ts +++ b/src/legacy/ui/public/courier/index.ts @@ -17,31 +17,46 @@ * under the License. */ -export { SearchSource } from './search_source'; +/** + * Nothing to see here! + * + * Courier / SearchSource has moved to the data plugin, and is being + * re-exported from ui/courier for backwards compatibility. + */ + +import { start as dataStart } from '../../../core_plugins/data/public/legacy'; + +// runtime contracts +export const { defaultSearchStrategy, SearchSource } = dataStart.search; + +// types +export { + ISearchSource, + EsQuerySortValue, // used externally by Discover + FetchOptions, // used externally by AggTypes + SortDirection, // used externally by Discover +} from '../../../core_plugins/data/public'; + +// static code +export { + getRequestInspectorStats, + getResponseInspectorStats, +} from '../../../core_plugins/data/public'; // TODO: Exporting this mock outside of jest tests causes errors because // jest is undefined. Need to refactor the mock to be consistent with // other NP-style mocks. // export { searchSourceMock } from './search_source/mocks'; +// Most these can probably be made internal to the search +// service, so we are temporarily deeply importing them +// until we relocate them to a longer-term home. +/* eslint-disable @kbn/eslint/no-restricted-paths */ export { addSearchStrategy, // used externally by Rollups getSearchErrorType, // used externally by Rollups hasSearchStategyForIndexPattern, // used externally by Discover isDefaultTypeIndexPattern, // used externally by Discover SearchError, // used externally by Visualizations & Rollups -} from './search_strategy'; - -export { - getRequestInspectorStats, - getResponseInspectorStats, -} from './utils/courier_inspector_utils'; - -// types -export { SearchSourceContract } from './search_source'; - -export { - EsQuerySortValue, // used externally by Discover - FetchOptions, // used externally by AggTypes - SortDirection, // used externally by Discover -} from './types'; +} from '../../../core_plugins/data/public/search/search_strategy'; +/* eslint-enable @kbn/eslint/no-restricted-paths */ diff --git a/src/legacy/ui/public/courier/search_source/index.ts b/src/legacy/ui/public/courier/search_source/index.ts index 72170adc2b129..e7ca48a894b3d 100644 --- a/src/legacy/ui/public/courier/search_source/index.ts +++ b/src/legacy/ui/public/courier/search_source/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export * from './search_source'; +export { SearchSource, ISearchSource } from '../index'; diff --git a/src/legacy/ui/public/courier/search_source/mocks.ts b/src/legacy/ui/public/courier/search_source/mocks.ts index 2b83f379b4f09..7b7843d22f519 100644 --- a/src/legacy/ui/public/courier/search_source/mocks.ts +++ b/src/legacy/ui/public/courier/search_source/mocks.ts @@ -36,9 +36,11 @@ * under the License. */ -import { SearchSourceContract } from './search_source'; +// This mock is here for BWC, but will be left behind and replaced by +// the data service mock in the new platform. +import { ISearchSource } from '../index'; -export const searchSourceMock: MockedKeys = { +export const searchSourceMock: MockedKeys = { setPreferredSearchStrategyId: jest.fn(), setFields: jest.fn().mockReturnThis(), setField: jest.fn().mockReturnThis(), diff --git a/src/legacy/ui/public/courier/search_source/search_source.ts b/src/legacy/ui/public/courier/search_source/search_source.ts index e862bb1118a74..e7ca48a894b3d 100644 --- a/src/legacy/ui/public/courier/search_source/search_source.ts +++ b/src/legacy/ui/public/courier/search_source/search_source.ts @@ -17,394 +17,4 @@ * under the License. */ -/** - * @name SearchSource - * - * @description A promise-based stream of search results that can inherit from other search sources. - * - * Because filters/queries in Kibana have different levels of persistence and come from different - * places, it is important to keep track of where filters come from for when they are saved back to - * the savedObject store in the Kibana index. To do this, we create trees of searchSource objects - * that can have associated query parameters (index, query, filter, etc) which can also inherit from - * other searchSource objects. - * - * At query time, all of the searchSource objects that have subscribers are "flattened", at which - * point the query params from the searchSource are collected while traversing up the inheritance - * chain. At each link in the chain a decision about how to merge the query params is made until a - * single set of query parameters is created for each active searchSource (a searchSource with - * subscribers). - * - * That set of query parameters is then sent to elasticsearch. This is how the filter hierarchy - * works in Kibana. - * - * Visualize, starting from a new search: - * - * - the `savedVis.searchSource` is set as the `appSearchSource`. - * - The `savedVis.searchSource` would normally inherit from the `appSearchSource`, but now it is - * upgraded to inherit from the `rootSearchSource`. - * - Any interaction with the visualization will still apply filters to the `appSearchSource`, so - * they will be stored directly on the `savedVis.searchSource`. - * - Any interaction with the time filter will be written to the `rootSearchSource`, so those - * filters will not be saved by the `savedVis`. - * - When the `savedVis` is saved to elasticsearch, it takes with it all the filters that are - * defined on it directly, but none of the ones that it inherits from other places. - * - * Visualize, starting from an existing search: - * - * - The `savedVis` loads the `savedSearch` on which it is built. - * - The `savedVis.searchSource` is set to inherit from the `saveSearch.searchSource` and set as - * the `appSearchSource`. - * - The `savedSearch.searchSource`, is set to inherit from the `rootSearchSource`. - * - Then the `savedVis` is written to elasticsearch it will be flattened and only include the - * filters created in the visualize application and will reconnect the filters from the - * `savedSearch` at runtime to prevent losing the relationship - * - * Dashboard search sources: - * - * - Each panel in a dashboard has a search source. - * - The `savedDashboard` also has a searchsource, and it is set as the `appSearchSource`. - * - Each panel's search source inherits from the `appSearchSource`, meaning that they inherit from - * the dashboard search source. - * - When a filter is added to the search box, or via a visualization, it is written to the - * `appSearchSource`. - */ - -import _ from 'lodash'; -import { npSetup } from 'ui/new_platform'; -import { normalizeSortRequest } from './normalize_sort_request'; -import { fetchSoon } from '../fetch'; -import { fieldWildcardFilter } from '../../field_wildcard'; -import { getHighlightRequest, esFilters, esQuery } from '../../../../../plugins/data/public'; -import chrome from '../../chrome'; -import { RequestFailure } from '../fetch/errors'; -import { filterDocvalueFields } from './filter_docvalue_fields'; -import { SearchSourceOptions, SearchSourceFields, SearchRequest } from './types'; -import { FetchOptions, ApiCaller } from '../fetch/types'; - -const esShardTimeout = npSetup.core.injectedMetadata.getInjectedVar('esShardTimeout') as number; -const config = npSetup.core.uiSettings; - -export type SearchSourceContract = Pick; - -export class SearchSource { - private id: string = _.uniqueId('data_source'); - private searchStrategyId?: string; - private parent?: SearchSource; - private requestStartHandlers: Array< - (searchSource: SearchSourceContract, options?: FetchOptions) => Promise - > = []; - private inheritOptions: SearchSourceOptions = {}; - public history: SearchRequest[] = []; - - constructor(private fields: SearchSourceFields = {}) {} - - /** *** - * PUBLIC API - *****/ - - setPreferredSearchStrategyId(searchStrategyId: string) { - this.searchStrategyId = searchStrategyId; - } - - setFields(newFields: SearchSourceFields) { - this.fields = newFields; - return this; - } - - setField(field: K, value: SearchSourceFields[K]) { - if (value == null) { - delete this.fields[field]; - } else { - this.fields[field] = value; - } - return this; - } - - getId() { - return this.id; - } - - getFields() { - return { ...this.fields }; - } - - /** - * Get fields from the fields - */ - getField(field: K, recurse = true): SearchSourceFields[K] { - if (!recurse || this.fields[field] !== void 0) { - return this.fields[field]; - } - const parent = this.getParent(); - return parent && parent.getField(field); - } - - /** - * Get the field from our own fields, don't traverse up the chain - */ - getOwnField(field: K): SearchSourceFields[K] { - return this.getField(field, false); - } - - create() { - return new SearchSource(); - } - - createCopy() { - const newSearchSource = new SearchSource(); - newSearchSource.setFields({ ...this.fields }); - // when serializing the internal fields we lose the internal classes used in the index - // pattern, so we have to set it again to workaround this behavior - newSearchSource.setField('index', this.getField('index')); - newSearchSource.setParent(this.getParent()); - return newSearchSource; - } - - createChild(options = {}) { - const childSearchSource = new SearchSource(); - childSearchSource.setParent(this, options); - return childSearchSource; - } - - /** - * Set a searchSource that this source should inherit from - * @param {SearchSource} parent - the parent searchSource - * @param {SearchSourceOptions} options - the inherit options - * @return {this} - chainable - */ - setParent(parent?: SearchSourceContract, options: SearchSourceOptions = {}) { - this.parent = parent as SearchSource; - this.inheritOptions = options; - return this; - } - - /** - * Get the parent of this SearchSource - * @return {undefined|searchSource} - */ - getParent() { - return this.parent; - } - - /** - * Fetch this source and reject the returned Promise on error - * - * @async - */ - async fetch(options: FetchOptions = {}) { - const $injector = await chrome.dangerouslyGetActiveInjector(); - const es = $injector.get('es') as ApiCaller; - - await this.requestIsStarting(options); - - const searchRequest = await this.flatten(); - this.history = [searchRequest]; - - const response = await fetchSoon( - searchRequest, - { - ...(this.searchStrategyId && { searchStrategyId: this.searchStrategyId }), - ...options, - }, - { es, config, esShardTimeout } - ); - - if (response.error) { - throw new RequestFailure(null, response); - } - - return response; - } - - /** - * Add a handler that will be notified whenever requests start - * @param {Function} handler - * @return {undefined} - */ - onRequestStart( - handler: (searchSource: SearchSourceContract, options?: FetchOptions) => Promise - ) { - this.requestStartHandlers.push(handler); - } - - async getSearchRequestBody() { - const searchRequest = await this.flatten(); - return searchRequest.body; - } - - /** - * Completely destroy the SearchSource. - * @return {undefined} - */ - destroy() { - this.requestStartHandlers.length = 0; - } - - /** **** - * PRIVATE APIS - ******/ - - /** - * Called by requests of this search source when they are started - * @param {Courier.Request} request - * @param options - * @return {Promise} - */ - private requestIsStarting(options: FetchOptions = {}) { - const handlers = [...this.requestStartHandlers]; - // If callParentStartHandlers has been set to true, we also call all - // handlers of parent search sources. - if (this.inheritOptions.callParentStartHandlers) { - let searchSource = this.getParent(); - while (searchSource) { - handlers.push(...searchSource.requestStartHandlers); - searchSource = searchSource.getParent(); - } - } - - return Promise.all(handlers.map(fn => fn(this, options))); - } - - /** - * Used to merge properties into the data within ._flatten(). - * The data is passed in and modified by the function - * - * @param {object} data - the current merged data - * @param {*} val - the value at `key` - * @param {*} key - The key of `val` - * @return {undefined} - */ - private mergeProp( - data: SearchRequest, - val: SearchSourceFields[K], - key: K - ) { - val = typeof val === 'function' ? val(this) : val; - if (val == null || !key) return; - - const addToRoot = (rootKey: string, value: any) => { - data[rootKey] = value; - }; - - /** - * Add the key and val to the body of the request - */ - const addToBody = (bodyKey: string, value: any) => { - // ignore if we already have a value - if (data.body[bodyKey] == null) { - data.body[bodyKey] = value; - } - }; - - switch (key) { - case 'filter': - return addToRoot('filters', (data.filters || []).concat(val)); - case 'query': - return addToRoot(key, (data[key] || []).concat(val)); - case 'fields': - const fields = _.uniq((data[key] || []).concat(val)); - return addToRoot(key, fields); - case 'index': - case 'type': - case 'highlightAll': - return key && data[key] == null && addToRoot(key, val); - case 'searchAfter': - return addToBody('search_after', val); - case 'source': - return addToBody('_source', val); - case 'sort': - const sort = normalizeSortRequest(val, this.getField('index'), config.get('sort:options')); - return addToBody(key, sort); - default: - return addToBody(key, val); - } - } - - /** - * Walk the inheritance chain of a source and return its - * flat representation (taking into account merging rules) - * @returns {Promise} - * @resolved {Object|null} - the flat data of the SearchSource - */ - private mergeProps(root = this, searchRequest: SearchRequest = { body: {} }) { - Object.entries(this.fields).forEach(([key, value]) => { - this.mergeProp(searchRequest, value, key as keyof SearchSourceFields); - }); - if (this.parent) { - this.parent.mergeProps(root, searchRequest); - } - return searchRequest; - } - - private flatten() { - const searchRequest = this.mergeProps(); - - searchRequest.body = searchRequest.body || {}; - const { body, index, fields, query, filters, highlightAll } = searchRequest; - - const computedFields = index ? index.getComputedFields() : {}; - - body.stored_fields = computedFields.storedFields; - body.script_fields = body.script_fields || {}; - _.extend(body.script_fields, computedFields.scriptFields); - - const defaultDocValueFields = computedFields.docvalueFields - ? computedFields.docvalueFields - : []; - body.docvalue_fields = body.docvalue_fields || defaultDocValueFields; - - if (!body.hasOwnProperty('_source') && index) { - body._source = index.getSourceFiltering(); - } - - if (body._source) { - // exclude source fields for this index pattern specified by the user - const filter = fieldWildcardFilter(body._source.excludes, config.get('metaFields')); - body.docvalue_fields = body.docvalue_fields.filter((docvalueField: any) => - filter(docvalueField.field) - ); - } - - // if we only want to search for certain fields - if (fields) { - // filter out the docvalue_fields, and script_fields to only include those that we are concerned with - body.docvalue_fields = filterDocvalueFields(body.docvalue_fields, fields); - body.script_fields = _.pick(body.script_fields, fields); - - // request the remaining fields from both stored_fields and _source - const remainingFields = _.difference(fields, _.keys(body.script_fields)); - body.stored_fields = remainingFields; - _.set(body, '_source.includes', remainingFields); - } - - const esQueryConfigs = esQuery.getEsQueryConfig(config); - body.query = esQuery.buildEsQuery(index, query, filters, esQueryConfigs); - - if (highlightAll && body.query) { - body.highlight = getHighlightRequest(body.query, config.get('doc_table:highlight')); - delete searchRequest.highlightAll; - } - - const translateToQuery = (filter: esFilters.Filter) => filter && (filter.query || filter); - - // re-write filters within filter aggregations - (function recurse(aggBranch) { - if (!aggBranch) return; - Object.keys(aggBranch).forEach(function(id) { - const agg = aggBranch[id]; - - if (agg.filters) { - // translate filters aggregations - const { filters: aggFilters } = agg.filters; - Object.keys(aggFilters).forEach(filterId => { - aggFilters[filterId] = translateToQuery(aggFilters[filterId]); - }); - } - - recurse(agg.aggs || agg.aggregations); - }); - })(body.aggs || body.aggregations); - - return searchRequest; - } -} +export { SearchSource, ISearchSource } from '../index'; diff --git a/src/legacy/ui/public/courier/search_strategy/default_search_strategy.ts b/src/legacy/ui/public/courier/search_strategy/default_search_strategy.ts index 5be4fef076655..55dee19cae32a 100644 --- a/src/legacy/ui/public/courier/search_strategy/default_search_strategy.ts +++ b/src/legacy/ui/public/courier/search_strategy/default_search_strategy.ts @@ -17,65 +17,8 @@ * under the License. */ -import { SearchStrategyProvider, SearchStrategySearchParams } from './types'; -import { addSearchStrategy } from './search_strategy_registry'; -import { isDefaultTypeIndexPattern } from './is_default_type_index_pattern'; -import { - getSearchParams, - getMSearchParams, - getPreference, - getTimeout, -} from '../fetch/get_search_params'; - -export const defaultSearchStrategy: SearchStrategyProvider = { - id: 'default', - - search: params => { - return params.config.get('courier:batchSearches') ? msearch(params) : search(params); - }, - - isViable: indexPattern => { - return indexPattern && isDefaultTypeIndexPattern(indexPattern); - }, -}; - -function msearch({ searchRequests, es, config, esShardTimeout }: SearchStrategySearchParams) { - const inlineRequests = searchRequests.map(({ index, body, search_type: searchType }) => { - const inlineHeader = { - index: index.title || index, - search_type: searchType, - ignore_unavailable: true, - preference: getPreference(config), - }; - const inlineBody = { - ...body, - timeout: getTimeout(esShardTimeout), - }; - return `${JSON.stringify(inlineHeader)}\n${JSON.stringify(inlineBody)}`; - }); - - const searching = es.msearch({ - ...getMSearchParams(config), - body: `${inlineRequests.join('\n')}\n`, - }); - return { - searching: searching.then(({ responses }) => responses), - abort: searching.abort, - }; -} - -function search({ searchRequests, es, config, esShardTimeout }: SearchStrategySearchParams) { - const abortController = new AbortController(); - const searchParams = getSearchParams(config, esShardTimeout); - const promises = searchRequests.map(({ index, body }) => { - const searching = es.search({ index: index.title || index, body, ...searchParams }); - abortController.signal.addEventListener('abort', searching.abort); - return searching.catch(({ response }) => JSON.parse(response)); - }); - return { - searching: Promise.all(promises), - abort: () => abortController.abort(), - }; -} +import { addSearchStrategy, defaultSearchStrategy } from '../index'; addSearchStrategy(defaultSearchStrategy); + +export { defaultSearchStrategy }; diff --git a/src/legacy/ui/public/courier/search_strategy/index.ts b/src/legacy/ui/public/courier/search_strategy/index.ts index 229d0cbb1da5d..1dce0316596d0 100644 --- a/src/legacy/ui/public/courier/search_strategy/index.ts +++ b/src/legacy/ui/public/courier/search_strategy/index.ts @@ -20,10 +20,6 @@ export { addSearchStrategy, hasSearchStategyForIndexPattern, - getSearchStrategyById, - getSearchStrategyForSearchRequest, -} from './search_strategy_registry'; - -export { isDefaultTypeIndexPattern } from './is_default_type_index_pattern'; - -export { SearchError, getSearchErrorType } from './search_error'; + isDefaultTypeIndexPattern, + SearchError, +} from '../index'; diff --git a/src/legacy/ui/public/courier/search_strategy/search_error.ts b/src/legacy/ui/public/courier/search_strategy/search_error.ts index d4042fb17499c..a815ac4ff008f 100644 --- a/src/legacy/ui/public/courier/search_strategy/search_error.ts +++ b/src/legacy/ui/public/courier/search_strategy/search_error.ts @@ -17,46 +17,4 @@ * under the License. */ -interface SearchErrorOptions { - status: string; - title: string; - message: string; - path: string; - type: string; -} - -export class SearchError extends Error { - public name: string; - public status: string; - public title: string; - public message: string; - public path: string; - public type: string; - - constructor({ status, title, message, path, type }: SearchErrorOptions) { - super(message); - this.name = 'SearchError'; - this.status = status; - this.title = title; - this.message = message; - this.path = path; - this.type = type; - - // captureStackTrace is only available in the V8 engine, so any browser using - // a different JS engine won't have access to this method. - if (Error.captureStackTrace) { - Error.captureStackTrace(this, SearchError); - } - - // Babel doesn't support traditional `extends` syntax for built-in classes. - // https://babeljs.io/docs/en/caveats/#classes - Object.setPrototypeOf(this, SearchError.prototype); - } -} - -export function getSearchErrorType({ message }: Pick) { - const msg = message.toLowerCase(); - if (msg.indexOf('unsupported query') > -1) { - return 'UNSUPPORTED_QUERY'; - } -} +export { SearchError } from '../index'; diff --git a/src/legacy/ui/public/courier/types.ts b/src/legacy/ui/public/courier/types.ts index 23d74ce6a57da..75035ceef321f 100644 --- a/src/legacy/ui/public/courier/types.ts +++ b/src/legacy/ui/public/courier/types.ts @@ -17,7 +17,9 @@ * under the License. */ -export * from './fetch/types'; -export * from './search_source/types'; -export * from './search_strategy/types'; -export * from './utils/types'; +export { + ISearchSource, + EsQuerySortValue, // used externally by Discover + FetchOptions, // used externally by AggTypes + SortDirection, // used externally by Discover +} from './index'; diff --git a/src/legacy/ui/public/vis/editors/default/components/agg.tsx b/src/legacy/ui/public/vis/editors/default/components/agg.tsx index 345c9254ff6c1..308376adfa58f 100644 --- a/src/legacy/ui/public/vis/editors/default/components/agg.tsx +++ b/src/legacy/ui/public/vis/editors/default/components/agg.tsx @@ -79,7 +79,7 @@ function DefaultEditorAgg({ if (['date_histogram', 'histogram'].includes(agg.type.name)) { disabledParams = ['min_doc_count']; } else { - aggError = i18n.translate('common.ui.aggTypes.metrics.wrongLastBucketTypeErrorMessage', { + aggError = i18n.translate('data.search.aggs.metrics.wrongLastBucketTypeErrorMessage', { defaultMessage: 'Last bucket aggregation must be "Date Histogram" or "Histogram" when using "{type}" metric aggregation.', values: { type: lastParentPipelineAggTitle }, diff --git a/src/legacy/ui/public/vis/editors/default/components/agg_group.tsx b/src/legacy/ui/public/vis/editors/default/components/agg_group.tsx index 528914f4fd006..2aa87afd364bd 100644 --- a/src/legacy/ui/public/vis/editors/default/components/agg_group.tsx +++ b/src/legacy/ui/public/vis/editors/default/components/agg_group.tsx @@ -84,7 +84,7 @@ function DefaultEditorAggGroup({ const bucketsError = lastParentPipelineAggTitle && groupName === AggGroupNames.Buckets && !group.length - ? i18n.translate('common.ui.aggTypes.buckets.mustHaveBucketErrorMessage', { + ? i18n.translate('data.search.aggs.buckets.mustHaveBucketErrorMessage', { defaultMessage: 'Add a bucket with "Date Histogram" or "Histogram" aggregation.', description: 'Date Histogram and Histogram should not be translated', }) diff --git a/src/legacy/ui/public/vis/editors/default/controls/__snapshots__/size.test.tsx.snap b/src/legacy/ui/public/vis/editors/default/controls/__snapshots__/size.test.tsx.snap index 024865ec733d6..0a142c4260deb 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/__snapshots__/size.test.tsx.snap +++ b/src/legacy/ui/public/vis/editors/default/controls/__snapshots__/size.test.tsx.snap @@ -13,7 +13,7 @@ exports[`SizeParamEditor should init with the default set of props 1`] = ` diff --git a/src/legacy/ui/public/vis/editors/default/controls/__snapshots__/top_aggregate.test.tsx.snap b/src/legacy/ui/public/vis/editors/default/controls/__snapshots__/top_aggregate.test.tsx.snap index 74c952dbf059f..ed49639e32973 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/__snapshots__/top_aggregate.test.tsx.snap +++ b/src/legacy/ui/public/vis/editors/default/controls/__snapshots__/top_aggregate.test.tsx.snap @@ -13,7 +13,7 @@ exports[`TopAggregateParamEditor should init with the default set of props 1`] = diff --git a/src/legacy/ui/public/vis/editors/default/controls/agg_utils.ts b/src/legacy/ui/public/vis/editors/default/controls/agg_utils.ts index 6491ef2e46054..f630d2928838a 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/agg_utils.ts +++ b/src/legacy/ui/public/vis/editors/default/controls/agg_utils.ts @@ -25,7 +25,7 @@ type AggFilter = string[]; const DEFAULT_METRIC = 'custom'; const CUSTOM_METRIC = { - text: i18n.translate('common.ui.aggTypes.customMetricLabel', { + text: i18n.translate('data.search.aggs.customMetricLabel', { defaultMessage: 'Custom metric', }), value: DEFAULT_METRIC, @@ -76,7 +76,7 @@ function useAvailableOptions( const options = useMemo( () => [ ...metricAggs.map(respAgg => ({ - text: i18n.translate('common.ui.aggTypes.definiteMetricLabel', { + text: i18n.translate('data.search.aggs.definiteMetricLabel', { defaultMessage: 'Metric: {metric}', values: { metric: safeMakeLabel(respAgg), @@ -110,7 +110,7 @@ function safeMakeLabel(agg: AggConfig): string { try { return agg.makeLabel(); } catch (e) { - return i18n.translate('common.ui.aggTypes.aggNotValidLabel', { + return i18n.translate('data.search.aggs.aggNotValidLabel', { defaultMessage: '- agg not valid -', }); } diff --git a/src/legacy/ui/public/vis/editors/default/controls/auto_precision.tsx b/src/legacy/ui/public/vis/editors/default/controls/auto_precision.tsx index 53f74465e90a5..3f46a77b3b181 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/auto_precision.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/auto_precision.tsx @@ -24,7 +24,7 @@ import { i18n } from '@kbn/i18n'; import { AggParamEditorProps } from '..'; function AutoPrecisionParamEditor({ value = false, setValue }: AggParamEditorProps) { - const label = i18n.translate('common.ui.aggTypes.changePrecisionLabel', { + const label = i18n.translate('data.search.aggs.changePrecisionLabel', { defaultMessage: 'Change precision on map zoom', }); diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/from_to_list.tsx b/src/legacy/ui/public/vis/editors/default/controls/components/from_to_list.tsx index 57787c58a2e5b..2849937e562b9 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/components/from_to_list.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/components/from_to_list.tsx @@ -59,7 +59,7 @@ function FromToList({ showValidation, onBlur, ...rest }: FromToListProps) { to: { value: item.to || EMPTY_STRING, model: item.to || EMPTY_STRING, isInvalid: false }, }), getRemoveBtnAriaLabel: (item: FromToModel) => - i18n.translate('common.ui.aggTypes.ipRanges.removeRangeAriaLabel', { + i18n.translate('data.search.aggs.ipRanges.removeRangeAriaLabel', { defaultMessage: 'Remove the range of {from} to {to}', values: { from: item.from.value || '*', to: item.to.value || '*' }, }), @@ -78,7 +78,7 @@ function FromToList({ showValidation, onBlur, ...rest }: FromToListProps) { <> diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/mask_list.tsx b/src/legacy/ui/public/vis/editors/default/controls/components/mask_list.tsx index b48f07512332e..0523f09e044a3 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/components/mask_list.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/components/mask_list.tsx @@ -56,11 +56,11 @@ function MaskList({ showValidation, onBlur, ...rest }: MaskListProps) { }), getRemoveBtnAriaLabel: (item: MaskModel) => item.mask.value - ? i18n.translate('common.ui.aggTypes.ipRanges.removeCidrMaskButtonAriaLabel', { + ? i18n.translate('data.search.aggs.ipRanges.removeCidrMaskButtonAriaLabel', { defaultMessage: 'Remove the CIDR mask value of {mask}', values: { mask: item.mask.value }, }) - : i18n.translate('common.ui.aggTypes.ipRanges.removeEmptyCidrMaskButtonAriaLabel', { + : i18n.translate('data.search.aggs.ipRanges.removeEmptyCidrMaskButtonAriaLabel', { defaultMessage: 'Remove the CIDR mask default value', }), onChangeFn: ({ mask }: MaskModel) => { @@ -73,7 +73,7 @@ function MaskList({ showValidation, onBlur, ...rest }: MaskListProps) { renderInputRow: ({ mask }: MaskModel, index, onChangeValue) => ( diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/number_row.tsx b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/number_row.tsx index 777b0a94f0f3d..70237f84c4d35 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/number_row.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/number_row.tsx @@ -54,7 +54,7 @@ function NumberRow({ onChange, }: NumberRowProps) { const deleteBtnAriaLabel = i18n.translate( - 'common.ui.aggTypes.numberList.removeUnitButtonAriaLabel', + 'data.search.aggs.numberList.removeUnitButtonAriaLabel', { defaultMessage: 'Remove the rank value of {value}', values: { value: model.value }, @@ -80,7 +80,7 @@ function NumberRow({ autoFocus={autoFocus} compressed={true} isInvalid={isInvalid} - placeholder={i18n.translate('common.ui.aggTypes.numberList.enterValuePlaceholder', { + placeholder={i18n.translate('data.search.aggs.numberList.enterValuePlaceholder', { defaultMessage: 'Enter a value', })} onChange={onValueChanged} diff --git a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.ts b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.ts index 399253f27445c..c4fa59e203dc1 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.ts +++ b/src/legacy/ui/public/vis/editors/default/controls/components/number_list/utils.ts @@ -51,7 +51,7 @@ function validateValue(value: number | '', numberRange: NumberListRange) { result.isInvalid = true; } else if (!numberRange.within(value)) { result.isInvalid = true; - result.error = i18n.translate('common.ui.aggTypes.numberList.invalidRangeErrorMessage', { + result.error = i18n.translate('data.search.aggs.numberList.invalidRangeErrorMessage', { defaultMessage: 'The value should be in the range of {min} to {max}.', values: { min: numberRange.min, max: numberRange.max }, }); diff --git a/src/legacy/ui/public/vis/editors/default/controls/date_ranges.tsx b/src/legacy/ui/public/vis/editors/default/controls/date_ranges.tsx index 9cef3e1b218e9..c88457485e3a4 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/date_ranges.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/date_ranges.tsx @@ -116,7 +116,7 @@ function DateRangesParamEditor({ @@ -125,7 +125,7 @@ function DateRangesParamEditor({ {ranges.map(({ from, to, id }) => { const deleteBtnTitle = i18n.translate( - 'common.ui.aggTypes.dateRanges.removeRangeButtonAriaLabel', + 'data.search.aggs.dateRanges.removeRangeButtonAriaLabel', { defaultMessage: 'Remove the range of {from} to {to}', values: { from: from || FROM_PLACEHOLDER, to: to || TO_PLACEHOLDER }, @@ -138,7 +138,7 @@ function DateRangesParamEditor({ @@ -197,7 +197,7 @@ function DateRangesParamEditor({ diff --git a/src/legacy/ui/public/vis/editors/default/controls/drop_partials.tsx b/src/legacy/ui/public/vis/editors/default/controls/drop_partials.tsx index 52189452af776..881e18200b956 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/drop_partials.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/drop_partials.tsx @@ -26,10 +26,10 @@ function DropPartialsParamEditor(props: AggParamEditorProps) { return ( ) { - const minLabel = i18n.translate('common.ui.aggTypes.extendedBounds.minLabel', { + const minLabel = i18n.translate('data.search.aggs.extendedBounds.minLabel', { defaultMessage: 'Min', }); - const maxLabel = i18n.translate('common.ui.aggTypes.extendedBounds.maxLabel', { + const maxLabel = i18n.translate('data.search.aggs.extendedBounds.maxLabel', { defaultMessage: 'Max', }); @@ -57,7 +57,7 @@ function ExtendedBoundsParamEditor({ let error; if (!isValid) { - error = i18n.translate('common.ui.aggTypes.extendedBounds.errorMessage', { + error = i18n.translate('data.search.aggs.extendedBounds.errorMessage', { defaultMessage: 'Min should be less than or equal to Max.', }); } diff --git a/src/legacy/ui/public/vis/editors/default/controls/field.tsx b/src/legacy/ui/public/vis/editors/default/controls/field.tsx index a96be3a14b7ef..a1fc8cb2cdaee 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/field.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/field.tsx @@ -28,7 +28,7 @@ import { formatListAsProse, parseCommaSeparatedList } from '../../../../../../ut import { AggParam, FieldParamType } from '../../../../agg_types'; import { AggParamEditorProps, ComboBoxGroupedOptions } from '..'; -const label = i18n.translate('common.ui.aggTypes.field.fieldLabel', { defaultMessage: 'Field' }); +const label = i18n.translate('data.search.aggs.field.fieldLabel', { defaultMessage: 'Field' }); export interface FieldParamEditorProps extends AggParamEditorProps { customError?: string; @@ -65,7 +65,7 @@ function FieldParamEditor({ if (!indexedFields.length) { errors.push( - i18n.translate('common.ui.aggTypes.field.noCompatibleFieldsDescription', { + i18n.translate('data.search.aggs.field.noCompatibleFieldsDescription', { defaultMessage: 'The index pattern {indexPatternTitle} does not contain any of the following compatible field types: {fieldTypes}', values: { @@ -111,7 +111,7 @@ function FieldParamEditor({ > onRemoveFilter(id)} @@ -113,7 +113,7 @@ function FilterRow({ {showCustomLabel ? ( onChangeValue(id, value, ev.target.value)} diff --git a/src/legacy/ui/public/vis/editors/default/controls/filters.tsx b/src/legacy/ui/public/vis/editors/default/controls/filters.tsx index aa654d26a23fd..6a36ff00117d2 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/filters.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/filters.tsx @@ -111,7 +111,7 @@ function FiltersParamEditor({ agg, value = [], setValue }: AggParamEditorProps diff --git a/src/legacy/ui/public/vis/editors/default/controls/has_extended_bounds.tsx b/src/legacy/ui/public/vis/editors/default/controls/has_extended_bounds.tsx index 5ab41e1abcde2..1297b88a5bb72 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/has_extended_bounds.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/has_extended_bounds.tsx @@ -30,10 +30,10 @@ function HasExtendedBoundsParamEditor(props: AggParamEditorProps) { return ( diff --git a/src/legacy/ui/public/vis/editors/default/controls/is_filtered_by_collar.tsx b/src/legacy/ui/public/vis/editors/default/controls/is_filtered_by_collar.tsx index 012e8f30534eb..4bcfdfa47e61c 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/is_filtered_by_collar.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/is_filtered_by_collar.tsx @@ -25,10 +25,10 @@ import { AggParamEditorProps } from '..'; function IsFilteredByCollarParamEditor(props: AggParamEditorProps) { return ( ) { - const label = i18n.translate('common.ui.aggTypes.metricLabel', { + const label = i18n.translate('data.search.aggs.metricLabel', { defaultMessage: 'Metric', }); const isValid = !!value; diff --git a/src/legacy/ui/public/vis/editors/default/controls/min_doc_count.tsx b/src/legacy/ui/public/vis/editors/default/controls/min_doc_count.tsx index e366c2daa9007..c150fbaa68261 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/min_doc_count.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/min_doc_count.tsx @@ -26,10 +26,10 @@ import { AggParamEditorProps } from '..'; function MinDocCountParamEditor(props: AggParamEditorProps) { return ( ) { return ( {' '} @@ -86,7 +86,7 @@ function NumberIntervalParamEditor({ onBlur={setTouched} fullWidth={true} compressed - placeholder={i18n.translate('common.ui.aggTypes.numberInterval.selectIntervalPlaceholder', { + placeholder={i18n.translate('data.search.aggs.numberInterval.selectIntervalPlaceholder', { defaultMessage: 'Enter an interval', })} /> diff --git a/src/legacy/ui/public/vis/editors/default/controls/order.tsx b/src/legacy/ui/public/vis/editors/default/controls/order.tsx index ec9be206fe130..d47df11db1d5d 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/order.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/order.tsx @@ -34,7 +34,7 @@ function OrderParamEditor({ setValidity, setTouched, }: AggParamEditorProps & OptionedParamEditorProps) { - const label = i18n.translate('common.ui.aggTypes.orderLabel', { + const label = i18n.translate('data.search.aggs.orderLabel', { defaultMessage: 'Order', }); const isValid = !!value; diff --git a/src/legacy/ui/public/vis/editors/default/controls/order_by.tsx b/src/legacy/ui/public/vis/editors/default/controls/order_by.tsx index 644135c068275..a9ae98ce8b419 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/order_by.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/order_by.tsx @@ -31,7 +31,7 @@ import { AggParamEditorProps } from '..'; const DEFAULT_VALUE = '_key'; const DEFAULT_OPTIONS = [ { - text: i18n.translate('common.ui.aggTypes.orderAgg.alphabeticalLabel', { + text: i18n.translate('data.search.aggs.orderAgg.alphabeticalLabel', { defaultMessage: 'Alphabetical', }), value: DEFAULT_VALUE, @@ -62,7 +62,7 @@ function OrderByParamEditor({ setTouched, metricAggs, }: AggParamEditorProps) { - const label = i18n.translate('common.ui.aggTypes.orderAgg.orderByLabel', { + const label = i18n.translate('data.search.aggs.orderAgg.orderByLabel', { defaultMessage: 'Order by', }); const isValid = !!value; diff --git a/src/legacy/ui/public/vis/editors/default/controls/other_bucket.tsx b/src/legacy/ui/public/vis/editors/default/controls/other_bucket.tsx index 80a1e8fa362be..d41bd5f3ad688 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/other_bucket.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/other_bucket.tsx @@ -26,10 +26,10 @@ function OtherBucketParamEditor(props: AggParamEditorProps) { return ( >) { - const label = i18n.translate('common.ui.aggTypes.percentileRanks.valuesLabel', { + const label = i18n.translate('data.search.aggs.percentileRanks.valuesLabel', { defaultMessage: 'Values', }); const [isValid, setIsValid] = useState(true); @@ -56,7 +56,7 @@ function PercentileRanksEditor({ labelledbyId={`visEditorPercentileRanksLabel${agg.id}-legend`} numberArray={value} range="[-Infinity,Infinity]" - unitName={i18n.translate('common.ui.aggTypes.percentileRanks.valueUnitNameText', { + unitName={i18n.translate('data.search.aggs.percentileRanks.valueUnitNameText', { defaultMessage: 'value', })} showValidation={showValidation} diff --git a/src/legacy/ui/public/vis/editors/default/controls/percentiles.tsx b/src/legacy/ui/public/vis/editors/default/controls/percentiles.tsx index b8ad212edead9..fe5680e22a41e 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/percentiles.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/percentiles.tsx @@ -32,7 +32,7 @@ function PercentilesEditor({ setValidity, setValue, }: AggParamEditorProps>) { - const label = i18n.translate('common.ui.aggTypes.percentiles.percentsLabel', { + const label = i18n.translate('data.search.aggs.percentiles.percentsLabel', { defaultMessage: 'Percents', }); const [isValid, setIsValid] = useState(true); @@ -56,7 +56,7 @@ function PercentilesEditor({ numberArray={value} range="[0,100]" validateAscendingOrder={false} - unitName={i18n.translate('common.ui.aggTypes.percentileRanks.percentUnitNameText', { + unitName={i18n.translate('data.search.aggs.percentileRanks.percentUnitNameText', { defaultMessage: 'percent', })} showValidation={showValidation} diff --git a/src/legacy/ui/public/vis/editors/default/controls/precision.tsx b/src/legacy/ui/public/vis/editors/default/controls/precision.tsx index 88f389cb7c009..81da51b205a3d 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/precision.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/precision.tsx @@ -31,7 +31,7 @@ function PrecisionParamEditor({ agg, value, setValue }: AggParamEditorProps {ranges.map(({ from, to, id }, index) => { const deleteBtnTitle = i18n.translate( - 'common.ui.aggTypes.ranges.removeRangeButtonAriaLabel', + 'data.search.aggs.ranges.removeRangeButtonAriaLabel', { defaultMessage: 'Remove the range of {from} to {to}', values: { @@ -157,21 +157,21 @@ function RangesParamEditor({ } const gtePrependLabel = i18n.translate( - 'common.ui.aggTypes.ranges.greaterThanOrEqualPrepend', + 'data.search.aggs.ranges.greaterThanOrEqualPrepend', { defaultMessage: '\u2265', } ); const gteTooltipContent = i18n.translate( - 'common.ui.aggTypes.ranges.greaterThanOrEqualTooltip', + 'data.search.aggs.ranges.greaterThanOrEqualTooltip', { defaultMessage: 'Greater than or equal to', } ); - const ltPrependLabel = i18n.translate('common.ui.aggTypes.ranges.lessThanPrepend', { + const ltPrependLabel = i18n.translate('data.search.aggs.ranges.lessThanPrepend', { defaultMessage: '\u003c', }); - const ltTooltipContent = i18n.translate('common.ui.aggTypes.ranges.lessThanTooltip', { + const ltTooltipContent = i18n.translate('data.search.aggs.ranges.lessThanTooltip', { defaultMessage: 'Less than', }); @@ -180,7 +180,7 @@ function RangesParamEditor({ diff --git a/src/legacy/ui/public/vis/editors/default/controls/raw_json.tsx b/src/legacy/ui/public/vis/editors/default/controls/raw_json.tsx index 78ef1bf939b7d..bcb2ab6134715 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/raw_json.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/raw_json.tsx @@ -35,10 +35,10 @@ function RawJsonParamEditor({ }: AggParamEditorProps) { const label = ( <> - {' '} + {' '} ) { return ( - + {iconTip} ); diff --git a/src/legacy/ui/public/vis/editors/default/controls/sub_metric.tsx b/src/legacy/ui/public/vis/editors/default/controls/sub_metric.tsx index df1640273135e..e874b0af599f2 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/sub_metric.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/sub_metric.tsx @@ -34,10 +34,10 @@ function SubMetricParamEditor({ setTouched, subAggParams, }: AggParamEditorProps) { - const metricTitle = i18n.translate('common.ui.aggTypes.metrics.metricTitle', { + const metricTitle = i18n.translate('data.search.aggs.metrics.metricTitle', { defaultMessage: 'Metric', }); - const bucketTitle = i18n.translate('common.ui.aggTypes.metrics.bucketTitle', { + const bucketTitle = i18n.translate('data.search.aggs.metrics.bucketTitle', { defaultMessage: 'Bucket', }); const type = aggParam.name; diff --git a/src/legacy/ui/public/vis/editors/default/controls/time_interval.tsx b/src/legacy/ui/public/vis/editors/default/controls/time_interval.tsx index 8c3590386b49a..4256a61cdc124 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/time_interval.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/time_interval.tsx @@ -68,7 +68,7 @@ function TimeIntervalParamEditor({ interval && interval.scaled && isValid ? ( {' '} @@ -91,7 +91,7 @@ function TimeIntervalParamEditor({ if (!isValid && value) { errors.push( - i18n.translate('common.ui.aggTypes.timeInterval.invalidFormatErrorMessage', { + i18n.translate('data.search.aggs.timeInterval.invalidFormatErrorMessage', { defaultMessage: 'Invalid interval format.', }) ); @@ -126,7 +126,7 @@ function TimeIntervalParamEditor({ fullWidth={true} helpText={helpText} isInvalid={showValidation ? !isValid : false} - label={i18n.translate('common.ui.aggTypes.timeInterval.minimumIntervalLabel', { + label={i18n.translate('data.search.aggs.timeInterval.minimumIntervalLabel', { defaultMessage: 'Minimum interval', })} > @@ -141,7 +141,7 @@ function TimeIntervalParamEditor({ options={options} selectedOptions={selectedOptions} singleSelection={{ asPlainText: true }} - placeholder={i18n.translate('common.ui.aggTypes.timeInterval.selectIntervalPlaceholder', { + placeholder={i18n.translate('data.search.aggs.timeInterval.selectIntervalPlaceholder', { defaultMessage: 'Select an interval', })} onBlur={setTouched} @@ -152,19 +152,19 @@ function TimeIntervalParamEditor({ const tooManyBucketsTooltip = ( ); const tooLargeBucketsTooltip = ( ); const selectOptionHelpText = ( ); diff --git a/src/legacy/ui/public/vis/editors/default/controls/top_aggregate.tsx b/src/legacy/ui/public/vis/editors/default/controls/top_aggregate.tsx index 45f898805709e..26f6b025fb329 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/top_aggregate.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/top_aggregate.tsx @@ -65,14 +65,11 @@ export function TopAggregateParamEditor({ const label = ( <> - {' '} + {' '} ) { let customError; if (props.value && !compatibleAggs.length) { - customError = i18n.translate('common.ui.aggTypes.aggregateWith.noAggsErrorTooltip', { + customError = i18n.translate('data.search.aggs.aggregateWith.noAggsErrorTooltip', { defaultMessage: 'The chosen field has no compatible aggregations.', }); } diff --git a/src/legacy/ui/public/vis/editors/default/controls/top_size.tsx b/src/legacy/ui/public/vis/editors/default/controls/top_size.tsx index 4810b6fa9c232..3c5a90a2db214 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/top_size.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/top_size.tsx @@ -30,7 +30,7 @@ function TopSizeParamEditor(props: AggParamEditorProps) { {' '} ) { - const customLabel = i18n.translate('common.ui.aggTypes.sortOnLabel', { + const customLabel = i18n.translate('data.search.aggs.sortOnLabel', { defaultMessage: 'Sort on', }); diff --git a/src/legacy/ui/public/vis/editors/default/controls/use_geocentroid.tsx b/src/legacy/ui/public/vis/editors/default/controls/use_geocentroid.tsx index 932a4d19b495c..93d7babbc291a 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/use_geocentroid.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/use_geocentroid.tsx @@ -24,7 +24,7 @@ import { i18n } from '@kbn/i18n'; import { AggParamEditorProps } from '..'; function UseGeocentroidParamEditor({ value = false, setValue }: AggParamEditorProps) { - const label = i18n.translate('common.ui.aggTypes.placeMarkersOffGridLabel', { + const label = i18n.translate('data.search.aggs.placeMarkersOffGridLabel', { defaultMessage: 'Place markers off grid (use geocentroid)', }); diff --git a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts index d754c1d395595..3ebcd7307c43d 100644 --- a/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts +++ b/src/legacy/ui/public/visualize/loader/pipeline_helpers/utilities.ts @@ -103,7 +103,7 @@ export const getFormat: FormatFactory = mapping => { const format = getFieldFormat(id, mapping.params); const gte = '\u2265'; const lt = '\u003c'; - return i18n.translate('common.ui.aggTypes.buckets.ranges.rangesFormatMessage', { + return i18n.translate('data.search.aggs.buckets.ranges.rangesFormatMessage', { defaultMessage: '{gte} {from} and {lt} {to}', values: { gte, diff --git a/src/legacy/ui/public/visualize/loader/utils/query_geohash_bounds.ts b/src/legacy/ui/public/visualize/loader/utils/query_geohash_bounds.ts index a9203415321fa..5054c34118f78 100644 --- a/src/legacy/ui/public/visualize/loader/utils/query_geohash_bounds.ts +++ b/src/legacy/ui/public/visualize/loader/utils/query_geohash_bounds.ts @@ -24,13 +24,13 @@ import { toastNotifications } from 'ui/notify'; import { AggConfig } from 'ui/vis'; import { timefilter } from 'ui/timefilter'; import { Vis } from '../../../vis'; -import { SearchSource, SearchSourceContract } from '../../../courier'; +import { SearchSource, ISearchSource } from '../../../courier'; import { esFilters, Query } from '../../../../../../plugins/data/public'; interface QueryGeohashBoundsParams { filters?: esFilters.Filter[]; query?: Query; - searchSource?: SearchSourceContract; + searchSource?: ISearchSource; } /** diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx index f7125a1adae52..ecba6ff20de41 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/date_histogram.test.tsx @@ -14,19 +14,26 @@ import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { createMockedIndexPattern } from '../../mocks'; import { IndexPatternPrivateState } from '../../types'; -jest.mock('ui/new_platform', () => ({ - npStart: { - core: { - uiSettings: { - get: (path: string) => { - if (path === 'histogram:maxBars') { - return 10; - } +jest.mock('ui/new_platform', () => { + const { coreMock } = require('src/core/public/mocks'); // eslint-disable-line @typescript-eslint/no-var-requires + return { + npSetup: { + core: coreMock.createSetup(), + }, + npStart: { + core: { + ...coreMock.createStart(), + uiSettings: { + get: (path: string) => { + if (path === 'histogram:maxBars') { + return 10; + } + }, }, }, }, - }, -})); + }; +}); const defaultOptions = { storage: {} as IStorageWrapper, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d6e72583e4d2e..c0764da045040 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -79,206 +79,188 @@ "common.ui.aggResponse.allDocsTitle": "すべてのドキュメント", "common.ui.aggResponse.fieldLabel": "フィールド", "common.ui.aggResponse.valueLabel": "値", - "common.ui.aggTypes.aggNotValidLabel": "- 無効な集約 -", - "common.ui.aggTypes.aggregateWith.noAggsErrorTooltip": "選択されたフィールドには互換性のある集約がありません。", - "common.ui.aggTypes.aggregateWithLabel": "アグリゲーション:", - "common.ui.aggTypes.aggregateWithTooltip": "複数ヒットまたは複数値のフィールドを 1 つのメトリックにまとめる方法を選択します。", - "common.ui.aggTypes.buckets.dateHistogramLabel": "{intervalDescription}ごとの {fieldName}", - "common.ui.aggTypes.buckets.dateHistogramTitle": "Date Histogram", - "common.ui.aggTypes.buckets.dateRangeTitle": "日付範囲", - "common.ui.aggTypes.buckets.filtersTitle": "フィルター", - "common.ui.aggTypes.buckets.filterTitle": "フィルター", - "common.ui.aggTypes.buckets.geohashGridTitle": "ジオハッシュ", - "common.ui.aggTypes.buckets.geotileGridTitle": "ジオタイル", - "common.ui.aggTypes.buckets.histogramTitle": "Histogram", - "common.ui.aggTypes.buckets.intervalOptions.autoDisplayName": "自動", - "common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName": "日ごと", - "common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName": "1 時間ごと", - "common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName": "ミリ秒", - "common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName": "分", - "common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName": "月ごと", - "common.ui.aggTypes.buckets.intervalOptions.secondDisplayName": "秒", - "common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName": "週ごと", - "common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName": "1 年ごと", - "common.ui.aggTypes.buckets.ipRangeLabel": "{fieldName} IP 範囲", - "common.ui.aggTypes.buckets.ipRangeTitle": "IPv4 範囲", - "common.ui.aggTypes.buckets.rangesLabel": "{fieldName} の範囲", - "common.ui.aggTypes.buckets.rangeTitle": "範囲", - "common.ui.aggTypes.buckets.significantTerms.excludeLabel": "除外", - "common.ui.aggTypes.buckets.significantTerms.includeLabel": "含める", - "common.ui.aggTypes.buckets.significantTermsLabel": "{fieldName} のトップ {size} の珍しいアイテム", - "common.ui.aggTypes.buckets.significantTermsTitle": "Significant Terms", - "common.ui.aggTypes.buckets.terms.excludeLabel": "除外", - "common.ui.aggTypes.buckets.terms.includeLabel": "含める", - "common.ui.aggTypes.buckets.terms.missingBucketLabel": "欠測値", - "common.ui.aggTypes.buckets.terms.orderAscendingTitle": "昇順", - "common.ui.aggTypes.buckets.terms.orderDescendingTitle": "降順", - "common.ui.aggTypes.buckets.terms.otherBucketDescription": "このリクエストは、データバケットの基準外のドキュメントの数をカウントします。", - "common.ui.aggTypes.buckets.terms.otherBucketLabel": "その他", - "common.ui.aggTypes.buckets.terms.otherBucketTitle": "他のバケット", - "common.ui.aggTypes.buckets.termsTitle": "用語", - "common.ui.aggTypes.changePrecisionLabel": "マップズームの精度を変更", - "common.ui.aggTypes.customMetricLabel": "カスタムメトリック", - "common.ui.aggTypes.dateRanges.acceptedDateFormatsLinkText": "対応データフォーマット", - "common.ui.aggTypes.dateRanges.addRangeButtonLabel": "範囲を追加", - "common.ui.aggTypes.dateRanges.fromColumnLabel": "From", - "common.ui.aggTypes.dateRanges.toColumnLabel": "To", - "common.ui.aggTypes.definiteMetricLabel": "メトリック: {metric}", - "common.ui.aggTypes.dropPartialBucketsLabel": "不完全なバケットをドロップ", - "common.ui.aggTypes.dropPartialBucketsTooltip": "時間範囲外にわたるバケットを削除してヒストグラムが不完全なバケットで開始・終了しないようにします。", - "common.ui.aggTypes.extendedBounds.errorMessage": "最低値は最大値以下でなければなりません。", - "common.ui.aggTypes.extendedBounds.maxLabel": "最高", - "common.ui.aggTypes.extendedBounds.minLabel": "最低", - "common.ui.aggTypes.extendedBoundsLabel": "拡張された境界", - "common.ui.aggTypes.extendedBoundsTooltip": "最低値と最高値は結果を絞るのではなく、結果セットのバウンドを拡張します", - "common.ui.aggTypes.field.fieldLabel": "フィールド", - "common.ui.aggTypes.field.noCompatibleFieldsDescription": "インデックスパターン` {indexPatternTitle} に次の互換性のあるフィールドタイプが 1 つも含まれていません: {fieldTypes}", - "common.ui.aggTypes.field.selectFieldPlaceholder": "フィールドを選択", - "common.ui.aggTypes.filters.addFilterButtonLabel": "フィルターを追加します", - "common.ui.aggTypes.filters.definiteFilterLabel": "{index} ラベルでフィルタリング", - "common.ui.aggTypes.filters.filterLabel": "{index} でフィルタリング", - "common.ui.aggTypes.filters.labelPlaceholder": "ラベル", - "common.ui.aggTypes.filters.removeFilterButtonAriaLabel": "このフィルターを削除", - "common.ui.aggTypes.filters.toggleFilterButtonAriaLabel": "フィルターラベルを切り替える", - "common.ui.aggTypes.histogram.missingMaxMinValuesWarning": "自動スケールヒストグラムバケットから最高値と最低値を取得できません。これによりビジュアライゼーションのパフォーマンスが低下する可能性があります。", - "common.ui.aggTypes.ipRanges.addRangeButtonLabel": "範囲を追加", - "common.ui.aggTypes.ipRanges.cidrMaskAriaLabel": "CIDR マスク: {mask}", - "common.ui.aggTypes.ipRanges.cidrMasksButtonLabel": "CIDR マスク", - "common.ui.aggTypes.ipRanges.fromToButtonLabel": "開始/終了", - "common.ui.aggTypes.ipRanges.ipRangeFromAriaLabel": "IP 範囲の開始値: {value}", - "common.ui.aggTypes.ipRanges.ipRangeToAriaLabel": "IP 範囲の終了値: {value}", - "common.ui.aggTypes.ipRanges.removeCidrMaskButtonAriaLabel": "{mask} の CIDR マスクの値を削除", - "common.ui.aggTypes.ipRanges.removeEmptyCidrMaskButtonAriaLabel": "CIDR マスクのデフォルトの値を削除", - "common.ui.aggTypes.ipRanges.removeRangeAriaLabel": "{from} から {to} の範囲を削除", - "common.ui.aggTypes.ipRangesAriaLabel": "IP 範囲", - "common.ui.aggTypes.jsonInputLabel": "JSON インプット", - "common.ui.aggTypes.jsonInputTooltip": "ここに追加された JSON フォーマットのプロパティは、すべてこのセクションの Elasticsearch アグリゲーション定義に融合されます。用語集約における「shard_size」がその例です。", - "common.ui.aggTypes.metricLabel": "メトリック", - "common.ui.aggTypes.metrics.averageBucketTitle": "平均バケット", - "common.ui.aggTypes.metrics.averageLabel": "平均 {field}", - "common.ui.aggTypes.metrics.averageTitle": "平均", - "common.ui.aggTypes.metrics.bucketAggTitle": "バケット集約", - "common.ui.aggTypes.metrics.bucketTitle": "バケット", - "common.ui.aggTypes.metrics.countLabel": "カウント", - "common.ui.aggTypes.metrics.countTitle": "カウント", - "common.ui.aggTypes.metrics.cumulativeSumLabel": "累積合計", - "common.ui.aggTypes.metrics.cumulativeSumTitle": "累積合計", - "common.ui.aggTypes.metrics.derivativeLabel": "派生", - "common.ui.aggTypes.metrics.derivativeTitle": "派生", - "common.ui.aggTypes.metrics.geoBoundsLabel": "境界", - "common.ui.aggTypes.metrics.geoBoundsTitle": "境界", - "common.ui.aggTypes.metrics.geoCentroidLabel": "ジオセントロイド", - "common.ui.aggTypes.metrics.geoCentroidTitle": "ジオセントロイド", - "common.ui.aggTypes.metrics.maxBucketTitle": "最高バケット", - "common.ui.aggTypes.metrics.maxLabel": "最高 {field}", - "common.ui.aggTypes.metrics.maxTitle": "最高", - "common.ui.aggTypes.metrics.medianLabel": "中央 {field}", - "common.ui.aggTypes.metrics.medianTitle": "中央", - "common.ui.aggTypes.metrics.metricAggregationsSubtypeTitle": "メトリック集約", - "common.ui.aggTypes.metrics.metricAggTitle": "メトリック集約", - "common.ui.aggTypes.metrics.metricTitle": "メトリック", - "common.ui.aggTypes.metrics.minBucketTitle": "最低バケット", - "common.ui.aggTypes.metrics.minLabel": "最低 {field}", - "common.ui.aggTypes.metrics.minTitle": "最低", - "common.ui.aggTypes.metrics.movingAvgLabel": "移動平均", - "common.ui.aggTypes.metrics.movingAvgTitle": "移動平均", - "common.ui.aggTypes.metrics.overallAverageLabel": "全体平均", - "common.ui.aggTypes.metrics.overallMaxLabel": "全体最高", - "common.ui.aggTypes.metrics.overallMinLabel": "全体最低", - "common.ui.aggTypes.metrics.overallSumLabel": "全体合計", - "common.ui.aggTypes.metrics.parentPipelineAggregationsSubtypeTitle": "親パイプライン集約", - "common.ui.aggTypes.metrics.percentileRanks.valuePropsLabel": "「{label}」の {format} のパーセンタイル順位", - "common.ui.aggTypes.metrics.percentileRanksLabel": "{field} のパーセンタイル順位", - "common.ui.aggTypes.metrics.percentileRanksTitle": "パーセンタイル順位", - "common.ui.aggTypes.metrics.percentiles.valuePropsLabel": "{label} の {percentile} パーセンタイル", - "common.ui.aggTypes.metrics.percentilesLabel": "{field} のパーセンタイル", - "common.ui.aggTypes.metrics.percentilesTitle": "パーセンタイル", - "common.ui.aggTypes.metrics.serialDiffLabel": "serial diff", - "common.ui.aggTypes.metrics.serialDiffTitle": "Serial Diff", - "common.ui.aggTypes.metrics.siblingPipelineAggregationsSubtypeTitle": "シブリングパイプラインアグリゲーション", - "common.ui.aggTypes.metrics.standardDeviation.keyDetailsLabel": "{fieldDisplayName} の標準偏差", - "common.ui.aggTypes.metrics.standardDeviation.lowerKeyDetailsTitle": "下の{label}", - "common.ui.aggTypes.metrics.standardDeviation.upperKeyDetailsTitle": "上の{label}", - "common.ui.aggTypes.metrics.standardDeviationLabel": "{field} の標準偏差", - "common.ui.aggTypes.metrics.standardDeviationTitle": "標準偏差", - "common.ui.aggTypes.metrics.sumBucketTitle": "合計バケット", - "common.ui.aggTypes.metrics.sumLabel": "{field} の合計", - "common.ui.aggTypes.metrics.sumTitle": "合計", - "common.ui.aggTypes.metrics.topHit.ascendingLabel": "昇順", - "common.ui.aggTypes.metrics.topHit.averageLabel": "平均", - "common.ui.aggTypes.metrics.topHit.concatenateLabel": "連結", - "common.ui.aggTypes.metrics.topHit.descendingLabel": "降順", - "common.ui.aggTypes.metrics.topHit.firstPrefixLabel": "最初", - "common.ui.aggTypes.metrics.topHit.lastPrefixLabel": "最後", - "common.ui.aggTypes.metrics.topHit.maxLabel": "最高", - "common.ui.aggTypes.metrics.topHit.minLabel": "最低", - "common.ui.aggTypes.metrics.topHit.sumLabel": "合計", - "common.ui.aggTypes.metrics.topHitTitle": "トップヒット", - "common.ui.aggTypes.metrics.uniqueCountLabel": "{field} のユニークカウント", - "common.ui.aggTypes.metrics.uniqueCountTitle": "ユニークカウント", - "common.ui.aggTypes.metrics.wrongLastBucketTypeErrorMessage": "「{type}」メトリック集約を使用する場合、最後のバケット集約は「Date Histogram」または「Histogram」でなければなりません。", - "common.ui.aggTypes.numberInterval.minimumIntervalLabel": "最低間隔", - "common.ui.aggTypes.numberInterval.minimumIntervalTooltip": "入力された値により高度な設定の {histogramMaxBars} で指定されたよりも多くのバケットが作成される場合、間隔は自動的にスケーリングされます。", - "common.ui.aggTypes.numberInterval.selectIntervalPlaceholder": "間隔を入力", - "common.ui.aggTypes.numberList.addUnitButtonLabel": "{unitName} を追加", - "common.ui.aggTypes.numberList.enterValuePlaceholder": "値を入力", - "common.ui.aggTypes.numberList.invalidAscOrderErrorMessage": "値は昇順でなければなりません。", - "common.ui.aggTypes.numberList.invalidRangeErrorMessage": "値は {min} から {max} の範囲でなければなりません。", - "common.ui.aggTypes.numberList.removeUnitButtonAriaLabel": "{value} のランク値を削除", - "common.ui.aggTypes.onlyRequestDataAroundMapExtentLabel": "マップ範囲のデータのみリクエストしてください", - "common.ui.aggTypes.onlyRequestDataAroundMapExtentTooltip": "geo_bounding_box フィルター集約を適用して、襟付きのマップビューボックスにサブジェクトエリアを絞ります", - "common.ui.aggTypes.orderAgg.alphabeticalLabel": "アルファベット順", - "common.ui.aggTypes.orderAgg.orderByLabel": "並び順", - "common.ui.aggTypes.orderLabel": "順序", - "common.ui.aggTypes.otherBucket.groupValuesLabel": "他の値を別のバケットにまとめる", - "common.ui.aggTypes.otherBucket.groupValuesTooltip": "トップ N 以外の値はこのバケットにまとめられます。欠測値があるドキュメントを含めるには、「欠測値を表示」を有効にしてください。", - "common.ui.aggTypes.otherBucket.labelForMissingValuesLabel": "欠測値のラベル", - "common.ui.aggTypes.otherBucket.labelForOtherBucketLabel": "他のバケットのラベル", - "common.ui.aggTypes.otherBucket.showMissingValuesLabel": "欠測値を表示", - "common.ui.aggTypes.otherBucket.showMissingValuesTooltip": "「文字列」タイプのフィールドにのみ使用できます。有効にすると、欠測値があるドキュメントが検索に含まれます。バケットがトップ N の場合、チャートに表示されます。トップ N ではなく、「他の値を別のバケットにまとえる」が有効な場合、Elasticsearch は欠測値を「他」のバケットに追加します。", - "common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage": "保存された {fieldParameter} パラメーターが無効になりました。新しいフィールドを選択してください。", - "common.ui.aggTypes.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} は必須パラメーターです", - "common.ui.aggTypes.percentileRanks.percentUnitNameText": "パーセント", - "common.ui.aggTypes.percentileRanks.valuesLabel": "値", - "common.ui.aggTypes.percentileRanks.valueUnitNameText": "値", - "common.ui.aggTypes.percentiles.percentsLabel": "パーセント", - "common.ui.aggTypes.placeMarkersOffGridLabel": "グリッド外にマーカーを配置 (ジオセントロイドを使用)", - "common.ui.aggTypes.precisionLabel": "精度", - "common.ui.aggTypes.ranges.addRangeButtonLabel": "範囲を追加", - "common.ui.aggTypes.ranges.fromLabel": "開始値:", - "common.ui.aggTypes.ranges.removeRangeButtonAriaLabel": "{from} から {to} の範囲を削除", - "common.ui.aggTypes.ranges.toLabel": "To", - "common.ui.aggTypes.showEmptyBucketsLabel": "空のバケットを表示", - "common.ui.aggTypes.showEmptyBucketsTooltip": "結果のあるバケットだけでなくすべてのバケットを表示します", - "common.ui.aggTypes.sizeLabel": "サイズ", - "common.ui.aggTypes.sizeTooltip": "トップ K のヒットをリクエスト。複数ヒットは「集約基準」でまとめられます。", - "common.ui.aggTypes.sortOnLabel": "並べ替えオン", - "common.ui.aggTypes.string.customLabel": "カスタムラベル", - "common.ui.aggTypes.timeInterval.createsTooLargeBucketsTooltip": "この間隔は、選択された時間範囲に表示するには大きすぎるバケットが作成されるため、にスケーリングされています。", - "common.ui.aggTypes.timeInterval.createsTooManyBucketsTooltip": "この間隔は選択された時間範囲に表示しきれない数のバケットが作成されるため、にスケーリングされています。", - "common.ui.aggTypes.timeInterval.invalidFormatErrorMessage": "無効な間隔フォーマット。", - "common.ui.aggTypes.timeInterval.minimumIntervalLabel": "最低間隔", - "common.ui.aggTypes.timeInterval.scaledHelpText": "現在 {bucketDescription} にスケーリングされています", - "common.ui.aggTypes.timeInterval.selectIntervalPlaceholder": "間隔を選択", - "common.ui.aggTypes.timeInterval.selectOptionHelpText": "オプションを選択するかカスタム値を作成します。例30s、20m、24h、2d、1w、1M", - "common.ui.courier.fetch.requestTimedOutNotificationMessage": "リクエストがタイムアウトしたため、データが不完全な可能性があります", - "common.ui.courier.fetch.shardsFailedNotificationMessage": "{shardsTotal} 件中 {shardsFailed} 件のシャードでエラーが発生しました", - "common.ui.courier.hitsDescription": "クエリにより返されたドキュメントの数です。", - "common.ui.courier.hitsLabel": "ヒット数", - "common.ui.courier.hitsTotalDescription": "クエリに一致するドキュメントの数です。", - "common.ui.courier.hitsTotalLabel": "ヒット数 (合計)", - "common.ui.courier.indexPatternDescription": "Elasticsearch インデックスに接続したインデックスパターンです。", - "common.ui.courier.indexPatternIdDescription": "{kibanaIndexPattern} インデックス内の ID です。", - "common.ui.courier.indexPatternIdLabel": "インデックスパターン ID", - "common.ui.courier.indexPatternLabel": "インデックスパターン", - "common.ui.courier.noSearchStrategyRegisteredErrorMessageDescription": "検索リクエストの検索方法が見つかりませんでした", - "common.ui.courier.noSearchStrategyRegisteredErrorMessageTitle": "検索方法が登録されていません", - "common.ui.courier.queryTimeDescription": "クエリの処理の所要時間です。リクエストの送信やブラウザでのパースの時間は含まれません。", - "common.ui.courier.queryTimeLabel": "クエリ時間", - "common.ui.courier.queryTimeValue": "{queryTime}ms", - "common.ui.courier.requestTimeDescription": "ブラウザから Elasticsearch にリクエストが送信され返されるまでの所要時間です。リクエストがキューで待機していた時間は含まれません。", - "common.ui.courier.requestTimeLabel": "リクエスト時間", - "common.ui.courier.requestTimeValue": "{requestTime}ms", + "data.search.aggs.aggNotValidLabel": "- 無効な集約 -", + "data.search.aggs.aggregateWith.noAggsErrorTooltip": "選択されたフィールドには互換性のある集約がありません。", + "data.search.aggs.aggregateWithLabel": "アグリゲーション:", + "data.search.aggs.aggregateWithTooltip": "複数ヒットまたは複数値のフィールドを 1 つのメトリックにまとめる方法を選択します。", + "data.search.aggs.buckets.dateHistogramLabel": "{intervalDescription}ごとの {fieldName}", + "data.search.aggs.buckets.dateHistogramTitle": "Date Histogram", + "data.search.aggs.buckets.dateRangeTitle": "日付範囲", + "data.search.aggs.buckets.filtersTitle": "フィルター", + "data.search.aggs.buckets.filterTitle": "フィルター", + "data.search.aggs.buckets.geohashGridTitle": "ジオハッシュ", + "data.search.aggs.buckets.geotileGridTitle": "ジオタイル", + "data.search.aggs.buckets.histogramTitle": "Histogram", + "data.search.aggs.buckets.intervalOptions.autoDisplayName": "自動", + "data.search.aggs.buckets.intervalOptions.dailyDisplayName": "日ごと", + "data.search.aggs.buckets.intervalOptions.hourlyDisplayName": "1 時間ごと", + "data.search.aggs.buckets.intervalOptions.millisecondDisplayName": "ミリ秒", + "data.search.aggs.buckets.intervalOptions.minuteDisplayName": "分", + "data.search.aggs.buckets.intervalOptions.monthlyDisplayName": "月ごと", + "data.search.aggs.buckets.intervalOptions.secondDisplayName": "秒", + "data.search.aggs.buckets.intervalOptions.weeklyDisplayName": "週ごと", + "data.search.aggs.buckets.intervalOptions.yearlyDisplayName": "1 年ごと", + "data.search.aggs.buckets.ipRangeLabel": "{fieldName} IP 範囲", + "data.search.aggs.buckets.ipRangeTitle": "IPv4 範囲", + "data.search.aggs.buckets.rangesLabel": "{fieldName} の範囲", + "data.search.aggs.buckets.rangeTitle": "範囲", + "data.search.aggs.buckets.significantTerms.excludeLabel": "除外", + "data.search.aggs.buckets.significantTerms.includeLabel": "含める", + "data.search.aggs.buckets.significantTermsLabel": "{fieldName} のトップ {size} の珍しいアイテム", + "data.search.aggs.buckets.significantTermsTitle": "Significant Terms", + "data.search.aggs.buckets.terms.excludeLabel": "除外", + "data.search.aggs.buckets.terms.includeLabel": "含める", + "data.search.aggs.buckets.terms.missingBucketLabel": "欠測値", + "data.search.aggs.buckets.terms.orderAscendingTitle": "昇順", + "data.search.aggs.buckets.terms.orderDescendingTitle": "降順", + "data.search.aggs.buckets.terms.otherBucketDescription": "このリクエストは、データバケットの基準外のドキュメントの数をカウントします。", + "data.search.aggs.buckets.terms.otherBucketLabel": "その他", + "data.search.aggs.buckets.terms.otherBucketTitle": "他のバケット", + "data.search.aggs.buckets.termsTitle": "用語", + "data.search.aggs.changePrecisionLabel": "マップズームの精度を変更", + "data.search.aggs.customMetricLabel": "カスタムメトリック", + "data.search.aggs.dateRanges.acceptedDateFormatsLinkText": "対応データフォーマット", + "data.search.aggs.dateRanges.addRangeButtonLabel": "範囲を追加", + "data.search.aggs.dateRanges.fromColumnLabel": "From", + "data.search.aggs.dateRanges.toColumnLabel": "To", + "data.search.aggs.definiteMetricLabel": "メトリック: {metric}", + "data.search.aggs.dropPartialBucketsLabel": "不完全なバケットをドロップ", + "data.search.aggs.dropPartialBucketsTooltip": "時間範囲外にわたるバケットを削除してヒストグラムが不完全なバケットで開始・終了しないようにします。", + "data.search.aggs.extendedBounds.errorMessage": "最低値は最大値以下でなければなりません。", + "data.search.aggs.extendedBounds.maxLabel": "最高", + "data.search.aggs.extendedBounds.minLabel": "最低", + "data.search.aggs.extendedBoundsLabel": "拡張された境界", + "data.search.aggs.extendedBoundsTooltip": "最低値と最高値は結果を絞るのではなく、結果セットのバウンドを拡張します", + "data.search.aggs.field.fieldLabel": "フィールド", + "data.search.aggs.field.noCompatibleFieldsDescription": "インデックスパターン` {indexPatternTitle} に次の互換性のあるフィールドタイプが 1 つも含まれていません: {fieldTypes}", + "data.search.aggs.field.selectFieldPlaceholder": "フィールドを選択", + "data.search.aggs.filters.addFilterButtonLabel": "フィルターを追加します", + "data.search.aggs.filters.definiteFilterLabel": "{index} ラベルでフィルタリング", + "data.search.aggs.filters.filterLabel": "{index} でフィルタリング", + "data.search.aggs.filters.labelPlaceholder": "ラベル", + "data.search.aggs.filters.removeFilterButtonAriaLabel": "このフィルターを削除", + "data.search.aggs.filters.toggleFilterButtonAriaLabel": "フィルターラベルを切り替える", + "data.search.aggs.histogram.missingMaxMinValuesWarning": "自動スケールヒストグラムバケットから最高値と最低値を取得できません。これによりビジュアライゼーションのパフォーマンスが低下する可能性があります。", + "data.search.aggs.ipRanges.addRangeButtonLabel": "範囲を追加", + "data.search.aggs.ipRanges.cidrMaskAriaLabel": "CIDR マスク: {mask}", + "data.search.aggs.ipRanges.cidrMasksButtonLabel": "CIDR マスク", + "data.search.aggs.ipRanges.fromToButtonLabel": "開始/終了", + "data.search.aggs.ipRanges.ipRangeFromAriaLabel": "IP 範囲の開始値: {value}", + "data.search.aggs.ipRanges.ipRangeToAriaLabel": "IP 範囲の終了値: {value}", + "data.search.aggs.ipRanges.removeCidrMaskButtonAriaLabel": "{mask} の CIDR マスクの値を削除", + "data.search.aggs.ipRanges.removeEmptyCidrMaskButtonAriaLabel": "CIDR マスクのデフォルトの値を削除", + "data.search.aggs.ipRanges.removeRangeAriaLabel": "{from} から {to} の範囲を削除", + "data.search.aggs.ipRangesAriaLabel": "IP 範囲", + "data.search.aggs.jsonInputLabel": "JSON インプット", + "data.search.aggs.jsonInputTooltip": "ここに追加された JSON フォーマットのプロパティは、すべてこのセクションの Elasticsearch アグリゲーション定義に融合されます。用語集約における「shard_size」がその例です。", + "data.search.aggs.metricLabel": "メトリック", + "data.search.aggs.metrics.averageBucketTitle": "平均バケット", + "data.search.aggs.metrics.averageLabel": "平均 {field}", + "data.search.aggs.metrics.averageTitle": "平均", + "data.search.aggs.metrics.bucketAggTitle": "バケット集約", + "data.search.aggs.metrics.bucketTitle": "バケット", + "data.search.aggs.metrics.countLabel": "カウント", + "data.search.aggs.metrics.countTitle": "カウント", + "data.search.aggs.metrics.cumulativeSumLabel": "累積合計", + "data.search.aggs.metrics.cumulativeSumTitle": "累積合計", + "data.search.aggs.metrics.derivativeLabel": "派生", + "data.search.aggs.metrics.derivativeTitle": "派生", + "data.search.aggs.metrics.geoBoundsLabel": "境界", + "data.search.aggs.metrics.geoBoundsTitle": "境界", + "data.search.aggs.metrics.geoCentroidLabel": "ジオセントロイド", + "data.search.aggs.metrics.geoCentroidTitle": "ジオセントロイド", + "data.search.aggs.metrics.maxBucketTitle": "最高バケット", + "data.search.aggs.metrics.maxLabel": "最高 {field}", + "data.search.aggs.metrics.maxTitle": "最高", + "data.search.aggs.metrics.medianLabel": "中央 {field}", + "data.search.aggs.metrics.medianTitle": "中央", + "data.search.aggs.metrics.metricAggregationsSubtypeTitle": "メトリック集約", + "data.search.aggs.metrics.metricAggTitle": "メトリック集約", + "data.search.aggs.metrics.metricTitle": "メトリック", + "data.search.aggs.metrics.minBucketTitle": "最低バケット", + "data.search.aggs.metrics.minLabel": "最低 {field}", + "data.search.aggs.metrics.minTitle": "最低", + "data.search.aggs.metrics.movingAvgLabel": "移動平均", + "data.search.aggs.metrics.movingAvgTitle": "移動平均", + "data.search.aggs.metrics.overallAverageLabel": "全体平均", + "data.search.aggs.metrics.overallMaxLabel": "全体最高", + "data.search.aggs.metrics.overallMinLabel": "全体最低", + "data.search.aggs.metrics.overallSumLabel": "全体合計", + "data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle": "親パイプライン集約", + "data.search.aggs.metrics.percentileRanks.valuePropsLabel": "「{label}」の {format} のパーセンタイル順位", + "data.search.aggs.metrics.percentileRanksLabel": "{field} のパーセンタイル順位", + "data.search.aggs.metrics.percentileRanksTitle": "パーセンタイル順位", + "data.search.aggs.metrics.percentiles.valuePropsLabel": "{label} の {percentile} パーセンタイル", + "data.search.aggs.metrics.percentilesLabel": "{field} のパーセンタイル", + "data.search.aggs.metrics.percentilesTitle": "パーセンタイル", + "data.search.aggs.metrics.serialDiffLabel": "serial diff", + "data.search.aggs.metrics.serialDiffTitle": "Serial Diff", + "data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle": "シブリングパイプラインアグリゲーション", + "data.search.aggs.metrics.standardDeviation.keyDetailsLabel": "{fieldDisplayName} の標準偏差", + "data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle": "下の{label}", + "data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle": "上の{label}", + "data.search.aggs.metrics.standardDeviationLabel": "{field} の標準偏差", + "data.search.aggs.metrics.standardDeviationTitle": "標準偏差", + "data.search.aggs.metrics.sumBucketTitle": "合計バケット", + "data.search.aggs.metrics.sumLabel": "{field} の合計", + "data.search.aggs.metrics.sumTitle": "合計", + "data.search.aggs.metrics.topHit.ascendingLabel": "昇順", + "data.search.aggs.metrics.topHit.averageLabel": "平均", + "data.search.aggs.metrics.topHit.concatenateLabel": "連結", + "data.search.aggs.metrics.topHit.descendingLabel": "降順", + "data.search.aggs.metrics.topHit.firstPrefixLabel": "最初", + "data.search.aggs.metrics.topHit.lastPrefixLabel": "最後", + "data.search.aggs.metrics.topHit.maxLabel": "最高", + "data.search.aggs.metrics.topHit.minLabel": "最低", + "data.search.aggs.metrics.topHit.sumLabel": "合計", + "data.search.aggs.metrics.topHitTitle": "トップヒット", + "data.search.aggs.metrics.uniqueCountLabel": "{field} のユニークカウント", + "data.search.aggs.metrics.uniqueCountTitle": "ユニークカウント", + "data.search.aggs.metrics.wrongLastBucketTypeErrorMessage": "「{type}」メトリック集約を使用する場合、最後のバケット集約は「Date Histogram」または「Histogram」でなければなりません。", + "data.search.aggs.numberInterval.minimumIntervalLabel": "最低間隔", + "data.search.aggs.numberInterval.minimumIntervalTooltip": "入力された値により高度な設定の {histogramMaxBars} で指定されたよりも多くのバケットが作成される場合、間隔は自動的にスケーリングされます。", + "data.search.aggs.numberInterval.selectIntervalPlaceholder": "間隔を入力", + "data.search.aggs.numberList.addUnitButtonLabel": "{unitName} を追加", + "data.search.aggs.numberList.enterValuePlaceholder": "値を入力", + "data.search.aggs.numberList.invalidAscOrderErrorMessage": "値は昇順でなければなりません。", + "data.search.aggs.numberList.invalidRangeErrorMessage": "値は {min} から {max} の範囲でなければなりません。", + "data.search.aggs.numberList.removeUnitButtonAriaLabel": "{value} のランク値を削除", + "data.search.aggs.onlyRequestDataAroundMapExtentLabel": "マップ範囲のデータのみリクエストしてください", + "data.search.aggs.onlyRequestDataAroundMapExtentTooltip": "geo_bounding_box フィルター集約を適用して、襟付きのマップビューボックスにサブジェクトエリアを絞ります", + "data.search.aggs.orderAgg.alphabeticalLabel": "アルファベット順", + "data.search.aggs.orderAgg.orderByLabel": "並び順", + "data.search.aggs.orderLabel": "順序", + "data.search.aggs.otherBucket.groupValuesLabel": "他の値を別のバケットにまとめる", + "data.search.aggs.otherBucket.groupValuesTooltip": "トップ N 以外の値はこのバケットにまとめられます。欠測値があるドキュメントを含めるには、「欠測値を表示」を有効にしてください。", + "data.search.aggs.otherBucket.labelForMissingValuesLabel": "欠測値のラベル", + "data.search.aggs.otherBucket.labelForOtherBucketLabel": "他のバケットのラベル", + "data.search.aggs.otherBucket.showMissingValuesLabel": "欠測値を表示", + "data.search.aggs.otherBucket.showMissingValuesTooltip": "「文字列」タイプのフィールドにのみ使用できます。有効にすると、欠測値があるドキュメントが検索に含まれます。バケットがトップ N の場合、チャートに表示されます。トップ N ではなく、「他の値を別のバケットにまとえる」が有効な場合、Elasticsearch は欠測値を「他」のバケットに追加します。", + "data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage": "保存された {fieldParameter} パラメーターが無効になりました。新しいフィールドを選択してください。", + "data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} は必須パラメーターです", + "data.search.aggs.percentileRanks.percentUnitNameText": "パーセント", + "data.search.aggs.percentileRanks.valuesLabel": "値", + "data.search.aggs.percentileRanks.valueUnitNameText": "値", + "data.search.aggs.percentiles.percentsLabel": "パーセント", + "data.search.aggs.placeMarkersOffGridLabel": "グリッド外にマーカーを配置 (ジオセントロイドを使用)", + "data.search.aggs.precisionLabel": "精度", + "data.search.aggs.ranges.addRangeButtonLabel": "範囲を追加", + "data.search.aggs.ranges.fromLabel": "開始値:", + "data.search.aggs.ranges.removeRangeButtonAriaLabel": "{from} から {to} の範囲を削除", + "data.search.aggs.ranges.toLabel": "To", + "data.search.aggs.showEmptyBucketsLabel": "空のバケットを表示", + "data.search.aggs.showEmptyBucketsTooltip": "結果のあるバケットだけでなくすべてのバケットを表示します", + "data.search.aggs.sizeLabel": "サイズ", + "data.search.aggs.sizeTooltip": "トップ K のヒットをリクエスト。複数ヒットは「集約基準」でまとめられます。", + "data.search.aggs.sortOnLabel": "並べ替えオン", + "data.search.aggs.string.customLabel": "カスタムラベル", + "data.search.aggs.timeInterval.createsTooLargeBucketsTooltip": "この間隔は、選択された時間範囲に表示するには大きすぎるバケットが作成されるため、にスケーリングされています。", + "data.search.aggs.timeInterval.createsTooManyBucketsTooltip": "この間隔は選択された時間範囲に表示しきれない数のバケットが作成されるため、にスケーリングされています。", + "data.search.aggs.timeInterval.invalidFormatErrorMessage": "無効な間隔フォーマット。", + "data.search.aggs.timeInterval.minimumIntervalLabel": "最低間隔", + "data.search.aggs.timeInterval.scaledHelpText": "現在 {bucketDescription} にスケーリングされています", + "data.search.aggs.timeInterval.selectIntervalPlaceholder": "間隔を選択", + "data.search.aggs.timeInterval.selectOptionHelpText": "オプションを選択するかカスタム値を作成します。例30s、20m、24h、2d、1w、1M", "common.ui.directives.fieldNameIcons.booleanAriaLabel": "ブールフィールド", "common.ui.directives.fieldNameIcons.conflictFieldAriaLabel": "矛盾フィールド", "common.ui.directives.fieldNameIcons.dateFieldAriaLabel": "日付フィールド", @@ -541,28 +523,14 @@ "common.ui.visualize.queryGeohashBounds.unableToGetBoundErrorTitle": "バウンドを取得できませんでした", "common.ui.welcomeErrorMessage": "Kibana が正常に読み込まれませんでした。詳細はサーバーアウトプットを確認してください。", "common.ui.welcomeMessage": "Kibana を読み込み中", - "common.ui.courier.fetch.shardsFailedModal.close": "閉じる", - "common.ui.courier.fetch.shardsFailedModal.copyToClipboard": "応答をクリップボードにコピー", - "common.ui.courier.fetch.shardsFailedModal.failureHeader": "{failureName} で {failureDetails}", - "common.ui.courier.fetch.shardsFailedModal.showDetails": "詳細を表示", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderRequest": "リクエスト", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderResponse": "応答", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderShardFailures": "シャードエラー", - "common.ui.courier.fetch.shardsFailedModal.tableColIndex": "インデックス", - "common.ui.courier.fetch.shardsFailedModal.tableColNode": "ノード", - "common.ui.courier.fetch.shardsFailedModal.tableColReason": "理由", - "common.ui.courier.fetch.shardsFailedModal.tableColShard": "シャード", - "common.ui.courier.fetch.shardsFailedModal.tableRowCollapse": "{rowDescription} を折りたたむ", - "common.ui.courier.fetch.shardsFailedModal.tableRowExpand": "{rowDescription} を展開する", - "common.ui.courier.fetch.shardsFailedNotificationDescription": "表示されているデータは不完全か誤りの可能性があります。", "common.ui.directives.fieldNameIcons.geoShapeFieldAriaLabel": "地理情報図形", "common.ui.vis.editors.agg.errorsAriaLabel": "集約にエラーがあります", "common.ui.vislib.heatmap.maxBucketsText": "定義された数列が多すぎます ({nr}).構成されている最高値は {max} です。", - "common.ui.aggTypes.ranges.greaterThanOrEqualPrepend": "≥", - "common.ui.aggTypes.ranges.lessThanPrepend": "<", - "common.ui.aggTypes.scaleMetricsLabel": "メトリック値のスケーリング (廃止)", - "common.ui.aggTypes.scaleMetricsTooltip": "これを有効にすると、手動最低間隔を選択し、広い間隔が使用された場合、カウントと合計メトリックが手動で選択された間隔にスケーリングされます。", - "common.ui.aggTypes.buckets.ranges.rangesFormatMessage": "{gte} {from} と {lt} {to}", + "data.search.aggs.ranges.greaterThanOrEqualPrepend": "≥", + "data.search.aggs.ranges.lessThanPrepend": "<", + "data.search.aggs.scaleMetricsLabel": "メトリック値のスケーリング (廃止)", + "data.search.aggs.scaleMetricsTooltip": "これを有効にすると、手動最低間隔を選択し、広い間隔が使用された場合、カウントと合計メトリックが手動で選択された間隔にスケーリングされます。", + "data.search.aggs.buckets.ranges.rangesFormatMessage": "{gte} {from} と {lt} {to}", "management.editIndexPattern.createIndex.defaultButtonDescription": "すべてのデータに完全集約を実行", "management.editIndexPattern.createIndex.defaultButtonText": "標準インデックスパターン", "management.editIndexPattern.createIndex.defaultTypeName": "インデックスパターン", @@ -873,6 +841,38 @@ "data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} の説明", "data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "選択されたクエリボタン {savedQueryName} を保存しました。変更を破棄するには押してください。", "data.search.searchBar.savedQueryPopoverTitleText": "保存されたクエリ", + "data.search.searchSource.fetch.shardsFailedModal.close": "閉じる", + "data.search.searchSource.fetch.shardsFailedModal.copyToClipboard": "応答をクリップボードにコピー", + "data.search.searchSource.fetch.shardsFailedModal.failureHeader": "{failureName} で {failureDetails}", + "data.search.searchSource.fetch.shardsFailedModal.showDetails": "詳細を表示", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "リクエスト", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "応答", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "シャードエラー", + "data.search.searchSource.fetch.shardsFailedModal.tableColIndex": "インデックス", + "data.search.searchSource.fetch.shardsFailedModal.tableColNode": "ノード", + "data.search.searchSource.fetch.shardsFailedModal.tableColReason": "理由", + "data.search.searchSource.fetch.shardsFailedModal.tableColShard": "シャード", + "data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse": "{rowDescription} を折りたたむ", + "data.search.searchSource.fetch.shardsFailedModal.tableRowExpand": "{rowDescription} を展開する", + "data.search.searchSource.fetch.shardsFailedNotificationDescription": "表示されているデータは不完全か誤りの可能性があります。", + "data.search.searchSource.fetch.requestTimedOutNotificationMessage": "リクエストがタイムアウトしたため、データが不完全な可能性があります", + "data.search.searchSource.fetch.shardsFailedNotificationMessage": "{shardsTotal} 件中 {shardsFailed} 件のシャードでエラーが発生しました", + "data.search.searchSource.hitsDescription": "クエリにより返されたドキュメントの数です。", + "data.search.searchSource.hitsLabel": "ヒット数", + "data.search.searchSource.hitsTotalDescription": "クエリに一致するドキュメントの数です。", + "data.search.searchSource.hitsTotalLabel": "ヒット数 (合計)", + "data.search.searchSource.indexPatternDescription": "Elasticsearch インデックスに接続したインデックスパターンです。", + "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} インデックス内の ID です。", + "data.search.searchSource.indexPatternIdLabel": "インデックスパターン ID", + "data.search.searchSource.indexPatternLabel": "インデックスパターン", + "data.search.searchSource.noSearchStrategyRegisteredErrorMessageDescription": "検索リクエストの検索方法が見つかりませんでした", + "data.search.searchSource.noSearchStrategyRegisteredErrorMessageTitle": "検索方法が登録されていません", + "data.search.searchSource.queryTimeDescription": "クエリの処理の所要時間です。リクエストの送信やブラウザでのパースの時間は含まれません。", + "data.search.searchSource.queryTimeLabel": "クエリ時間", + "data.search.searchSource.queryTimeValue": "{queryTime}ms", + "data.search.searchSource.requestTimeDescription": "ブラウザから Elasticsearch にリクエストが送信され返されるまでの所要時間です。リクエストがキューで待機していた時間は含まれません。", + "data.search.searchSource.requestTimeLabel": "リクエスト時間", + "data.search.searchSource.requestTimeValue": "{requestTime}ms", "data.filter.filterEditor.operatorSelectPlaceholderSelect": "選択してください", "data.filter.filterEditor.operatorSelectPlaceholderWaiting": "待機中", "data.filter.filterEditor.rangeInputLabel": "範囲", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0f0a45ea19417..fe8eaed72901b 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -79,206 +79,188 @@ "common.ui.aggResponse.allDocsTitle": "所有文档", "common.ui.aggResponse.fieldLabel": "字段", "common.ui.aggResponse.valueLabel": "值", - "common.ui.aggTypes.aggNotValidLabel": "- 聚合无效 -", - "common.ui.aggTypes.aggregateWith.noAggsErrorTooltip": "选择的字段没有兼容的聚合。", - "common.ui.aggTypes.aggregateWithLabel": "聚合对象", - "common.ui.aggTypes.aggregateWithTooltip": "选择将多个命中或多值字段组合成单个指标的策略。", - "common.ui.aggTypes.buckets.dateHistogramLabel": "{fieldName}/{intervalDescription}", - "common.ui.aggTypes.buckets.dateHistogramTitle": "Date Histogram", - "common.ui.aggTypes.buckets.dateRangeTitle": "日期范围", - "common.ui.aggTypes.buckets.filtersTitle": "筛选", - "common.ui.aggTypes.buckets.filterTitle": "筛选", - "common.ui.aggTypes.buckets.geohashGridTitle": "Geohash", - "common.ui.aggTypes.buckets.geotileGridTitle": "地理磁贴", - "common.ui.aggTypes.buckets.histogramTitle": "Histogram", - "common.ui.aggTypes.buckets.intervalOptions.autoDisplayName": "自动", - "common.ui.aggTypes.buckets.intervalOptions.dailyDisplayName": "每日", - "common.ui.aggTypes.buckets.intervalOptions.hourlyDisplayName": "每小时", - "common.ui.aggTypes.buckets.intervalOptions.millisecondDisplayName": "毫秒", - "common.ui.aggTypes.buckets.intervalOptions.minuteDisplayName": "分钟", - "common.ui.aggTypes.buckets.intervalOptions.monthlyDisplayName": "每月", - "common.ui.aggTypes.buckets.intervalOptions.secondDisplayName": "秒", - "common.ui.aggTypes.buckets.intervalOptions.weeklyDisplayName": "每周", - "common.ui.aggTypes.buckets.intervalOptions.yearlyDisplayName": "每年", - "common.ui.aggTypes.buckets.ipRangeLabel": "{fieldName} IP 范围", - "common.ui.aggTypes.buckets.ipRangeTitle": "IPv4 范围", - "common.ui.aggTypes.buckets.rangesLabel": "{fieldName} 范围", - "common.ui.aggTypes.buckets.rangeTitle": "范围", - "common.ui.aggTypes.buckets.significantTerms.excludeLabel": "排除", - "common.ui.aggTypes.buckets.significantTerms.includeLabel": "包括", - "common.ui.aggTypes.buckets.significantTermsLabel": "{fieldName} 中排名前 {size} 的罕见词", - "common.ui.aggTypes.buckets.significantTermsTitle": "重要词", - "common.ui.aggTypes.buckets.terms.excludeLabel": "排除", - "common.ui.aggTypes.buckets.terms.includeLabel": "包括", - "common.ui.aggTypes.buckets.terms.missingBucketLabel": "缺失", - "common.ui.aggTypes.buckets.terms.orderAscendingTitle": "升序", - "common.ui.aggTypes.buckets.terms.orderDescendingTitle": "降序", - "common.ui.aggTypes.buckets.terms.otherBucketDescription": "此请求计数不符合数据存储桶条件的文档数目。", - "common.ui.aggTypes.buckets.terms.otherBucketLabel": "其他", - "common.ui.aggTypes.buckets.terms.otherBucketTitle": "其他存储桶", - "common.ui.aggTypes.buckets.termsTitle": "词", - "common.ui.aggTypes.changePrecisionLabel": "更改地图缩放的精确度", - "common.ui.aggTypes.customMetricLabel": "定制指标", - "common.ui.aggTypes.dateRanges.acceptedDateFormatsLinkText": "已接受日期格式", - "common.ui.aggTypes.dateRanges.addRangeButtonLabel": "添加范围", - "common.ui.aggTypes.dateRanges.fromColumnLabel": "从", - "common.ui.aggTypes.dateRanges.toColumnLabel": "到", - "common.ui.aggTypes.definiteMetricLabel": "指标:{metric}", - "common.ui.aggTypes.dropPartialBucketsLabel": "丢弃部分存储桶", - "common.ui.aggTypes.dropPartialBucketsTooltip": "移除超出时间范围的存储桶,以便直方图不以不完整的存储桶开始和结束。", - "common.ui.aggTypes.extendedBounds.errorMessage": "最小值应小于或等于最大值。", - "common.ui.aggTypes.extendedBounds.maxLabel": "最大值", - "common.ui.aggTypes.extendedBounds.minLabel": "最小值", - "common.ui.aggTypes.extendedBoundsLabel": "延伸边界", - "common.ui.aggTypes.extendedBoundsTooltip": "“最小值”和“最大值”不会筛选结果,而会扩展结果集的边界", - "common.ui.aggTypes.field.fieldLabel": "字段", - "common.ui.aggTypes.field.noCompatibleFieldsDescription": "索引模式“{indexPatternTitle}”不包含任何以下兼容字段类型:{fieldTypes}", - "common.ui.aggTypes.field.selectFieldPlaceholder": "选择字段", - "common.ui.aggTypes.filters.addFilterButtonLabel": "添加筛选", - "common.ui.aggTypes.filters.definiteFilterLabel": "筛选 {index} 标签", - "common.ui.aggTypes.filters.filterLabel": "筛选 {index}", - "common.ui.aggTypes.filters.labelPlaceholder": "标签", - "common.ui.aggTypes.filters.removeFilterButtonAriaLabel": "移除此筛选", - "common.ui.aggTypes.filters.toggleFilterButtonAriaLabel": "切换筛选标签", - "common.ui.aggTypes.histogram.missingMaxMinValuesWarning": "无法检索最大值和最小值以自动缩放直方图存储桶。这可能会导致可视化性能低下。", - "common.ui.aggTypes.ipRanges.addRangeButtonLabel": "添加范围", - "common.ui.aggTypes.ipRanges.cidrMaskAriaLabel": "CIDR 掩码:{mask}", - "common.ui.aggTypes.ipRanges.cidrMasksButtonLabel": "CIDR 掩码", - "common.ui.aggTypes.ipRanges.fromToButtonLabel": "起始/结束", - "common.ui.aggTypes.ipRanges.ipRangeFromAriaLabel": "IP 范围起始:{value}", - "common.ui.aggTypes.ipRanges.ipRangeToAriaLabel": "IP 范围结束:{value}", - "common.ui.aggTypes.ipRanges.removeCidrMaskButtonAriaLabel": "移除 {mask} 的 CIDR 掩码值", - "common.ui.aggTypes.ipRanges.removeEmptyCidrMaskButtonAriaLabel": "移除 CIDR 掩码默认值", - "common.ui.aggTypes.ipRanges.removeRangeAriaLabel": "移除范围 {from} 至 {to}", - "common.ui.aggTypes.ipRangesAriaLabel": "IP 范围", - "common.ui.aggTypes.jsonInputLabel": "JSON 输入", - "common.ui.aggTypes.jsonInputTooltip": "此处以 JSON 格式添加的任何属性将与此部分的 elasticsearch 聚合定义合并。例如,词聚合上的“shard_size”。", - "common.ui.aggTypes.metricLabel": "指标", - "common.ui.aggTypes.metrics.averageBucketTitle": "平均存储桶", - "common.ui.aggTypes.metrics.averageLabel": "{field}平均值", - "common.ui.aggTypes.metrics.averageTitle": "平均值", - "common.ui.aggTypes.metrics.bucketAggTitle": "存储桶聚合", - "common.ui.aggTypes.metrics.bucketTitle": "存储桶", - "common.ui.aggTypes.metrics.countLabel": "计数", - "common.ui.aggTypes.metrics.countTitle": "计数", - "common.ui.aggTypes.metrics.cumulativeSumLabel": "累计和", - "common.ui.aggTypes.metrics.cumulativeSumTitle": "累计和", - "common.ui.aggTypes.metrics.derivativeLabel": "导数", - "common.ui.aggTypes.metrics.derivativeTitle": "导数", - "common.ui.aggTypes.metrics.geoBoundsLabel": "地理边界", - "common.ui.aggTypes.metrics.geoBoundsTitle": "地理边界", - "common.ui.aggTypes.metrics.geoCentroidLabel": "地理重心", - "common.ui.aggTypes.metrics.geoCentroidTitle": "地理重心", - "common.ui.aggTypes.metrics.maxBucketTitle": "最大存储桶", - "common.ui.aggTypes.metrics.maxLabel": "{field}最大值", - "common.ui.aggTypes.metrics.maxTitle": "最大值", - "common.ui.aggTypes.metrics.medianLabel": "{field}中值", - "common.ui.aggTypes.metrics.medianTitle": "中值", - "common.ui.aggTypes.metrics.metricAggregationsSubtypeTitle": "指标聚合", - "common.ui.aggTypes.metrics.metricAggTitle": "指标聚合", - "common.ui.aggTypes.metrics.metricTitle": "指标", - "common.ui.aggTypes.metrics.minBucketTitle": "最小存储桶", - "common.ui.aggTypes.metrics.minLabel": "{field}最小值", - "common.ui.aggTypes.metrics.minTitle": "最小值", - "common.ui.aggTypes.metrics.movingAvgLabel": "移动平均值", - "common.ui.aggTypes.metrics.movingAvgTitle": "移动平均值", - "common.ui.aggTypes.metrics.overallAverageLabel": "总体平均值", - "common.ui.aggTypes.metrics.overallMaxLabel": "总体最大值", - "common.ui.aggTypes.metrics.overallMinLabel": "总体最大值", - "common.ui.aggTypes.metrics.overallSumLabel": "总和", - "common.ui.aggTypes.metrics.parentPipelineAggregationsSubtypeTitle": "父级管道聚合", - "common.ui.aggTypes.metrics.percentileRanks.valuePropsLabel": "“{label}” 的百分位数排名 {format}", - "common.ui.aggTypes.metrics.percentileRanksLabel": "“{field}” 的百分位数排名", - "common.ui.aggTypes.metrics.percentileRanksTitle": "百分位数排名", - "common.ui.aggTypes.metrics.percentiles.valuePropsLabel": "“{label}” 的 {percentile} 百分位数", - "common.ui.aggTypes.metrics.percentilesLabel": "“{field}” 的百分位数", - "common.ui.aggTypes.metrics.percentilesTitle": "百分位数", - "common.ui.aggTypes.metrics.serialDiffLabel": "序列差异", - "common.ui.aggTypes.metrics.serialDiffTitle": "序列差异", - "common.ui.aggTypes.metrics.siblingPipelineAggregationsSubtypeTitle": "同级管道聚合", - "common.ui.aggTypes.metrics.standardDeviation.keyDetailsLabel": "“{fieldDisplayName}” 的标准偏差", - "common.ui.aggTypes.metrics.standardDeviation.lowerKeyDetailsTitle": "下{label}", - "common.ui.aggTypes.metrics.standardDeviation.upperKeyDetailsTitle": "上{label}", - "common.ui.aggTypes.metrics.standardDeviationLabel": "“{field}” 的标准偏差", - "common.ui.aggTypes.metrics.standardDeviationTitle": "标准偏差", - "common.ui.aggTypes.metrics.sumBucketTitle": "求和存储桶", - "common.ui.aggTypes.metrics.sumLabel": "“{field}” 的和", - "common.ui.aggTypes.metrics.sumTitle": "和", - "common.ui.aggTypes.metrics.topHit.ascendingLabel": "升序", - "common.ui.aggTypes.metrics.topHit.averageLabel": "平均值", - "common.ui.aggTypes.metrics.topHit.concatenateLabel": "连接", - "common.ui.aggTypes.metrics.topHit.descendingLabel": "降序", - "common.ui.aggTypes.metrics.topHit.firstPrefixLabel": "第一", - "common.ui.aggTypes.metrics.topHit.lastPrefixLabel": "最后", - "common.ui.aggTypes.metrics.topHit.maxLabel": "最大值", - "common.ui.aggTypes.metrics.topHit.minLabel": "最小值", - "common.ui.aggTypes.metrics.topHit.sumLabel": "和", - "common.ui.aggTypes.metrics.topHitTitle": "最高命中结果", - "common.ui.aggTypes.metrics.uniqueCountLabel": "“{field}” 的唯一计数", - "common.ui.aggTypes.metrics.uniqueCountTitle": "唯一计数", - "common.ui.aggTypes.metrics.wrongLastBucketTypeErrorMessage": "使用“{type}”指标聚合时,上一存储桶聚合必须是“Date Histogram”或“Histogram”。", - "common.ui.aggTypes.numberInterval.minimumIntervalLabel": "最小时间间隔", - "common.ui.aggTypes.numberInterval.minimumIntervalTooltip": "提供的值创建的存储桶数目大于“高级设置”的 {histogramMaxBars} 指定的数目时,将自动缩放时间间隔", - "common.ui.aggTypes.numberInterval.selectIntervalPlaceholder": "输入时间间隔", - "common.ui.aggTypes.numberList.addUnitButtonLabel": "添加{unitName}", - "common.ui.aggTypes.numberList.enterValuePlaceholder": "输入值", - "common.ui.aggTypes.numberList.invalidAscOrderErrorMessage": "这些值应为升序。", - "common.ui.aggTypes.numberList.invalidRangeErrorMessage": "值应在 {min} 至 {max} 范围内。", - "common.ui.aggTypes.numberList.removeUnitButtonAriaLabel": "移除 {value} 的排名值", - "common.ui.aggTypes.onlyRequestDataAroundMapExtentLabel": "仅请求地图范围的数据", - "common.ui.aggTypes.onlyRequestDataAroundMapExtentTooltip": "应用 geo_bounding_box 筛选聚合以使用领口将主题区域缩小到地图视图框", - "common.ui.aggTypes.orderAgg.alphabeticalLabel": "按字母顺序", - "common.ui.aggTypes.orderAgg.orderByLabel": "排序依据", - "common.ui.aggTypes.orderLabel": "顺序", - "common.ui.aggTypes.otherBucket.groupValuesLabel": "在单独的存储桶中对其他值分组", - "common.ui.aggTypes.otherBucket.groupValuesTooltip": "不在排名前 N 中的值将在此存储桶中进行分组。要包括缺失值的文档,请启用“显示缺失值”。", - "common.ui.aggTypes.otherBucket.labelForMissingValuesLabel": "缺失值的标签", - "common.ui.aggTypes.otherBucket.labelForOtherBucketLabel": "其他存储桶的标签", - "common.ui.aggTypes.otherBucket.showMissingValuesLabel": "显示缺失值", - "common.ui.aggTypes.otherBucket.showMissingValuesTooltip": "仅对“字符串”类型的字段有效。启用后,在搜索中包括缺失值的文档。如果此存储桶在排名前 N 中,其将会显示在图表中。如果不在排名前 N 中,并且启用了“在单独的存储桶中对其他值分组”,Elasticsearch 会将缺失值添加到“其他”存储桶。", - "common.ui.aggTypes.paramTypes.field.invalidSavedFieldParameterErrorMessage": "已保存的 {fieldParameter} 参数现在无效。请选择新字段。", - "common.ui.aggTypes.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} 是必需字段", - "common.ui.aggTypes.percentileRanks.percentUnitNameText": "百分比", - "common.ui.aggTypes.percentileRanks.valuesLabel": "值", - "common.ui.aggTypes.percentileRanks.valueUnitNameText": "值", - "common.ui.aggTypes.percentiles.percentsLabel": "百分数", - "common.ui.aggTypes.placeMarkersOffGridLabel": "将标记置于网格外(使用 geocentroid)", - "common.ui.aggTypes.precisionLabel": "精确度", - "common.ui.aggTypes.ranges.addRangeButtonLabel": "添加范围", - "common.ui.aggTypes.ranges.fromLabel": "从", - "common.ui.aggTypes.ranges.removeRangeButtonAriaLabel": "移除范围 {from} 至 {to}", - "common.ui.aggTypes.ranges.toLabel": "到", - "common.ui.aggTypes.showEmptyBucketsLabel": "显示空存储桶", - "common.ui.aggTypes.showEmptyBucketsTooltip": "显示所有存储桶,不仅仅有结果的存储桶", - "common.ui.aggTypes.sizeLabel": "大小", - "common.ui.aggTypes.sizeTooltip": "请求排名前 K 的命中。多个命中将通过“聚合对象”组合。", - "common.ui.aggTypes.sortOnLabel": "排序依据", - "common.ui.aggTypes.string.customLabel": "定制标签", - "common.ui.aggTypes.timeInterval.createsTooLargeBucketsTooltip": "此时间间隔将创建过大而无法在选定时间范围内显示的存储桶,因此其已缩放至", - "common.ui.aggTypes.timeInterval.createsTooManyBucketsTooltip": "此时间间隔将创建过多的存储桶,而无法在选定时间范围内全部显示,因此其已缩放至", - "common.ui.aggTypes.timeInterval.invalidFormatErrorMessage": "时间间隔格式无效。", - "common.ui.aggTypes.timeInterval.minimumIntervalLabel": "最小时间间隔", - "common.ui.aggTypes.timeInterval.scaledHelpText": "当前缩放至 {bucketDescription}", - "common.ui.aggTypes.timeInterval.selectIntervalPlaceholder": "选择时间间隔", - "common.ui.aggTypes.timeInterval.selectOptionHelpText": "选择选项或创建定制值示例:30s、20m、24h、2d、1w、1M", - "common.ui.courier.fetch.requestTimedOutNotificationMessage": "由于您的请求超时,因此数据可能不完整", - "common.ui.courier.fetch.shardsFailedNotificationMessage": "{shardsTotal} 个分片有 {shardsFailed} 个失败", - "common.ui.courier.hitsDescription": "查询返回的文档数目。", - "common.ui.courier.hitsLabel": "命中", - "common.ui.courier.hitsTotalDescription": "匹配查询的文档数目。", - "common.ui.courier.hitsTotalLabel": "命中(总计)", - "common.ui.courier.indexPatternDescription": "连接到 Elasticsearch 索引的索引模式。", - "common.ui.courier.indexPatternIdDescription": "{kibanaIndexPattern} 索引中的 ID。", - "common.ui.courier.indexPatternIdLabel": "索引模式 ID", - "common.ui.courier.indexPatternLabel": "索引模式", - "common.ui.courier.noSearchStrategyRegisteredErrorMessageDescription": "无法为该搜索请求找到搜索策略", - "common.ui.courier.noSearchStrategyRegisteredErrorMessageTitle": "未注册任何搜索策略", - "common.ui.courier.queryTimeDescription": "处理查询所花费的时间。不包括发送请求或在浏览器中解析它的时间。", - "common.ui.courier.queryTimeLabel": "查询时间", - "common.ui.courier.queryTimeValue": "{queryTime}ms", - "common.ui.courier.requestTimeDescription": "请求从浏览器到 Elasticsearch 以及返回的时间。不包括请求在队列中等候的时间。", - "common.ui.courier.requestTimeLabel": "请求时间", - "common.ui.courier.requestTimeValue": "{requestTime}ms", + "data.search.aggs.aggNotValidLabel": "- 聚合无效 -", + "data.search.aggs.aggregateWith.noAggsErrorTooltip": "选择的字段没有兼容的聚合。", + "data.search.aggs.aggregateWithLabel": "聚合对象", + "data.search.aggs.aggregateWithTooltip": "选择将多个命中或多值字段组合成单个指标的策略。", + "data.search.aggs.buckets.dateHistogramLabel": "{fieldName}/{intervalDescription}", + "data.search.aggs.buckets.dateHistogramTitle": "Date Histogram", + "data.search.aggs.buckets.dateRangeTitle": "日期范围", + "data.search.aggs.buckets.filtersTitle": "筛选", + "data.search.aggs.buckets.filterTitle": "筛选", + "data.search.aggs.buckets.geohashGridTitle": "Geohash", + "data.search.aggs.buckets.geotileGridTitle": "地理磁贴", + "data.search.aggs.buckets.histogramTitle": "Histogram", + "data.search.aggs.buckets.intervalOptions.autoDisplayName": "自动", + "data.search.aggs.buckets.intervalOptions.dailyDisplayName": "每日", + "data.search.aggs.buckets.intervalOptions.hourlyDisplayName": "每小时", + "data.search.aggs.buckets.intervalOptions.millisecondDisplayName": "毫秒", + "data.search.aggs.buckets.intervalOptions.minuteDisplayName": "分钟", + "data.search.aggs.buckets.intervalOptions.monthlyDisplayName": "每月", + "data.search.aggs.buckets.intervalOptions.secondDisplayName": "秒", + "data.search.aggs.buckets.intervalOptions.weeklyDisplayName": "每周", + "data.search.aggs.buckets.intervalOptions.yearlyDisplayName": "每年", + "data.search.aggs.buckets.ipRangeLabel": "{fieldName} IP 范围", + "data.search.aggs.buckets.ipRangeTitle": "IPv4 范围", + "data.search.aggs.buckets.rangesLabel": "{fieldName} 范围", + "data.search.aggs.buckets.rangeTitle": "范围", + "data.search.aggs.buckets.significantTerms.excludeLabel": "排除", + "data.search.aggs.buckets.significantTerms.includeLabel": "包括", + "data.search.aggs.buckets.significantTermsLabel": "{fieldName} 中排名前 {size} 的罕见词", + "data.search.aggs.buckets.significantTermsTitle": "重要词", + "data.search.aggs.buckets.terms.excludeLabel": "排除", + "data.search.aggs.buckets.terms.includeLabel": "包括", + "data.search.aggs.buckets.terms.missingBucketLabel": "缺失", + "data.search.aggs.buckets.terms.orderAscendingTitle": "升序", + "data.search.aggs.buckets.terms.orderDescendingTitle": "降序", + "data.search.aggs.buckets.terms.otherBucketDescription": "此请求计数不符合数据存储桶条件的文档数目。", + "data.search.aggs.buckets.terms.otherBucketLabel": "其他", + "data.search.aggs.buckets.terms.otherBucketTitle": "其他存储桶", + "data.search.aggs.buckets.termsTitle": "词", + "data.search.aggs.changePrecisionLabel": "更改地图缩放的精确度", + "data.search.aggs.customMetricLabel": "定制指标", + "data.search.aggs.dateRanges.acceptedDateFormatsLinkText": "已接受日期格式", + "data.search.aggs.dateRanges.addRangeButtonLabel": "添加范围", + "data.search.aggs.dateRanges.fromColumnLabel": "从", + "data.search.aggs.dateRanges.toColumnLabel": "到", + "data.search.aggs.definiteMetricLabel": "指标:{metric}", + "data.search.aggs.dropPartialBucketsLabel": "丢弃部分存储桶", + "data.search.aggs.dropPartialBucketsTooltip": "移除超出时间范围的存储桶,以便直方图不以不完整的存储桶开始和结束。", + "data.search.aggs.extendedBounds.errorMessage": "最小值应小于或等于最大值。", + "data.search.aggs.extendedBounds.maxLabel": "最大值", + "data.search.aggs.extendedBounds.minLabel": "最小值", + "data.search.aggs.extendedBoundsLabel": "延伸边界", + "data.search.aggs.extendedBoundsTooltip": "“最小值”和“最大值”不会筛选结果,而会扩展结果集的边界", + "data.search.aggs.field.fieldLabel": "字段", + "data.search.aggs.field.noCompatibleFieldsDescription": "索引模式“{indexPatternTitle}”不包含任何以下兼容字段类型:{fieldTypes}", + "data.search.aggs.field.selectFieldPlaceholder": "选择字段", + "data.search.aggs.filters.addFilterButtonLabel": "添加筛选", + "data.search.aggs.filters.definiteFilterLabel": "筛选 {index} 标签", + "data.search.aggs.filters.filterLabel": "筛选 {index}", + "data.search.aggs.filters.labelPlaceholder": "标签", + "data.search.aggs.filters.removeFilterButtonAriaLabel": "移除此筛选", + "data.search.aggs.filters.toggleFilterButtonAriaLabel": "切换筛选标签", + "data.search.aggs.histogram.missingMaxMinValuesWarning": "无法检索最大值和最小值以自动缩放直方图存储桶。这可能会导致可视化性能低下。", + "data.search.aggs.ipRanges.addRangeButtonLabel": "添加范围", + "data.search.aggs.ipRanges.cidrMaskAriaLabel": "CIDR 掩码:{mask}", + "data.search.aggs.ipRanges.cidrMasksButtonLabel": "CIDR 掩码", + "data.search.aggs.ipRanges.fromToButtonLabel": "起始/结束", + "data.search.aggs.ipRanges.ipRangeFromAriaLabel": "IP 范围起始:{value}", + "data.search.aggs.ipRanges.ipRangeToAriaLabel": "IP 范围结束:{value}", + "data.search.aggs.ipRanges.removeCidrMaskButtonAriaLabel": "移除 {mask} 的 CIDR 掩码值", + "data.search.aggs.ipRanges.removeEmptyCidrMaskButtonAriaLabel": "移除 CIDR 掩码默认值", + "data.search.aggs.ipRanges.removeRangeAriaLabel": "移除范围 {from} 至 {to}", + "data.search.aggs.ipRangesAriaLabel": "IP 范围", + "data.search.aggs.jsonInputLabel": "JSON 输入", + "data.search.aggs.jsonInputTooltip": "此处以 JSON 格式添加的任何属性将与此部分的 elasticsearch 聚合定义合并。例如,词聚合上的“shard_size”。", + "data.search.aggs.metricLabel": "指标", + "data.search.aggs.metrics.averageBucketTitle": "平均存储桶", + "data.search.aggs.metrics.averageLabel": "{field}平均值", + "data.search.aggs.metrics.averageTitle": "平均值", + "data.search.aggs.metrics.bucketAggTitle": "存储桶聚合", + "data.search.aggs.metrics.bucketTitle": "存储桶", + "data.search.aggs.metrics.countLabel": "计数", + "data.search.aggs.metrics.countTitle": "计数", + "data.search.aggs.metrics.cumulativeSumLabel": "累计和", + "data.search.aggs.metrics.cumulativeSumTitle": "累计和", + "data.search.aggs.metrics.derivativeLabel": "导数", + "data.search.aggs.metrics.derivativeTitle": "导数", + "data.search.aggs.metrics.geoBoundsLabel": "地理边界", + "data.search.aggs.metrics.geoBoundsTitle": "地理边界", + "data.search.aggs.metrics.geoCentroidLabel": "地理重心", + "data.search.aggs.metrics.geoCentroidTitle": "地理重心", + "data.search.aggs.metrics.maxBucketTitle": "最大存储桶", + "data.search.aggs.metrics.maxLabel": "{field}最大值", + "data.search.aggs.metrics.maxTitle": "最大值", + "data.search.aggs.metrics.medianLabel": "{field}中值", + "data.search.aggs.metrics.medianTitle": "中值", + "data.search.aggs.metrics.metricAggregationsSubtypeTitle": "指标聚合", + "data.search.aggs.metrics.metricAggTitle": "指标聚合", + "data.search.aggs.metrics.metricTitle": "指标", + "data.search.aggs.metrics.minBucketTitle": "最小存储桶", + "data.search.aggs.metrics.minLabel": "{field}最小值", + "data.search.aggs.metrics.minTitle": "最小值", + "data.search.aggs.metrics.movingAvgLabel": "移动平均值", + "data.search.aggs.metrics.movingAvgTitle": "移动平均值", + "data.search.aggs.metrics.overallAverageLabel": "总体平均值", + "data.search.aggs.metrics.overallMaxLabel": "总体最大值", + "data.search.aggs.metrics.overallMinLabel": "总体最大值", + "data.search.aggs.metrics.overallSumLabel": "总和", + "data.search.aggs.metrics.parentPipelineAggregationsSubtypeTitle": "父级管道聚合", + "data.search.aggs.metrics.percentileRanks.valuePropsLabel": "“{label}” 的百分位数排名 {format}", + "data.search.aggs.metrics.percentileRanksLabel": "“{field}” 的百分位数排名", + "data.search.aggs.metrics.percentileRanksTitle": "百分位数排名", + "data.search.aggs.metrics.percentiles.valuePropsLabel": "“{label}” 的 {percentile} 百分位数", + "data.search.aggs.metrics.percentilesLabel": "“{field}” 的百分位数", + "data.search.aggs.metrics.percentilesTitle": "百分位数", + "data.search.aggs.metrics.serialDiffLabel": "序列差异", + "data.search.aggs.metrics.serialDiffTitle": "序列差异", + "data.search.aggs.metrics.siblingPipelineAggregationsSubtypeTitle": "同级管道聚合", + "data.search.aggs.metrics.standardDeviation.keyDetailsLabel": "“{fieldDisplayName}” 的标准偏差", + "data.search.aggs.metrics.standardDeviation.lowerKeyDetailsTitle": "下{label}", + "data.search.aggs.metrics.standardDeviation.upperKeyDetailsTitle": "上{label}", + "data.search.aggs.metrics.standardDeviationLabel": "“{field}” 的标准偏差", + "data.search.aggs.metrics.standardDeviationTitle": "标准偏差", + "data.search.aggs.metrics.sumBucketTitle": "求和存储桶", + "data.search.aggs.metrics.sumLabel": "“{field}” 的和", + "data.search.aggs.metrics.sumTitle": "和", + "data.search.aggs.metrics.topHit.ascendingLabel": "升序", + "data.search.aggs.metrics.topHit.averageLabel": "平均值", + "data.search.aggs.metrics.topHit.concatenateLabel": "连接", + "data.search.aggs.metrics.topHit.descendingLabel": "降序", + "data.search.aggs.metrics.topHit.firstPrefixLabel": "第一", + "data.search.aggs.metrics.topHit.lastPrefixLabel": "最后", + "data.search.aggs.metrics.topHit.maxLabel": "最大值", + "data.search.aggs.metrics.topHit.minLabel": "最小值", + "data.search.aggs.metrics.topHit.sumLabel": "和", + "data.search.aggs.metrics.topHitTitle": "最高命中结果", + "data.search.aggs.metrics.uniqueCountLabel": "“{field}” 的唯一计数", + "data.search.aggs.metrics.uniqueCountTitle": "唯一计数", + "data.search.aggs.metrics.wrongLastBucketTypeErrorMessage": "使用“{type}”指标聚合时,上一存储桶聚合必须是“Date Histogram”或“Histogram”。", + "data.search.aggs.numberInterval.minimumIntervalLabel": "最小时间间隔", + "data.search.aggs.numberInterval.minimumIntervalTooltip": "提供的值创建的存储桶数目大于“高级设置”的 {histogramMaxBars} 指定的数目时,将自动缩放时间间隔", + "data.search.aggs.numberInterval.selectIntervalPlaceholder": "输入时间间隔", + "data.search.aggs.numberList.addUnitButtonLabel": "添加{unitName}", + "data.search.aggs.numberList.enterValuePlaceholder": "输入值", + "data.search.aggs.numberList.invalidAscOrderErrorMessage": "这些值应为升序。", + "data.search.aggs.numberList.invalidRangeErrorMessage": "值应在 {min} 至 {max} 范围内。", + "data.search.aggs.numberList.removeUnitButtonAriaLabel": "移除 {value} 的排名值", + "data.search.aggs.onlyRequestDataAroundMapExtentLabel": "仅请求地图范围的数据", + "data.search.aggs.onlyRequestDataAroundMapExtentTooltip": "应用 geo_bounding_box 筛选聚合以使用领口将主题区域缩小到地图视图框", + "data.search.aggs.orderAgg.alphabeticalLabel": "按字母顺序", + "data.search.aggs.orderAgg.orderByLabel": "排序依据", + "data.search.aggs.orderLabel": "顺序", + "data.search.aggs.otherBucket.groupValuesLabel": "在单独的存储桶中对其他值分组", + "data.search.aggs.otherBucket.groupValuesTooltip": "不在排名前 N 中的值将在此存储桶中进行分组。要包括缺失值的文档,请启用“显示缺失值”。", + "data.search.aggs.otherBucket.labelForMissingValuesLabel": "缺失值的标签", + "data.search.aggs.otherBucket.labelForOtherBucketLabel": "其他存储桶的标签", + "data.search.aggs.otherBucket.showMissingValuesLabel": "显示缺失值", + "data.search.aggs.otherBucket.showMissingValuesTooltip": "仅对“字符串”类型的字段有效。启用后,在搜索中包括缺失值的文档。如果此存储桶在排名前 N 中,其将会显示在图表中。如果不在排名前 N 中,并且启用了“在单独的存储桶中对其他值分组”,Elasticsearch 会将缺失值添加到“其他”存储桶。", + "data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage": "已保存的 {fieldParameter} 参数现在无效。请选择新字段。", + "data.search.aggs.paramTypes.field.requiredFieldParameterErrorMessage": "{fieldParameter} 是必需字段", + "data.search.aggs.percentileRanks.percentUnitNameText": "百分比", + "data.search.aggs.percentileRanks.valuesLabel": "值", + "data.search.aggs.percentileRanks.valueUnitNameText": "值", + "data.search.aggs.percentiles.percentsLabel": "百分数", + "data.search.aggs.placeMarkersOffGridLabel": "将标记置于网格外(使用 geocentroid)", + "data.search.aggs.precisionLabel": "精确度", + "data.search.aggs.ranges.addRangeButtonLabel": "添加范围", + "data.search.aggs.ranges.fromLabel": "从", + "data.search.aggs.ranges.removeRangeButtonAriaLabel": "移除范围 {from} 至 {to}", + "data.search.aggs.ranges.toLabel": "到", + "data.search.aggs.showEmptyBucketsLabel": "显示空存储桶", + "data.search.aggs.showEmptyBucketsTooltip": "显示所有存储桶,不仅仅有结果的存储桶", + "data.search.aggs.sizeLabel": "大小", + "data.search.aggs.sizeTooltip": "请求排名前 K 的命中。多个命中将通过“聚合对象”组合。", + "data.search.aggs.sortOnLabel": "排序依据", + "data.search.aggs.string.customLabel": "定制标签", + "data.search.aggs.timeInterval.createsTooLargeBucketsTooltip": "此时间间隔将创建过大而无法在选定时间范围内显示的存储桶,因此其已缩放至", + "data.search.aggs.timeInterval.createsTooManyBucketsTooltip": "此时间间隔将创建过多的存储桶,而无法在选定时间范围内全部显示,因此其已缩放至", + "data.search.aggs.timeInterval.invalidFormatErrorMessage": "时间间隔格式无效。", + "data.search.aggs.timeInterval.minimumIntervalLabel": "最小时间间隔", + "data.search.aggs.timeInterval.scaledHelpText": "当前缩放至 {bucketDescription}", + "data.search.aggs.timeInterval.selectIntervalPlaceholder": "选择时间间隔", + "data.search.aggs.timeInterval.selectOptionHelpText": "选择选项或创建定制值示例:30s、20m、24h、2d、1w、1M", "common.ui.directives.fieldNameIcons.booleanAriaLabel": "布尔字段", "common.ui.directives.fieldNameIcons.conflictFieldAriaLabel": "冲突字段", "common.ui.directives.fieldNameIcons.dateFieldAriaLabel": "日期字段", @@ -542,28 +524,14 @@ "common.ui.visualize.queryGeohashBounds.unableToGetBoundErrorTitle": "无法获取边界", "common.ui.welcomeErrorMessage": "Kibana 未正确加载。检查服务器输出以了解详情。", "common.ui.welcomeMessage": "正在加载 Kibana", - "common.ui.courier.fetch.shardsFailedModal.close": "关闭", - "common.ui.courier.fetch.shardsFailedModal.copyToClipboard": "将响应复制到剪贴板", - "common.ui.courier.fetch.shardsFailedModal.failureHeader": "{failureDetails} 时为 {failureName}", - "common.ui.courier.fetch.shardsFailedModal.showDetails": "显示详情", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderRequest": "请求", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderResponse": "响应", - "common.ui.courier.fetch.shardsFailedModal.tabHeaderShardFailures": "分片错误", - "common.ui.courier.fetch.shardsFailedModal.tableColIndex": "索引", - "common.ui.courier.fetch.shardsFailedModal.tableColNode": "节点", - "common.ui.courier.fetch.shardsFailedModal.tableColReason": "原因", - "common.ui.courier.fetch.shardsFailedModal.tableColShard": "分片", - "common.ui.courier.fetch.shardsFailedModal.tableRowCollapse": "折叠 {rowDescription}", - "common.ui.courier.fetch.shardsFailedModal.tableRowExpand": "展开 {rowDescription}", - "common.ui.courier.fetch.shardsFailedNotificationDescription": "您正在查看的数据可能不完整或有错误。", "common.ui.directives.fieldNameIcons.geoShapeFieldAriaLabel": "几何形状字段", "common.ui.vis.editors.agg.errorsAriaLabel": "聚合有错误", "common.ui.vislib.heatmap.maxBucketsText": "定义了过多的序列 ({nr})。配置的最大值为 {max}。", - "common.ui.aggTypes.ranges.greaterThanOrEqualPrepend": "≥", - "common.ui.aggTypes.ranges.lessThanPrepend": "<", - "common.ui.aggTypes.scaleMetricsLabel": "缩放指标值(已弃用)", - "common.ui.aggTypes.scaleMetricsTooltip": "如果选择手动最小时间间隔并将使用较大的时间间隔,则启用此设置将使计数和求和指标缩放到手动选择的时间间隔。", - "common.ui.aggTypes.buckets.ranges.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", + "data.search.aggs.ranges.greaterThanOrEqualPrepend": "≥", + "data.search.aggs.ranges.lessThanPrepend": "<", + "data.search.aggs.scaleMetricsLabel": "缩放指标值(已弃用)", + "data.search.aggs.scaleMetricsTooltip": "如果选择手动最小时间间隔并将使用较大的时间间隔,则启用此设置将使计数和求和指标缩放到手动选择的时间间隔。", + "data.search.aggs.buckets.ranges.rangesFormatMessage": "{gte} {from} 且 {lt} {to}", "management.editIndexPattern.createIndex.defaultButtonDescription": "对任何数据执行完全聚合", "management.editIndexPattern.createIndex.defaultButtonText": "标准索引模式", "management.editIndexPattern.createIndex.defaultTypeName": "索引模式", @@ -874,6 +842,38 @@ "data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} 描述", "data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "已保存查询按钮已选择 {savedQueryName}。按下可清除任何更改。", "data.search.searchBar.savedQueryPopoverTitleText": "已保存查询", + "data.search.searchSource.fetch.shardsFailedModal.close": "关闭", + "data.search.searchSource.fetch.shardsFailedModal.copyToClipboard": "将响应复制到剪贴板", + "data.search.searchSource.fetch.shardsFailedModal.failureHeader": "{failureDetails} 时为 {failureName}", + "data.search.searchSource.fetch.shardsFailedModal.showDetails": "显示详情", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "请求", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "响应", + "data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "分片错误", + "data.search.searchSource.fetch.shardsFailedModal.tableColIndex": "索引", + "data.search.searchSource.fetch.shardsFailedModal.tableColNode": "节点", + "data.search.searchSource.fetch.shardsFailedModal.tableColReason": "原因", + "data.search.searchSource.fetch.shardsFailedModal.tableColShard": "分片", + "data.search.searchSource.fetch.shardsFailedModal.tableRowCollapse": "折叠 {rowDescription}", + "data.search.searchSource.fetch.shardsFailedModal.tableRowExpand": "展开 {rowDescription}", + "data.search.searchSource.fetch.shardsFailedNotificationDescription": "您正在查看的数据可能不完整或有错误。", + "data.search.searchSource.fetch.requestTimedOutNotificationMessage": "由于您的请求超时,因此数据可能不完整", + "data.search.searchSource.fetch.shardsFailedNotificationMessage": "{shardsTotal} 个分片有 {shardsFailed} 个失败", + "data.search.searchSource.hitsDescription": "查询返回的文档数目。", + "data.search.searchSource.hitsLabel": "命中", + "data.search.searchSource.hitsTotalDescription": "匹配查询的文档数目。", + "data.search.searchSource.hitsTotalLabel": "命中(总计)", + "data.search.searchSource.indexPatternDescription": "连接到 Elasticsearch 索引的索引模式。", + "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} 索引中的 ID。", + "data.search.searchSource.indexPatternIdLabel": "索引模式 ID", + "data.search.searchSource.indexPatternLabel": "索引模式", + "data.search.searchSource.noSearchStrategyRegisteredErrorMessageDescription": "无法为该搜索请求找到搜索策略", + "data.search.searchSource.noSearchStrategyRegisteredErrorMessageTitle": "未注册任何搜索策略", + "data.search.searchSource.queryTimeDescription": "处理查询所花费的时间。不包括发送请求或在浏览器中解析它的时间。", + "data.search.searchSource.queryTimeLabel": "查询时间", + "data.search.searchSource.queryTimeValue": "{queryTime}ms", + "data.search.searchSource.requestTimeDescription": "请求从浏览器到 Elasticsearch 以及返回的时间。不包括请求在队列中等候的时间。", + "data.search.searchSource.requestTimeLabel": "请求时间", + "data.search.searchSource.requestTimeValue": "{requestTime}ms", "data.filter.filterEditor.operatorSelectPlaceholderSelect": "选择", "data.filter.filterEditor.operatorSelectPlaceholderWaiting": "正在等候", "data.filter.filterEditor.rangeInputLabel": "范围",