diff --git a/.eslintrc.js b/.eslintrc.js
index e66331594b4ae..3c173e5244009 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -552,29 +552,6 @@ module.exports = {
},
},
- /**
- * Graph overrides
- */
- {
- files: ['x-pack/legacy/plugins/graph/**/*.js'],
- globals: {
- angular: true,
- $: true,
- },
- rules: {
- 'block-scoped-var': 'off',
- camelcase: 'off',
- eqeqeq: 'off',
- 'guard-for-in': 'off',
- 'new-cap': 'off',
- 'no-loop-func': 'off',
- 'no-redeclare': 'off',
- 'no-shadow': 'off',
- 'no-unused-vars': 'off',
- 'one-var': 'off',
- },
- },
-
/**
* ML overrides
*/
@@ -771,7 +748,7 @@ module.exports = {
* Lens overrides
*/
{
- files: ['x-pack/legacy/plugins/lens/**/*.ts', 'x-pack/legacy/plugins/lens/**/*.tsx'],
+ files: ['x-pack/legacy/plugins/lens/**/*.{ts,tsx}', 'x-pack/plugins/lens/**/*.{ts,tsx}'],
rules: {
'@typescript-eslint/no-explicit-any': 'error',
},
@@ -885,8 +862,10 @@ module.exports = {
* TSVB overrides
*/
{
- files: ['src/legacy/core_plugins/metrics/**/*.js'],
- excludedFiles: 'src/legacy/core_plugins/metrics/index.js',
+ files: [
+ 'src/plugins/vis_type_timeseries/**/*.{js,ts,tsx}',
+ 'src/legacy/core_plugins/vis_type_timeseries/**/*.{js,ts,tsx}',
+ ],
rules: {
'import/no-default-export': 'error',
},
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index da85fb986ae01..feaf47e45fd69 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -15,18 +15,20 @@
/src/legacy/core_plugins/metrics/ @elastic/kibana-app
/src/legacy/core_plugins/vis_type_vislib/ @elastic/kibana-app
/src/legacy/core_plugins/vis_type_xy/ @elastic/kibana-app
-# Exclude tutorials folder for now because they are not owned by Kibana app and most will move out soon
-/src/plugins/home/public @elastic/kibana-app
-/src/plugins/home/server/*.ts @elastic/kibana-app
-/src/plugins/home/server/services/ @elastic/kibana-app
-# Exclude tutorial resources folder for now because they are not owned by Kibana app and most will move out soon
-/src/legacy/core_plugins/kibana/public/home/*.ts @elastic/kibana-app
-/src/legacy/core_plugins/kibana/public/home/*.scss @elastic/kibana-app
-/src/legacy/core_plugins/kibana/public/home/np_ready/ @elastic/kibana-app
/src/plugins/kibana_legacy/ @elastic/kibana-app
/src/plugins/timelion/ @elastic/kibana-app
-/src/plugins/dev_tools/ @elastic/kibana-app
/src/plugins/dashboard/ @elastic/kibana-app
+/src/plugins/discover/ @elastic/kibana-app
+
+# Core UI
+# Exclude tutorials folder for now because they are not owned by Kibana app and most will move out soon
+/src/plugins/home/public @elastic/kibana-core-ui
+/src/plugins/home/server/*.ts @elastic/kibana-core-ui
+/src/plugins/home/server/services/ @elastic/kibana-core-ui
+# Exclude tutorial resources folder for now because they are not owned by Kibana app and most will move out soon
+/src/legacy/core_plugins/kibana/public/home/*.ts @elastic/kibana-core-ui
+/src/legacy/core_plugins/kibana/public/home/*.scss @elastic/kibana-core-ui
+/src/legacy/core_plugins/kibana/public/home/np_ready/ @elastic/kibana-core-ui
# App Architecture
/examples/url_generators_examples/ @elastic/kibana-app-arch
@@ -85,9 +87,8 @@
/x-pack/test/functional/apps/machine_learning/ @elastic/ml-ui
/x-pack/test/functional/services/machine_learning/ @elastic/ml-ui
/x-pack/test/functional/services/ml.ts @elastic/ml-ui
-# ML team owns the transform plugin, ES team added here for visibility
-# because the plugin lives in Kibana's Elasticsearch management section.
-/x-pack/plugins/transform/ @elastic/ml-ui @elastic/es-ui
+# ML team owns and maintains the transform plugin despite it living in the Elasticsearch management section.
+/x-pack/plugins/transform/ @elastic/ml-ui
/x-pack/test/functional/apps/transform/ @elastic/ml-ui
/x-pack/test/functional/services/transform_ui/ @elastic/ml-ui
/x-pack/test/functional/services/transform.ts @elastic/ml-ui
@@ -175,6 +176,7 @@
**/*.scss @elastic/kibana-design
# Elasticsearch UI
+/src/plugins/dev_tools/ @elastic/es-ui
/src/plugins/console/ @elastic/es-ui
/src/plugins/es_ui_shared/ @elastic/es-ui
/x-pack/legacy/plugins/cross_cluster_replication/ @elastic/es-ui
diff --git a/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc b/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc
index 7f35dc3834f00..565d12513815b 100644
--- a/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc
+++ b/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc
@@ -103,7 +103,7 @@ Execute the <>, w
.Properties of `error`
[%collapsible%open]
=======
- `type`:::::
+ `type`::::
(string) The type of error. For example, `unsupported_type`, `missing_references`, or `unknown`.
=======
======
diff --git a/docs/apm/api.asciidoc b/docs/apm/api.asciidoc
index 76d898ba0cb11..a8f4f4bf0baaa 100644
--- a/docs/apm/api.asciidoc
+++ b/docs/apm/api.asciidoc
@@ -44,7 +44,7 @@ The following Agent configuration APIs are available:
`service`::
(required, object) Service identifying the configuration to create or update.
-
++
.Properties of `service`
[%collapsible%open]
======
@@ -100,7 +100,7 @@ PUT /api/apm/settings/agent-configuration
===== Request body
`service`::
(required, object) Service identifying the configuration to delete
-
++
.Properties of `service`
[%collapsible%open]
======
@@ -217,7 +217,7 @@ GET /api/apm/settings/agent-configuration
`service`::
(required, object) Service identifying the configuration.
-
++
.Properties of `service`
[%collapsible%open]
======
diff --git a/docs/apm/transactions.asciidoc b/docs/apm/transactions.asciidoc
index 536ab2ec29c80..5c92afa55109d 100644
--- a/docs/apm/transactions.asciidoc
+++ b/docs/apm/transactions.asciidoc
@@ -103,9 +103,7 @@ The number of requests per bucket is displayed when hovering over the graph, and
[role="screenshot"]
image::apm/images/apm-transaction-duration-dist.png[Example view of transactions duration distribution graph]
-Most of the requests fall into buckets on the left side of the graph,
-with a long tail of smaller buckets to the right.
-This is a typical distribution, and indicates most of our requests were served quickly - awesome!
+This graph shows a typical distribution, and indicates most of our requests were served quickly - awesome!
It's the requests on the right, the ones taking longer than average, that we probably want to focus on.
When you select one of these buckets,
you're presented with up to ten trace samples.
diff --git a/docs/canvas/canvas-elements.asciidoc b/docs/canvas/canvas-elements.asciidoc
index 163579d5763b2..a25460a20eb50 100644
--- a/docs/canvas/canvas-elements.asciidoc
+++ b/docs/canvas/canvas-elements.asciidoc
@@ -138,7 +138,9 @@ To apply CSS overrides:
. Next to *Element style*, click *+*, then select *CSS*.
-. Enter the *CSS*. For example, to center the Markdown element, enter:
+. Enter the *CSS*.
++
+For example, to center the Markdown element, enter:
+
[source,text]
--------------------------------------------------
diff --git a/docs/canvas/canvas-present-workpad.asciidoc b/docs/canvas/canvas-present-workpad.asciidoc
index 486686cd857b5..9cd4ecc9519e1 100644
--- a/docs/canvas/canvas-present-workpad.asciidoc
+++ b/docs/canvas/canvas-present-workpad.asciidoc
@@ -8,7 +8,7 @@ When you are ready to present your workpad, use and enable the presentation opti
[[view-fullscreen-mode]]
==== View your workpad in fullscreen mode
-In the upper left corner, click the *Enter fullscreen mode* icon.
+Click the *Enter fullscreen mode* icon.
[role="screenshot"]
image::images/canvas-fullscreen.png[Fullscreen mode]
@@ -19,7 +19,7 @@ image::images/canvas-fullscreen.png[Fullscreen mode]
Automatically cycle through your workpads pages in fullscreen mode.
-. In the upper left corner, click the *Control settings* icon.
+. Click the *Control settings* icon.
. Under *Change cycling interval*, select the interval you want to use.
+
diff --git a/docs/canvas/canvas-share-workpad.asciidoc b/docs/canvas/canvas-share-workpad.asciidoc
index dbba12865b8ca..ee29926914ad6 100644
--- a/docs/canvas/canvas-share-workpad.asciidoc
+++ b/docs/canvas/canvas-share-workpad.asciidoc
@@ -10,7 +10,7 @@ When you've finished your workpad, you can share it outside of {kib}.
Create a JSON file of your workpad that you can export outside of {kib}.
-. From your workpad, click the *Share workpad* icon in the upper left corner.
+. From your workpad, click the *Share workpad* icon.
. Select *Download as JSON*.
+
@@ -27,7 +27,7 @@ If you have a license that supports the {report-features}, you can create a PDF
For more information, refer to <>.
-. From your workpad, click the *Share workpad* icon in the upper left corner, then select *PDF reports*.
+. From your workpad, click the *Share workpad* icon, then select *PDF reports*.
. Click *Generate PDF*.
+
@@ -42,7 +42,7 @@ If you have a license that supports the {report-features}, you can create a POST
For more information, refer to <>.
-. From your workpad, click the *Share workpad* icon in the upper left corner, then select *PDF reports*.
+. From your workpad, click the *Share workpad* icon, then select *PDF reports*.
. Click *Copy POST URL*.
+
@@ -55,7 +55,7 @@ image::images/canvas-create-URL.gif[Create POST URL]
beta[] Canvas allows you to create _shareables_, which are workpads that you download and securely share on any website. To customize the behavior of the workpad on your website, you can choose to autoplay the pages or hide the workpad toolbar.
-. From your workpad, click the *Share this workpad* icon in the upper left corner, then select *Share on a website*.
+. From your workpad, click the *Share this workpad* icon, then select *Share on a website*.
. On the *Share on a website* pane, follow the instructions.
diff --git a/docs/dev-tools/searchprofiler/getting-started.asciidoc b/docs/dev-tools/searchprofiler/getting-started.asciidoc
index 2360e4c28ff15..4a87d4b84b783 100644
--- a/docs/dev-tools/searchprofiler/getting-started.asciidoc
+++ b/docs/dev-tools/searchprofiler/getting-started.asciidoc
@@ -3,10 +3,10 @@
=== Getting Started
The {searchprofiler} is automatically enabled in {kib}. Go to *Dev Tools > Search Profiler*
-to get started.
+to get started.
{searchprofiler} displays the names of the indices searched, the shards in each index,
-and how long it took for the query to complete. To try it out, replace the default `match_all` query
+and how long it took for the query to complete. To try it out, replace the default `match_all` query
with the query you want to profile and click *Profile*.
The following example shows the results of profiling the `match_all` query.
@@ -29,8 +29,8 @@ While the Cumulative Time metric is useful for comparing the performance of your
indices and shards, it doesn't necessarily represent the actual physical query times.
====
-You can select the name of the shard and then click *View details* to see more profiling information,
-including details about the query component(s) that ran on the shard, as well as the timing
+You can select the name of the shard and then click *View details* to see more profiling information,
+including details about the query component(s) that ran on the shard, as well as the timing
breakdown of low-level Lucene methods. For more information, see {ref}/search-profile.html#profiling-queries[Profiling queries].
[float]
@@ -40,10 +40,10 @@ By default, all queries executed by the {searchprofiler} are sent
to `GET /_search`. It searches across your entire cluster (all indices, all types).
If you need to query a specific index or type (or several), you can use the Index
-and Type filters at the top left.
+and Type filters.
In the following example, the query is executed against the indices `test` and `kibana_1`
and the type `my_type`. This is equivalent making a request to `GET /test,kibana_1/my_type/_search`.
[role="screenshot"]
-image::dev-tools/searchprofiler/images/filter.png["Filtering by index and type"]
\ No newline at end of file
+image::dev-tools/searchprofiler/images/filter.png["Filtering by index and type"]
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md
index afb6ea88f9fad..78ac05b9fd386 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md
@@ -19,7 +19,7 @@ search: {
intervalOptions: ({
display: string;
val: string;
- enabled(agg: import("./search/aggs/buckets/_bucket_agg_type").IBucketAggConfig): boolean | "" | undefined;
+ enabled(agg: import("./search/aggs/buckets/bucket_agg_type").IBucketAggConfig): boolean | "" | undefined;
} | {
display: string;
val: string;
diff --git a/docs/discover/document-data.asciidoc b/docs/discover/document-data.asciidoc
index 6e9218d66c115..477c2ec90e95c 100644
--- a/docs/discover/document-data.asciidoc
+++ b/docs/discover/document-data.asciidoc
@@ -26,7 +26,7 @@ and click image:images/sort-icon.png[].
The first click sorts by ascending order, the second click sorts by descending order, and the third
click removes the field from the sorted fields.
-Move a field column:: Hover over the column header and click the move left (<<) or move right icon (>>).
+Move a field column:: Hover over the column header and click the (<<) or (>>) icons.
Remove a field column :: Hover over the list of *Specified fields*
and then click *remove*.
Or, use the (x) control in the column header.
diff --git a/docs/getting-started/tutorial-visualizing.asciidoc b/docs/getting-started/tutorial-visualizing.asciidoc
index a16343aa4850a..acd4d6d908fd4 100644
--- a/docs/getting-started/tutorial-visualizing.asciidoc
+++ b/docs/getting-started/tutorial-visualizing.asciidoc
@@ -180,5 +180,5 @@ The map now looks like this:
image::images/tutorial-visualize-map-2.png[]
. Navigate the map by clicking and dragging. Use the controls
-on the left to zoom the map and set filters.
+to zoom the map and set filters.
. *Save* this map with the name `Map Example`.
diff --git a/docs/infrastructure/view-metrics.asciidoc b/docs/infrastructure/view-metrics.asciidoc
index bbb981acc3ad6..1bd64dde76ee1 100644
--- a/docs/infrastructure/view-metrics.asciidoc
+++ b/docs/infrastructure/view-metrics.asciidoc
@@ -30,11 +30,3 @@ For complete control over the start and end times, click the start time or end t
=== Refresh the metrics
You can click *Refresh* to manually refresh the metrics.
-
-[float]
-[[infra-view-go-to-chart]]
-=== Go to a specific chart
-
-The charts available for this component are shown in a list on the left of the page. Click a chart in the list to quickly go to that chart.
-
-
diff --git a/docs/management/managing-licenses.asciidoc b/docs/management/managing-licenses.asciidoc
index 72accdb5fe2aa..a7ed4e942f3f6 100644
--- a/docs/management/managing-licenses.asciidoc
+++ b/docs/management/managing-licenses.asciidoc
@@ -15,8 +15,7 @@ already activated a trial for 6.0, you cannot start a new trial until
7.0. You can, however, contact `info@elastic.co` to request an extended trial
license.
-When you activate a new license level, new features appear in the left sidebar
-of the *Management* page.
+When you activate a new license level, new features appear in *Management*.
[role="screenshot"]
image::images/management-license.png[]
diff --git a/docs/spaces/index.asciidoc b/docs/spaces/index.asciidoc
index fb5ef670692dc..990af3a018b1f 100644
--- a/docs/spaces/index.asciidoc
+++ b/docs/spaces/index.asciidoc
@@ -9,10 +9,10 @@ the dashboards and saved objects that belong to that space.
{kib} creates a default space for you.
After you create your own
spaces, you're asked to choose a space when you log in to Kibana. You can change your
-current space at any time by using the menu in the upper left.
+current space at any time by using the menu.
[role="screenshot"]
-image::spaces/images/change-space.png["Change current space"]
+image::spaces/images/change-space.png["Change current space menu"]
Kibana supports spaces in several ways. You can:
diff --git a/docs/user/dashboard.asciidoc b/docs/user/dashboard.asciidoc
index 490edb9d26338..a17e46c5b3542 100644
--- a/docs/user/dashboard.asciidoc
+++ b/docs/user/dashboard.asciidoc
@@ -93,7 +93,7 @@ In *Edit* mode, you can move, resize, customize, and delete panels to suit your
* To resize a panel, click the resize control on the lower right and drag
to the new dimensions.
-* To toggle the use of margins and panel titles, use the *Options* menu in the upper left.
+* To toggle the use of margins and panel titles, use the *Options* menu.
* To delete a panel, open the panel menu and select *Delete from dashboard.* Deleting a panel from a
dashboard does *not* delete the saved visualization or search.
diff --git a/docs/user/discover.asciidoc b/docs/user/discover.asciidoc
index 7de7d73bf1664..4222ba40debb7 100644
--- a/docs/user/discover.asciidoc
+++ b/docs/user/discover.asciidoc
@@ -24,7 +24,7 @@ image::images/Discover-Start.png[Discover]
=== Set up your index pattern
The first thing to do in *Discover* is to select an <>, which
-defines the data you want to explore and visualize. The current index pattern is in the upper left.
+defines the data you want to explore and visualize.
If you haven't yet created an index pattern, you can add a <>,
which has a pre-built index pattern.
@@ -69,7 +69,7 @@ image::images/filter-field.png[height=317]
The sortable documents table
lists the documents that match your search.
By default, the table includes columns for the time field and the document `_source`.
-To zero in on a specific field, click *add* next to the field name in the left sidebar.
+To zero in on a specific field, click *add* next to the field name.
For example, if you add the `currency`, `customer_last_name`, and `day_of_week` fields,
the document table includes columns for those three fields.
diff --git a/docs/visualize/lens.asciidoc b/docs/visualize/lens.asciidoc
index e3f61565453b5..35570ea7ca1dc 100644
--- a/docs/visualize/lens.asciidoc
+++ b/docs/visualize/lens.asciidoc
@@ -32,7 +32,7 @@ Lens supports the following aggregations:
[[drag-drop]]
=== Drag and drop
-The data panel in the left column shows the data fields for the selected time period. When
+The panel shows the data fields for the selected time period. When
you drag a field from the data panel, Lens highlights where you can drop that field. The first time you drag a data field,
you'll see two places highlighted in green:
@@ -57,7 +57,7 @@ Lens shows you fields based on the <> you have d
{kib}, and the current time range. When you change the index pattern or time filter,
the list of fields are updated.
-To narrow the list of fields you see in the left panel, you can:
+To narrow the list of fields, you can:
* Enter the field name in *Search field names*.
@@ -100,11 +100,7 @@ still allows you to make the change.
Lens allows some customizations of the data for each visualization.
-. Change the index pattern.
-
-.. In the left column, click the index pattern name.
-
-.. Select the new index pattern.
+. Click the index pattern name, then select the new index pattern.
+
If there is a match, Lens displays the new data. All fields that do not match the index pattern are removed.
@@ -147,7 +143,7 @@ Drag and drop your data onto the visualization builder pane.
. On the *New Visualization* window, click *Lens*.
-. In the left column, select the *kibana_sample_data_ecommerce* index.
+. Select the *kibana_sample_data_ecommerce* index.
. Click image:images/time-filter-calendar.png[], then click *Last 7 days*. The list of data fields are updated.
diff --git a/examples/embeddable_examples/public/list_container/embeddable_list_item.tsx b/examples/embeddable_examples/public/list_container/embeddable_list_item.tsx
deleted file mode 100644
index 2c80cef8a6364..0000000000000
--- a/examples/embeddable_examples/public/list_container/embeddable_list_item.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import React from 'react';
-import { EuiPanel, EuiLoadingSpinner, EuiFlexItem } from '@elastic/eui';
-import { IEmbeddable } from '../../../../src/plugins/embeddable/public';
-
-interface Props {
- embeddable: IEmbeddable;
-}
-
-export class EmbeddableListItem extends React.Component {
- private embeddableRoot: React.RefObject;
- private rendered = false;
-
- constructor(props: Props) {
- super(props);
- this.embeddableRoot = React.createRef();
- }
-
- public componentDidMount() {
- if (this.embeddableRoot.current && this.props.embeddable) {
- this.props.embeddable.render(this.embeddableRoot.current);
- this.rendered = true;
- }
- }
-
- public componentDidUpdate() {
- if (this.embeddableRoot.current && this.props.embeddable && !this.rendered) {
- this.props.embeddable.render(this.embeddableRoot.current);
- this.rendered = true;
- }
- }
-
- public render() {
- return (
-
-
- {this.props.embeddable ? (
-
- ) : (
-
- )}
-
-
- );
- }
-}
diff --git a/examples/embeddable_examples/public/list_container/list_container.tsx b/examples/embeddable_examples/public/list_container/list_container.tsx
index bbbd0d6e32304..9e7bec7a1c951 100644
--- a/examples/embeddable_examples/public/list_container/list_container.tsx
+++ b/examples/embeddable_examples/public/list_container/list_container.tsx
@@ -31,16 +31,14 @@ export class ListContainer extends Container<{}, ContainerInput> {
public readonly type = LIST_CONTAINER;
private node?: HTMLElement;
- constructor(
- input: ContainerInput,
- getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']
- ) {
- super(input, { embeddableLoaded: {} }, getEmbeddableFactory);
+ constructor(input: ContainerInput, private embeddableServices: EmbeddableStart) {
+ super(input, { embeddableLoaded: {} }, embeddableServices.getEmbeddableFactory);
}
- // This container has no input itself.
- getInheritedInput(id: string) {
- return {};
+ getInheritedInput() {
+ return {
+ viewMode: this.input.viewMode,
+ };
}
public render(node: HTMLElement) {
@@ -48,7 +46,10 @@ export class ListContainer extends Container<{}, ContainerInput> {
if (this.node) {
ReactDOM.unmountComponentAtNode(this.node);
}
- ReactDOM.render(, node);
+ ReactDOM.render(
+ ,
+ node
+ );
}
public destroy() {
diff --git a/examples/embeddable_examples/public/list_container/list_container_component.tsx b/examples/embeddable_examples/public/list_container/list_container_component.tsx
index f6e04933ee897..da27889a27603 100644
--- a/examples/embeddable_examples/public/list_container/list_container_component.tsx
+++ b/examples/embeddable_examples/public/list_container/list_container_component.tsx
@@ -24,30 +24,35 @@ import {
withEmbeddableSubscription,
ContainerInput,
ContainerOutput,
+ EmbeddableStart,
} from '../../../../src/plugins/embeddable/public';
-import { EmbeddableListItem } from './embeddable_list_item';
interface Props {
embeddable: IContainer;
input: ContainerInput;
output: ContainerOutput;
+ embeddableServices: EmbeddableStart;
}
-function renderList(embeddable: IContainer, panels: ContainerInput['panels']) {
+function renderList(
+ embeddable: IContainer,
+ panels: ContainerInput['panels'],
+ embeddableServices: EmbeddableStart
+) {
let number = 0;
const list = Object.values(panels).map(panel => {
const child = embeddable.getChild(panel.explicitInput.id);
number++;
return (
-
+
{number}
-
+
@@ -56,12 +61,12 @@ function renderList(embeddable: IContainer, panels: ContainerInput['panels']) {
return list;
}
-export function ListContainerComponentInner(props: Props) {
+export function ListContainerComponentInner({ embeddable, input, embeddableServices }: Props) {
return (
-
{props.embeddable.getTitle()}
+ {embeddable.getTitle()}
- {renderList(props.embeddable, props.input.panels)}
+ {renderList(embeddable, input.panels, embeddableServices)}
);
}
@@ -71,4 +76,9 @@ export function ListContainerComponentInner(props: Props) {
// anything on input or output state changes. If you don't want that to happen (for example
// if you expect something on input or output state to change frequently that your react
// component does not care about, then you should probably hook this up manually).
-export const ListContainerComponent = withEmbeddableSubscription(ListContainerComponentInner);
+export const ListContainerComponent = withEmbeddableSubscription<
+ ContainerInput,
+ ContainerOutput,
+ IContainer,
+ { embeddableServices: EmbeddableStart }
+>(ListContainerComponentInner);
diff --git a/examples/embeddable_examples/public/list_container/list_container_factory.ts b/examples/embeddable_examples/public/list_container/list_container_factory.ts
index 1fde254110c62..02a024b95349f 100644
--- a/examples/embeddable_examples/public/list_container/list_container_factory.ts
+++ b/examples/embeddable_examples/public/list_container/list_container_factory.ts
@@ -26,7 +26,7 @@ import {
import { LIST_CONTAINER, ListContainer } from './list_container';
interface StartServices {
- getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'];
+ embeddableServices: EmbeddableStart;
}
export class ListContainerFactory implements EmbeddableFactoryDefinition {
@@ -40,8 +40,8 @@ export class ListContainerFactory implements EmbeddableFactoryDefinition {
}
public create = async (initialInput: ContainerInput) => {
- const { getEmbeddableFactory } = await this.getStartServices();
- return new ListContainer(initialInput, getEmbeddableFactory);
+ const { embeddableServices } = await this.getStartServices();
+ return new ListContainer(initialInput, embeddableServices);
};
public getDisplayName() {
diff --git a/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_component.tsx b/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_component.tsx
index e33dfab0eaf4a..b2882c97ef501 100644
--- a/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_component.tsx
+++ b/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_component.tsx
@@ -54,7 +54,7 @@ function wrapSearchTerms(task: string, search?: string) {
);
}
-function renderTasks(tasks: MultiTaskTodoOutput['tasks'], search?: string) {
+function renderTasks(tasks: MultiTaskTodoInput['tasks'], search?: string) {
return tasks.map(task => (
+
{icon ? : }
-
+
{wrapSearchTerms(title, search)}
@@ -89,6 +88,8 @@ export function MultiTaskTodoEmbeddableComponentInner({
);
}
-export const MultiTaskTodoEmbeddableComponent = withEmbeddableSubscription(
- MultiTaskTodoEmbeddableComponentInner
-);
+export const MultiTaskTodoEmbeddableComponent = withEmbeddableSubscription<
+ MultiTaskTodoInput,
+ MultiTaskTodoOutput,
+ MultiTaskTodoEmbeddable
+>(MultiTaskTodoEmbeddableComponentInner);
diff --git a/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable.tsx b/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable.tsx
index a2197c9c06fe9..a9e58c5538107 100644
--- a/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable.tsx
+++ b/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable.tsx
@@ -36,30 +36,27 @@ export interface MultiTaskTodoInput extends EmbeddableInput {
title: string;
}
-// This embeddable has output! It's the tasks list that is filtered.
-// Output state is something only the embeddable itself can update. It
-// can be something completely internal, or it can be state that is
+// This embeddable has output! Output state is something only the embeddable itself
+// can update. It can be something completely internal, or it can be state that is
// derived from input state and updates when input does.
export interface MultiTaskTodoOutput extends EmbeddableOutput {
- tasks: string[];
+ hasMatch: boolean;
}
-function getFilteredTasks(tasks: string[], search?: string) {
- const filteredTasks: string[] = [];
- if (search === undefined) return tasks;
+function getHasMatch(tasks: string[], title?: string, search?: string) {
+ if (search === undefined || search === '') return false;
- tasks.forEach(task => {
- if (task.match(search)) {
- filteredTasks.push(task);
- }
- });
+ if (title && title.match(search)) return true;
+
+ const match = tasks.find(task => task.match(search));
+ if (match) return true;
- return filteredTasks;
+ return false;
}
function getOutput(input: MultiTaskTodoInput) {
- const tasks = getFilteredTasks(input.tasks, input.search);
- return { tasks, hasMatch: tasks.length > 0 || (input.search && input.title.match(input.search)) };
+ const hasMatch = getHasMatch(input.tasks, input.title, input.search);
+ return { hasMatch };
}
export class MultiTaskTodoEmbeddable extends Embeddable {
diff --git a/examples/embeddable_examples/public/plugin.ts b/examples/embeddable_examples/public/plugin.ts
index 5c202d96ceb1a..31a3037332dda 100644
--- a/examples/embeddable_examples/public/plugin.ts
+++ b/examples/embeddable_examples/public/plugin.ts
@@ -53,20 +53,17 @@ export class EmbeddableExamplesPlugin
new MultiTaskTodoEmbeddableFactory()
);
- // These are registered in the start method because `getEmbeddableFactory `
- // is only available in start. We could reconsider this I think and make it
- // available in both.
deps.embeddable.registerEmbeddableFactory(
SEARCHABLE_LIST_CONTAINER,
new SearchableListContainerFactory(async () => ({
- getEmbeddableFactory: (await core.getStartServices())[1].embeddable.getEmbeddableFactory,
+ embeddableServices: (await core.getStartServices())[1].embeddable,
}))
);
deps.embeddable.registerEmbeddableFactory(
LIST_CONTAINER,
new ListContainerFactory(async () => ({
- getEmbeddableFactory: (await core.getStartServices())[1].embeddable.getEmbeddableFactory,
+ embeddableServices: (await core.getStartServices())[1].embeddable,
}))
);
diff --git a/examples/embeddable_examples/public/searchable_list_container/searchable_list_container.tsx b/examples/embeddable_examples/public/searchable_list_container/searchable_list_container.tsx
index 06462937c768d..f6efb0b722c4c 100644
--- a/examples/embeddable_examples/public/searchable_list_container/searchable_list_container.tsx
+++ b/examples/embeddable_examples/public/searchable_list_container/searchable_list_container.tsx
@@ -40,11 +40,8 @@ export class SearchableListContainer extends Container, node);
+ ReactDOM.render(
+ ,
+ node
+ );
}
public destroy() {
diff --git a/examples/embeddable_examples/public/searchable_list_container/searchable_list_container_component.tsx b/examples/embeddable_examples/public/searchable_list_container/searchable_list_container_component.tsx
index b79f86e2a0192..49dbce74788bf 100644
--- a/examples/embeddable_examples/public/searchable_list_container/searchable_list_container_component.tsx
+++ b/examples/embeddable_examples/public/searchable_list_container/searchable_list_container_component.tsx
@@ -34,14 +34,15 @@ import {
withEmbeddableSubscription,
ContainerOutput,
EmbeddableOutput,
+ EmbeddableStart,
} from '../../../../src/plugins/embeddable/public';
-import { EmbeddableListItem } from '../list_container/embeddable_list_item';
import { SearchableListContainer, SearchableContainerInput } from './searchable_list_container';
interface Props {
embeddable: SearchableListContainer;
input: SearchableContainerInput;
output: ContainerOutput;
+ embeddableServices: EmbeddableStart;
}
interface State {
@@ -111,13 +112,27 @@ export class SearchableListContainerComponentInner extends Component {
+ const { input, embeddable } = this.props;
+ const checked: { [key: string]: boolean } = {};
+ Object.values(input.panels).map(panel => {
+ const child = embeddable.getChild(panel.explicitInput.id);
+ const output = child.getOutput();
+ if (hasHasMatchOutput(output) && output.hasMatch) {
+ checked[panel.explicitInput.id] = true;
+ }
+ });
+ this.setState({ checked });
+ };
+
private toggleCheck = (isChecked: boolean, id: string) => {
this.setState(prevState => ({ checked: { ...prevState.checked, [id]: isChecked } }));
};
public renderControls() {
+ const { input } = this.props;
return (
-
+
this.deleteChecked()}>
@@ -125,6 +140,17 @@ export class SearchableListContainerComponentInner extends Component
+
+
+ this.checkMatching()}
+ >
+ Check matching
+
+
+
- {embeddable.getTitle()}
-
- {this.renderControls()}
-
- {this.renderList()}
-
+
+
+ {embeddable.getTitle()}
+
+ {this.renderControls()}
+
+ {this.renderList()}
+
+
);
}
private renderList() {
+ const { embeddableServices, input, embeddable } = this.props;
let id = 0;
- const list = Object.values(this.props.input.panels).map(panel => {
- const embeddable = this.props.embeddable.getChild(panel.explicitInput.id);
- if (this.props.input.search && !this.state.hasMatch[panel.explicitInput.id]) return;
+ const list = Object.values(input.panels).map(panel => {
+ const childEmbeddable = embeddable.getChild(panel.explicitInput.id);
id++;
- return embeddable ? (
-
-
+ return childEmbeddable ? (
+
+
this.toggleCheck(e.target.checked, embeddable.id)}
+ data-test-subj={`todoCheckBox-${childEmbeddable.id}`}
+ disabled={!childEmbeddable}
+ id={childEmbeddable ? childEmbeddable.id : ''}
+ checked={this.state.checked[childEmbeddable.id]}
+ onChange={e => this.toggleCheck(e.target.checked, childEmbeddable.id)}
/>
-
+
@@ -183,6 +211,9 @@ export class SearchableListContainerComponentInner extends Component(SearchableListContainerComponentInner);
diff --git a/examples/embeddable_examples/public/searchable_list_container/searchable_list_container_factory.ts b/examples/embeddable_examples/public/searchable_list_container/searchable_list_container_factory.ts
index 382bb65e769ef..34ea43c29462a 100644
--- a/examples/embeddable_examples/public/searchable_list_container/searchable_list_container_factory.ts
+++ b/examples/embeddable_examples/public/searchable_list_container/searchable_list_container_factory.ts
@@ -29,7 +29,7 @@ import {
} from './searchable_list_container';
interface StartServices {
- getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'];
+ embeddableServices: EmbeddableStart;
}
export class SearchableListContainerFactory implements EmbeddableFactoryDefinition {
@@ -43,8 +43,8 @@ export class SearchableListContainerFactory implements EmbeddableFactoryDefiniti
}
public create = async (initialInput: SearchableContainerInput) => {
- const { getEmbeddableFactory } = await this.getStartServices();
- return new SearchableListContainer(initialInput, getEmbeddableFactory);
+ const { embeddableServices } = await this.getStartServices();
+ return new SearchableListContainer(initialInput, embeddableServices);
};
public getDisplayName() {
diff --git a/examples/embeddable_examples/public/todo/todo_component.tsx b/examples/embeddable_examples/public/todo/todo_component.tsx
index fbebfc98627b5..a4593bea3cc5e 100644
--- a/examples/embeddable_examples/public/todo/todo_component.tsx
+++ b/examples/embeddable_examples/public/todo/todo_component.tsx
@@ -51,12 +51,12 @@ function wrapSearchTerms(task: string, search?: string) {
export function TodoEmbeddableComponentInner({ input: { icon, title, task, search } }: Props) {
return (
-
+
{icon ? : }
-
+
{wrapSearchTerms(title || '', search)}
@@ -71,4 +71,8 @@ export function TodoEmbeddableComponentInner({ input: { icon, title, task, searc
);
}
-export const TodoEmbeddableComponent = withEmbeddableSubscription(TodoEmbeddableComponentInner);
+export const TodoEmbeddableComponent = withEmbeddableSubscription<
+ TodoInput,
+ EmbeddableOutput,
+ TodoEmbeddable
+>(TodoEmbeddableComponentInner);
diff --git a/examples/embeddable_explorer/public/app.tsx b/examples/embeddable_explorer/public/app.tsx
index 9c8568454855d..e18012b4b3d80 100644
--- a/examples/embeddable_explorer/public/app.tsx
+++ b/examples/embeddable_explorer/public/app.tsx
@@ -117,18 +117,7 @@ const EmbeddableExplorerApp = ({
{
title: 'Dynamically adding children to a container',
id: 'embeddablePanelExamplae',
- component: (
-
- ),
+ component: ,
},
];
diff --git a/examples/embeddable_explorer/public/embeddable_panel_example.tsx b/examples/embeddable_explorer/public/embeddable_panel_example.tsx
index b26111bed7ff2..54cd7c5b5b2c0 100644
--- a/examples/embeddable_explorer/public/embeddable_panel_example.tsx
+++ b/examples/embeddable_explorer/public/embeddable_panel_example.tsx
@@ -29,43 +29,19 @@ import {
EuiText,
} from '@elastic/eui';
import { EuiSpacer } from '@elastic/eui';
-import { OverlayStart, CoreStart, SavedObjectsStart, IUiSettingsClient } from 'kibana/public';
-import {
- EmbeddablePanel,
- EmbeddableStart,
- IEmbeddable,
-} from '../../../src/plugins/embeddable/public';
+import { EmbeddableStart, IEmbeddable } from '../../../src/plugins/embeddable/public';
import {
HELLO_WORLD_EMBEDDABLE,
TODO_EMBEDDABLE,
MULTI_TASK_TODO_EMBEDDABLE,
SEARCHABLE_LIST_CONTAINER,
} from '../../embeddable_examples/public';
-import { UiActionsStart } from '../../../src/plugins/ui_actions/public';
-import { Start as InspectorStartContract } from '../../../src/plugins/inspector/public';
-import { getSavedObjectFinder } from '../../../src/plugins/saved_objects/public';
interface Props {
- getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories'];
- getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'];
- uiActionsApi: UiActionsStart;
- overlays: OverlayStart;
- notifications: CoreStart['notifications'];
- inspector: InspectorStartContract;
- savedObject: SavedObjectsStart;
- uiSettingsClient: IUiSettingsClient;
+ embeddableServices: EmbeddableStart;
}
-export function EmbeddablePanelExample({
- inspector,
- notifications,
- overlays,
- getAllEmbeddableFactories,
- getEmbeddableFactory,
- uiActionsApi,
- savedObject,
- uiSettingsClient,
-}: Props) {
+export function EmbeddablePanelExample({ embeddableServices }: Props) {
const searchableInput = {
id: '1',
title: 'My searchable todo list',
@@ -105,7 +81,7 @@ export function EmbeddablePanelExample({
useEffect(() => {
ref.current = true;
if (!embeddable) {
- const factory = getEmbeddableFactory(SEARCHABLE_LIST_CONTAINER);
+ const factory = embeddableServices.getEmbeddableFactory(SEARCHABLE_LIST_CONTAINER);
const promise = factory?.create(searchableInput);
if (promise) {
promise.then(e => {
@@ -134,22 +110,13 @@ export function EmbeddablePanelExample({
You can render your embeddable inside the EmbeddablePanel component. This adds some
extra rendering and offers a context menu with pluggable actions. Using EmbeddablePanel
- to render your embeddable means you get access to the "e;Add panel flyout"e;.
- Now you can see how to add embeddables to your container, and how
- "e;getExplicitInput"e; is used to grab input not provided by the container.
+ to render your embeddable means you get access to the "Add panel flyout". Now
+ you can see how to add embeddables to your container, and how
+ "getExplicitInput" is used to grab input not provided by the container.
{embeddable ? (
-
+
) : (
Loading...
)}
diff --git a/examples/embeddable_explorer/public/list_container_example.tsx b/examples/embeddable_explorer/public/list_container_example.tsx
index 969fdb0ca46db..98ad50418d3fe 100644
--- a/examples/embeddable_explorer/public/list_container_example.tsx
+++ b/examples/embeddable_explorer/public/list_container_example.tsx
@@ -29,7 +29,11 @@ import {
EuiText,
} from '@elastic/eui';
import { EuiSpacer } from '@elastic/eui';
-import { EmbeddableFactoryRenderer, EmbeddableStart } from '../../../src/plugins/embeddable/public';
+import {
+ EmbeddableFactoryRenderer,
+ EmbeddableStart,
+ ViewMode,
+} from '../../../src/plugins/embeddable/public';
import {
HELLO_WORLD_EMBEDDABLE,
TODO_EMBEDDABLE,
@@ -46,6 +50,7 @@ export function ListContainerExample({ getEmbeddableFactory }: Props) {
const listInput = {
id: 'hello',
title: 'My todo list',
+ viewMode: ViewMode.VIEW,
panels: {
'1': {
type: HELLO_WORLD_EMBEDDABLE,
@@ -76,6 +81,7 @@ export function ListContainerExample({ getEmbeddableFactory }: Props) {
const searchableInput = {
id: '1',
title: 'My searchable todo list',
+ viewMode: ViewMode.VIEW,
panels: {
'1': {
type: HELLO_WORLD_EMBEDDABLE,
@@ -150,7 +156,7 @@ export function ListContainerExample({ getEmbeddableFactory }: Props) {
- Check out the "e;Dynamically adding children"e; section, to see how to add
+ Check out the "Dynamically adding children" section, to see how to add
children to this container, and see it rendered inside an `EmbeddablePanel` component.
diff --git a/package.json b/package.json
index 46e0b9adfea25..4c5db5321c282 100644
--- a/package.json
+++ b/package.json
@@ -104,7 +104,8 @@
"examples/*",
"test/plugin_functional/plugins/*",
"test/interpreter_functional/plugins/*",
- "x-pack/test/functional_with_es_ssl/fixtures/plugins/*"
+ "x-pack/test/functional_with_es_ssl/fixtures/plugins/*",
+ "x-pack/test/plugin_api_integration/plugins/*"
],
"nohoist": [
"**/@types/*",
@@ -125,7 +126,7 @@
"@elastic/filesaver": "1.1.2",
"@elastic/good": "8.1.1-kibana2",
"@elastic/numeral": "2.4.0",
- "@elastic/request-crypto": "^1.0.2",
+ "@elastic/request-crypto": "1.1.2",
"@elastic/ui-ace": "0.2.3",
"@hapi/good-squeeze": "5.2.1",
"@hapi/wreck": "^15.0.2",
diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
index 25647e4a08897..f70ef069dd134 100644
--- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
+++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
@@ -88,6 +88,9 @@ const mockCoreStart = {
get: sinon.fake.returns(''),
},
},
+ notifications: {
+ toasts: {},
+ },
i18n: {},
overlays: {},
savedObjects: {
@@ -164,8 +167,11 @@ const mockAggTypesRegistry = () => {
const registrySetup = registry.setup();
const aggTypes = getAggTypes({
uiSettings: mockCoreSetup.uiSettings,
- notifications: mockCoreStart.notifications,
query: querySetup,
+ getInternalStartServices: () => ({
+ fieldFormats: getFieldFormatsRegistry(mockCoreStart),
+ notifications: mockCoreStart.notifications,
+ }),
});
aggTypes.buckets.forEach(type => registrySetup.registerBucket(type));
aggTypes.metrics.forEach(type => registrySetup.registerMetric(type));
diff --git a/src/plugins/data/common/field_formats/mocks.ts b/src/plugins/data/common/field_formats/mocks.ts
index bc38374e147cf..394d4c383032f 100644
--- a/src/plugins/data/common/field_formats/mocks.ts
+++ b/src/plugins/data/common/field_formats/mocks.ts
@@ -17,23 +17,14 @@
* under the License.
*/
-import { FieldFormat, IFieldFormatsRegistry } from '.';
-
-const fieldFormatMock = ({
- convert: jest.fn(),
- getConverterFor: jest.fn(),
- getParamDefaults: jest.fn(),
- param: jest.fn(),
- params: jest.fn(),
- toJSON: jest.fn(),
- type: jest.fn(),
- setupContentType: jest.fn(),
-} as unknown) as FieldFormat;
+import { IFieldFormatsRegistry } from '.';
export const fieldFormatsMock: IFieldFormatsRegistry = {
getByFieldType: jest.fn(),
getDefaultConfig: jest.fn(),
- getDefaultInstance: jest.fn().mockImplementation(() => fieldFormatMock) as any,
+ getDefaultInstance: jest.fn().mockImplementation(() => ({
+ getConverterFor: jest.fn().mockImplementation(() => (t: string) => t),
+ })) as any,
getDefaultInstanceCacheResolver: jest.fn(),
getDefaultInstancePlain: jest.fn(),
getDefaultType: jest.fn(),
diff --git a/typings/elastic__node_crypto.d.ts b/src/plugins/data/public/field_formats/mocks.ts
similarity index 50%
rename from typings/elastic__node_crypto.d.ts
rename to src/plugins/data/public/field_formats/mocks.ts
index 8d4b47da96b73..ec1233a085bce 100644
--- a/typings/elastic__node_crypto.d.ts
+++ b/src/plugins/data/public/field_formats/mocks.ts
@@ -17,4 +17,25 @@
* under the License.
*/
-declare module '@elastic/node-crypto';
+import { FieldFormatsStart, FieldFormatsSetup, FieldFormatsService } from '.';
+import { fieldFormatsMock } from '../../common/field_formats/mocks';
+
+type FieldFormatsServiceClientContract = PublicMethodsOf;
+
+const createSetupContractMock = () => fieldFormatsMock as FieldFormatsSetup;
+const createStartContractMock = () => fieldFormatsMock as FieldFormatsStart;
+
+const createMock = () => {
+ const mocked: jest.Mocked = {
+ setup: jest.fn().mockReturnValue(createSetupContractMock()),
+ start: jest.fn().mockReturnValue(createStartContractMock()),
+ };
+
+ return mocked;
+};
+
+export const fieldFormatsServiceMock = {
+ create: createMock,
+ createSetupContract: createSetupContractMock,
+ createStartContract: createStartContractMock,
+};
diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts
index 4d4e8d8827b48..0007d1780c25b 100644
--- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts
+++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns_api_client.ts
@@ -45,7 +45,7 @@ export class IndexPatternsApiClient {
query,
})
.catch((resp: any) => {
- if (resp.body.statusCode === 404 && resp.body.statuscode === 'no_matching_indices') {
+ if (resp.body.statusCode === 404 && resp.body.attributes?.code === 'no_matching_indices') {
throw new IndexPatternMissingIndices(resp.body.message);
}
diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts
index e3fc0e97af09b..ea1c27550867e 100644
--- a/src/plugins/data/public/mocks.ts
+++ b/src/plugins/data/public/mocks.ts
@@ -17,8 +17,8 @@
* under the License.
*/
-import { Plugin, DataPublicPluginSetup, DataPublicPluginStart, IndexPatternsContract } from '.';
-import { fieldFormatsMock } from '../common/field_formats/mocks';
+import { Plugin, IndexPatternsContract } from '.';
+import { fieldFormatsServiceMock } from './field_formats/mocks';
import { searchSetupMock, searchStartMock } from './search/mocks';
import { queryServiceMock } from './query/mocks';
@@ -36,7 +36,7 @@ const createSetupContract = (): Setup => {
return {
autocomplete: autocompleteMock,
search: searchSetupMock,
- fieldFormats: fieldFormatsMock as DataPublicPluginSetup['fieldFormats'],
+ fieldFormats: fieldFormatsServiceMock.createSetupContract(),
query: querySetupMock,
};
};
@@ -49,7 +49,7 @@ const createStartContract = (): Start => {
},
autocomplete: autocompleteMock,
search: searchStartMock,
- fieldFormats: fieldFormatsMock as DataPublicPluginStart['fieldFormats'],
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
query: queryStartMock,
ui: {
IndexPatternSelect: jest.fn(),
diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts
index 26587470adfd9..15067077afc43 100644
--- a/src/plugins/data/public/plugin.ts
+++ b/src/plugins/data/public/plugin.ts
@@ -30,6 +30,7 @@ import {
DataPublicPluginStart,
DataSetupDependencies,
DataStartDependencies,
+ GetInternalStartServicesFn,
} from './types';
import { AutocompleteService } from './autocomplete';
import { SearchService } from './search/search_service';
@@ -47,6 +48,8 @@ import {
setQueryService,
setSearchService,
setUiSettings,
+ getFieldFormats,
+ getNotifications,
} from './services';
import { createSearchBar } from './ui/search_bar/create_search_bar';
import { esaggs } from './search/expressions';
@@ -100,6 +103,11 @@ export class DataPublicPlugin implements Plugin ({
+ fieldFormats: getFieldFormats(),
+ notifications: getNotifications(),
+ });
+
const queryService = this.queryService.setup({
uiSettings: core.uiSettings,
storage: this.storage,
@@ -122,6 +130,7 @@ export class DataPublicPlugin implements Plugin {
+export interface IDataPluginServices extends Partial {
// (undocumented)
appName: string;
// (undocumented)
data: DataPublicPluginStart;
// (undocumented)
- http: CoreStart_2['http'];
+ http: CoreStart['http'];
// (undocumented)
- notifications: CoreStart_2['notifications'];
+ notifications: CoreStart['notifications'];
// (undocumented)
- savedObjects: CoreStart_2['savedObjects'];
+ savedObjects: CoreStart['savedObjects'];
// (undocumented)
storage: IStorageWrapper;
// (undocumented)
- uiSettings: CoreStart_2['uiSettings'];
+ uiSettings: CoreStart['uiSettings'];
}
// Warning: (ae-missing-release-tag) "IEsSearchRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -1094,7 +1094,7 @@ export type ISearch =
// @public (undocumented)
export interface ISearchContext {
// (undocumented)
- core: CoreStart;
+ core: CoreStart_2;
// (undocumented)
getSearchStrategy: (name: T) => TSearchStrategyProvider;
}
@@ -1307,7 +1307,7 @@ export class Plugin implements Plugin_2 {
let indexPattern: IndexPattern;
@@ -400,13 +398,6 @@ describe('AggConfig', () => {
describe('#fieldFormatter - custom getFormat handler', () => {
it('returns formatter from getFormat handler', () => {
- setFieldFormats({
- ...dataPluginMock.createStartContract().fieldFormats,
- getDefaultInstance: jest.fn().mockImplementation(() => ({
- getConverterFor: jest.fn().mockImplementation(() => (t: string) => t),
- })) as any,
- });
-
const ac = new AggConfigs(indexPattern, [], { typesRegistry });
const configStates = {
enabled: true,
@@ -429,12 +420,6 @@ describe('AggConfig', () => {
let aggConfig: AggConfig;
beforeEach(() => {
- setFieldFormats({
- ...dataPluginMock.createStartContract().fieldFormats,
- getDefaultInstance: jest.fn().mockImplementation(() => ({
- getConverterFor: (t?: string) => t || identity,
- })) as any,
- });
indexPattern.fields.getByName = name =>
({
format: {
diff --git a/src/plugins/data/public/search/aggs/agg_params.test.ts b/src/plugins/data/public/search/aggs/agg_params.test.ts
index b08fcf309e9ed..784be803e2644 100644
--- a/src/plugins/data/public/search/aggs/agg_params.test.ts
+++ b/src/plugins/data/public/search/aggs/agg_params.test.ts
@@ -22,12 +22,22 @@ import { BaseParamType } from './param_types/base';
import { FieldParamType } from './param_types/field';
import { OptionedParamType } from './param_types/optioned';
import { AggParamType } from '../aggs/param_types/agg';
+import { fieldFormatsServiceMock } from '../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../src/core/public/mocks';
+import { AggTypeDependencies } from './agg_type';
describe('AggParams class', () => {
+ const aggTypesDependencies: AggTypeDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
+
describe('constructor args', () => {
it('accepts an array of param defs', () => {
const params = [{ name: 'one' }, { name: 'two' }] as AggParamType[];
- const aggParams = initParams(params);
+ const aggParams = initParams(params, aggTypesDependencies);
expect(aggParams).toHaveLength(params.length);
expect(Array.isArray(aggParams)).toBeTruthy();
@@ -37,7 +47,7 @@ describe('AggParams class', () => {
describe('AggParam creation', () => {
it('Uses the FieldParamType class for params with the name "field"', () => {
const params = [{ name: 'field', type: 'field' }] as AggParamType[];
- const aggParams = initParams(params);
+ const aggParams = initParams(params, aggTypesDependencies);
expect(aggParams).toHaveLength(params.length);
expect(aggParams[0] instanceof FieldParamType).toBeTruthy();
@@ -50,7 +60,7 @@ describe('AggParams class', () => {
type: 'optioned',
},
] as AggParamType[];
- const aggParams = initParams(params);
+ const aggParams = initParams(params, aggTypesDependencies);
expect(aggParams).toHaveLength(params.length);
expect(aggParams[0] instanceof OptionedParamType).toBeTruthy();
@@ -72,7 +82,7 @@ describe('AggParams class', () => {
},
] as AggParamType[];
- const aggParams = initParams(params);
+ const aggParams = initParams(params, aggTypesDependencies);
expect(aggParams).toHaveLength(params.length);
diff --git a/src/plugins/data/public/search/aggs/agg_params.ts b/src/plugins/data/public/search/aggs/agg_params.ts
index 551cb81529a0a..e7b2f72bae656 100644
--- a/src/plugins/data/public/search/aggs/agg_params.ts
+++ b/src/plugins/data/public/search/aggs/agg_params.ts
@@ -26,6 +26,7 @@ import { BaseParamType } from './param_types/base';
import { AggConfig } from './agg_config';
import { IAggConfigs } from './agg_configs';
+import { AggTypeDependencies } from './agg_type';
const paramTypeMap = {
field: FieldParamType,
@@ -45,12 +46,13 @@ export interface AggParamOption {
}
export const initParams = (
- params: TAggParam[]
+ params: TAggParam[],
+ { getInternalStartServices }: AggTypeDependencies
): TAggParam[] =>
params.map((config: TAggParam) => {
const Class = paramTypeMap[config.type] || paramTypeMap._default;
- return new Class(config);
+ return new Class(config, { getInternalStartServices });
}) as TAggParam[];
/**
diff --git a/src/plugins/data/public/search/aggs/agg_type.test.ts b/src/plugins/data/public/search/aggs/agg_type.test.ts
index 3fb03dc31e2b2..0c9e110c34ae6 100644
--- a/src/plugins/data/public/search/aggs/agg_type.test.ts
+++ b/src/plugins/data/public/search/aggs/agg_type.test.ts
@@ -17,40 +17,49 @@
* under the License.
*/
-import { AggType, AggTypeConfig } from './agg_type';
+import { AggType, AggTypeConfig, AggTypeDependencies } from './agg_type';
import { IAggConfig } from './agg_config';
-import { mockDataServices } from './test_helpers';
-import { dataPluginMock } from '../../../public/mocks';
-import { setFieldFormats } from '../../../public/services';
+import { fieldFormatsServiceMock } from '../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../src/core/public/mocks';
describe('AggType Class', () => {
+ let dependencies: AggTypeDependencies;
+
beforeEach(() => {
- mockDataServices();
+ dependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: {
+ ...fieldFormatsServiceMock.createStartContract(),
+ getDefaultInstance: jest.fn(() => 'default') as any,
+ },
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
});
describe('constructor', () => {
- it("requires a valid config object as it's first param", () => {
+ test("requires a valid config object as it's first param", () => {
expect(() => {
const aggConfig: AggTypeConfig = (undefined as unknown) as AggTypeConfig;
- new AggType(aggConfig);
+ new AggType(aggConfig, dependencies);
}).toThrowError();
});
describe('application of config properties', () => {
- it('assigns the config value to itself', () => {
+ test('assigns the config value to itself', () => {
const config: AggTypeConfig = {
name: 'name',
title: 'title',
};
- const aggType = new AggType(config);
+ const aggType = new AggType(config, dependencies);
expect(aggType.name).toBe('name');
expect(aggType.title).toBe('title');
});
describe('makeLabel', () => {
- it('makes a function when the makeLabel config is not specified', () => {
+ test('makes a function when the makeLabel config is not specified', () => {
const makeLabel = () => 'label';
const aggConfig = {} as IAggConfig;
const config: AggTypeConfig = {
@@ -59,7 +68,7 @@ describe('AggType Class', () => {
makeLabel,
};
- const aggType = new AggType(config);
+ const aggType = new AggType(config, dependencies);
expect(aggType.makeLabel).toBe(makeLabel);
expect(aggType.makeLabel(aggConfig)).toBe('label');
@@ -67,26 +76,32 @@ describe('AggType Class', () => {
});
describe('getResponseAggs/getRequestAggs', () => {
- it('copies the value', () => {
+ test('copies the value', () => {
const testConfig = (aggConfig: IAggConfig) => [aggConfig];
- const aggType = new AggType({
- name: 'name',
- title: 'title',
- getResponseAggs: testConfig,
- getRequestAggs: testConfig,
- });
+ const aggType = new AggType(
+ {
+ name: 'name',
+ title: 'title',
+ getResponseAggs: testConfig,
+ getRequestAggs: testConfig,
+ },
+ dependencies
+ );
expect(aggType.getResponseAggs).toBe(testConfig);
expect(aggType.getResponseAggs).toBe(testConfig);
});
- it('defaults to noop', () => {
+ test('defaults to noop', () => {
const aggConfig = {} as IAggConfig;
- const aggType = new AggType({
- name: 'name',
- title: 'title',
- });
+ const aggType = new AggType(
+ {
+ name: 'name',
+ title: 'title',
+ },
+ dependencies
+ );
const responseAggs = aggType.getRequestAggs(aggConfig);
expect(responseAggs).toBe(undefined);
@@ -94,11 +109,14 @@ describe('AggType Class', () => {
});
describe('params', () => {
- it('defaults to AggParams object with JSON param', () => {
- const aggType = new AggType({
- name: 'smart agg',
- title: 'title',
- });
+ test('defaults to AggParams object with JSON param', () => {
+ const aggType = new AggType(
+ {
+ name: 'smart agg',
+ title: 'title',
+ },
+ dependencies
+ );
expect(Array.isArray(aggType.params)).toBeTruthy();
expect(aggType.params.length).toBe(2);
@@ -106,26 +124,32 @@ describe('AggType Class', () => {
expect(aggType.params[1].name).toBe('customLabel');
});
- it('can disable customLabel', () => {
- const aggType = new AggType({
- name: 'smart agg',
- title: 'title',
- customLabels: false,
- });
+ test('can disable customLabel', () => {
+ const aggType = new AggType(
+ {
+ name: 'smart agg',
+ title: 'title',
+ customLabels: false,
+ },
+ dependencies
+ );
expect(aggType.params.length).toBe(1);
expect(aggType.params[0].name).toBe('json');
});
- it('passes the params arg directly to the AggParams constructor', () => {
+ test('passes the params arg directly to the AggParams constructor', () => {
const params = [{ name: 'one' }, { name: 'two' }];
const paramLength = params.length + 2; // json and custom label are always appended
- const aggType = new AggType({
- name: 'bucketeer',
- title: 'title',
- params,
- });
+ const aggType = new AggType(
+ {
+ name: 'bucketeer',
+ title: 'title',
+ params,
+ },
+ dependencies
+ );
expect(Array.isArray(aggType.params)).toBeTruthy();
expect(aggType.params.length).toBe(paramLength);
@@ -143,11 +167,14 @@ describe('AggType Class', () => {
} as unknown) as IAggConfig;
});
- it('returns the formatter for the aggConfig', () => {
- const aggType = new AggType({
- name: 'name',
- title: 'title',
- });
+ test('returns the formatter for the aggConfig', () => {
+ const aggType = new AggType(
+ {
+ name: 'name',
+ title: 'title',
+ },
+ dependencies
+ );
field = {
format: 'format',
@@ -156,16 +183,14 @@ describe('AggType Class', () => {
expect(aggType.getFormat(aggConfig)).toBe('format');
});
- it('returns default formatter', () => {
- setFieldFormats({
- ...dataPluginMock.createStartContract().fieldFormats,
- getDefaultInstance: jest.fn(() => 'default') as any,
- });
-
- const aggType = new AggType({
- name: 'name',
- title: 'title',
- });
+ test('returns default formatter', () => {
+ const aggType = new AggType(
+ {
+ name: 'name',
+ title: 'title',
+ },
+ dependencies
+ );
field = undefined;
diff --git a/src/plugins/data/public/search/aggs/agg_type.ts b/src/plugins/data/public/search/aggs/agg_type.ts
index a63d01e196612..70c116d560c6f 100644
--- a/src/plugins/data/public/search/aggs/agg_type.ts
+++ b/src/plugins/data/public/search/aggs/agg_type.ts
@@ -28,7 +28,7 @@ import { BaseParamType } from './param_types/base';
import { AggParamType } from './param_types/agg';
import { KBN_FIELD_TYPES, IFieldFormat } from '../../../common';
import { ISearchSource } from '../search_source';
-import { getFieldFormats } from '../../../public/services';
+import { GetInternalStartServicesFn } from '../../types';
export interface AggTypeConfig<
TAggConfig extends AggConfig = AggConfig,
@@ -60,16 +60,13 @@ export interface AggTypeConfig<
getKey?: (bucket: any, key: any, agg: TAggConfig) => any;
}
-const getFormat = (agg: AggConfig) => {
- const field = agg.getField();
- const fieldFormatsService = getFieldFormats();
-
- return field ? field.format : fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.STRING);
-};
-
// TODO need to make a more explicit interface for this
export type IAggType = AggType;
+export interface AggTypeDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
export class AggType<
TAggConfig extends AggConfig = AggConfig,
TParam extends AggParamType = AggParamType
@@ -215,7 +212,10 @@ export class AggType<
* @private
* @param {object} config - used to set the properties of the AggType
*/
- constructor(config: AggTypeConfig) {
+ constructor(
+ config: AggTypeConfig,
+ { getInternalStartServices }: AggTypeDependencies
+ ) {
this.name = config.name;
this.type = config.type || 'metrics';
this.dslName = config.dslName || config.name;
@@ -251,14 +251,22 @@ export class AggType<
});
}
- this.params = initParams(params);
+ this.params = initParams(params, { getInternalStartServices });
}
this.getRequestAggs = config.getRequestAggs || noop;
this.getResponseAggs = config.getResponseAggs || (() => {});
this.decorateAggConfig = config.decorateAggConfig || (() => ({}));
this.postFlightRequest = config.postFlightRequest || identity;
- this.getFormat = config.getFormat || getFormat;
+
+ this.getFormat =
+ config.getFormat ||
+ ((agg: TAggConfig) => {
+ const field = agg.getField();
+ const { fieldFormats } = getInternalStartServices();
+
+ return field ? field.format : fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.STRING);
+ });
this.getValue = config.getValue || ((agg: TAggConfig, bucket: any) => {});
}
}
diff --git a/src/plugins/data/public/search/aggs/agg_types.ts b/src/plugins/data/public/search/aggs/agg_types.ts
index 556f6b0c93c41..4b154c338d48c 100644
--- a/src/plugins/data/public/search/aggs/agg_types.ts
+++ b/src/plugins/data/public/search/aggs/agg_types.ts
@@ -17,83 +17,89 @@
* under the License.
*/
-import { IUiSettingsClient, NotificationsSetup } from 'src/core/public';
+import { IUiSettingsClient } from 'src/core/public';
import { QuerySetup } from '../../query/query_service';
-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 { getCountMetricAgg } from './metrics/count';
+import { getAvgMetricAgg } from './metrics/avg';
+import { getSumMetricAgg } from './metrics/sum';
+import { getMedianMetricAgg } from './metrics/median';
+import { getMinMetricAgg } from './metrics/min';
+import { getMaxMetricAgg } from './metrics/max';
+import { getTopHitMetricAgg } from './metrics/top_hit';
+import { getStdDeviationMetricAgg } from './metrics/std_deviation';
+import { getCardinalityMetricAgg } from './metrics/cardinality';
+import { getPercentilesMetricAgg } from './metrics/percentiles';
+import { getGeoBoundsMetricAgg } from './metrics/geo_bounds';
+import { getGeoCentroidMetricAgg } from './metrics/geo_centroid';
+import { getPercentileRanksMetricAgg } from './metrics/percentile_ranks';
+import { getDerivativeMetricAgg } from './metrics/derivative';
+import { getCumulativeSumMetricAgg } from './metrics/cumulative_sum';
+import { getMovingAvgMetricAgg } from './metrics/moving_avg';
+import { getSerialDiffMetricAgg } from './metrics/serial_diff';
import { getDateHistogramBucketAgg } from './buckets/date_histogram';
import { getHistogramBucketAgg } from './buckets/histogram';
-import { rangeBucketAgg } from './buckets/range';
+import { getRangeBucketAgg } from './buckets/range';
import { getDateRangeBucketAgg } from './buckets/date_range';
-import { ipRangeBucketAgg } from './buckets/ip_range';
-import { termsBucketAgg } from './buckets/terms';
-import { filterBucketAgg } from './buckets/filter';
+import { getIpRangeBucketAgg } from './buckets/ip_range';
+import { getTermsBucketAgg } from './buckets/terms';
+import { getFilterBucketAgg } from './buckets/filter';
import { getFiltersBucketAgg } 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';
+import { getSignificantTermsBucketAgg } from './buckets/significant_terms';
+import { getGeoHashBucketAgg } from './buckets/geo_hash';
+import { getGeoTitleBucketAgg } from './buckets/geo_tile';
+import { getBucketSumMetricAgg } from './metrics/bucket_sum';
+import { getBucketAvgMetricAgg } from './metrics/bucket_avg';
+import { getBucketMinMetricAgg } from './metrics/bucket_min';
+import { getBucketMaxMetricAgg } from './metrics/bucket_max';
+
+import { GetInternalStartServicesFn } from '../../types';
export interface AggTypesDependencies {
- notifications: NotificationsSetup;
uiSettings: IUiSettingsClient;
query: QuerySetup;
+ getInternalStartServices: GetInternalStartServicesFn;
}
-export const getAggTypes = ({ notifications, uiSettings, query }: AggTypesDependencies) => ({
+export const getAggTypes = ({
+ uiSettings,
+ query,
+ getInternalStartServices,
+}: AggTypesDependencies) => ({
metrics: [
- countMetricAgg,
- avgMetricAgg,
- sumMetricAgg,
- medianMetricAgg,
- minMetricAgg,
- maxMetricAgg,
- stdDeviationMetricAgg,
- cardinalityMetricAgg,
- percentilesMetricAgg,
- percentileRanksMetricAgg,
- topHitMetricAgg,
- derivativeMetricAgg,
- cumulativeSumMetricAgg,
- movingAvgMetricAgg,
- serialDiffMetricAgg,
- bucketAvgMetricAgg,
- bucketSumMetricAgg,
- bucketMinMetricAgg,
- bucketMaxMetricAgg,
- geoBoundsMetricAgg,
- geoCentroidMetricAgg,
+ getCountMetricAgg({ getInternalStartServices }),
+ getAvgMetricAgg({ getInternalStartServices }),
+ getSumMetricAgg({ getInternalStartServices }),
+ getMedianMetricAgg({ getInternalStartServices }),
+ getMinMetricAgg({ getInternalStartServices }),
+ getMaxMetricAgg({ getInternalStartServices }),
+ getStdDeviationMetricAgg({ getInternalStartServices }),
+ getCardinalityMetricAgg({ getInternalStartServices }),
+ getPercentilesMetricAgg({ getInternalStartServices }),
+ getPercentileRanksMetricAgg({ getInternalStartServices }),
+ getTopHitMetricAgg({ getInternalStartServices }),
+ getDerivativeMetricAgg({ getInternalStartServices }),
+ getCumulativeSumMetricAgg({ getInternalStartServices }),
+ getMovingAvgMetricAgg({ getInternalStartServices }),
+ getSerialDiffMetricAgg({ getInternalStartServices }),
+ getBucketAvgMetricAgg({ getInternalStartServices }),
+ getBucketSumMetricAgg({ getInternalStartServices }),
+ getBucketMinMetricAgg({ getInternalStartServices }),
+ getBucketMaxMetricAgg({ getInternalStartServices }),
+ getGeoBoundsMetricAgg({ getInternalStartServices }),
+ getGeoCentroidMetricAgg({ getInternalStartServices }),
],
buckets: [
- getDateHistogramBucketAgg({ uiSettings, query }),
- getHistogramBucketAgg({ uiSettings, notifications }),
- rangeBucketAgg,
- getDateRangeBucketAgg({ uiSettings }),
- ipRangeBucketAgg,
- termsBucketAgg,
- filterBucketAgg,
- getFiltersBucketAgg({ uiSettings }),
- significantTermsBucketAgg,
- geoHashBucketAgg,
- geoTileBucketAgg,
+ getDateHistogramBucketAgg({ uiSettings, query, getInternalStartServices }),
+ getHistogramBucketAgg({ uiSettings, getInternalStartServices }),
+ getRangeBucketAgg({ getInternalStartServices }),
+ getDateRangeBucketAgg({ uiSettings, getInternalStartServices }),
+ getIpRangeBucketAgg({ getInternalStartServices }),
+ getTermsBucketAgg({ getInternalStartServices }),
+ getFilterBucketAgg({ getInternalStartServices }),
+ getFiltersBucketAgg({ uiSettings, getInternalStartServices }),
+ getSignificantTermsBucketAgg({ getInternalStartServices }),
+ getGeoHashBucketAgg({ getInternalStartServices }),
+ getGeoTitleBucketAgg({ getInternalStartServices }),
],
});
diff --git a/src/plugins/data/public/search/aggs/agg_types_registry.test.ts b/src/plugins/data/public/search/aggs/agg_types_registry.test.ts
index 405f83e237de8..58d1a07d965e2 100644
--- a/src/plugins/data/public/search/aggs/agg_types_registry.test.ts
+++ b/src/plugins/data/public/search/aggs/agg_types_registry.test.ts
@@ -22,7 +22,7 @@ import {
AggTypesRegistrySetup,
AggTypesRegistryStart,
} from './agg_types_registry';
-import { BucketAggType } from './buckets/_bucket_agg_type';
+import { BucketAggType } from './buckets/bucket_agg_type';
import { MetricAggType } from './metrics/metric_agg_type';
const bucketType = { name: 'terms', type: 'bucket' } as BucketAggType;
diff --git a/src/plugins/data/public/search/aggs/agg_types_registry.ts b/src/plugins/data/public/search/aggs/agg_types_registry.ts
index 8a8746106ae58..5a0c58120d810 100644
--- a/src/plugins/data/public/search/aggs/agg_types_registry.ts
+++ b/src/plugins/data/public/search/aggs/agg_types_registry.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { BucketAggType } from './buckets/_bucket_agg_type';
+import { BucketAggType } from './buckets/bucket_agg_type';
import { MetricAggType } from './metrics/metric_agg_type';
export type AggTypesRegistrySetup = ReturnType;
diff --git a/src/plugins/data/public/search/aggs/buckets/_interval_options.ts b/src/plugins/data/public/search/aggs/buckets/_interval_options.ts
index 393d3b745250f..1c4c04c40a5c1 100644
--- a/src/plugins/data/public/search/aggs/buckets/_interval_options.ts
+++ b/src/plugins/data/public/search/aggs/buckets/_interval_options.ts
@@ -18,7 +18,7 @@
*/
import { i18n } from '@kbn/i18n';
-import { IBucketAggConfig } from './_bucket_agg_type';
+import { IBucketAggConfig } from './bucket_agg_type';
export const intervalOptions = [
{
diff --git a/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts
index 9e4b93035384f..c664325a168b1 100644
--- a/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts
@@ -24,8 +24,8 @@ import {
} from './_terms_other_bucket_helper';
import { AggConfigs, CreateAggConfigParams } from '../agg_configs';
import { BUCKET_TYPES } from './bucket_agg_types';
-import { IBucketAggConfig } from './_bucket_agg_type';
-import { mockDataServices, mockAggTypesRegistry } from '../test_helpers';
+import { IBucketAggConfig } from './bucket_agg_type';
+import { mockAggTypesRegistry } from '../test_helpers';
const indexPattern = {
id: '1234',
@@ -223,10 +223,6 @@ describe('Terms Agg Other bucket helper', () => {
return new AggConfigs(indexPattern, [...aggs], { typesRegistry });
};
- beforeEach(() => {
- mockDataServices();
- });
-
describe('buildOtherBucketAgg', () => {
test('returns a function', () => {
const aggConfigs = getAggConfigs(singleTerm.aggs);
diff --git a/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts
index 4fd988e7b7e66..abda6b5fc5980 100644
--- a/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts
+++ b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts
@@ -21,7 +21,7 @@ import { isNumber, keys, values, find, each, cloneDeep, flatten } from 'lodash';
import { buildExistsFilter, buildPhrasesFilter, buildQueryFromFilters } from '../../../../common';
import { AggGroupNames } from '../agg_groups';
import { IAggConfigs } from '../agg_configs';
-import { IBucketAggConfig } from './_bucket_agg_type';
+import { IBucketAggConfig } from './bucket_agg_type';
/**
* walks the aggregation DSL and returns DSL starting at aggregation with id of startFromAggId
diff --git a/src/plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts b/src/plugins/data/public/search/aggs/buckets/bucket_agg_type.ts
similarity index 86%
rename from src/plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts
rename to src/plugins/data/public/search/aggs/buckets/bucket_agg_type.ts
index 03629c3189cbb..f3c95b444dee9 100644
--- a/src/plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts
+++ b/src/plugins/data/public/search/aggs/buckets/bucket_agg_type.ts
@@ -21,6 +21,7 @@ import { IAggConfig } from '../agg_config';
import { KBN_FIELD_TYPES } from '../../../../common';
import { AggType, AggTypeConfig } from '../agg_type';
import { AggParamType } from '../param_types/agg';
+import { GetInternalStartServicesFn } from '../../../types';
export interface IBucketAggConfig extends IAggConfig {
type: InstanceType;
@@ -39,6 +40,10 @@ interface BucketAggTypeConfig
getKey?: (bucket: any, key: any, agg: IAggConfig) => any;
}
+interface BucketAggTypeDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
export class BucketAggType extends AggType<
TBucketAggConfig,
BucketAggParam
@@ -46,8 +51,11 @@ export class BucketAggType any;
type = bucketType;
- constructor(config: BucketAggTypeConfig) {
- super(config);
+ constructor(
+ config: BucketAggTypeConfig,
+ dependencies: BucketAggTypeDependencies
+ ) {
+ super(config, dependencies);
this.getKey =
config.getKey ||
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts
index def354c4557cb..97c940b4ff4b1 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts
@@ -29,8 +29,9 @@ import {
} from '../date_histogram';
import { BUCKET_TYPES } from '../bucket_agg_types';
import { RangeFilter } from '../../../../../common';
-import { coreMock } from '../../../../../../../core/public/mocks';
+import { coreMock, notificationServiceMock } from '../../../../../../../core/public/mocks';
import { queryServiceMock } from '../../../../query/mocks';
+import { fieldFormatsServiceMock } from '../../../../field_formats/mocks';
describe('AggConfig Filters', () => {
describe('date_histogram', () => {
@@ -46,6 +47,10 @@ describe('AggConfig Filters', () => {
aggTypesDependencies = {
uiSettings,
query: queryServiceMock.createSetupContract(),
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
};
mockDataServices();
@@ -90,7 +95,7 @@ describe('AggConfig Filters', () => {
filter = createFilterDateHistogram(agg, bucketKey);
};
- it('creates a valid range filter', () => {
+ test('creates a valid range filter', () => {
init();
expect(filter).toHaveProperty('range');
@@ -110,7 +115,7 @@ describe('AggConfig Filters', () => {
expect(filter.meta).toHaveProperty('index', '1234');
});
- it('extends the filter edge to 1ms before the next bucket for all interval options', () => {
+ test('extends the filter edge to 1ms before the next bucket for all interval options', () => {
intervalOptions.forEach(option => {
let duration;
if (option.val !== 'custom' && moment(1, option.val).isValid()) {
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts
index 6a03176959a83..8c0466b769a7e 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts
@@ -25,8 +25,9 @@ import { DateFormat } from '../../../../field_formats';
import { AggConfigs } from '../../agg_configs';
import { mockAggTypesRegistry } from '../../test_helpers';
import { BUCKET_TYPES } from '../bucket_agg_types';
-import { IBucketAggConfig } from '../_bucket_agg_type';
-import { coreMock } from '../../../../../../../core/public/mocks';
+import { IBucketAggConfig } from '../bucket_agg_type';
+import { coreMock, notificationServiceMock } from '../../../../../../../core/public/mocks';
+import { fieldFormatsServiceMock } from '../../../../field_formats/mocks';
describe('AggConfig Filters', () => {
describe('Date range', () => {
@@ -37,6 +38,10 @@ describe('AggConfig Filters', () => {
aggTypesDependencies = {
uiSettings,
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
};
});
@@ -71,7 +76,7 @@ describe('AggConfig Filters', () => {
);
};
- it('should return a range filter for date_range agg', () => {
+ test('should return a range filter for date_range agg', () => {
const aggConfigs = getAggConfigs();
const from = new Date('1 Feb 2015');
const to = new Date('7 Feb 2015');
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.ts
index 9bfded0ce9729..118e9b26e87d5 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.ts
@@ -18,7 +18,7 @@
*/
import moment from 'moment';
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
import { DateRangeKey } from '../lib/date_range';
import { buildRangeFilter, RangeFilterParams } from '../../../../../common';
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts
index 32ada8d57c768..f5a0b5a7b9094 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts
@@ -21,8 +21,9 @@ import { getFiltersBucketAgg, FiltersBucketAggDependencies } from '../filters';
import { createFilterFilters } from './filters';
import { AggConfigs } from '../../agg_configs';
import { mockAggTypesRegistry } from '../../test_helpers';
-import { IBucketAggConfig } from '../_bucket_agg_type';
-import { coreMock } from '../../../../../../../core/public/mocks';
+import { IBucketAggConfig } from '../bucket_agg_type';
+import { coreMock, notificationServiceMock } from '../../../../../../../core/public/mocks';
+import { fieldFormatsServiceMock } from '../../../../field_formats/mocks';
describe('AggConfig Filters', () => {
describe('filters', () => {
@@ -33,6 +34,10 @@ describe('AggConfig Filters', () => {
aggTypesDependencies = {
uiSettings,
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
};
});
@@ -67,7 +72,8 @@ describe('AggConfig Filters', () => {
{ typesRegistry: mockAggTypesRegistry([getFiltersBucketAgg(aggTypesDependencies)]) }
);
};
- it('should return a filters filter', () => {
+
+ test('should return a filters filter', () => {
const aggConfigs = getAggConfigs();
const filter = createFilterFilters(aggConfigs.aggs[0] as IBucketAggConfig, 'type:nginx');
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/filters.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.ts
index 3b568d805f7c0..1999b759a23d0 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/filters.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.ts
@@ -18,7 +18,7 @@
*/
import { get } from 'lodash';
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
import { buildQueryFilter } from '../../../../../common';
export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => {
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts
index dc8414d80c024..18b388be74877 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts
@@ -19,19 +19,13 @@
import { createFilterHistogram } from './histogram';
import { AggConfigs } from '../../agg_configs';
-import { mockDataServices, mockAggTypesRegistry } from '../../test_helpers';
+import { mockAggTypesRegistry } from '../../test_helpers';
import { BUCKET_TYPES } from '../bucket_agg_types';
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
import { BytesFormat, FieldFormatsGetConfigFn } from '../../../../../common';
describe('AggConfig Filters', () => {
describe('histogram', () => {
- beforeEach(() => {
- mockDataServices();
- });
-
- const typesRegistry = mockAggTypesRegistry();
-
const getConfig = (() => {}) as FieldFormatsGetConfigFn;
const getAggConfigs = () => {
const field = {
@@ -61,11 +55,11 @@ describe('AggConfig Filters', () => {
},
},
],
- { typesRegistry }
+ { typesRegistry: mockAggTypesRegistry() }
);
};
- it('should return an range filter for histogram', () => {
+ test('should return an range filter for histogram', () => {
const aggConfigs = getAggConfigs();
const filter = createFilterHistogram(aggConfigs.aggs[0] as IBucketAggConfig, '2048');
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts
index d4c00a0991fe2..f8e7747d49147 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
import { buildRangeFilter, RangeFilterParams } from '../../../../../common';
export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => {
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts
index ca51094da2f58..b528313b080d0 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts
@@ -17,17 +17,26 @@
* under the License.
*/
-import { ipRangeBucketAgg } from '../ip_range';
+import { getIpRangeBucketAgg } from '../ip_range';
import { createFilterIpRange } from './ip_range';
import { AggConfigs, CreateAggConfigParams } from '../../agg_configs';
import { mockAggTypesRegistry } from '../../test_helpers';
import { IpFormat } from '../../../../../common';
import { BUCKET_TYPES } from '../bucket_agg_types';
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
+import { fieldFormatsServiceMock } from '../../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../core/public/mocks';
describe('AggConfig Filters', () => {
describe('IP range', () => {
- const typesRegistry = mockAggTypesRegistry([ipRangeBucketAgg]);
+ const typesRegistry = mockAggTypesRegistry([
+ getIpRangeBucketAgg({
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ }),
+ ]);
const getAggConfigs = (aggs: CreateAggConfigParams[]) => {
const field = {
name: 'ip',
@@ -46,7 +55,7 @@ describe('AggConfig Filters', () => {
return new AggConfigs(indexPattern, aggs, { typesRegistry });
};
- it('should return a range filter for ip_range agg', () => {
+ test('should return a range filter for ip_range agg', () => {
const aggConfigs = getAggConfigs([
{
type: BUCKET_TYPES.IP_RANGE,
@@ -75,7 +84,7 @@ describe('AggConfig Filters', () => {
expect(filter.range.ip).toHaveProperty('lte', '1.1.1.1');
});
- it('should return a range filter for ip_range agg using a CIDR mask', () => {
+ test('should return a range filter for ip_range agg using a CIDR mask', () => {
const aggConfigs = getAggConfigs([
{
type: BUCKET_TYPES.IP_RANGE,
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts
index 2d34c45aaab9d..aae212783b873 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts
@@ -18,7 +18,7 @@
*/
import { CidrMask } from '../lib/cidr_mask';
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
import { IpRangeKey } from '../lib/ip_range';
import { buildRangeFilter, RangeFilterParams } from '../../../../../common';
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts
index 3a6f8b36a9d96..14a7538aa95a4 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts
@@ -17,22 +17,31 @@
* under the License.
*/
-import { rangeBucketAgg } from '../range';
+import { getRangeBucketAgg, RangeBucketAggDependencies } from '../range';
import { createFilterRange } from './range';
import { BytesFormat, FieldFormatsGetConfigFn } from '../../../../../common';
import { AggConfigs } from '../../agg_configs';
import { mockDataServices, mockAggTypesRegistry } from '../../test_helpers';
import { BUCKET_TYPES } from '../bucket_agg_types';
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
+import { fieldFormatsServiceMock } from '../../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../core/public/mocks';
describe('AggConfig Filters', () => {
describe('range', () => {
+ let aggTypesDependencies: RangeBucketAggDependencies;
+
beforeEach(() => {
+ aggTypesDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
+
mockDataServices();
});
- const typesRegistry = mockAggTypesRegistry([rangeBucketAgg]);
-
const getConfig = (() => {}) as FieldFormatsGetConfigFn;
const getAggConfigs = () => {
const field = {
@@ -62,11 +71,11 @@ describe('AggConfig Filters', () => {
},
},
],
- { typesRegistry }
+ { typesRegistry: mockAggTypesRegistry([getRangeBucketAgg(aggTypesDependencies)]) }
);
};
- it('should return a range filter for range agg', () => {
+ test('should return a range filter for range agg', () => {
const aggConfigs = getAggConfigs();
const filter = createFilterRange(aggConfigs.aggs[0] as IBucketAggConfig, {
gte: 1024,
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts
index d3d85f2441a8b..cbad8742bfab6 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
import { buildRangeFilter } from '../../../../../common';
export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => {
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts
index 511af450b0113..c11a7d1a4e6b8 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts
@@ -17,17 +17,30 @@
* under the License.
*/
-import { termsBucketAgg } from '../terms';
+import { getTermsBucketAgg } from '../terms';
import { createFilterTerms } from './terms';
import { AggConfigs, CreateAggConfigParams } from '../../agg_configs';
import { mockAggTypesRegistry } from '../../test_helpers';
import { BUCKET_TYPES } from '../bucket_agg_types';
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
import { Filter, ExistsFilter } from '../../../../../common';
+import { RangeBucketAggDependencies } from '../range';
+import { fieldFormatsServiceMock } from '../../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../core/public/mocks';
describe('AggConfig Filters', () => {
describe('terms', () => {
- const typesRegistry = mockAggTypesRegistry([termsBucketAgg]);
+ let aggTypesDependencies: RangeBucketAggDependencies;
+
+ beforeEach(() => {
+ aggTypesDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
+ });
+
const getAggConfigs = (aggs: CreateAggConfigParams[]) => {
const indexPattern = {
id: '1234',
@@ -43,10 +56,12 @@ describe('AggConfig Filters', () => {
indexPattern,
};
- return new AggConfigs(indexPattern, aggs, { typesRegistry });
+ return new AggConfigs(indexPattern, aggs, {
+ typesRegistry: mockAggTypesRegistry([getTermsBucketAgg(aggTypesDependencies)]),
+ });
};
- it('should return a match_phrase filter for terms', () => {
+ test('should return a match_phrase filter for terms', () => {
const aggConfigs = getAggConfigs([
{ type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } },
]);
@@ -65,7 +80,7 @@ describe('AggConfig Filters', () => {
expect(filter.meta).toHaveProperty('index', '1234');
});
- it('should set query to true or false for boolean filter', () => {
+ test('should set query to true or false for boolean filter', () => {
const aggConfigs = getAggConfigs([
{ type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } },
]);
@@ -93,7 +108,7 @@ describe('AggConfig Filters', () => {
expect(filterTrue.query.match_phrase.field).toBeTruthy();
});
- it('should generate correct __missing__ filter', () => {
+ test('should generate correct __missing__ filter', () => {
const aggConfigs = getAggConfigs([
{ type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } },
]);
@@ -110,7 +125,7 @@ describe('AggConfig Filters', () => {
expect(filter.meta).toHaveProperty('negate', true);
});
- it('should generate correct __other__ filter', () => {
+ test('should generate correct __other__ filter', () => {
const aggConfigs = getAggConfigs([
{ type: BUCKET_TYPES.TERMS, schema: 'segment', params: { field: 'field' } },
]);
diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/terms.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.ts
index 43ebfc0e90db2..95de19b96abd4 100644
--- a/src/plugins/data/public/search/aggs/buckets/create_filter/terms.ts
+++ b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { IBucketAggConfig } from '../_bucket_agg_type';
+import { IBucketAggConfig } from '../bucket_agg_type';
import {
buildPhrasesFilter,
buildExistsFilter,
diff --git a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts
index 7701f1bbcb4d0..e6fd259fabc92 100644
--- a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts
+++ b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts
@@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n';
import { IUiSettingsClient } from 'src/core/public';
import { TimeBuckets } from './lib/time_buckets';
-import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
+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';
@@ -33,8 +33,8 @@ import { isMetricAggType } from '../metrics/metric_agg_type';
import { FIELD_FORMAT_IDS, KBN_FIELD_TYPES } from '../../../../common';
import { TimefilterContract } from '../../../query';
-import { getFieldFormats } from '../../../../public/services';
import { QuerySetup } from '../../../query/query_service';
+import { GetInternalStartServicesFn } from '../../../types';
const detectedTimezone = moment.tz.guess();
const tzOffset = moment().format('Z');
@@ -61,6 +61,7 @@ interface ITimeBuckets {
export interface DateHistogramBucketAggDependencies {
uiSettings: IUiSettingsClient;
query: QuerySetup;
+ getInternalStartServices: GetInternalStartServicesFn;
}
export interface IBucketDateHistogramAggConfig extends IBucketAggConfig {
@@ -74,211 +75,218 @@ export function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHist
export const getDateHistogramBucketAgg = ({
uiSettings,
query,
+ getInternalStartServices,
}: DateHistogramBucketAggDependencies) =>
- 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 = {};
+ 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);
- }
+ 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;
+ 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;
+ return {
+ buckets: {
+ configurable: true,
+ get() {
+ if (buckets) return buckets;
- const { timefilter } = query.timefilter;
- buckets = new TimeBuckets({ uiSettings });
- updateTimeBuckets(this, timefilter, buckets);
+ const { timefilter } = query.timefilter;
+ buckets = new TimeBuckets({ uiSettings });
+ updateTimeBuckets(this, timefilter, buckets);
- return buckets;
- },
- } as any,
- };
- },
- getFormat(agg) {
- const DateFieldFormat = getFieldFormats().getType(FIELD_FORMAT_IDS.DATE);
+ return buckets;
+ },
+ } as any,
+ };
+ },
+ getFormat(agg) {
+ const { fieldFormats } = getInternalStartServices();
+ const DateFieldFormat = fieldFormats.getType(FIELD_FORMAT_IDS.DATE);
- if (!DateFieldFormat) {
- throw new Error('Unable to retrieve Date Field Format');
- }
+ if (!DateFieldFormat) {
+ throw new Error('Unable to retrieve Date Field Format');
+ }
- return new DateFieldFormat(
+ return new DateFieldFormat(
+ {
+ pattern: agg.buckets.getScaledDateFormat(),
+ },
+ (key: string) => uiSettings.get(key)
+ );
+ },
+ params: [
{
- pattern: agg.buckets.getScaledDateFormat(),
+ 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;
+ }
+ },
},
- (key: string) => uiSettings.get(key)
- );
- },
- params: [
- {
- name: 'field',
- type: 'field',
- filterFieldTypes: KBN_FIELD_TYPES.DATE,
- default(agg: IBucketDateHistogramAggConfig) {
- return agg.getIndexPattern().timeFieldName;
+ {
+ name: 'timeRange',
+ default: null,
+ write: noop,
},
- onChange(agg: IBucketDateHistogramAggConfig) {
- if (get(agg, 'params.interval') === 'auto' && !agg.fieldIsTimeField()) {
- delete agg.params.interval;
- }
+ {
+ name: 'useNormalizedEsInterval',
+ default: true,
+ write: noop,
},
- },
- {
- name: 'timeRange',
- default: null,
- write: noop,
- },
- {
- name: 'useNormalizedEsInterval',
- default: true,
- write: noop,
- },
- {
- name: 'scaleMetricValues',
- default: false,
- write: noop,
- advanced: true,
- },
- {
- name: 'interval',
- 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');
- }
+ {
+ name: 'scaleMetricValues',
+ default: false,
+ write: noop,
+ advanced: true,
+ },
+ {
+ name: 'interval',
+ 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 });
+ 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,
- write(agg, output, aggs) {
- const { timefilter } = query.timefilter;
- updateTimeBuckets(agg, timefilter);
+ // 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,
+ write(agg, output, aggs) {
+ const { timefilter } = query.timefilter;
+ updateTimeBuckets(agg, timefilter);
- 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 { 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;
+ 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 (isMetricAggType(type)) {
+ return type.isScalable();
+ }
+ });
+ if (all) {
+ output.metricScale = interval.scale;
+ output.metricScaleText = interval.preScaled.description;
}
- });
- 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) {
- // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz
- const isDefaultTimezone = uiSettings.isDefault('dateFormat:tz');
- tz = isDefaultTimezone ? detectedTimezone || tzOffset : uiSettings.get('dateFormat:tz');
- }
- output.params.time_zone = tz;
+ {
+ 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) {
+ // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz
+ const isDefaultTimezone = uiSettings.isDefault('dateFormat:tz');
+ tz = isDefaultTimezone
+ ? detectedTimezone || tzOffset
+ : uiSettings.get('dateFormat:tz');
+ }
+ output.params.time_zone = tz;
+ },
},
- },
- {
- name: 'drop_partials',
- default: false,
- write: noop,
- shouldShow: agg => {
- const field = agg.params.field;
- return field && field.name && field.name === agg.getIndexPattern().timeFieldName;
+ {
+ name: 'drop_partials',
+ default: false,
+ write: noop,
+ 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;
+ {
+ 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(),
- };
+ if (val.min != null || val.max != null) {
+ output.params.extended_bounds = {
+ min: moment(val.min).valueOf(),
+ max: moment(val.max).valueOf(),
+ };
- return;
- }
+ return;
+ }
+ },
},
- },
- ],
- });
+ ],
+ },
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/date_range.test.ts b/src/plugins/data/public/search/aggs/buckets/date_range.test.ts
index 4ea550492fa09..c050620c3a856 100644
--- a/src/plugins/data/public/search/aggs/buckets/date_range.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/date_range.test.ts
@@ -17,11 +17,12 @@
* under the License.
*/
-import { coreMock } from '../../../../../../../src/core/public/mocks';
+import { coreMock, notificationServiceMock } from '../../../../../../../src/core/public/mocks';
import { getDateRangeBucketAgg, DateRangeBucketAggDependencies } from './date_range';
import { AggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { BUCKET_TYPES } from './bucket_agg_types';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
describe('date_range params', () => {
let aggTypesDependencies: DateRangeBucketAggDependencies;
@@ -31,6 +32,10 @@ describe('date_range params', () => {
aggTypesDependencies = {
uiSettings,
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
};
});
diff --git a/src/plugins/data/public/search/aggs/buckets/date_range.ts b/src/plugins/data/public/search/aggs/buckets/date_range.ts
index 8133a47ec7248..07d927e64a943 100644
--- a/src/plugins/data/public/search/aggs/buckets/date_range.ts
+++ b/src/plugins/data/public/search/aggs/buckets/date_range.ts
@@ -23,12 +23,12 @@ import { i18n } from '@kbn/i18n';
import { IUiSettingsClient } from 'src/core/public';
import { BUCKET_TYPES } from './bucket_agg_types';
-import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
+import { BucketAggType, IBucketAggConfig } from './bucket_agg_type';
import { createFilterDateRange } from './create_filter/date_range';
import { convertDateRangeToString, DateRangeKey } from './lib/date_range';
import { KBN_FIELD_TYPES, FieldFormat, TEXT_CONTEXT_TYPE } from '../../../../common';
-import { getFieldFormats } from '../../../../public/services';
+import { GetInternalStartServicesFn } from '../../../types';
const dateRangeTitle = i18n.translate('data.search.aggs.buckets.dateRangeTitle', {
defaultMessage: 'Date Range',
@@ -36,76 +36,85 @@ const dateRangeTitle = i18n.translate('data.search.aggs.buckets.dateRangeTitle',
export interface DateRangeBucketAggDependencies {
uiSettings: IUiSettingsClient;
+ getInternalStartServices: GetInternalStartServicesFn;
}
-export const getDateRangeBucketAgg = ({ uiSettings }: DateRangeBucketAggDependencies) =>
- new BucketAggType({
- name: BUCKET_TYPES.DATE_RANGE,
- title: dateRangeTitle,
- createFilter: createFilterDateRange,
- getKey({ from, to }): DateRangeKey {
- return { from, to };
- },
- getFormat(agg) {
- const fieldFormatsService = getFieldFormats();
+export const getDateRangeBucketAgg = ({
+ uiSettings,
+ getInternalStartServices,
+}: DateRangeBucketAggDependencies) =>
+ new BucketAggType(
+ {
+ name: BUCKET_TYPES.DATE_RANGE,
+ title: dateRangeTitle,
+ createFilter: createFilterDateRange,
+ getKey({ from, to }): DateRangeKey {
+ return { from, to };
+ },
+ getFormat(agg) {
+ const { fieldFormats } = getInternalStartServices();
- const formatter = agg.fieldOwnFormatter(
- TEXT_CONTEXT_TYPE,
- fieldFormatsService.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;
- },
+ 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();
},
- {
- name: 'ranges',
- default: [
- {
- from: 'now-1w/w',
- to: 'now',
- },
- ],
+ makeLabel(aggConfig) {
+ return aggConfig.getFieldDisplayName() + ' date ranges';
},
- {
- 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');
+ 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',
+ },
+ ],
+ },
+ {
+ 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 detectedTimezone = moment.tz.guess();
- const tzOffset = moment().format('Z');
- const isDefaultTimezone = uiSettings.isDefault('dateFormat:tz');
+ if (!tz && field) {
+ tz = get(agg.getIndexPattern(), [
+ 'typeMeta',
+ 'aggs',
+ 'date_range',
+ field.name,
+ 'time_zone',
+ ]);
+ }
+ if (!tz) {
+ const detectedTimezone = moment.tz.guess();
+ const tzOffset = moment().format('Z');
+ const isDefaultTimezone = uiSettings.isDefault('dateFormat:tz');
- tz = isDefaultTimezone ? detectedTimezone || tzOffset : uiSettings.get('dateFormat:tz');
- }
- output.params.time_zone = tz;
+ tz = isDefaultTimezone
+ ? detectedTimezone || tzOffset
+ : uiSettings.get('dateFormat:tz');
+ }
+ output.params.time_zone = tz;
+ },
},
- },
- ],
- });
+ ],
+ },
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/filter.ts b/src/plugins/data/public/search/aggs/buckets/filter.ts
index 80efc0cf92071..accbdf4dd783d 100644
--- a/src/plugins/data/public/search/aggs/buckets/filter.ts
+++ b/src/plugins/data/public/search/aggs/buckets/filter.ts
@@ -18,19 +18,28 @@
*/
import { i18n } from '@kbn/i18n';
-import { BucketAggType } from './_bucket_agg_type';
+import { BucketAggType } from './bucket_agg_type';
import { BUCKET_TYPES } from './bucket_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
const filterTitle = i18n.translate('data.search.aggs.buckets.filterTitle', {
defaultMessage: 'Filter',
});
-export const filterBucketAgg = new BucketAggType({
- name: BUCKET_TYPES.FILTER,
- title: filterTitle,
- params: [
+export interface FilterBucketAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getFilterBucketAgg = ({ getInternalStartServices }: FilterBucketAggDependencies) =>
+ new BucketAggType(
{
- name: 'geo_bounding_box',
+ name: BUCKET_TYPES.FILTER,
+ title: filterTitle,
+ params: [
+ {
+ name: 'geo_bounding_box',
+ },
+ ],
},
- ],
-});
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/filters.ts b/src/plugins/data/public/search/aggs/buckets/filters.ts
index 8b9aca87f8735..a42cb70a62b7d 100644
--- a/src/plugins/data/public/search/aggs/buckets/filters.ts
+++ b/src/plugins/data/public/search/aggs/buckets/filters.ts
@@ -23,11 +23,12 @@ import { IUiSettingsClient } from 'src/core/public';
import { createFilterFilters } from './create_filter/filters';
import { toAngularJSON } from '../utils';
-import { BucketAggType } from './_bucket_agg_type';
+import { BucketAggType } from './bucket_agg_type';
import { BUCKET_TYPES } from './bucket_agg_types';
import { Storage } from '../../../../../../plugins/kibana_utils/public';
import { getEsQueryConfig, buildEsQuery, Query } from '../../../../common';
import { getQueryLog } from '../../../query';
+import { GetInternalStartServicesFn } from '../../../types';
const filtersTitle = i18n.translate('data.search.aggs.buckets.filtersTitle', {
defaultMessage: 'Filters',
@@ -43,69 +44,81 @@ interface FilterValue {
export interface FiltersBucketAggDependencies {
uiSettings: IUiSettingsClient;
+ getInternalStartServices: GetInternalStartServicesFn;
}
-export const getFiltersBucketAgg = ({ uiSettings }: FiltersBucketAggDependencies) =>
- new BucketAggType({
- name: BUCKET_TYPES.FILTERS,
- title: filtersTitle,
- createFilter: createFilterFilters,
- customLabels: false,
- params: [
- {
- name: 'filters',
- default: [
- { input: { query: '', language: uiSettings.get('search:queryLanguage') }, label: '' },
- ],
- write(aggConfig, output) {
- const inFilters: FilterValue[] = aggConfig.params.filters;
- if (!size(inFilters)) return;
+export const getFiltersBucketAgg = ({
+ uiSettings,
+ getInternalStartServices,
+}: FiltersBucketAggDependencies) =>
+ new BucketAggType(
+ {
+ name: BUCKET_TYPES.FILTERS,
+ title: filtersTitle,
+ createFilter: createFilterFilters,
+ customLabels: false,
+ params: [
+ {
+ name: 'filters',
+ default: [
+ { input: { query: '', language: uiSettings.get('search:queryLanguage') }, label: '' },
+ ],
+ write(aggConfig, output) {
+ const inFilters: FilterValue[] = aggConfig.params.filters;
+ if (!size(inFilters)) return;
- inFilters.forEach(filter => {
- const persistedLog = getQueryLog(
- uiSettings,
- new Storage(window.localStorage),
- 'vis_default_editor',
- filter.input.language
- );
- persistedLog.add(filter.input.query);
- });
+ inFilters.forEach(filter => {
+ const persistedLog = getQueryLog(
+ uiSettings,
+ new Storage(window.localStorage),
+ 'vis_default_editor',
+ filter.input.language
+ );
+ persistedLog.add(filter.input.query);
+ });
- const outFilters = transform(
- inFilters,
- function(filters, filter) {
- const input = cloneDeep(filter.input);
+ const outFilters = transform(
+ inFilters,
+ function(filters, filter) {
+ const input = cloneDeep(filter.input);
- if (!input) {
- console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console
- return;
- }
+ if (!input) {
+ console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console
+ return;
+ }
- const esQueryConfigs = getEsQueryConfig(uiSettings);
- const query = buildEsQuery(aggConfig.getIndexPattern(), [input], [], esQueryConfigs);
+ const esQueryConfigs = getEsQueryConfig(uiSettings);
+ const query = buildEsQuery(
+ aggConfig.getIndexPattern(),
+ [input],
+ [],
+ esQueryConfigs
+ );
- if (!query) {
- console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console
- return;
- }
+ if (!query) {
+ console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console
+ return;
+ }
- const matchAllLabel = filter.input.query === '' ? '*' : '';
- const label =
- filter.label ||
- matchAllLabel ||
- (typeof filter.input.query === 'string'
- ? filter.input.query
- : toAngularJSON(filter.input.query));
- filters[label] = { query };
- },
- {}
- );
+ const matchAllLabel = filter.input.query === '' ? '*' : '';
+ const label =
+ filter.label ||
+ matchAllLabel ||
+ (typeof filter.input.query === 'string'
+ ? filter.input.query
+ : toAngularJSON(filter.input.query));
+ filters[label] = { query };
+ },
+ {}
+ );
- if (!size(outFilters)) return;
+ if (!size(outFilters)) return;
- const params = output.params || (output.params = {});
- params.filters = outFilters;
+ const params = output.params || (output.params = {});
+ params.filters = outFilters;
+ },
},
- },
- ],
- });
+ ],
+ },
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts b/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts
index 408cdf22bcbc2..24270dd33a576 100644
--- a/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts
@@ -17,13 +17,29 @@
* under the License.
*/
-import { geoHashBucketAgg } from './geo_hash';
+import { getGeoHashBucketAgg, GeoHashBucketAggDependencies } from './geo_hash';
import { AggConfigs, IAggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { BUCKET_TYPES } from './bucket_agg_types';
-import { IBucketAggConfig } from './_bucket_agg_type';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { BucketAggType, IBucketAggConfig } from './bucket_agg_type';
describe('Geohash Agg', () => {
+ let aggTypesDependencies: GeoHashBucketAggDependencies;
+ let geoHashBucketAgg: BucketAggType;
+
+ beforeEach(() => {
+ aggTypesDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
+
+ geoHashBucketAgg = getGeoHashBucketAgg(aggTypesDependencies);
+ });
+
const getAggConfigs = (params?: Record) => {
const indexPattern = {
id: '1234',
@@ -74,7 +90,7 @@ describe('Geohash Agg', () => {
precisionParam = geoHashBucketAgg.params[PRECISION_PARAM_INDEX];
});
- it('should select precision parameter', () => {
+ test('should select precision parameter', () => {
expect(precisionParam.name).toEqual('precision');
});
});
@@ -89,7 +105,7 @@ describe('Geohash Agg', () => {
geoHashGridAgg = aggConfigs.aggs[0] as IBucketAggConfig;
});
- it('should create filter, geohash_grid, and geo_centroid aggregations', () => {
+ test('should create filter, geohash_grid, and geo_centroid aggregations', () => {
const requestAggs = geoHashBucketAgg.getRequestAggs(geoHashGridAgg) as IBucketAggConfig[];
expect(requestAggs.length).toEqual(3);
@@ -101,7 +117,7 @@ describe('Geohash Agg', () => {
});
describe('aggregation options', () => {
- it('should only create geohash_grid and geo_centroid aggregations when isFilteredByCollar is false', () => {
+ test('should only create geohash_grid and geo_centroid aggregations when isFilteredByCollar is false', () => {
const aggConfigs = getAggConfigs({ isFilteredByCollar: false });
const requestAggs = geoHashBucketAgg.getRequestAggs(
aggConfigs.aggs[0] as IBucketAggConfig
@@ -112,7 +128,7 @@ describe('Geohash Agg', () => {
expect(requestAggs[1].type.name).toEqual('geo_centroid');
});
- it('should only create filter and geohash_grid aggregations when useGeocentroid is false', () => {
+ test('should only create filter and geohash_grid aggregations when useGeocentroid is false', () => {
const aggConfigs = getAggConfigs({ useGeocentroid: false });
const requestAggs = geoHashBucketAgg.getRequestAggs(
aggConfigs.aggs[0] as IBucketAggConfig
@@ -138,7 +154,7 @@ describe('Geohash Agg', () => {
) as IBucketAggConfig[];
});
- it('should change geo_bounding_box filter aggregation and vis session state when map movement is outside map collar', () => {
+ test('should change geo_bounding_box filter aggregation and vis session state when map movement is outside map collar', () => {
const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs(
getAggConfigs({
boundingBox: {
@@ -151,7 +167,7 @@ describe('Geohash Agg', () => {
expect(originalRequestAggs[1].params).not.toEqual(geoBoxingBox.params);
});
- it('should not change geo_bounding_box filter aggregation and vis session state when map movement is within map collar', () => {
+ test('should not change geo_bounding_box filter aggregation and vis session state when map movement is within map collar', () => {
const [, geoBoxingBox] = geoHashBucketAgg.getRequestAggs(
getAggConfigs({
boundingBox: {
diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash.ts b/src/plugins/data/public/search/aggs/buckets/geo_hash.ts
index 3ffec09a84387..eab10edad60f6 100644
--- a/src/plugins/data/public/search/aggs/buckets/geo_hash.ts
+++ b/src/plugins/data/public/search/aggs/buckets/geo_hash.ts
@@ -18,9 +18,10 @@
*/
import { i18n } from '@kbn/i18n';
-import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
+import { BucketAggType, IBucketAggConfig } from './bucket_agg_type';
import { KBN_FIELD_TYPES } from '../../../../common';
import { BUCKET_TYPES } from './bucket_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
const defaultBoundingBox = {
top_left: { lat: 1, lon: 1 },
@@ -33,83 +34,91 @@ const geohashGridTitle = i18n.translate('data.search.aggs.buckets.geohashGridTit
defaultMessage: 'Geohash',
});
-export const geoHashBucketAgg = new BucketAggType({
- name: BUCKET_TYPES.GEOHASH_GRID,
- title: geohashGridTitle,
- params: [
- {
- name: 'field',
- type: 'field',
- filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
- },
- {
- name: 'autoPrecision',
- default: true,
- write: () => {},
- },
- {
- name: 'precision',
- default: defaultPrecision,
- write(aggConfig, output) {
- output.params.precision = aggConfig.params.precision;
- },
- },
- {
- name: 'useGeocentroid',
- default: true,
- write: () => {},
- },
- {
- name: 'isFilteredByCollar',
- default: true,
- write: () => {},
- },
+export interface GeoHashBucketAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getGeoHashBucketAgg = ({ getInternalStartServices }: GeoHashBucketAggDependencies) =>
+ new BucketAggType(
{
- name: 'boundingBox',
- default: null,
- write: () => {},
- },
- ],
- getRequestAggs(agg) {
- const aggs = [];
- const params = agg.params;
+ name: BUCKET_TYPES.GEOHASH_GRID,
+ title: geohashGridTitle,
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
+ },
+ {
+ name: 'autoPrecision',
+ default: true,
+ write: () => {},
+ },
+ {
+ name: 'precision',
+ default: defaultPrecision,
+ write(aggConfig, output) {
+ output.params.precision = aggConfig.params.precision;
+ },
+ },
+ {
+ name: 'useGeocentroid',
+ default: true,
+ write: () => {},
+ },
+ {
+ name: 'isFilteredByCollar',
+ default: true,
+ write: () => {},
+ },
+ {
+ name: 'boundingBox',
+ default: null,
+ write: () => {},
+ },
+ ],
+ getRequestAggs(agg) {
+ const aggs = [];
+ const params = agg.params;
- if (params.isFilteredByCollar && agg.getField()) {
- aggs.push(
- agg.aggConfigs.createAggConfig(
- {
- type: 'filter',
- id: 'filter_agg',
- enabled: true,
- params: {
- geo_bounding_box: {
- ignore_unmapped: true,
- [agg.getField().name]: params.boundingBox || defaultBoundingBox,
- },
- },
- } as any,
- { addToAggConfigs: false }
- )
- );
- }
+ if (params.isFilteredByCollar && agg.getField()) {
+ aggs.push(
+ agg.aggConfigs.createAggConfig(
+ {
+ type: 'filter',
+ id: 'filter_agg',
+ enabled: true,
+ params: {
+ geo_bounding_box: {
+ ignore_unmapped: true,
+ [agg.getField().name]: params.boundingBox || defaultBoundingBox,
+ },
+ },
+ } as any,
+ { addToAggConfigs: false }
+ )
+ );
+ }
- aggs.push(agg);
+ aggs.push(agg);
- if (params.useGeocentroid) {
- aggs.push(
- agg.aggConfigs.createAggConfig(
- {
- type: 'geo_centroid',
- enabled: true,
- params: {
- field: agg.getField(),
- },
- },
- { addToAggConfigs: false }
- )
- );
- }
+ if (params.useGeocentroid) {
+ aggs.push(
+ agg.aggConfigs.createAggConfig(
+ {
+ type: 'geo_centroid',
+ enabled: true,
+ params: {
+ field: agg.getField(),
+ },
+ },
+ { addToAggConfigs: false }
+ )
+ );
+ }
- return aggs;
- },
-});
+ return aggs;
+ },
+ },
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/geo_tile.ts b/src/plugins/data/public/search/aggs/buckets/geo_tile.ts
index 759601fc0c180..c981e8400f9a1 100644
--- a/src/plugins/data/public/search/aggs/buckets/geo_tile.ts
+++ b/src/plugins/data/public/search/aggs/buckets/geo_tile.ts
@@ -20,53 +20,61 @@
import { i18n } from '@kbn/i18n';
import { noop } from 'lodash';
-import { BucketAggType } from './_bucket_agg_type';
+import { BucketAggType, IBucketAggConfig } from './bucket_agg_type';
import { BUCKET_TYPES } from './bucket_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
-import { IBucketAggConfig } from './_bucket_agg_type';
import { METRIC_TYPES } from '../metrics/metric_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface GeoTitleBucketAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const geotileGridTitle = i18n.translate('data.search.aggs.buckets.geotileGridTitle', {
defaultMessage: 'Geotile',
});
-export const geoTileBucketAgg = new BucketAggType({
- name: BUCKET_TYPES.GEOTILE_GRID,
- title: geotileGridTitle,
- params: [
- {
- name: 'field',
- type: 'field',
- filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
- },
+export const getGeoTitleBucketAgg = ({ getInternalStartServices }: GeoTitleBucketAggDependencies) =>
+ new BucketAggType(
{
- name: 'useGeocentroid',
- default: true,
- write: noop,
- },
- {
- name: 'precision',
- default: 0,
- },
- ],
- getRequestAggs(agg) {
- const aggs = [];
- const useGeocentroid = agg.getParam('useGeocentroid');
+ name: BUCKET_TYPES.GEOTILE_GRID,
+ title: geotileGridTitle,
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
+ },
+ {
+ name: 'useGeocentroid',
+ default: true,
+ write: noop,
+ },
+ {
+ name: 'precision',
+ default: 0,
+ },
+ ],
+ getRequestAggs(agg) {
+ const aggs = [];
+ const useGeocentroid = agg.getParam('useGeocentroid');
- aggs.push(agg);
+ aggs.push(agg);
- if (useGeocentroid) {
- const aggConfig = {
- type: METRIC_TYPES.GEO_CENTROID,
- enabled: true,
- params: {
- field: agg.getField(),
- },
- };
+ if (useGeocentroid) {
+ const aggConfig = {
+ type: METRIC_TYPES.GEO_CENTROID,
+ enabled: true,
+ params: {
+ field: agg.getField(),
+ },
+ };
- aggs.push(agg.aggConfigs.createAggConfig(aggConfig, { addToAggConfigs: false }));
- }
+ aggs.push(agg.aggConfigs.createAggConfig(aggConfig, { addToAggConfigs: false }));
+ }
- return aggs as IBucketAggConfig[];
- },
-});
+ return aggs as IBucketAggConfig[];
+ },
+ },
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/histogram.test.ts b/src/plugins/data/public/search/aggs/buckets/histogram.test.ts
index c61b4ff37935a..bbfc263df4268 100644
--- a/src/plugins/data/public/search/aggs/buckets/histogram.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/histogram.test.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { coreMock } from '../../../../../../../src/core/public/mocks';
+import { coreMock, notificationServiceMock } from '../../../../../../../src/core/public/mocks';
import { AggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { BUCKET_TYPES } from './bucket_agg_types';
@@ -27,17 +27,21 @@ import {
AutoBounds,
HistogramBucketAggDependencies,
} from './histogram';
-import { BucketAggType } from './_bucket_agg_type';
+import { BucketAggType } from './bucket_agg_type';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
describe('Histogram Agg', () => {
let aggTypesDependencies: HistogramBucketAggDependencies;
beforeEach(() => {
- const { uiSettings, notifications } = coreMock.createSetup();
+ const { uiSettings } = coreMock.createSetup();
aggTypesDependencies = {
uiSettings,
- notifications,
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
};
});
@@ -87,18 +91,18 @@ describe('Histogram Agg', () => {
histogramType = getHistogramBucketAgg(aggTypesDependencies);
});
- it('is ordered', () => {
+ test('is ordered', () => {
expect(histogramType.ordered).toBeDefined();
});
- it('is not ordered by date', () => {
+ test('is not ordered by date', () => {
expect(histogramType.ordered).not.toHaveProperty('date');
});
});
describe('params', () => {
describe('intervalBase', () => {
- it('should not be written to the DSL', () => {
+ test('should not be written to the DSL', () => {
const aggConfigs = getAggConfigs({
intervalBase: 100,
field: {
@@ -112,7 +116,7 @@ describe('Histogram Agg', () => {
});
describe('interval', () => {
- it('accepts a whole number', () => {
+ test('accepts a whole number', () => {
const params = getParams({
interval: 100,
});
@@ -120,7 +124,7 @@ describe('Histogram Agg', () => {
expect(params).toHaveProperty('interval', 100);
});
- it('accepts a decimal number', function() {
+ test('accepts a decimal number', () => {
const params = getParams({
interval: 0.1,
});
@@ -128,7 +132,7 @@ describe('Histogram Agg', () => {
expect(params).toHaveProperty('interval', 0.1);
});
- it('accepts a decimal number string', function() {
+ test('accepts a decimal number string', () => {
const params = getParams({
interval: '0.1',
});
@@ -136,7 +140,7 @@ describe('Histogram Agg', () => {
expect(params).toHaveProperty('interval', 0.1);
});
- it('accepts a whole number string', function() {
+ test('accepts a whole number string', () => {
const params = getParams({
interval: '10',
});
@@ -144,7 +148,7 @@ describe('Histogram Agg', () => {
expect(params).toHaveProperty('interval', 10);
});
- it('fails on non-numeric values', function() {
+ test('fails on non-numeric values', () => {
const params = getParams({
interval: [],
});
@@ -181,7 +185,7 @@ describe('Histogram Agg', () => {
return aggConfig.write(aggConfigs).params;
};
- it('will respect the histogram:maxBars setting', () => {
+ test('will respect the histogram:maxBars setting', () => {
const params = getInterval(
5,
{ interval: 5 },
@@ -194,19 +198,19 @@ describe('Histogram Agg', () => {
expect(params).toHaveProperty('interval', 2000);
});
- it('will return specified interval, if bars are below histogram:maxBars config', () => {
+ test('will return specified interval, if bars are below histogram:maxBars config', () => {
const params = getInterval(100, { interval: 5 });
expect(params).toHaveProperty('interval', 5);
});
- it('will set to intervalBase if interval is below base', () => {
+ test('will set to intervalBase if interval is below base', () => {
const params = getInterval(1000, { interval: 3, intervalBase: 8 });
expect(params).toHaveProperty('interval', 8);
});
- it('will round to nearest intervalBase multiple if interval is above base', () => {
+ test('will round to nearest intervalBase multiple if interval is above base', () => {
const roundUp = getInterval(1000, { interval: 46, intervalBase: 10 });
expect(roundUp).toHaveProperty('interval', 50);
@@ -214,13 +218,13 @@ describe('Histogram Agg', () => {
expect(roundDown).toHaveProperty('interval', 40);
});
- it('will not change interval if it is a multiple of base', () => {
+ test('will not change interval if it is a multiple of base', () => {
const output = getInterval(1000, { interval: 35, intervalBase: 5 });
expect(output).toHaveProperty('interval', 35);
});
- it('will round to intervalBase after scaling histogram:maxBars', () => {
+ test('will round to intervalBase after scaling histogram:maxBars', () => {
const output = getInterval(100, { interval: 5, intervalBase: 6 }, { min: 0, max: 1000 });
// 100 buckets in 0 to 1000 would result in an interval of 10, so we should
@@ -232,7 +236,7 @@ describe('Histogram Agg', () => {
describe('min_doc_count', () => {
let output: Record;
- it('casts true values to 0', () => {
+ test('casts true values to 0', () => {
output = getParams({ min_doc_count: true });
expect(output).toHaveProperty('min_doc_count', 0);
@@ -246,7 +250,7 @@ describe('Histogram Agg', () => {
expect(output).toHaveProperty('min_doc_count', 0);
});
- it('writes 1 for falsy values', () => {
+ test('writes 1 for falsy values', () => {
output = getParams({ min_doc_count: '' });
expect(output).toHaveProperty('min_doc_count', 1);
@@ -258,8 +262,8 @@ describe('Histogram Agg', () => {
});
});
- describe('extended_bounds', function() {
- it('does not write when only eb.min is set', function() {
+ describe('extended_bounds', () => {
+ test('does not write when only eb.min is set', () => {
const output = getParams({
has_extended_bounds: true,
extended_bounds: { min: 0 },
@@ -267,7 +271,7 @@ describe('Histogram Agg', () => {
expect(output).not.toHaveProperty('extended_bounds');
});
- it('does not write when only eb.max is set', function() {
+ test('does not write when only eb.max is set', () => {
const output = getParams({
has_extended_bounds: true,
extended_bounds: { max: 0 },
@@ -276,7 +280,7 @@ describe('Histogram Agg', () => {
expect(output).not.toHaveProperty('extended_bounds');
});
- it('writes when both eb.min and eb.max are set', function() {
+ test('writes when both eb.min and eb.max are set', () => {
const output = getParams({
has_extended_bounds: true,
extended_bounds: { min: 99, max: 100 },
@@ -286,7 +290,7 @@ describe('Histogram Agg', () => {
expect(output.extended_bounds).toHaveProperty('max', 100);
});
- it('does not write when nothing is set', function() {
+ test('does not write when nothing is set', () => {
const output = getParams({
has_extended_bounds: true,
extended_bounds: {},
@@ -295,7 +299,7 @@ describe('Histogram Agg', () => {
expect(output).not.toHaveProperty('extended_bounds');
});
- it('does not write when has_extended_bounds is false', function() {
+ test('does not write when has_extended_bounds is false', () => {
const output = getParams({
has_extended_bounds: false,
extended_bounds: { min: 99, max: 100 },
diff --git a/src/plugins/data/public/search/aggs/buckets/histogram.ts b/src/plugins/data/public/search/aggs/buckets/histogram.ts
index bbffc0912bf0d..f8e8720d24ea9 100644
--- a/src/plugins/data/public/search/aggs/buckets/histogram.ts
+++ b/src/plugins/data/public/search/aggs/buckets/histogram.ts
@@ -19,12 +19,13 @@
import { get } from 'lodash';
import { i18n } from '@kbn/i18n';
-import { IUiSettingsClient, NotificationsSetup } from 'src/core/public';
+import { IUiSettingsClient } from 'src/core/public';
-import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type';
+import { BucketAggType, IBucketAggConfig } from './bucket_agg_type';
import { createFilterHistogram } from './create_filter/histogram';
import { BUCKET_TYPES } from './bucket_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
export interface AutoBounds {
min: number;
@@ -33,7 +34,7 @@ export interface AutoBounds {
export interface HistogramBucketAggDependencies {
uiSettings: IUiSettingsClient;
- notifications: NotificationsSetup;
+ getInternalStartServices: GetInternalStartServicesFn;
}
export interface IBucketHistogramAggConfig extends IBucketAggConfig {
@@ -43,164 +44,167 @@ export interface IBucketHistogramAggConfig extends IBucketAggConfig {
export const getHistogramBucketAgg = ({
uiSettings,
- notifications,
+ getInternalStartServices,
}: HistogramBucketAggDependencies) =>
- new BucketAggType({
- name: BUCKET_TYPES.HISTOGRAM,
- title: i18n.translate('data.search.aggs.buckets.histogramTitle', {
- defaultMessage: 'Histogram',
- }),
- ordered: {},
- makeLabel(aggConfig) {
- return aggConfig.getFieldDisplayName();
- },
- createFilter: createFilterHistogram,
- decorateAggConfig() {
- let autoBounds: AutoBounds;
-
- return {
- setAutoBounds: {
- configurable: true,
- value(newValue: AutoBounds) {
- autoBounds = newValue;
+ new BucketAggType(
+ {
+ name: BUCKET_TYPES.HISTOGRAM,
+ title: i18n.translate('data.search.aggs.buckets.histogramTitle', {
+ defaultMessage: 'Histogram',
+ }),
+ ordered: {},
+ makeLabel(aggConfig) {
+ return aggConfig.getFieldDisplayName();
+ },
+ createFilter: createFilterHistogram,
+ decorateAggConfig() {
+ let autoBounds: AutoBounds;
+
+ return {
+ setAutoBounds: {
+ configurable: true,
+ value(newValue: AutoBounds) {
+ autoBounds = newValue;
+ },
},
- },
- getAutoBounds: {
- configurable: true,
- value() {
- return autoBounds;
+ getAutoBounds: {
+ configurable: true,
+ value() {
+ return autoBounds;
+ },
},
- },
- };
- },
- params: [
- {
- name: 'field',
- type: 'field',
- filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
- },
- {
- /*
- * This parameter can be set if you want the auto scaled interval to always
- * be a multiple of a specific base.
- */
- name: 'intervalBase',
- default: null,
- write: () => {},
+ };
},
- {
- name: 'interval',
- modifyAggConfigOnSearchRequestStart(
- aggConfig: IBucketHistogramAggConfig,
- searchSource: any,
- options: any
- ) {
- const field = aggConfig.getField();
- const aggBody = field.scripted
- ? { script: { source: field.script, lang: field.lang } }
- : { field: field.name };
-
- const childSearchSource = searchSource
- .createChild()
- .setField('size', 0)
- .setField('aggs', {
- maxAgg: {
- max: aggBody,
- },
- minAgg: {
- min: aggBody,
- },
- });
-
- return childSearchSource
- .fetch(options)
- .then((resp: any) => {
- aggConfig.setAutoBounds({
- min: get(resp, 'aggregations.minAgg.value'),
- max: get(resp, 'aggregations.maxAgg.value'),
- });
- })
- .catch((e: Error) => {
- if (e.name === 'AbortError') return;
- notifications.toasts.addWarning(
- i18n.translate('data.search.aggs.histogram.missingMaxMinValuesWarning', {
- defaultMessage:
- 'Unable to retrieve max and min values to auto-scale histogram buckets. This may lead to poor visualization performance.',
- })
- );
- });
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
+ },
+ {
+ /*
+ * This parameter can be set if you want the auto scaled interval to always
+ * be a multiple of a specific base.
+ */
+ name: 'intervalBase',
+ default: null,
+ write: () => {},
},
- write(aggConfig, output) {
- let interval = parseFloat(aggConfig.params.interval);
- if (interval <= 0) {
- interval = 1;
- }
- const autoBounds = aggConfig.getAutoBounds();
-
- // ensure interval does not create too many buckets and crash browser
- if (autoBounds) {
- const range = autoBounds.max - autoBounds.min;
- const bars = range / interval;
-
- if (bars > uiSettings.get('histogram:maxBars')) {
- const minInterval = range / uiSettings.get('histogram:maxBars');
-
- // Round interval by order of magnitude to provide clean intervals
- // Always round interval up so there will always be less buckets than histogram:maxBars
- const orderOfMagnitude = Math.pow(10, Math.floor(Math.log10(minInterval)));
- let roundInterval = orderOfMagnitude;
-
- while (roundInterval < minInterval) {
- roundInterval += orderOfMagnitude;
+ {
+ name: 'interval',
+ modifyAggConfigOnSearchRequestStart(
+ aggConfig: IBucketHistogramAggConfig,
+ searchSource: any,
+ options: any
+ ) {
+ const field = aggConfig.getField();
+ const aggBody = field.scripted
+ ? { script: { source: field.script, lang: field.lang } }
+ : { field: field.name };
+
+ const childSearchSource = searchSource
+ .createChild()
+ .setField('size', 0)
+ .setField('aggs', {
+ maxAgg: {
+ max: aggBody,
+ },
+ minAgg: {
+ min: aggBody,
+ },
+ });
+
+ return childSearchSource
+ .fetch(options)
+ .then((resp: any) => {
+ aggConfig.setAutoBounds({
+ min: get(resp, 'aggregations.minAgg.value'),
+ max: get(resp, 'aggregations.maxAgg.value'),
+ });
+ })
+ .catch((e: Error) => {
+ if (e.name === 'AbortError') return;
+ getInternalStartServices().notifications.toasts.addWarning(
+ i18n.translate('data.search.aggs.histogram.missingMaxMinValuesWarning', {
+ defaultMessage:
+ 'Unable to retrieve max and min values to auto-scale histogram buckets. This may lead to poor visualization performance.',
+ })
+ );
+ });
+ },
+ write(aggConfig, output) {
+ let interval = parseFloat(aggConfig.params.interval);
+ if (interval <= 0) {
+ interval = 1;
+ }
+ const autoBounds = aggConfig.getAutoBounds();
+
+ // ensure interval does not create too many buckets and crash browser
+ if (autoBounds) {
+ const range = autoBounds.max - autoBounds.min;
+ const bars = range / interval;
+
+ if (bars > uiSettings.get('histogram:maxBars')) {
+ const minInterval = range / uiSettings.get('histogram:maxBars');
+
+ // Round interval by order of magnitude to provide clean intervals
+ // Always round interval up so there will always be less buckets than histogram:maxBars
+ const orderOfMagnitude = Math.pow(10, Math.floor(Math.log10(minInterval)));
+ let roundInterval = orderOfMagnitude;
+
+ while (roundInterval < minInterval) {
+ roundInterval += orderOfMagnitude;
+ }
+ interval = roundInterval;
}
- interval = roundInterval;
}
- }
- const base = aggConfig.params.intervalBase;
-
- if (base) {
- if (interval < base) {
- // In case the specified interval is below the base, just increase it to it's base
- interval = base;
- } else if (interval % base !== 0) {
- // In case the interval is not a multiple of the base round it to the next base
- interval = Math.round(interval / base) * base;
+ const base = aggConfig.params.intervalBase;
+
+ if (base) {
+ if (interval < base) {
+ // In case the specified interval is below the base, just increase it to it's base
+ interval = base;
+ } else if (interval % base !== 0) {
+ // In case the interval is not a multiple of the base round it to the next base
+ interval = Math.round(interval / base) * base;
+ }
}
- }
- output.params.interval = interval;
+ output.params.interval = interval;
+ },
},
- },
- {
- name: 'min_doc_count',
- default: false,
- write(aggConfig, output) {
- if (aggConfig.params.min_doc_count) {
- output.params.min_doc_count = 0;
- } else {
- output.params.min_doc_count = 1;
- }
+ {
+ name: 'min_doc_count',
+ default: false,
+ write(aggConfig, output) {
+ if (aggConfig.params.min_doc_count) {
+ output.params.min_doc_count = 0;
+ } else {
+ output.params.min_doc_count = 1;
+ }
+ },
},
- },
- {
- name: 'has_extended_bounds',
- default: false,
- write: () => {},
- },
- {
- name: 'extended_bounds',
- default: {
- min: '',
- max: '',
+ {
+ name: 'has_extended_bounds',
+ default: false,
+ write: () => {},
},
- write(aggConfig, output) {
- const { min, max } = aggConfig.params.extended_bounds;
+ {
+ name: 'extended_bounds',
+ default: {
+ min: '',
+ max: '',
+ },
+ write(aggConfig, output) {
+ const { min, max } = aggConfig.params.extended_bounds;
- if (aggConfig.params.has_extended_bounds && (min || min === 0) && (max || max === 0)) {
- output.params.extended_bounds = { min, max };
- }
+ if (aggConfig.params.has_extended_bounds && (min || min === 0) && (max || max === 0)) {
+ output.params.extended_bounds = { min, max };
+ }
+ },
+ shouldShow: (aggConfig: IBucketAggConfig) => aggConfig.params.has_extended_bounds,
},
- shouldShow: (aggConfig: IBucketAggConfig) => aggConfig.params.has_extended_bounds,
- },
- ],
- });
+ ],
+ },
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/ip_range.ts b/src/plugins/data/public/search/aggs/buckets/ip_range.ts
index da6866d40a52f..bde347d6e673d 100644
--- a/src/plugins/data/public/search/aggs/buckets/ip_range.ts
+++ b/src/plugins/data/public/search/aggs/buckets/ip_range.ts
@@ -19,77 +19,85 @@
import { noop, map, omit, isNull } from 'lodash';
import { i18n } from '@kbn/i18n';
-import { BucketAggType } from './_bucket_agg_type';
+import { BucketAggType } from './bucket_agg_type';
import { BUCKET_TYPES } from './bucket_agg_types';
import { createFilterIpRange } from './create_filter/ip_range';
import { IpRangeKey, convertIPRangeToString } from './lib/ip_range';
import { KBN_FIELD_TYPES, FieldFormat, TEXT_CONTEXT_TYPE } from '../../../../common';
-import { getFieldFormats } from '../../../../public/services';
+import { GetInternalStartServicesFn } from '../../../types';
const ipRangeTitle = i18n.translate('data.search.aggs.buckets.ipRangeTitle', {
defaultMessage: 'IPv4 Range',
});
-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 fieldFormatsService = getFieldFormats();
- const formatter = agg.fieldOwnFormatter(
- TEXT_CONTEXT_TYPE,
- fieldFormatsService.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',
- default: 'fromTo',
- write: noop,
- },
+export interface IpRangeBucketAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getIpRangeBucketAgg = ({ getInternalStartServices }: IpRangeBucketAggDependencies) =>
+ new BucketAggType(
{
- 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' }],
+ 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 } = getInternalStartServices();
+ 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(),
+ },
+ });
},
- write(aggConfig, output) {
- const ipRangeType = aggConfig.params.ipRangeType;
- let ranges = aggConfig.params.ranges[ipRangeType];
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: KBN_FIELD_TYPES.IP,
+ },
+ {
+ name: 'ipRangeType',
+ 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' }],
+ },
+ 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));
- }
+ if (ipRangeType === 'fromTo') {
+ ranges = map(ranges, (range: any) => omit(range, isNull));
+ }
- output.params.ranges = ranges;
- },
+ output.params.ranges = ranges;
+ },
+ },
+ ],
},
- ],
-});
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts b/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts
index d94477b588f8d..0beeb1c372275 100644
--- a/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts
+++ b/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts
@@ -18,7 +18,7 @@
*/
import { isString, isObject } from 'lodash';
-import { IBucketAggConfig, BucketAggType, BucketAggParam } from './_bucket_agg_type';
+import { IBucketAggConfig, BucketAggType, BucketAggParam } from './bucket_agg_type';
import { IAggConfig } from '../agg_config';
export const isType = (type: string) => {
diff --git a/src/plugins/data/public/search/aggs/buckets/range.test.ts b/src/plugins/data/public/search/aggs/buckets/range.test.ts
index bf3711543ae88..a1f0ab6a2326a 100644
--- a/src/plugins/data/public/search/aggs/buckets/range.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/range.test.ts
@@ -17,11 +17,13 @@
* under the License.
*/
-import { rangeBucketAgg } from './range';
+import { getRangeBucketAgg, RangeBucketAggDependencies } from './range';
import { AggConfigs } from '../agg_configs';
import { mockDataServices, mockAggTypesRegistry } from '../test_helpers';
import { BUCKET_TYPES } from './bucket_agg_types';
import { FieldFormatsGetConfigFn, NumberFormat } from '../../../../common';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
const buckets = [
{
@@ -44,7 +46,16 @@ const buckets = [
];
describe('Range Agg', () => {
+ let aggTypesDependencies: RangeBucketAggDependencies;
+
beforeEach(() => {
+ aggTypesDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
+
mockDataServices();
});
@@ -84,15 +95,14 @@ describe('Range Agg', () => {
},
},
],
- { typesRegistry: mockAggTypesRegistry([rangeBucketAgg]) }
+ { typesRegistry: mockAggTypesRegistry([getRangeBucketAgg(aggTypesDependencies)]) }
);
};
describe('formating', () => {
- it('formats bucket keys properly', () => {
+ test('formats bucket keys properly', () => {
const aggConfigs = getAggConfigs();
const agg = aggConfigs.aggs[0];
-
const format = (val: any) => agg.fieldFormatter()(agg.getKey(val));
expect(format(buckets[0])).toBe('≥ -∞ and < 1 KB');
diff --git a/src/plugins/data/public/search/aggs/buckets/range.ts b/src/plugins/data/public/search/aggs/buckets/range.ts
index 036a0d4c1e8da..2c1303814a88a 100644
--- a/src/plugins/data/public/search/aggs/buckets/range.ts
+++ b/src/plugins/data/public/search/aggs/buckets/range.ts
@@ -18,11 +18,12 @@
*/
import { i18n } from '@kbn/i18n';
-import { BucketAggType } from './_bucket_agg_type';
+import { BucketAggType } from './bucket_agg_type';
import { FieldFormat, KBN_FIELD_TYPES } from '../../../../common';
import { RangeKey } from './range_key';
import { createFilterRange } from './create_filter/range';
import { BUCKET_TYPES } from './bucket_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
const keyCaches = new WeakMap();
const formats = new WeakMap();
@@ -31,76 +32,84 @@ const rangeTitle = i18n.translate('data.search.aggs.buckets.rangeTitle', {
defaultMessage: 'Range',
});
-export const rangeBucketAgg = new BucketAggType({
- name: BUCKET_TYPES.RANGE,
- title: rangeTitle,
- createFilter: createFilterRange,
- makeLabel(aggConfig) {
- return i18n.translate('data.search.aggs.aggTypesLabel', {
- defaultMessage: '{fieldName} ranges',
- values: {
- fieldName: aggConfig.getFieldDisplayName(),
+export interface RangeBucketAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getRangeBucketAgg = ({ getInternalStartServices }: RangeBucketAggDependencies) =>
+ new BucketAggType(
+ {
+ name: BUCKET_TYPES.RANGE,
+ title: rangeTitle,
+ createFilter: createFilterRange,
+ makeLabel(aggConfig) {
+ return i18n.translate('data.search.aggs.aggTypesLabel', {
+ defaultMessage: '{fieldName} ranges',
+ values: {
+ fieldName: aggConfig.getFieldDisplayName(),
+ },
+ });
},
- });
- },
- getKey(bucket, key, agg) {
- let keys = keyCaches.get(agg);
+ getKey(bucket, key, agg) {
+ let keys = keyCaches.get(agg);
- if (!keys) {
- keys = new Map();
- keyCaches.set(agg, keys);
- }
+ if (!keys) {
+ keys = new Map();
+ keyCaches.set(agg, keys);
+ }
- const id = RangeKey.idBucket(bucket);
+ const id = RangeKey.idBucket(bucket);
- key = keys.get(id);
- if (!key) {
- key = new RangeKey(bucket);
- keys.set(id, key);
- }
+ key = keys.get(id);
+ if (!key) {
+ key = new RangeKey(bucket);
+ keys.set(id, key);
+ }
- return key;
- },
- getFormat(agg) {
- let aggFormat = formats.get(agg);
- if (aggFormat) return aggFormat;
+ return key;
+ },
+ getFormat(agg) {
+ let aggFormat = formats.get(agg);
+ if (aggFormat) return aggFormat;
- const RangeFormat = FieldFormat.from((range: any) => {
- const format = agg.fieldOwnFormatter();
- const gte = '\u2265';
- const lt = '\u003c';
- return i18n.translate('data.search.aggs.aggTypes.rangesFormatMessage', {
- defaultMessage: '{gte} {from} and {lt} {to}',
- values: {
- gte,
- from: format(range.gte),
- lt,
- to: format(range.lt),
- },
- });
- });
+ const RangeFormat = FieldFormat.from((range: any) => {
+ const format = agg.fieldOwnFormatter();
+ const gte = '\u2265';
+ const lt = '\u003c';
+ return i18n.translate('data.search.aggs.aggTypes.rangesFormatMessage', {
+ defaultMessage: '{gte} {from} and {lt} {to}',
+ values: {
+ gte,
+ from: format(range.gte),
+ lt,
+ to: format(range.lt),
+ },
+ });
+ });
- aggFormat = new RangeFormat();
+ aggFormat = new RangeFormat();
- formats.set(agg, aggFormat);
- return aggFormat;
- },
- params: [
- {
- name: 'field',
- type: 'field',
- filterFieldTypes: [KBN_FIELD_TYPES.NUMBER],
- },
- {
- name: 'ranges',
- default: [
- { from: 0, to: 1000 },
- { from: 1000, to: 2000 },
- ],
- write(aggConfig, output) {
- output.params.ranges = aggConfig.params.ranges;
- output.params.keyed = true;
+ formats.set(agg, aggFormat);
+ return aggFormat;
},
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: [KBN_FIELD_TYPES.NUMBER],
+ },
+ {
+ name: 'ranges',
+ default: [
+ { from: 0, to: 1000 },
+ { from: 1000, to: 2000 },
+ ],
+ write(aggConfig, output) {
+ output.params.ranges = aggConfig.params.ranges;
+ output.params.keyed = true;
+ },
+ },
+ ],
},
- ],
-});
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts b/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts
index 1c221126c35e0..761d0ced6a114 100644
--- a/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts
@@ -20,12 +20,27 @@
import { AggConfigs, IAggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { BUCKET_TYPES } from './bucket_agg_types';
-import { significantTermsBucketAgg } from './significant_terms';
-import { IBucketAggConfig } from './_bucket_agg_type';
+import {
+ getSignificantTermsBucketAgg,
+ SignificantTermsBucketAggDependencies,
+} from './significant_terms';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
describe('Significant Terms Agg', () => {
describe('order agg editor UI', () => {
describe('convert include/exclude from old format', () => {
+ let aggTypesDependencies: SignificantTermsBucketAggDependencies;
+
+ beforeEach(() => {
+ aggTypesDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
+ });
+
const getAggConfigs = (params: Record = {}) => {
const indexPattern = {
id: '1234',
@@ -51,7 +66,11 @@ describe('Significant Terms Agg', () => {
params,
},
],
- { typesRegistry: mockAggTypesRegistry([significantTermsBucketAgg]) }
+ {
+ typesRegistry: mockAggTypesRegistry([
+ getSignificantTermsBucketAgg(aggTypesDependencies),
+ ]),
+ }
);
};
@@ -64,19 +83,19 @@ describe('Significant Terms Agg', () => {
expect(params.exclude).toBe('400');
};
- it('should generate correct label', () => {
+ test('should generate correct label', () => {
const aggConfigs = getAggConfigs({
size: 'SIZE',
field: {
name: 'FIELD',
},
});
- const label = significantTermsBucketAgg.makeLabel(aggConfigs.aggs[0] as IBucketAggConfig);
+ const label = aggConfigs.aggs[0].makeLabel();
expect(label).toBe('Top SIZE unusual terms in FIELD');
});
- it('should doesnt do anything with string type', () => {
+ test('should doesnt do anything with string type', () => {
const aggConfigs = getAggConfigs({
include: '404',
exclude: '400',
@@ -89,7 +108,7 @@ describe('Significant Terms Agg', () => {
testSerializeAndWrite(aggConfigs);
});
- it('should converts object to string type', () => {
+ test('should converts object to string type', () => {
const aggConfigs = getAggConfigs({
include: {
pattern: '404',
diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms.ts b/src/plugins/data/public/search/aggs/buckets/significant_terms.ts
index f12ebe58e2de2..49d797f3afbc9 100644
--- a/src/plugins/data/public/search/aggs/buckets/significant_terms.ts
+++ b/src/plugins/data/public/search/aggs/buckets/significant_terms.ts
@@ -18,59 +18,72 @@
*/
import { i18n } from '@kbn/i18n';
-import { BucketAggType } from './_bucket_agg_type';
+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 '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
const significantTermsTitle = i18n.translate('data.search.aggs.buckets.significantTermsTitle', {
defaultMessage: 'Significant Terms',
});
-export const significantTermsBucketAgg = new BucketAggType({
- name: BUCKET_TYPES.SIGNIFICANT_TERMS,
- title: significantTermsTitle,
- makeLabel(aggConfig) {
- return i18n.translate('data.search.aggs.buckets.significantTermsLabel', {
- defaultMessage: 'Top {size} unusual terms in {fieldName}',
- values: {
- size: aggConfig.params.size,
- fieldName: aggConfig.getFieldDisplayName(),
- },
- });
- },
- createFilter: createFilterTerms,
- params: [
- {
- name: 'field',
- type: 'field',
- scriptable: false,
- filterFieldTypes: KBN_FIELD_TYPES.STRING,
- },
- {
- name: 'size',
- default: '',
- },
+export interface SignificantTermsBucketAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getSignificantTermsBucketAgg = ({
+ getInternalStartServices,
+}: SignificantTermsBucketAggDependencies) =>
+ new BucketAggType(
{
- name: 'exclude',
- displayName: i18n.translate('data.search.aggs.buckets.significantTerms.excludeLabel', {
- defaultMessage: 'Exclude',
- }),
- type: 'string',
- advanced: true,
- shouldShow: isStringType,
- ...migrateIncludeExcludeFormat,
+ name: BUCKET_TYPES.SIGNIFICANT_TERMS,
+ title: significantTermsTitle,
+ makeLabel(aggConfig) {
+ return i18n.translate('data.search.aggs.buckets.significantTermsLabel', {
+ defaultMessage: 'Top {size} unusual terms in {fieldName}',
+ values: {
+ size: aggConfig.params.size,
+ fieldName: aggConfig.getFieldDisplayName(),
+ },
+ });
+ },
+ createFilter: createFilterTerms,
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ scriptable: false,
+ filterFieldTypes: KBN_FIELD_TYPES.STRING,
+ },
+ {
+ name: 'size',
+ default: '',
+ },
+ {
+ name: 'exclude',
+ displayName: i18n.translate('data.search.aggs.buckets.significantTerms.excludeLabel', {
+ defaultMessage: 'Exclude',
+ }),
+ type: 'string',
+ advanced: true,
+ shouldShow: isStringType,
+ ...migrateIncludeExcludeFormat,
+ },
+ {
+ name: 'include',
+ displayName: i18n.translate('data.search.aggs.buckets.significantTerms.includeLabel', {
+ defaultMessage: 'Include',
+ }),
+ type: 'string',
+ advanced: true,
+ shouldShow: isStringType,
+ ...migrateIncludeExcludeFormat,
+ },
+ ],
},
{
- name: 'include',
- displayName: i18n.translate('data.search.aggs.buckets.significantTerms.includeLabel', {
- defaultMessage: 'Include',
- }),
- type: 'string',
- advanced: true,
- shouldShow: isStringType,
- ...migrateIncludeExcludeFormat,
- },
- ],
-});
+ getInternalStartServices,
+ }
+ );
diff --git a/src/plugins/data/public/search/aggs/buckets/terms.test.ts b/src/plugins/data/public/search/aggs/buckets/terms.test.ts
index 280d78f6620bd..5afe7d0b0c35c 100644
--- a/src/plugins/data/public/search/aggs/buckets/terms.test.ts
+++ b/src/plugins/data/public/search/aggs/buckets/terms.test.ts
@@ -51,7 +51,7 @@ describe('Terms Agg', () => {
);
};
- it('converts object to string type', function() {
+ test('converts object to string type', () => {
const aggConfigs = getAggConfigs({
include: {
pattern: '404',
diff --git a/src/plugins/data/public/search/aggs/buckets/terms.ts b/src/plugins/data/public/search/aggs/buckets/terms.ts
index 813c657934a76..5baa38af0e8d6 100644
--- a/src/plugins/data/public/search/aggs/buckets/terms.ts
+++ b/src/plugins/data/public/search/aggs/buckets/terms.ts
@@ -19,9 +19,8 @@
import { noop } from 'lodash';
import { i18n } from '@kbn/i18n';
-import { BucketAggType } from './_bucket_agg_type';
+import { BucketAggType, IBucketAggConfig } from './bucket_agg_type';
import { BUCKET_TYPES } from './bucket_agg_types';
-import { IBucketAggConfig } from './_bucket_agg_type';
import { createFilterTerms } from './create_filter/terms';
import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format';
import { IAggConfigs } from '../agg_configs';
@@ -36,6 +35,7 @@ import {
mergeOtherBucketAggResponse,
updateMissingBucket,
} from './_terms_other_bucket_helper';
+import { GetInternalStartServicesFn } from '../../../types';
export const termsAggFilter = [
'!top_hits',
@@ -56,220 +56,230 @@ const termsTitle = i18n.translate('data.search.aggs.buckets.termsTitle', {
defaultMessage: 'Terms',
});
-export const termsBucketAgg = new BucketAggType({
- name: BUCKET_TYPES.TERMS,
- title: termsTitle,
- makeLabel(agg) {
- const params = agg.params;
- return agg.getFieldDisplayName() + ': ' + params.order.text;
- },
- getFormat(bucket): IFieldFormat {
- return {
- getConverterFor: (type: FieldFormatsContentType) => {
- return (val: any) => {
- if (val === '__other__') {
- return bucket.params.otherBucketLabel;
- }
- if (val === '__missing__') {
- return bucket.params.missingBucketLabel;
- }
+export interface TermsBucketAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
- return bucket.params.field.format.convert(val, type);
- };
+export const getTermsBucketAgg = ({ getInternalStartServices }: TermsBucketAggDependencies) =>
+ new BucketAggType(
+ {
+ name: BUCKET_TYPES.TERMS,
+ title: termsTitle,
+ makeLabel(agg) {
+ const params = agg.params;
+ return agg.getFieldDisplayName() + ': ' + params.order.text;
},
- } as IFieldFormat;
- },
- createFilter: createFilterTerms,
- postFlightRequest: async (
- resp: any,
- aggConfigs: IAggConfigs,
- aggConfig: IBucketAggConfig,
- searchSource: ISearchSource,
- inspectorAdapters: Adapters,
- abortSignal?: AbortSignal
- ) => {
- if (!resp.aggregations) return resp;
- const nestedSearchSource = searchSource.createChild();
- if (aggConfig.params.otherBucket) {
- const filterAgg = buildOtherBucketAgg(aggConfigs, aggConfig, resp);
- if (!filterAgg) return resp;
+ getFormat(bucket): IFieldFormat {
+ return {
+ getConverterFor: (type: FieldFormatsContentType) => {
+ return (val: any) => {
+ if (val === '__other__') {
+ return bucket.params.otherBucketLabel;
+ }
+ if (val === '__missing__') {
+ return bucket.params.missingBucketLabel;
+ }
- nestedSearchSource.setField('aggs', filterAgg);
+ return bucket.params.field.format.convert(val, type);
+ };
+ },
+ } as IFieldFormat;
+ },
+ createFilter: createFilterTerms,
+ postFlightRequest: async (
+ resp: any,
+ aggConfigs: IAggConfigs,
+ aggConfig: IBucketAggConfig,
+ searchSource: ISearchSource,
+ inspectorAdapters: Adapters,
+ abortSignal?: AbortSignal
+ ) => {
+ if (!resp.aggregations) return resp;
+ const nestedSearchSource = searchSource.createChild();
+ if (aggConfig.params.otherBucket) {
+ const filterAgg = buildOtherBucketAgg(aggConfigs, aggConfig, resp);
+ if (!filterAgg) return resp;
- const request = inspectorAdapters.requests.start(
- i18n.translate('data.search.aggs.buckets.terms.otherBucketTitle', {
- defaultMessage: 'Other bucket',
- }),
- {
- 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.',
- }),
- }
- );
- nestedSearchSource.getSearchRequestBody().then((body: string) => {
- request.json(body);
- });
- request.stats(getRequestInspectorStats(nestedSearchSource));
+ nestedSearchSource.setField('aggs', filterAgg);
- const response = await nestedSearchSource.fetch({ abortSignal });
- request.stats(getResponseInspectorStats(nestedSearchSource, response)).ok({ json: response });
- resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg());
- }
- if (aggConfig.params.missingBucket) {
- resp = updateMissingBucket(resp, aggConfigs, aggConfig);
- }
- return resp;
- },
- params: [
- {
- name: 'field',
- type: 'field',
- filterFieldTypes: [
- KBN_FIELD_TYPES.NUMBER,
- KBN_FIELD_TYPES.BOOLEAN,
- KBN_FIELD_TYPES.DATE,
- KBN_FIELD_TYPES.IP,
- KBN_FIELD_TYPES.STRING,
- ],
- },
- {
- name: 'orderBy',
- write: noop, // prevent default write, it's handled by orderAgg
- },
- {
- name: 'orderAgg',
- type: 'agg',
- allowedAggs: termsAggFilter,
- default: null,
- makeAgg(termsAgg, state) {
- state = state || {};
- state.schema = 'orderAgg';
- const orderAgg = termsAgg.aggConfigs.createAggConfig(state, {
- addToAggConfigs: false,
- });
- orderAgg.id = termsAgg.id + '-orderAgg';
+ const request = inspectorAdapters.requests.start(
+ i18n.translate('data.search.aggs.buckets.terms.otherBucketTitle', {
+ defaultMessage: 'Other bucket',
+ }),
+ {
+ 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.',
+ }),
+ }
+ );
+ nestedSearchSource.getSearchRequestBody().then((body: string) => {
+ request.json(body);
+ });
+ request.stats(getRequestInspectorStats(nestedSearchSource));
- return orderAgg;
+ const response = await nestedSearchSource.fetch({ abortSignal });
+ request
+ .stats(getResponseInspectorStats(nestedSearchSource, response))
+ .ok({ json: response });
+ resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg());
+ }
+ if (aggConfig.params.missingBucket) {
+ resp = updateMissingBucket(resp, aggConfigs, aggConfig);
+ }
+ return resp;
},
- write(agg, output, aggs) {
- const dir = agg.params.order.value;
- const order: Record = (output.params.order = {});
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: [
+ KBN_FIELD_TYPES.NUMBER,
+ KBN_FIELD_TYPES.BOOLEAN,
+ KBN_FIELD_TYPES.DATE,
+ KBN_FIELD_TYPES.IP,
+ KBN_FIELD_TYPES.STRING,
+ ],
+ },
+ {
+ name: 'orderBy',
+ write: noop, // prevent default write, it's handled by orderAgg
+ },
+ {
+ name: 'orderAgg',
+ type: 'agg',
+ allowedAggs: termsAggFilter,
+ default: null,
+ makeAgg(termsAgg, state) {
+ state = state || {};
+ state.schema = 'orderAgg';
+ const orderAgg = termsAgg.aggConfigs.createAggConfig(state, {
+ addToAggConfigs: false,
+ });
+ orderAgg.id = termsAgg.id + '-orderAgg';
- let orderAgg = agg.params.orderAgg || aggs!.getResponseAggById(agg.params.orderBy);
+ return orderAgg;
+ },
+ write(agg, output, aggs) {
+ const dir = agg.params.order.value;
+ const order: Record = (output.params.order = {});
- // TODO: This works around an Elasticsearch bug the always casts terms agg scripts to strings
- // thus causing issues with filtering. This probably causes other issues since float might not
- // be able to contain the number on the elasticsearch side
- if (output.params.script) {
- output.params.value_type =
- agg.getField().type === 'number' ? 'float' : agg.getField().type;
- }
+ let orderAgg = agg.params.orderAgg || aggs!.getResponseAggById(agg.params.orderBy);
- if (agg.params.missingBucket && agg.params.field.type === 'string') {
- output.params.missing = '__missing__';
- }
+ // TODO: This works around an Elasticsearch bug the always casts terms agg scripts to strings
+ // thus causing issues with filtering. This probably causes other issues since float might not
+ // be able to contain the number on the elasticsearch side
+ if (output.params.script) {
+ output.params.value_type =
+ agg.getField().type === 'number' ? 'float' : agg.getField().type;
+ }
- if (!orderAgg) {
- order[agg.params.orderBy || '_count'] = dir;
- return;
- }
+ if (agg.params.missingBucket && agg.params.field.type === 'string') {
+ output.params.missing = '__missing__';
+ }
- if (orderAgg.type.name === 'count') {
- order._count = dir;
- return;
- }
+ if (!orderAgg) {
+ order[agg.params.orderBy || '_count'] = dir;
+ return;
+ }
- const orderAggId = orderAgg.id;
+ if (orderAgg.type.name === 'count') {
+ order._count = dir;
+ return;
+ }
- if (orderAgg.parentId && aggs) {
- orderAgg = aggs.byId(orderAgg.parentId);
- }
+ const orderAggId = orderAgg.id;
- output.subAggs = (output.subAggs || []).concat(orderAgg);
- order[orderAggId] = dir;
- },
- },
- {
- name: 'order',
- type: 'optioned',
- default: 'desc',
- options: [
+ if (orderAgg.parentId && aggs) {
+ orderAgg = aggs.byId(orderAgg.parentId);
+ }
+
+ output.subAggs = (output.subAggs || []).concat(orderAgg);
+ order[orderAggId] = dir;
+ },
+ },
{
- text: i18n.translate('data.search.aggs.buckets.terms.orderDescendingTitle', {
- defaultMessage: 'Descending',
+ name: 'order',
+ type: 'optioned',
+ default: 'desc',
+ options: [
+ {
+ text: i18n.translate('data.search.aggs.buckets.terms.orderDescendingTitle', {
+ defaultMessage: 'Descending',
+ }),
+ value: 'desc',
+ },
+ {
+ text: i18n.translate('data.search.aggs.buckets.terms.orderAscendingTitle', {
+ defaultMessage: 'Ascending',
+ }),
+ value: 'asc',
+ },
+ ],
+ write: noop, // prevent default write, it's handled by orderAgg
+ },
+ {
+ name: 'size',
+ default: 5,
+ },
+ {
+ name: 'otherBucket',
+ default: false,
+ write: noop,
+ },
+ {
+ name: 'otherBucketLabel',
+ type: 'string',
+ default: i18n.translate('data.search.aggs.buckets.terms.otherBucketLabel', {
+ defaultMessage: 'Other',
+ }),
+ displayName: i18n.translate('data.search.aggs.otherBucket.labelForOtherBucketLabel', {
+ defaultMessage: 'Label for other bucket',
}),
- value: 'desc',
+ shouldShow: agg => agg.getParam('otherBucket'),
+ write: noop,
},
{
- text: i18n.translate('data.search.aggs.buckets.terms.orderAscendingTitle', {
- defaultMessage: 'Ascending',
+ name: 'missingBucket',
+ default: false,
+ write: noop,
+ },
+ {
+ name: '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('data.search.aggs.otherBucket.labelForMissingValuesLabel', {
+ defaultMessage: 'Label for missing values',
}),
- value: 'asc',
+ shouldShow: agg => agg.getParam('missingBucket'),
+ write: noop,
+ },
+ {
+ name: 'exclude',
+ displayName: i18n.translate('data.search.aggs.buckets.terms.excludeLabel', {
+ defaultMessage: 'Exclude',
+ }),
+ type: 'string',
+ advanced: true,
+ shouldShow: isStringType,
+ ...migrateIncludeExcludeFormat,
+ },
+ {
+ name: 'include',
+ displayName: i18n.translate('data.search.aggs.buckets.terms.includeLabel', {
+ defaultMessage: 'Include',
+ }),
+ type: 'string',
+ advanced: true,
+ shouldShow: isStringType,
+ ...migrateIncludeExcludeFormat,
},
],
- write: noop, // prevent default write, it's handled by orderAgg
- },
- {
- name: 'size',
- default: 5,
- },
- {
- name: 'otherBucket',
- default: false,
- write: noop,
- },
- {
- name: 'otherBucketLabel',
- type: 'string',
- default: i18n.translate('data.search.aggs.buckets.terms.otherBucketLabel', {
- defaultMessage: 'Other',
- }),
- displayName: i18n.translate('data.search.aggs.otherBucket.labelForOtherBucketLabel', {
- defaultMessage: 'Label for other bucket',
- }),
- shouldShow: agg => agg.getParam('otherBucket'),
- write: noop,
- },
- {
- name: 'missingBucket',
- default: false,
- write: noop,
},
- {
- name: '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('data.search.aggs.otherBucket.labelForMissingValuesLabel', {
- defaultMessage: 'Label for missing values',
- }),
- shouldShow: agg => agg.getParam('missingBucket'),
- write: noop,
- },
- {
- name: 'exclude',
- displayName: i18n.translate('data.search.aggs.buckets.terms.excludeLabel', {
- defaultMessage: 'Exclude',
- }),
- type: 'string',
- advanced: true,
- shouldShow: isStringType,
- ...migrateIncludeExcludeFormat,
- },
- {
- name: 'include',
- displayName: i18n.translate('data.search.aggs.buckets.terms.includeLabel', {
- defaultMessage: 'Include',
- }),
- type: 'string',
- advanced: true,
- shouldShow: isStringType,
- ...migrateIncludeExcludeFormat,
- },
- ],
-});
+ { getInternalStartServices }
+ );
diff --git a/src/plugins/data/public/search/aggs/index.test.ts b/src/plugins/data/public/search/aggs/index.test.ts
index 8c0e47763c295..419c3fdab1caf 100644
--- a/src/plugins/data/public/search/aggs/index.test.ts
+++ b/src/plugins/data/public/search/aggs/index.test.ts
@@ -20,16 +20,22 @@
import { coreMock } from '../../../../../../src/core/public/mocks';
import { getAggTypes } from './index';
-import { isBucketAggType } from './buckets/_bucket_agg_type';
+import { isBucketAggType } from './buckets/bucket_agg_type';
import { isMetricAggType } from './metrics/metric_agg_type';
import { QueryStart } from '../../query';
+import { FieldFormatsStart } from '../../field_formats';
describe('AggTypesComponent', () => {
- const core = coreMock.createSetup();
+ const coreSetup = coreMock.createSetup();
+ const coreStart = coreMock.createSetup();
+
const aggTypes = getAggTypes({
- uiSettings: core.uiSettings,
- notifications: core.notifications,
+ uiSettings: coreSetup.uiSettings,
query: {} as QueryStart,
+ getInternalStartServices: () => ({
+ notifications: coreStart.notifications,
+ fieldFormats: {} as FieldFormatsStart,
+ }),
});
const { buckets, metrics } = aggTypes;
diff --git a/src/plugins/data/public/search/aggs/metrics/avg.ts b/src/plugins/data/public/search/aggs/metrics/avg.ts
index 008dede3e1985..d53ce8d3fc489 100644
--- a/src/plugins/data/public/search/aggs/metrics/avg.ts
+++ b/src/plugins/data/public/search/aggs/metrics/avg.ts
@@ -21,25 +21,37 @@ import { i18n } from '@kbn/i18n';
import { MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
const averageTitle = i18n.translate('data.search.aggs.metrics.averageTitle', {
defaultMessage: 'Average',
});
-export const avgMetricAgg = new MetricAggType({
- name: METRIC_TYPES.AVG,
- title: averageTitle,
- makeLabel: aggConfig => {
- return i18n.translate('data.search.aggs.metrics.averageLabel', {
- defaultMessage: 'Average {field}',
- values: { field: aggConfig.getFieldDisplayName() },
- });
- },
- params: [
+export interface AvgMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getAvgMetricAgg = ({ getInternalStartServices }: AvgMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'field',
- type: 'field',
- filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
+ name: METRIC_TYPES.AVG,
+ title: averageTitle,
+ makeLabel: aggConfig => {
+ return i18n.translate('data.search.aggs.metrics.averageLabel', {
+ defaultMessage: 'Average {field}',
+ values: { field: aggConfig.getFieldDisplayName() },
+ });
+ },
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
+ },
+ ],
},
- ],
-});
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts b/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts
index 11bb559274729..2c32ebc671539 100644
--- a/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts
+++ b/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts
@@ -23,6 +23,11 @@ import { MetricAggType } from './metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
import { METRIC_TYPES } from './metric_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface BucketAvgMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const overallAverageLabel = i18n.translate('data.search.aggs.metrics.overallAverageLabel', {
defaultMessage: 'overall average',
@@ -32,25 +37,34 @@ const averageBucketTitle = i18n.translate('data.search.aggs.metrics.averageBucke
defaultMessage: 'Average Bucket',
});
-export const bucketAvgMetricAgg = new MetricAggType({
- name: METRIC_TYPES.AVG_BUCKET,
- title: averageBucketTitle,
- makeLabel: agg => makeNestedLabel(agg, overallAverageLabel),
- subtype: siblingPipelineAggHelper.subtype,
- params: [...siblingPipelineAggHelper.params()],
- getFormat: siblingPipelineAggHelper.getFormat,
- getValue(agg, bucket) {
- const customMetric = agg.getParam('customMetric');
- const customBucket = agg.getParam('customBucket');
- const scaleMetrics = customMetric.type && customMetric.type.isScalable();
+export const getBucketAvgMetricAgg = ({
+ getInternalStartServices,
+}: BucketAvgMetricAggDependencies) => {
+ return new MetricAggType(
+ {
+ name: METRIC_TYPES.AVG_BUCKET,
+ title: averageBucketTitle,
+ makeLabel: agg => makeNestedLabel(agg, overallAverageLabel),
+ subtype: siblingPipelineAggHelper.subtype,
+ params: [...siblingPipelineAggHelper.params()],
+ getFormat: siblingPipelineAggHelper.getFormat,
+ getValue(agg, bucket) {
+ const customMetric = agg.getParam('customMetric');
+ const customBucket = agg.getParam('customBucket');
+ const scaleMetrics = customMetric.type && customMetric.type.isScalable();
- let value = bucket[agg.id] && bucket[agg.id].value;
+ let value = bucket[agg.id] && bucket[agg.id].value;
- if (scaleMetrics && customBucket.type.name === 'date_histogram') {
- const aggInfo = customBucket.write();
+ if (scaleMetrics && customBucket.type.name === 'date_histogram') {
+ const aggInfo = customBucket.write();
- value *= get(aggInfo, 'bucketInterval.scale', 1);
+ value *= get(aggInfo, 'bucketInterval.scale', 1);
+ }
+ return value;
+ },
+ },
+ {
+ getInternalStartServices,
}
- return value;
- },
-});
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_max.ts b/src/plugins/data/public/search/aggs/metrics/bucket_max.ts
index 0668a9bcf57a8..1e57a2dd8e38e 100644
--- a/src/plugins/data/public/search/aggs/metrics/bucket_max.ts
+++ b/src/plugins/data/public/search/aggs/metrics/bucket_max.ts
@@ -22,6 +22,11 @@ import { MetricAggType } from './metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
import { METRIC_TYPES } from './metric_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface BucketMaxMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const overallMaxLabel = i18n.translate('data.search.aggs.metrics.overallMaxLabel', {
defaultMessage: 'overall max',
@@ -31,11 +36,20 @@ const maxBucketTitle = i18n.translate('data.search.aggs.metrics.maxBucketTitle',
defaultMessage: 'Max Bucket',
});
-export const bucketMaxMetricAgg = new MetricAggType({
- name: METRIC_TYPES.MAX_BUCKET,
- title: maxBucketTitle,
- makeLabel: agg => makeNestedLabel(agg, overallMaxLabel),
- subtype: siblingPipelineAggHelper.subtype,
- params: [...siblingPipelineAggHelper.params()],
- getFormat: siblingPipelineAggHelper.getFormat,
-});
+export const getBucketMaxMetricAgg = ({
+ getInternalStartServices,
+}: BucketMaxMetricAggDependencies) => {
+ return new MetricAggType(
+ {
+ name: METRIC_TYPES.MAX_BUCKET,
+ title: maxBucketTitle,
+ makeLabel: agg => makeNestedLabel(agg, overallMaxLabel),
+ subtype: siblingPipelineAggHelper.subtype,
+ params: [...siblingPipelineAggHelper.params()],
+ getFormat: siblingPipelineAggHelper.getFormat,
+ },
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_min.ts b/src/plugins/data/public/search/aggs/metrics/bucket_min.ts
index 8f728cb5e7e42..0484af23a7141 100644
--- a/src/plugins/data/public/search/aggs/metrics/bucket_min.ts
+++ b/src/plugins/data/public/search/aggs/metrics/bucket_min.ts
@@ -22,6 +22,11 @@ import { MetricAggType } from './metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
import { METRIC_TYPES } from './metric_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface BucketMinMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const overallMinLabel = i18n.translate('data.search.aggs.metrics.overallMinLabel', {
defaultMessage: 'overall min',
@@ -31,11 +36,20 @@ const minBucketTitle = i18n.translate('data.search.aggs.metrics.minBucketTitle',
defaultMessage: 'Min Bucket',
});
-export const bucketMinMetricAgg = new MetricAggType({
- name: METRIC_TYPES.MIN_BUCKET,
- title: minBucketTitle,
- makeLabel: agg => makeNestedLabel(agg, overallMinLabel),
- subtype: siblingPipelineAggHelper.subtype,
- params: [...siblingPipelineAggHelper.params()],
- getFormat: siblingPipelineAggHelper.getFormat,
-});
+export const getBucketMinMetricAgg = ({
+ getInternalStartServices,
+}: BucketMinMetricAggDependencies) => {
+ return new MetricAggType(
+ {
+ name: METRIC_TYPES.MIN_BUCKET,
+ title: minBucketTitle,
+ makeLabel: agg => makeNestedLabel(agg, overallMinLabel),
+ subtype: siblingPipelineAggHelper.subtype,
+ params: [...siblingPipelineAggHelper.params()],
+ getFormat: siblingPipelineAggHelper.getFormat,
+ },
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts b/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts
index 1f9392c5bec35..0a4d29a18a980 100644
--- a/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts
+++ b/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts
@@ -22,6 +22,11 @@ import { MetricAggType } from './metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import { siblingPipelineAggHelper } from './lib/sibling_pipeline_agg_helper';
import { METRIC_TYPES } from './metric_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface BucketSumMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const overallSumLabel = i18n.translate('data.search.aggs.metrics.overallSumLabel', {
defaultMessage: 'overall sum',
@@ -31,11 +36,20 @@ const sumBucketTitle = i18n.translate('data.search.aggs.metrics.sumBucketTitle',
defaultMessage: 'Sum Bucket',
});
-export const bucketSumMetricAgg = new MetricAggType({
- name: METRIC_TYPES.SUM_BUCKET,
- title: sumBucketTitle,
- makeLabel: agg => makeNestedLabel(agg, overallSumLabel),
- subtype: siblingPipelineAggHelper.subtype,
- params: [...siblingPipelineAggHelper.params()],
- getFormat: siblingPipelineAggHelper.getFormat,
-});
+export const getBucketSumMetricAgg = ({
+ getInternalStartServices,
+}: BucketSumMetricAggDependencies) => {
+ return new MetricAggType(
+ {
+ name: METRIC_TYPES.SUM_BUCKET,
+ title: sumBucketTitle,
+ makeLabel: agg => makeNestedLabel(agg, overallSumLabel),
+ subtype: siblingPipelineAggHelper.subtype,
+ params: [...siblingPipelineAggHelper.params()],
+ getFormat: siblingPipelineAggHelper.getFormat,
+ },
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/cardinality.ts b/src/plugins/data/public/search/aggs/metrics/cardinality.ts
index 88cdf3175665e..10b6b5aff1abd 100644
--- a/src/plugins/data/public/search/aggs/metrics/cardinality.ts
+++ b/src/plugins/data/public/search/aggs/metrics/cardinality.ts
@@ -18,36 +18,48 @@
*/
import { i18n } from '@kbn/i18n';
-import { MetricAggType } from './metric_agg_type';
+import { MetricAggType, IMetricAggConfig } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
-import { getFieldFormats } from '../../../../public/services';
+import { GetInternalStartServicesFn } from '../../../types';
const uniqueCountTitle = i18n.translate('data.search.aggs.metrics.uniqueCountTitle', {
defaultMessage: 'Unique Count',
});
-export const cardinalityMetricAgg = new MetricAggType({
- name: METRIC_TYPES.CARDINALITY,
- title: uniqueCountTitle,
- makeLabel(aggConfig) {
- return i18n.translate('data.search.aggs.metrics.uniqueCountLabel', {
- defaultMessage: 'Unique count of {field}',
- values: { field: aggConfig.getFieldDisplayName() },
- });
- },
- getFormat() {
- const fieldFormatsService = getFieldFormats();
+export interface CardinalityMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
- return fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER);
- },
- params: [
+export const getCardinalityMetricAgg = ({
+ getInternalStartServices,
+}: CardinalityMetricAggDependencies) =>
+ new MetricAggType(
{
- name: 'field',
- type: 'field',
- filterFieldTypes: Object.values(KBN_FIELD_TYPES).filter(
- type => type !== KBN_FIELD_TYPES.HISTOGRAM
- ),
+ name: METRIC_TYPES.CARDINALITY,
+ title: uniqueCountTitle,
+ makeLabel(aggConfig: IMetricAggConfig) {
+ return i18n.translate('data.search.aggs.metrics.uniqueCountLabel', {
+ defaultMessage: 'Unique count of {field}',
+ values: { field: aggConfig.getFieldDisplayName() },
+ });
+ },
+ getFormat() {
+ const { fieldFormats } = getInternalStartServices();
+
+ return fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER);
+ },
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: Object.values(KBN_FIELD_TYPES).filter(
+ type => type !== KBN_FIELD_TYPES.HISTOGRAM
+ ),
+ },
+ ],
},
- ],
-});
+ {
+ getInternalStartServices,
+ }
+ );
diff --git a/src/plugins/data/public/search/aggs/metrics/count.ts b/src/plugins/data/public/search/aggs/metrics/count.ts
index 3ec1e18d66ab9..bd0b83798c7db 100644
--- a/src/plugins/data/public/search/aggs/metrics/count.ts
+++ b/src/plugins/data/public/search/aggs/metrics/count.ts
@@ -21,28 +21,38 @@ import { i18n } from '@kbn/i18n';
import { MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
-import { getFieldFormats } from '../../../../public/services';
+import { GetInternalStartServicesFn } from '../../../types';
-export const countMetricAgg = new MetricAggType({
- name: METRIC_TYPES.COUNT,
- title: i18n.translate('data.search.aggs.metrics.countTitle', {
- defaultMessage: 'Count',
- }),
- hasNoDsl: true,
- makeLabel() {
- return i18n.translate('data.search.aggs.metrics.countLabel', {
- defaultMessage: 'Count',
- });
- },
- getFormat() {
- const fieldFormatsService = getFieldFormats();
+export interface CountMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
- return fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER);
- },
- getValue(agg, bucket) {
- return bucket.doc_count;
- },
- isScalable() {
- return true;
- },
-});
+export const getCountMetricAgg = ({ getInternalStartServices }: CountMetricAggDependencies) =>
+ new MetricAggType(
+ {
+ name: METRIC_TYPES.COUNT,
+ title: i18n.translate('data.search.aggs.metrics.countTitle', {
+ defaultMessage: 'Count',
+ }),
+ hasNoDsl: true,
+ makeLabel() {
+ return i18n.translate('data.search.aggs.metrics.countLabel', {
+ defaultMessage: 'Count',
+ });
+ },
+ getFormat() {
+ const { fieldFormats } = getInternalStartServices();
+
+ return fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER);
+ },
+ getValue(agg, bucket) {
+ return bucket.doc_count;
+ },
+ isScalable() {
+ return true;
+ },
+ },
+ {
+ getInternalStartServices,
+ }
+ );
diff --git a/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts b/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts
index a5d02459900bb..8ca922e144a1f 100644
--- a/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts
+++ b/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts
@@ -22,6 +22,11 @@ import { MetricAggType } from './metric_agg_type';
import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper';
import { makeNestedLabel } from './lib/make_nested_label';
import { METRIC_TYPES } from './metric_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface CumulativeSumMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const cumulativeSumLabel = i18n.translate('data.search.aggs.metrics.cumulativeSumLabel', {
defaultMessage: 'cumulative sum',
@@ -31,11 +36,20 @@ const cumulativeSumTitle = i18n.translate('data.search.aggs.metrics.cumulativeSu
defaultMessage: 'Cumulative Sum',
});
-export const cumulativeSumMetricAgg = new MetricAggType({
- name: METRIC_TYPES.CUMULATIVE_SUM,
- title: cumulativeSumTitle,
- subtype: parentPipelineAggHelper.subtype,
- makeLabel: agg => makeNestedLabel(agg, cumulativeSumLabel),
- params: [...parentPipelineAggHelper.params()],
- getFormat: parentPipelineAggHelper.getFormat,
-});
+export const getCumulativeSumMetricAgg = ({
+ getInternalStartServices,
+}: CumulativeSumMetricAggDependencies) => {
+ return new MetricAggType(
+ {
+ name: METRIC_TYPES.CUMULATIVE_SUM,
+ title: cumulativeSumTitle,
+ subtype: parentPipelineAggHelper.subtype,
+ makeLabel: agg => makeNestedLabel(agg, cumulativeSumLabel),
+ params: [...parentPipelineAggHelper.params()],
+ getFormat: parentPipelineAggHelper.getFormat,
+ },
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/derivative.ts b/src/plugins/data/public/search/aggs/metrics/derivative.ts
index 1169a527b0668..5752a72c846aa 100644
--- a/src/plugins/data/public/search/aggs/metrics/derivative.ts
+++ b/src/plugins/data/public/search/aggs/metrics/derivative.ts
@@ -22,6 +22,11 @@ import { MetricAggType } from './metric_agg_type';
import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper';
import { makeNestedLabel } from './lib/make_nested_label';
import { METRIC_TYPES } from './metric_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface DerivativeMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const derivativeLabel = i18n.translate('data.search.aggs.metrics.derivativeLabel', {
defaultMessage: 'derivative',
@@ -31,13 +36,22 @@ const derivativeTitle = i18n.translate('data.search.aggs.metrics.derivativeTitle
defaultMessage: 'Derivative',
});
-export const derivativeMetricAgg = new MetricAggType({
- name: METRIC_TYPES.DERIVATIVE,
- title: derivativeTitle,
- subtype: parentPipelineAggHelper.subtype,
- makeLabel(agg) {
- return makeNestedLabel(agg, derivativeLabel);
- },
- params: [...parentPipelineAggHelper.params()],
- getFormat: parentPipelineAggHelper.getFormat,
-});
+export const getDerivativeMetricAgg = ({
+ getInternalStartServices,
+}: DerivativeMetricAggDependencies) => {
+ return new MetricAggType(
+ {
+ name: METRIC_TYPES.DERIVATIVE,
+ title: derivativeTitle,
+ subtype: parentPipelineAggHelper.subtype,
+ makeLabel(agg) {
+ return makeNestedLabel(agg, derivativeLabel);
+ },
+ params: [...parentPipelineAggHelper.params()],
+ getFormat: parentPipelineAggHelper.getFormat,
+ },
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/geo_bounds.ts b/src/plugins/data/public/search/aggs/metrics/geo_bounds.ts
index 8a9f66f4b22a8..00927ebba56bf 100644
--- a/src/plugins/data/public/search/aggs/metrics/geo_bounds.ts
+++ b/src/plugins/data/public/search/aggs/metrics/geo_bounds.ts
@@ -21,6 +21,11 @@ import { i18n } from '@kbn/i18n';
import { MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface GeoBoundsMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const geoBoundsTitle = i18n.translate('data.search.aggs.metrics.geoBoundsTitle', {
defaultMessage: 'Geo Bounds',
@@ -30,15 +35,24 @@ const geoBoundsLabel = i18n.translate('data.search.aggs.metrics.geoBoundsLabel',
defaultMessage: 'Geo Bounds',
});
-export const geoBoundsMetricAgg = new MetricAggType({
- name: METRIC_TYPES.GEO_BOUNDS,
- title: geoBoundsTitle,
- makeLabel: () => geoBoundsLabel,
- params: [
+export const getGeoBoundsMetricAgg = ({
+ getInternalStartServices,
+}: GeoBoundsMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'field',
- type: 'field',
- filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
+ name: METRIC_TYPES.GEO_BOUNDS,
+ title: geoBoundsTitle,
+ makeLabel: () => geoBoundsLabel,
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
+ },
+ ],
},
- ],
-});
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/geo_centroid.ts b/src/plugins/data/public/search/aggs/metrics/geo_centroid.ts
index a4e4413843bdd..a4b084f794a5d 100644
--- a/src/plugins/data/public/search/aggs/metrics/geo_centroid.ts
+++ b/src/plugins/data/public/search/aggs/metrics/geo_centroid.ts
@@ -21,6 +21,11 @@ import { i18n } from '@kbn/i18n';
import { MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface GeoCentroidMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const geoCentroidTitle = i18n.translate('data.search.aggs.metrics.geoCentroidTitle', {
defaultMessage: 'Geo Centroid',
@@ -30,18 +35,27 @@ const geoCentroidLabel = i18n.translate('data.search.aggs.metrics.geoCentroidLab
defaultMessage: 'Geo Centroid',
});
-export const geoCentroidMetricAgg = new MetricAggType({
- name: METRIC_TYPES.GEO_CENTROID,
- title: geoCentroidTitle,
- makeLabel: () => geoCentroidLabel,
- params: [
+export const getGeoCentroidMetricAgg = ({
+ getInternalStartServices,
+}: GeoCentroidMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'field',
- type: 'field',
- filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
+ name: METRIC_TYPES.GEO_CENTROID,
+ title: geoCentroidTitle,
+ makeLabel: () => geoCentroidLabel,
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: KBN_FIELD_TYPES.GEO_POINT,
+ },
+ ],
+ getValue(agg, bucket) {
+ return bucket[agg.id] && bucket[agg.id].location;
+ },
},
- ],
- getValue(agg, bucket) {
- return bucket[agg.id] && bucket[agg.id].location;
- },
-});
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/max.ts b/src/plugins/data/public/search/aggs/metrics/max.ts
index 0cfb7be699a95..88e8b485cb73f 100644
--- a/src/plugins/data/public/search/aggs/metrics/max.ts
+++ b/src/plugins/data/public/search/aggs/metrics/max.ts
@@ -21,25 +21,37 @@ import { i18n } from '@kbn/i18n';
import { MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
const maxTitle = i18n.translate('data.search.aggs.metrics.maxTitle', {
defaultMessage: 'Max',
});
-export const maxMetricAgg = new MetricAggType({
- name: METRIC_TYPES.MAX,
- title: maxTitle,
- makeLabel(aggConfig) {
- return i18n.translate('data.search.aggs.metrics.maxLabel', {
- defaultMessage: 'Max {field}',
- values: { field: aggConfig.getFieldDisplayName() },
- });
- },
- params: [
+export interface MaxMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getMaxMetricAgg = ({ getInternalStartServices }: MaxMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'field',
- type: 'field',
- filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE],
+ name: METRIC_TYPES.MAX,
+ title: maxTitle,
+ makeLabel(aggConfig) {
+ return i18n.translate('data.search.aggs.metrics.maxLabel', {
+ defaultMessage: 'Max {field}',
+ values: { field: aggConfig.getFieldDisplayName() },
+ });
+ },
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE],
+ },
+ ],
},
- ],
-});
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/median.test.ts b/src/plugins/data/public/search/aggs/metrics/median.test.ts
index ad55837ec9a30..f80c46026f50a 100644
--- a/src/plugins/data/public/search/aggs/metrics/median.test.ts
+++ b/src/plugins/data/public/search/aggs/metrics/median.test.ts
@@ -17,16 +17,24 @@
* under the License.
*/
-import { medianMetricAgg } from './median';
+import { getMedianMetricAgg, MedianMetricAggDependencies } from './median';
import { AggConfigs, IAggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { METRIC_TYPES } from './metric_agg_types';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
describe('AggTypeMetricMedianProvider class', () => {
let aggConfigs: IAggConfigs;
+ const aggTypesDependencies: MedianMetricAggDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
beforeEach(() => {
- const typesRegistry = mockAggTypesRegistry([medianMetricAgg]);
+ const typesRegistry = mockAggTypesRegistry([getMedianMetricAgg(aggTypesDependencies)]);
const field = {
name: 'bytes',
};
diff --git a/src/plugins/data/public/search/aggs/metrics/median.ts b/src/plugins/data/public/search/aggs/metrics/median.ts
index faa0694cd5312..a398f017602b0 100644
--- a/src/plugins/data/public/search/aggs/metrics/median.ts
+++ b/src/plugins/data/public/search/aggs/metrics/median.ts
@@ -21,33 +21,49 @@ import { i18n } from '@kbn/i18n';
import { MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
const medianTitle = i18n.translate('data.search.aggs.metrics.medianTitle', {
defaultMessage: 'Median',
});
-export const medianMetricAgg = new MetricAggType({
- name: METRIC_TYPES.MEDIAN,
- dslName: 'percentiles',
- title: medianTitle,
- makeLabel(aggConfig) {
- return i18n.translate('data.search.aggs.metrics.medianLabel', {
- defaultMessage: 'Median {field}',
- values: { field: aggConfig.getFieldDisplayName() },
- });
- },
- params: [
+export interface MedianMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getMedianMetricAgg = ({ getInternalStartServices }: MedianMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'field',
- type: 'field',
- filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE, KBN_FIELD_TYPES.HISTOGRAM],
- write(agg, output) {
- output.params.field = agg.getParam('field').name;
- output.params.percents = [50];
+ name: METRIC_TYPES.MEDIAN,
+ dslName: 'percentiles',
+ title: medianTitle,
+ makeLabel(aggConfig) {
+ return i18n.translate('data.search.aggs.metrics.medianLabel', {
+ defaultMessage: 'Median {field}',
+ values: { field: aggConfig.getFieldDisplayName() },
+ });
+ },
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: [
+ KBN_FIELD_TYPES.NUMBER,
+ KBN_FIELD_TYPES.DATE,
+ KBN_FIELD_TYPES.HISTOGRAM,
+ ],
+ write(agg, output) {
+ output.params.field = agg.getParam('field').name;
+ output.params.percents = [50];
+ },
+ },
+ ],
+ getValue(agg, bucket) {
+ return bucket[agg.id].values['50.0'];
},
},
- ],
- getValue(agg, bucket) {
- return bucket[agg.id].values['50.0'];
- },
-});
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts b/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts
index 05c4cb3de4bdf..bb16cba1bee62 100644
--- a/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts
+++ b/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts
@@ -23,8 +23,8 @@ import { AggParamType } from '../param_types/agg';
import { AggConfig } from '../agg_config';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
-import { getFieldFormats } from '../../../../public/services';
import { FieldTypes } from '../param_types';
+import { GetInternalStartServicesFn } from '../../../types';
export interface IMetricAggConfig extends AggConfig {
type: InstanceType;
@@ -44,6 +44,10 @@ interface MetricAggTypeConfig
subtype?: string;
}
+interface MetricAggTypeDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
// TODO need to make a more explicit interface for this
export type IMetricAggType = MetricAggType;
@@ -57,8 +61,11 @@ export class MetricAggType {};
- constructor(config: MetricAggTypeConfig) {
- super(config);
+ constructor(
+ config: MetricAggTypeConfig,
+ dependencies: MetricAggTypeDependencies
+ ) {
+ super(config, dependencies);
this.getValue =
config.getValue ||
@@ -78,11 +85,9 @@ export class MetricAggType {
- const fieldFormatsService = getFieldFormats();
+ const { fieldFormats } = dependencies.getInternalStartServices();
const field = agg.getField();
- return field
- ? field.format
- : fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER);
+ return field ? field.format : fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER);
});
this.subtype =
diff --git a/src/plugins/data/public/search/aggs/metrics/min.ts b/src/plugins/data/public/search/aggs/metrics/min.ts
index 0a9abf1edcd04..aae16f357186c 100644
--- a/src/plugins/data/public/search/aggs/metrics/min.ts
+++ b/src/plugins/data/public/search/aggs/metrics/min.ts
@@ -21,25 +21,37 @@ import { i18n } from '@kbn/i18n';
import { MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
const minTitle = i18n.translate('data.search.aggs.metrics.minTitle', {
defaultMessage: 'Min',
});
-export const minMetricAgg = new MetricAggType({
- name: METRIC_TYPES.MIN,
- title: minTitle,
- makeLabel(aggConfig) {
- return i18n.translate('data.search.aggs.metrics.minLabel', {
- defaultMessage: 'Min {field}',
- values: { field: aggConfig.getFieldDisplayName() },
- });
- },
- params: [
+export interface MinMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getMinMetricAgg = ({ getInternalStartServices }: MinMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'field',
- type: 'field',
- filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE],
+ name: METRIC_TYPES.MIN,
+ title: minTitle,
+ makeLabel(aggConfig) {
+ return i18n.translate('data.search.aggs.metrics.minLabel', {
+ defaultMessage: 'Min {field}',
+ values: { field: aggConfig.getFieldDisplayName() },
+ });
+ },
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE],
+ },
+ ],
},
- ],
-});
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/moving_avg.ts b/src/plugins/data/public/search/aggs/metrics/moving_avg.ts
index cb733507858bc..94b9b1d8cd487 100644
--- a/src/plugins/data/public/search/aggs/metrics/moving_avg.ts
+++ b/src/plugins/data/public/search/aggs/metrics/moving_avg.ts
@@ -22,6 +22,11 @@ import { MetricAggType } from './metric_agg_type';
import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper';
import { makeNestedLabel } from './lib/make_nested_label';
import { METRIC_TYPES } from './metric_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface MovingAvgMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const movingAvgTitle = i18n.translate('data.search.aggs.metrics.movingAvgTitle', {
defaultMessage: 'Moving Avg',
@@ -31,34 +36,43 @@ const movingAvgLabel = i18n.translate('data.search.aggs.metrics.movingAvgLabel',
defaultMessage: 'moving avg',
});
-export const movingAvgMetricAgg = new MetricAggType({
- name: METRIC_TYPES.MOVING_FN,
- dslName: 'moving_fn',
- title: movingAvgTitle,
- subtype: parentPipelineAggHelper.subtype,
- makeLabel: agg => makeNestedLabel(agg, movingAvgLabel),
- params: [
- ...parentPipelineAggHelper.params(),
+export const getMovingAvgMetricAgg = ({
+ getInternalStartServices,
+}: MovingAvgMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'window',
- default: 5,
+ name: METRIC_TYPES.MOVING_FN,
+ dslName: 'moving_fn',
+ title: movingAvgTitle,
+ subtype: parentPipelineAggHelper.subtype,
+ makeLabel: agg => makeNestedLabel(agg, movingAvgLabel),
+ params: [
+ ...parentPipelineAggHelper.params(),
+ {
+ name: 'window',
+ default: 5,
+ },
+ {
+ name: 'script',
+ default: 'MovingFunctions.unweightedAvg(values)',
+ },
+ ],
+ getValue(agg, bucket) {
+ /**
+ * The previous implementation using `moving_avg` did not
+ * return any bucket in case there are no documents or empty window.
+ * The `moving_fn` aggregation returns buckets with the value null if the
+ * window is empty or doesn't return any value if the sibiling metric
+ * is null. Since our generic MetricAggType.getValue implementation
+ * would return the value 0 for null buckets, we need a specific
+ * implementation here, that preserves the null value.
+ */
+ return bucket[agg.id] ? bucket[agg.id].value : null;
+ },
+ getFormat: parentPipelineAggHelper.getFormat,
},
{
- name: 'script',
- default: 'MovingFunctions.unweightedAvg(values)',
- },
- ],
- getValue(agg, bucket) {
- /**
- * The previous implementation using `moving_avg` did not
- * return any bucket in case there are no documents or empty window.
- * The `moving_fn` aggregation returns buckets with the value null if the
- * window is empty or doesn't return any value if the sibiling metric
- * is null. Since our generic MetricAggType.getValue implementation
- * would return the value 0 for null buckets, we need a specific
- * implementation here, that preserves the null value.
- */
- return bucket[agg.id] ? bucket[agg.id].value : null;
- },
- getFormat: parentPipelineAggHelper.getFormat,
-});
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts b/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts
index 02e63f653f94f..af983a50f6c23 100644
--- a/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts
+++ b/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts
@@ -17,26 +17,47 @@
* under the License.
*/
-import { derivativeMetricAgg } from './derivative';
-import { cumulativeSumMetricAgg } from './cumulative_sum';
-import { movingAvgMetricAgg } from './moving_avg';
-import { serialDiffMetricAgg } from './serial_diff';
+import { getDerivativeMetricAgg } from './derivative';
+import { getCumulativeSumMetricAgg } from './cumulative_sum';
+import { getMovingAvgMetricAgg } from './moving_avg';
+import { getSerialDiffMetricAgg } from './serial_diff';
import { AggConfigs } from '../agg_configs';
-import { mockDataServices, mockAggTypesRegistry } from '../test_helpers';
+import { mockAggTypesRegistry } from '../test_helpers';
import { IMetricAggConfig, MetricAggType } from './metric_agg_type';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { GetInternalStartServicesFn } from '../../../types';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
describe('parent pipeline aggs', function() {
- beforeEach(() => {
- mockDataServices();
+ const getInternalStartServices: GetInternalStartServicesFn = () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
});
const typesRegistry = mockAggTypesRegistry();
const metrics = [
- { name: 'derivative', title: 'Derivative', provider: derivativeMetricAgg },
- { name: 'cumulative_sum', title: 'Cumulative Sum', provider: cumulativeSumMetricAgg },
- { name: 'moving_avg', title: 'Moving Avg', provider: movingAvgMetricAgg, dslName: 'moving_fn' },
- { name: 'serial_diff', title: 'Serial Diff', provider: serialDiffMetricAgg },
+ {
+ name: 'derivative',
+ title: 'Derivative',
+ provider: getDerivativeMetricAgg({ getInternalStartServices }),
+ },
+ {
+ name: 'cumulative_sum',
+ title: 'Cumulative Sum',
+ provider: getCumulativeSumMetricAgg({ getInternalStartServices }),
+ },
+ {
+ name: 'moving_avg',
+ title: 'Moving Avg',
+ provider: getMovingAvgMetricAgg({ getInternalStartServices }),
+ dslName: 'moving_fn',
+ },
+ {
+ name: 'serial_diff',
+ title: 'Serial Diff',
+ provider: getSerialDiffMetricAgg({ getInternalStartServices }),
+ },
];
metrics.forEach(metric => {
diff --git a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts
index 628f1cd204ee5..2944fc8c11b23 100644
--- a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts
+++ b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts
@@ -17,18 +17,28 @@
* under the License.
*/
-import { IPercentileRanksAggConfig, percentileRanksMetricAgg } from './percentile_ranks';
+import {
+ IPercentileRanksAggConfig,
+ getPercentileRanksMetricAgg,
+ PercentileRanksMetricAggDependencies,
+} from './percentile_ranks';
import { AggConfigs, IAggConfigs } from '../agg_configs';
-import { mockDataServices, mockAggTypesRegistry } from '../test_helpers';
+import { mockAggTypesRegistry } from '../test_helpers';
import { METRIC_TYPES } from './metric_agg_types';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
describe('AggTypesMetricsPercentileRanksProvider class', function() {
let aggConfigs: IAggConfigs;
+ const aggTypesDependencies: PercentileRanksMetricAggDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
beforeEach(() => {
- mockDataServices();
-
- const typesRegistry = mockAggTypesRegistry([percentileRanksMetricAgg]);
+ const typesRegistry = mockAggTypesRegistry([getPercentileRanksMetricAgg(aggTypesDependencies)]);
const field = {
name: 'bytes',
};
@@ -65,7 +75,7 @@ describe('AggTypesMetricsPercentileRanksProvider class', function() {
});
it('uses the custom label if it is set', function() {
- const responseAggs: any = percentileRanksMetricAgg.getResponseAggs(
+ const responseAggs: any = getPercentileRanksMetricAgg(aggTypesDependencies).getResponseAggs(
aggConfigs.aggs[0] as IPercentileRanksAggConfig
);
diff --git a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts
index 7dc0f70ea7b80..0d79665ff9c4e 100644
--- a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts
+++ b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts
@@ -23,68 +23,86 @@ import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_respons
import { getPercentileValue } from './percentiles_get_value';
import { METRIC_TYPES } from './metric_agg_types';
import { FIELD_FORMAT_IDS, KBN_FIELD_TYPES } from '../../../../common';
-import { getFieldFormats } from '../../../../public/services';
+import { GetInternalStartServicesFn } from '../../../types';
// required by the values editor
export type IPercentileRanksAggConfig = IResponseAggConfig;
-const valueProps = {
- makeLabel(this: IPercentileRanksAggConfig) {
- const fieldFormatsService = getFieldFormats();
- const field = this.getField();
- const format =
- (field && field.format) || fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER);
- const customLabel = this.getParam('customLabel');
- const label = customLabel || this.getFieldDisplayName();
+export interface PercentileRanksMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
- return i18n.translate('data.search.aggs.metrics.percentileRanks.valuePropsLabel', {
- defaultMessage: 'Percentile rank {format} of "{label}"',
- values: { format: format.convert(this.key, 'text'), label },
- });
- },
-};
+const getValueProps = (getInternalStartServices: GetInternalStartServicesFn) => {
+ return {
+ makeLabel(this: IPercentileRanksAggConfig) {
+ const { fieldFormats } = getInternalStartServices();
+ const field = this.getField();
+ const format =
+ (field && field.format) || fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER);
+ const customLabel = this.getParam('customLabel');
+ const label = customLabel || this.getFieldDisplayName();
-export const percentileRanksMetricAgg = new MetricAggType({
- name: METRIC_TYPES.PERCENTILE_RANKS,
- title: i18n.translate('data.search.aggs.metrics.percentileRanksTitle', {
- defaultMessage: 'Percentile Ranks',
- }),
- makeLabel(agg) {
- return i18n.translate('data.search.aggs.metrics.percentileRanksLabel', {
- defaultMessage: 'Percentile ranks of {field}',
- values: { field: agg.getFieldDisplayName() },
- });
- },
- params: [
- {
- name: 'field',
- type: 'field',
- filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.HISTOGRAM],
- },
- {
- name: 'values',
- default: [],
+ return i18n.translate('data.search.aggs.metrics.percentileRanks.valuePropsLabel', {
+ defaultMessage: 'Percentile rank {format} of "{label}"',
+ values: { format: format.convert(this.key, 'text'), label },
+ });
},
+ };
+};
+
+export const getPercentileRanksMetricAgg = ({
+ getInternalStartServices,
+}: PercentileRanksMetricAggDependencies) => {
+ return new MetricAggType(
{
- write(agg, output) {
- output.params.keyed = false;
+ name: METRIC_TYPES.PERCENTILE_RANKS,
+ title: i18n.translate('data.search.aggs.metrics.percentileRanksTitle', {
+ defaultMessage: 'Percentile Ranks',
+ }),
+ makeLabel(agg) {
+ return i18n.translate('data.search.aggs.metrics.percentileRanksLabel', {
+ defaultMessage: 'Percentile ranks of {field}',
+ values: { field: agg.getFieldDisplayName() },
+ });
},
- },
- ],
- getResponseAggs(agg) {
- const ValueAggConfig = getResponseAggConfigClass(agg, valueProps);
- const values = agg.getParam('values');
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.HISTOGRAM],
+ },
+ {
+ name: 'values',
+ default: [],
+ },
+ {
+ write(agg, output) {
+ output.params.keyed = false;
+ },
+ },
+ ],
+ getResponseAggs(agg) {
+ const ValueAggConfig = getResponseAggConfigClass(
+ agg,
+ getValueProps(getInternalStartServices)
+ );
+ const values = agg.getParam('values');
- return values.map((value: any) => new ValueAggConfig(value));
- },
- getFormat() {
- const fieldFormatsService = getFieldFormats();
- return (
- fieldFormatsService.getInstance(FIELD_FORMAT_IDS.PERCENT) ||
- fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.NUMBER)
- );
- },
- getValue(agg, bucket) {
- return getPercentileValue(agg, bucket) / 100;
- },
-});
+ return values.map((value: any) => new ValueAggConfig(value));
+ },
+ getFormat() {
+ const { fieldFormats } = getInternalStartServices();
+ return (
+ fieldFormats.getInstance(FIELD_FORMAT_IDS.PERCENT) ||
+ fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER)
+ );
+ },
+ getValue(agg, bucket) {
+ return getPercentileValue(agg, bucket) / 100;
+ },
+ },
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts b/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts
index e077bc0f8c773..33bd42df74cc7 100644
--- a/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts
+++ b/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts
@@ -17,16 +17,28 @@
* under the License.
*/
-import { IPercentileAggConfig, percentilesMetricAgg } from './percentiles';
+import {
+ IPercentileAggConfig,
+ getPercentilesMetricAgg,
+ PercentilesMetricAggDependencies,
+} from './percentiles';
import { AggConfigs, IAggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { METRIC_TYPES } from './metric_agg_types';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
describe('AggTypesMetricsPercentilesProvider class', () => {
let aggConfigs: IAggConfigs;
+ const aggTypesDependencies: PercentilesMetricAggDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
beforeEach(() => {
- const typesRegistry = mockAggTypesRegistry([percentilesMetricAgg]);
+ const typesRegistry = mockAggTypesRegistry([getPercentilesMetricAgg(aggTypesDependencies)]);
const field = {
name: 'bytes',
};
@@ -63,7 +75,7 @@ describe('AggTypesMetricsPercentilesProvider class', () => {
});
it('uses the custom label if it is set', () => {
- const responseAggs: any = percentilesMetricAgg.getResponseAggs(
+ const responseAggs: any = getPercentilesMetricAgg(aggTypesDependencies).getResponseAggs(
aggConfigs.aggs[0] as IPercentileAggConfig
);
diff --git a/src/plugins/data/public/search/aggs/metrics/percentiles.ts b/src/plugins/data/public/search/aggs/metrics/percentiles.ts
index a39d68248d608..040a52588dd94 100644
--- a/src/plugins/data/public/search/aggs/metrics/percentiles.ts
+++ b/src/plugins/data/public/search/aggs/metrics/percentiles.ts
@@ -24,9 +24,14 @@ import { KBN_FIELD_TYPES } from '../../../../common';
import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class';
import { getPercentileValue } from './percentiles_get_value';
import { ordinalSuffix } from './lib/ordinal_suffix';
+import { GetInternalStartServicesFn } from '../../../types';
export type IPercentileAggConfig = IResponseAggConfig;
+export interface PercentilesMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
const valueProps = {
makeLabel(this: IPercentileAggConfig) {
const customLabel = this.getParam('customLabel');
@@ -39,38 +44,51 @@ const valueProps = {
},
};
-export const percentilesMetricAgg = new MetricAggType({
- name: METRIC_TYPES.PERCENTILES,
- title: i18n.translate('data.search.aggs.metrics.percentilesTitle', {
- defaultMessage: 'Percentiles',
- }),
- makeLabel(agg) {
- return i18n.translate('data.search.aggs.metrics.percentilesLabel', {
- defaultMessage: 'Percentiles of {field}',
- values: { field: agg.getFieldDisplayName() },
- });
- },
- params: [
- {
- name: 'field',
- type: 'field',
- filterFieldTypes: [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.DATE, KBN_FIELD_TYPES.HISTOGRAM],
- },
- {
- name: 'percents',
- default: [1, 5, 25, 50, 75, 95, 99],
- },
+export const getPercentilesMetricAgg = ({
+ getInternalStartServices,
+}: PercentilesMetricAggDependencies) => {
+ return new MetricAggType(
{
- write(agg, output) {
- output.params.keyed = false;
+ name: METRIC_TYPES.PERCENTILES,
+ title: i18n.translate('data.search.aggs.metrics.percentilesTitle', {
+ defaultMessage: 'Percentiles',
+ }),
+ makeLabel(agg) {
+ return i18n.translate('data.search.aggs.metrics.percentilesLabel', {
+ defaultMessage: 'Percentiles of {field}',
+ values: { field: agg.getFieldDisplayName() },
+ });
},
- },
- ],
- getResponseAggs(agg) {
- const ValueAggConfig = getResponseAggConfigClass(agg, valueProps);
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: [
+ KBN_FIELD_TYPES.NUMBER,
+ KBN_FIELD_TYPES.DATE,
+ KBN_FIELD_TYPES.HISTOGRAM,
+ ],
+ },
+ {
+ name: 'percents',
+ default: [1, 5, 25, 50, 75, 95, 99],
+ },
+ {
+ write(agg, output) {
+ output.params.keyed = false;
+ },
+ },
+ ],
+ getResponseAggs(agg) {
+ const ValueAggConfig = getResponseAggConfigClass(agg, valueProps);
- return agg.getParam('percents').map((percent: any) => new ValueAggConfig(percent));
- },
+ return agg.getParam('percents').map((percent: any) => new ValueAggConfig(percent));
+ },
- getValue: getPercentileValue,
-});
+ getValue: getPercentileValue,
+ },
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/serial_diff.ts b/src/plugins/data/public/search/aggs/metrics/serial_diff.ts
index 5af6e1952d135..2b1498560f862 100644
--- a/src/plugins/data/public/search/aggs/metrics/serial_diff.ts
+++ b/src/plugins/data/public/search/aggs/metrics/serial_diff.ts
@@ -22,6 +22,11 @@ import { MetricAggType } from './metric_agg_type';
import { parentPipelineAggHelper } from './lib/parent_pipeline_agg_helper';
import { makeNestedLabel } from './lib/make_nested_label';
import { METRIC_TYPES } from './metric_agg_types';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface SerialDiffMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const serialDiffTitle = i18n.translate('data.search.aggs.metrics.serialDiffTitle', {
defaultMessage: 'Serial Diff',
@@ -31,11 +36,20 @@ const serialDiffLabel = i18n.translate('data.search.aggs.metrics.serialDiffLabel
defaultMessage: 'serial diff',
});
-export const serialDiffMetricAgg = new MetricAggType({
- name: METRIC_TYPES.SERIAL_DIFF,
- title: serialDiffTitle,
- subtype: parentPipelineAggHelper.subtype,
- makeLabel: agg => makeNestedLabel(agg, serialDiffLabel),
- params: [...parentPipelineAggHelper.params()],
- getFormat: parentPipelineAggHelper.getFormat,
-});
+export const getSerialDiffMetricAgg = ({
+ getInternalStartServices,
+}: SerialDiffMetricAggDependencies) => {
+ return new MetricAggType(
+ {
+ name: METRIC_TYPES.SERIAL_DIFF,
+ title: serialDiffTitle,
+ subtype: parentPipelineAggHelper.subtype,
+ makeLabel: agg => makeNestedLabel(agg, serialDiffLabel),
+ params: [...parentPipelineAggHelper.params()],
+ getFormat: parentPipelineAggHelper.getFormat,
+ },
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts b/src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts
index 8389ed8262ce5..ab480fe44227e 100644
--- a/src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts
+++ b/src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts
@@ -17,27 +17,47 @@
* under the License.
*/
-import { bucketSumMetricAgg } from './bucket_sum';
-import { bucketAvgMetricAgg } from './bucket_avg';
-import { bucketMinMetricAgg } from './bucket_min';
-import { bucketMaxMetricAgg } from './bucket_max';
+import { getBucketSumMetricAgg } from './bucket_sum';
+import { getBucketAvgMetricAgg } from './bucket_avg';
+import { getBucketMinMetricAgg } from './bucket_min';
+import { getBucketMaxMetricAgg } from './bucket_max';
import { AggConfigs } from '../agg_configs';
import { IMetricAggConfig, MetricAggType } from './metric_agg_type';
-import { mockDataServices, mockAggTypesRegistry } from '../test_helpers';
+import { mockAggTypesRegistry } from '../test_helpers';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { GetInternalStartServicesFn } from '../../../types';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
describe('sibling pipeline aggs', () => {
- beforeEach(() => {
- mockDataServices();
+ const getInternalStartServices: GetInternalStartServicesFn = () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
});
const typesRegistry = mockAggTypesRegistry();
const metrics = [
- { name: 'sum_bucket', title: 'Overall Sum', provider: bucketSumMetricAgg },
- { name: 'avg_bucket', title: 'Overall Average', provider: bucketAvgMetricAgg },
- { name: 'min_bucket', title: 'Overall Min', provider: bucketMinMetricAgg },
- { name: 'max_bucket', title: 'Overall Max', provider: bucketMaxMetricAgg },
+ {
+ name: 'sum_bucket',
+ title: 'Overall Sum',
+ provider: getBucketSumMetricAgg({ getInternalStartServices }),
+ },
+ {
+ name: 'avg_bucket',
+ title: 'Overall Average',
+ provider: getBucketAvgMetricAgg({ getInternalStartServices }),
+ },
+ {
+ name: 'min_bucket',
+ title: 'Overall Min',
+ provider: getBucketMinMetricAgg({ getInternalStartServices }),
+ },
+ {
+ name: 'max_bucket',
+ title: 'Overall Max',
+ provider: getBucketMaxMetricAgg({ getInternalStartServices }),
+ },
];
metrics.forEach(metric => {
diff --git a/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts b/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts
index 0679831b1e6ac..6bbff3009cc11 100644
--- a/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts
+++ b/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts
@@ -17,13 +17,25 @@
* under the License.
*/
-import { IStdDevAggConfig, stdDeviationMetricAgg } from './std_deviation';
+import {
+ IStdDevAggConfig,
+ getStdDeviationMetricAgg,
+ StdDeviationMetricAggDependencies,
+} from './std_deviation';
import { AggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { METRIC_TYPES } from './metric_agg_types';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
describe('AggTypeMetricStandardDeviationProvider class', () => {
- const typesRegistry = mockAggTypesRegistry([stdDeviationMetricAgg]);
+ const aggTypesDependencies: StdDeviationMetricAggDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
+ const typesRegistry = mockAggTypesRegistry([getStdDeviationMetricAgg(aggTypesDependencies)]);
const getAggConfigs = (customLabel?: string) => {
const field = {
name: 'memory',
@@ -58,7 +70,7 @@ describe('AggTypeMetricStandardDeviationProvider class', () => {
it('uses the custom label if it is set', () => {
const aggConfigs = getAggConfigs('custom label');
- const responseAggs: any = stdDeviationMetricAgg.getResponseAggs(
+ const responseAggs: any = getStdDeviationMetricAgg(aggTypesDependencies).getResponseAggs(
aggConfigs.aggs[0] as IStdDevAggConfig
);
@@ -72,7 +84,7 @@ describe('AggTypeMetricStandardDeviationProvider class', () => {
it('uses the default labels if custom label is not set', () => {
const aggConfigs = getAggConfigs();
- const responseAggs: any = stdDeviationMetricAgg.getResponseAggs(
+ const responseAggs: any = getStdDeviationMetricAgg(aggTypesDependencies).getResponseAggs(
aggConfigs.aggs[0] as IStdDevAggConfig
);
diff --git a/src/plugins/data/public/search/aggs/metrics/std_deviation.ts b/src/plugins/data/public/search/aggs/metrics/std_deviation.ts
index 5e069e317e052..e972132542ceb 100644
--- a/src/plugins/data/public/search/aggs/metrics/std_deviation.ts
+++ b/src/plugins/data/public/search/aggs/metrics/std_deviation.ts
@@ -23,6 +23,7 @@ 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 '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
interface ValProp {
valProp: string[];
@@ -34,6 +35,10 @@ export interface IStdDevAggConfig extends IResponseAggConfig {
valProp: () => ValProp;
}
+export interface StdDeviationMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
const responseAggConfigProps = {
valProp(this: IStdDevAggConfig) {
const customLabel = this.getParam('customLabel');
@@ -75,33 +80,42 @@ const responseAggConfigProps = {
},
};
-export const stdDeviationMetricAgg = new MetricAggType({
- name: METRIC_TYPES.STD_DEV,
- dslName: 'extended_stats',
- title: i18n.translate('data.search.aggs.metrics.standardDeviationTitle', {
- defaultMessage: 'Standard Deviation',
- }),
- makeLabel(agg) {
- return i18n.translate('data.search.aggs.metrics.standardDeviationLabel', {
- defaultMessage: 'Standard Deviation of {field}',
- values: { field: agg.getFieldDisplayName() },
- });
- },
- params: [
+export const getStdDeviationMetricAgg = ({
+ getInternalStartServices,
+}: StdDeviationMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'field',
- type: 'field',
- filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
- },
- ],
+ name: METRIC_TYPES.STD_DEV,
+ dslName: 'extended_stats',
+ title: i18n.translate('data.search.aggs.metrics.standardDeviationTitle', {
+ defaultMessage: 'Standard Deviation',
+ }),
+ makeLabel(agg) {
+ return i18n.translate('data.search.aggs.metrics.standardDeviationLabel', {
+ defaultMessage: 'Standard Deviation of {field}',
+ values: { field: agg.getFieldDisplayName() },
+ });
+ },
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
+ },
+ ],
- getResponseAggs(agg) {
- const ValueAggConfig = getResponseAggConfigClass(agg, responseAggConfigProps);
+ getResponseAggs(agg) {
+ const ValueAggConfig = getResponseAggConfigClass(agg, responseAggConfigProps);
- return [new ValueAggConfig('std_lower'), new ValueAggConfig('std_upper')];
- },
+ return [new ValueAggConfig('std_lower'), new ValueAggConfig('std_upper')];
+ },
- getValue(agg, bucket) {
- return get(bucket[agg.parentId], agg.valProp());
- },
-});
+ getValue(agg, bucket) {
+ return get(bucket[agg.parentId], agg.valProp());
+ },
+ },
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/sum.ts b/src/plugins/data/public/search/aggs/metrics/sum.ts
index ffb117dda0839..545c6d6a4939e 100644
--- a/src/plugins/data/public/search/aggs/metrics/sum.ts
+++ b/src/plugins/data/public/search/aggs/metrics/sum.ts
@@ -21,28 +21,40 @@ import { i18n } from '@kbn/i18n';
import { MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
const sumTitle = i18n.translate('data.search.aggs.metrics.sumTitle', {
defaultMessage: 'Sum',
});
-export const sumMetricAgg = new MetricAggType({
- name: METRIC_TYPES.SUM,
- title: sumTitle,
- makeLabel(aggConfig) {
- return i18n.translate('data.search.aggs.metrics.sumLabel', {
- defaultMessage: 'Sum of {field}',
- values: { field: aggConfig.getFieldDisplayName() },
- });
- },
- isScalable() {
- return true;
- },
- params: [
+export interface SumMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
+export const getSumMetricAgg = ({ getInternalStartServices }: SumMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'field',
- type: 'field',
- filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
+ name: METRIC_TYPES.SUM,
+ title: sumTitle,
+ makeLabel(aggConfig) {
+ return i18n.translate('data.search.aggs.metrics.sumLabel', {
+ defaultMessage: 'Sum of {field}',
+ values: { field: aggConfig.getFieldDisplayName() },
+ });
+ },
+ isScalable() {
+ return true;
+ },
+ params: [
+ {
+ name: 'field',
+ type: 'field',
+ filterFieldTypes: KBN_FIELD_TYPES.NUMBER,
+ },
+ ],
},
- ],
-});
+ {
+ getInternalStartServices,
+ }
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts b/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts
index c65a714f26247..8294ad09bae22 100644
--- a/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts
+++ b/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts
@@ -18,15 +18,23 @@
*/
import { dropRight, last } from 'lodash';
-import { topHitMetricAgg } from './top_hit';
+import { getTopHitMetricAgg, TopHitMetricAggDependencies } from './top_hit';
import { AggConfigs } from '../agg_configs';
import { mockAggTypesRegistry } from '../test_helpers';
import { IMetricAggConfig } from './metric_agg_type';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
describe('Top hit metric', () => {
let aggDsl: Record;
let aggConfig: IMetricAggConfig;
+ const aggTypesDependencies: TopHitMetricAggDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
const init = ({
fieldName = 'field',
@@ -36,7 +44,7 @@ describe('Top hit metric', () => {
fieldType = KBN_FIELD_TYPES.NUMBER,
size = 1,
}: any) => {
- const typesRegistry = mockAggTypesRegistry([topHitMetricAgg]);
+ const typesRegistry = mockAggTypesRegistry([getTopHitMetricAgg(aggTypesDependencies)]);
const field = {
name: fieldName,
displayName: fieldName,
@@ -91,7 +99,7 @@ describe('Top hit metric', () => {
it('should return a label prefixed with Last if sorting in descending order', () => {
init({ fieldName: 'bytes' });
- expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('Last bytes');
+ expect(getTopHitMetricAgg(aggTypesDependencies).makeLabel(aggConfig)).toEqual('Last bytes');
});
it('should return a label prefixed with First if sorting in ascending order', () => {
@@ -99,7 +107,7 @@ describe('Top hit metric', () => {
fieldName: 'bytes',
sortOrder: 'asc',
});
- expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('First bytes');
+ expect(getTopHitMetricAgg(aggTypesDependencies).makeLabel(aggConfig)).toEqual('First bytes');
});
it('should request the _source field', () => {
@@ -140,7 +148,7 @@ describe('Top hit metric', () => {
};
init({ fieldName: '@tags' });
- expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe(null);
+ expect(getTopHitMetricAgg(aggTypesDependencies).getValue(aggConfig, bucket)).toBe(null);
});
//
it('should return undefined if the field does not appear in the source', () => {
@@ -159,7 +167,7 @@ describe('Top hit metric', () => {
};
init({ fieldName: '@tags' });
- expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe(undefined);
+ expect(getTopHitMetricAgg(aggTypesDependencies).getValue(aggConfig, bucket)).toBe(undefined);
});
it('should return the field value from the top hit', () => {
@@ -178,7 +186,7 @@ describe('Top hit metric', () => {
};
init({ fieldName: '@tags' });
- expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe('aaa');
+ expect(getTopHitMetricAgg(aggTypesDependencies).getValue(aggConfig, bucket)).toBe('aaa');
});
it('should return the object if the field value is an object', () => {
@@ -200,7 +208,9 @@ describe('Top hit metric', () => {
init({ fieldName: '@tags' });
- expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual({ label: 'aaa' });
+ expect(getTopHitMetricAgg(aggTypesDependencies).getValue(aggConfig, bucket)).toEqual({
+ label: 'aaa',
+ });
});
it('should return an array if the field has more than one values', () => {
@@ -219,7 +229,10 @@ describe('Top hit metric', () => {
};
init({ fieldName: '@tags' });
- expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual(['aaa', 'bbb']);
+ expect(getTopHitMetricAgg(aggTypesDependencies).getValue(aggConfig, bucket)).toEqual([
+ 'aaa',
+ 'bbb',
+ ]);
});
it('should return undefined if the field is not in the source nor in the doc_values field', () => {
@@ -241,7 +254,7 @@ describe('Top hit metric', () => {
};
init({ fieldName: 'machine.os.raw', readFromDocValues: true });
- expect(topHitMetricAgg.getValue(aggConfig, bucket)).toBe(undefined);
+ expect(getTopHitMetricAgg(aggTypesDependencies).getValue(aggConfig, bucket)).toBe(undefined);
});
describe('Multivalued field and first/last X docs', () => {
@@ -250,7 +263,9 @@ describe('Top hit metric', () => {
fieldName: 'bytes',
size: 2,
});
- expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('Last 2 bytes');
+ expect(getTopHitMetricAgg(aggTypesDependencies).makeLabel(aggConfig)).toEqual(
+ 'Last 2 bytes'
+ );
});
it('should return a label prefixed with First X docs if sorting in ascending order', () => {
@@ -259,7 +274,9 @@ describe('Top hit metric', () => {
size: 2,
sortOrder: 'asc',
});
- expect(topHitMetricAgg.makeLabel(aggConfig)).toEqual('First 2 bytes');
+ expect(getTopHitMetricAgg(aggTypesDependencies).makeLabel(aggConfig)).toEqual(
+ 'First 2 bytes'
+ );
});
[
@@ -334,7 +351,9 @@ describe('Top hit metric', () => {
};
init({ fieldName: 'bytes', aggregate: agg.type });
- expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual(agg.result);
+ expect(getTopHitMetricAgg(aggTypesDependencies).getValue(aggConfig, bucket)).toEqual(
+ agg.result
+ );
});
it(`should return the result of the ${agg.type} aggregation over the last X docs - ${agg.description}`, () => {
@@ -358,7 +377,9 @@ describe('Top hit metric', () => {
};
init({ fieldName: 'bytes', aggregate: agg.type });
- expect(topHitMetricAgg.getValue(aggConfig, bucket)).toEqual(agg.result);
+ expect(getTopHitMetricAgg(aggTypesDependencies).getValue(aggConfig, bucket)).toEqual(
+ agg.result
+ );
});
});
});
diff --git a/src/plugins/data/public/search/aggs/metrics/top_hit.ts b/src/plugins/data/public/search/aggs/metrics/top_hit.ts
index d0c668c577e62..15da2b485aee7 100644
--- a/src/plugins/data/public/search/aggs/metrics/top_hit.ts
+++ b/src/plugins/data/public/search/aggs/metrics/top_hit.ts
@@ -22,6 +22,11 @@ import { i18n } from '@kbn/i18n';
import { IMetricAggConfig, MetricAggType } from './metric_agg_type';
import { METRIC_TYPES } from './metric_agg_types';
import { KBN_FIELD_TYPES } from '../../../../common';
+import { GetInternalStartServicesFn } from '../../../types';
+
+export interface TopHitMetricAggDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
const isNumericFieldSelected = (agg: IMetricAggConfig) => {
const field = agg.getParam('field');
@@ -29,214 +34,225 @@ const isNumericFieldSelected = (agg: IMetricAggConfig) => {
return field && field.type && field.type === KBN_FIELD_TYPES.NUMBER;
};
-export const topHitMetricAgg = new MetricAggType({
- name: METRIC_TYPES.TOP_HITS,
- title: i18n.translate('data.search.aggs.metrics.topHitTitle', {
- defaultMessage: 'Top Hit',
- }),
- makeLabel(aggConfig) {
- const lastPrefixLabel = i18n.translate('data.search.aggs.metrics.topHit.lastPrefixLabel', {
- defaultMessage: 'Last',
- });
- const firstPrefixLabel = i18n.translate('data.search.aggs.metrics.topHit.firstPrefixLabel', {
- defaultMessage: 'First',
- });
-
- let prefix =
- aggConfig.getParam('sortOrder').value === 'desc' ? lastPrefixLabel : firstPrefixLabel;
-
- const size = aggConfig.getParam('size');
-
- if (size !== 1) {
- prefix += ` ${size}`;
- }
-
- const field = aggConfig.getParam('field');
-
- return `${prefix} ${field ? field.displayName : ''}`;
- },
- params: [
+export const getTopHitMetricAgg = ({ getInternalStartServices }: TopHitMetricAggDependencies) => {
+ return new MetricAggType(
{
- name: 'field',
- type: 'field',
- onlyAggregatable: false,
- filterFieldTypes: Object.values(KBN_FIELD_TYPES).filter(
- type => type !== KBN_FIELD_TYPES.HISTOGRAM
- ),
- write(agg, output) {
- const field = agg.getParam('field');
- output.params = {};
-
- if (field.scripted) {
- output.params.script_fields = {
- [field.name]: {
- script: {
- source: field.script,
- lang: field.lang,
- },
- },
- };
- } else {
- if (field.readFromDocValues) {
- // always format date fields as date_time to avoid
- // displaying unformatted dates like epoch_millis
- // or other not-accepted momentjs formats
- const format = field.type === KBN_FIELD_TYPES.DATE ? 'date_time' : 'use_field_mapping';
- output.params.docvalue_fields = [{ field: field.name, format }];
+ name: METRIC_TYPES.TOP_HITS,
+ title: i18n.translate('data.search.aggs.metrics.topHitTitle', {
+ defaultMessage: 'Top Hit',
+ }),
+ makeLabel(aggConfig) {
+ const lastPrefixLabel = i18n.translate('data.search.aggs.metrics.topHit.lastPrefixLabel', {
+ defaultMessage: 'Last',
+ });
+ const firstPrefixLabel = i18n.translate(
+ 'data.search.aggs.metrics.topHit.firstPrefixLabel',
+ {
+ defaultMessage: 'First',
}
- output.params._source = field.name === '_source' ? true : field.name;
+ );
+
+ let prefix =
+ aggConfig.getParam('sortOrder').value === 'desc' ? lastPrefixLabel : firstPrefixLabel;
+
+ const size = aggConfig.getParam('size');
+
+ if (size !== 1) {
+ prefix += ` ${size}`;
}
+
+ const field = aggConfig.getParam('field');
+
+ return `${prefix} ${field ? field.displayName : ''}`;
},
- },
- {
- name: 'aggregate',
- type: 'optioned',
- options: [
+ params: [
{
- text: i18n.translate('data.search.aggs.metrics.topHit.minLabel', {
- defaultMessage: 'Min',
- }),
- isCompatible: isNumericFieldSelected,
- disabled: true,
- value: 'min',
- },
- {
- text: i18n.translate('data.search.aggs.metrics.topHit.maxLabel', {
- defaultMessage: 'Max',
- }),
- isCompatible: isNumericFieldSelected,
- disabled: true,
- value: 'max',
+ name: 'field',
+ type: 'field',
+ onlyAggregatable: false,
+ filterFieldTypes: Object.values(KBN_FIELD_TYPES).filter(
+ type => type !== KBN_FIELD_TYPES.HISTOGRAM
+ ),
+ write(agg, output) {
+ const field = agg.getParam('field');
+ output.params = {};
+
+ if (field.scripted) {
+ output.params.script_fields = {
+ [field.name]: {
+ script: {
+ source: field.script,
+ lang: field.lang,
+ },
+ },
+ };
+ } else {
+ if (field.readFromDocValues) {
+ // always format date fields as date_time to avoid
+ // displaying unformatted dates like epoch_millis
+ // or other not-accepted momentjs formats
+ const format =
+ field.type === KBN_FIELD_TYPES.DATE ? 'date_time' : 'use_field_mapping';
+ output.params.docvalue_fields = [{ field: field.name, format }];
+ }
+ output.params._source = field.name === '_source' ? true : field.name;
+ }
+ },
},
{
- text: i18n.translate('data.search.aggs.metrics.topHit.sumLabel', {
- defaultMessage: 'Sum',
- }),
- isCompatible: isNumericFieldSelected,
- disabled: true,
- value: 'sum',
+ name: 'aggregate',
+ type: 'optioned',
+ options: [
+ {
+ text: i18n.translate('data.search.aggs.metrics.topHit.minLabel', {
+ defaultMessage: 'Min',
+ }),
+ isCompatible: isNumericFieldSelected,
+ disabled: true,
+ value: 'min',
+ },
+ {
+ text: i18n.translate('data.search.aggs.metrics.topHit.maxLabel', {
+ defaultMessage: 'Max',
+ }),
+ isCompatible: isNumericFieldSelected,
+ disabled: true,
+ value: 'max',
+ },
+ {
+ text: i18n.translate('data.search.aggs.metrics.topHit.sumLabel', {
+ defaultMessage: 'Sum',
+ }),
+ isCompatible: isNumericFieldSelected,
+ disabled: true,
+ value: 'sum',
+ },
+ {
+ text: i18n.translate('data.search.aggs.metrics.topHit.averageLabel', {
+ defaultMessage: 'Average',
+ }),
+ isCompatible: isNumericFieldSelected,
+ disabled: true,
+ value: 'average',
+ },
+ {
+ text: i18n.translate('data.search.aggs.metrics.topHit.concatenateLabel', {
+ defaultMessage: 'Concatenate',
+ }),
+ isCompatible(aggConfig: IMetricAggConfig) {
+ return _.get(aggConfig.params, 'field.filterFieldTypes', '*') === '*';
+ },
+ disabled: true,
+ value: 'concat',
+ },
+ ],
+ write: _.noop,
},
{
- text: i18n.translate('data.search.aggs.metrics.topHit.averageLabel', {
- defaultMessage: 'Average',
- }),
- isCompatible: isNumericFieldSelected,
- disabled: true,
- value: 'average',
+ name: 'size',
+ default: 1,
},
{
- text: i18n.translate('data.search.aggs.metrics.topHit.concatenateLabel', {
- defaultMessage: 'Concatenate',
- }),
- isCompatible(aggConfig: IMetricAggConfig) {
- return _.get(aggConfig.params, 'field.filterFieldTypes', '*') === '*';
+ name: 'sortField',
+ type: 'field',
+ filterFieldTypes: [
+ KBN_FIELD_TYPES.NUMBER,
+ KBN_FIELD_TYPES.DATE,
+ KBN_FIELD_TYPES.IP,
+ KBN_FIELD_TYPES.STRING,
+ ],
+ default(agg: IMetricAggConfig) {
+ return agg.getIndexPattern().timeFieldName;
},
- disabled: true,
- value: 'concat',
- },
- ],
- write: _.noop,
- },
- {
- name: 'size',
- default: 1,
- },
- {
- name: 'sortField',
- type: 'field',
- filterFieldTypes: [
- KBN_FIELD_TYPES.NUMBER,
- KBN_FIELD_TYPES.DATE,
- KBN_FIELD_TYPES.IP,
- KBN_FIELD_TYPES.STRING,
- ],
- default(agg: IMetricAggConfig) {
- return agg.getIndexPattern().timeFieldName;
- },
- write: _.noop, // prevent default write, it is handled below
- },
- {
- name: 'sortOrder',
- type: 'optioned',
- default: 'desc',
- options: [
- {
- text: i18n.translate('data.search.aggs.metrics.topHit.descendingLabel', {
- defaultMessage: 'Descending',
- }),
- value: 'desc',
+ write: _.noop, // prevent default write, it is handled below
},
{
- text: i18n.translate('data.search.aggs.metrics.topHit.ascendingLabel', {
- defaultMessage: 'Ascending',
- }),
- value: 'asc',
- },
- ],
- write(agg, output) {
- const sortField = agg.params.sortField;
- const sortOrder = agg.params.sortOrder;
-
- if (sortField.scripted) {
- output.params.sort = [
+ name: 'sortOrder',
+ type: 'optioned',
+ default: 'desc',
+ options: [
{
- _script: {
- script: {
- source: sortField.script,
- lang: sortField.lang,
- },
- type: sortField.type,
- order: sortOrder.value,
- },
+ text: i18n.translate('data.search.aggs.metrics.topHit.descendingLabel', {
+ defaultMessage: 'Descending',
+ }),
+ value: 'desc',
},
- ];
- } else {
- output.params.sort = [
{
- [sortField.name]: {
- order: sortOrder.value,
- },
+ text: i18n.translate('data.search.aggs.metrics.topHit.ascendingLabel', {
+ defaultMessage: 'Ascending',
+ }),
+ value: 'asc',
},
- ];
+ ],
+ write(agg, output) {
+ const sortField = agg.params.sortField;
+ const sortOrder = agg.params.sortOrder;
+
+ if (sortField.scripted) {
+ output.params.sort = [
+ {
+ _script: {
+ script: {
+ source: sortField.script,
+ lang: sortField.lang,
+ },
+ type: sortField.type,
+ order: sortOrder.value,
+ },
+ },
+ ];
+ } else {
+ output.params.sort = [
+ {
+ [sortField.name]: {
+ order: sortOrder.value,
+ },
+ },
+ ];
+ }
+ },
+ },
+ ],
+ getValue(agg, bucket) {
+ const hits: any[] = _.get(bucket, `${agg.id}.hits.hits`);
+ if (!hits || !hits.length) {
+ return null;
}
- },
- },
- ],
- getValue(agg, bucket) {
- const hits: any[] = _.get(bucket, `${agg.id}.hits.hits`);
- if (!hits || !hits.length) {
- return null;
- }
- const path = agg.getParam('field').name;
+ const path = agg.getParam('field').name;
- let values = _.flatten(
- hits.map(hit =>
- path === '_source' ? hit._source : agg.getIndexPattern().flattenHit(hit, true)[path]
- )
- );
+ let values = _.flatten(
+ hits.map(hit =>
+ path === '_source' ? hit._source : agg.getIndexPattern().flattenHit(hit, true)[path]
+ )
+ );
- if (values.length === 1) {
- values = values[0];
- }
+ if (values.length === 1) {
+ values = values[0];
+ }
+
+ if (Array.isArray(values)) {
+ if (!_.compact(values).length) {
+ return null;
+ }
+
+ const aggregate = agg.getParam('aggregate');
- if (Array.isArray(values)) {
- if (!_.compact(values).length) {
- return null;
- }
-
- const aggregate = agg.getParam('aggregate');
-
- switch (aggregate.value) {
- case 'max':
- return _.max(values);
- case 'min':
- return _.min(values);
- case 'sum':
- return _.sum(values);
- case 'average':
- return _.sum(values) / values.length;
- }
+ switch (aggregate.value) {
+ case 'max':
+ return _.max(values);
+ case 'min':
+ return _.min(values);
+ case 'sum':
+ return _.sum(values);
+ case 'average':
+ return _.sum(values) / values.length;
+ }
+ }
+ return values;
+ },
+ },
+ {
+ getInternalStartServices,
}
- return values;
- },
-});
+ );
+};
diff --git a/src/plugins/data/public/search/aggs/param_types/field.test.ts b/src/plugins/data/public/search/aggs/param_types/field.test.ts
index 0182471392910..ea7931130b84a 100644
--- a/src/plugins/data/public/search/aggs/param_types/field.test.ts
+++ b/src/plugins/data/public/search/aggs/param_types/field.test.ts
@@ -18,11 +18,20 @@
*/
import { BaseParamType } from './base';
-import { FieldParamType } from './field';
+import { FieldParamType, FieldParamTypeDependencies } from './field';
import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../common';
import { IAggConfig } from '../agg_config';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
+import { notificationServiceMock } from '../../../../../../../src/core/public/mocks';
describe('Field', () => {
+ const fieldParamTypeDependencies: FieldParamTypeDependencies = {
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
+ };
+
const indexPattern = {
id: '1234',
title: 'logstash-*',
@@ -52,10 +61,13 @@ describe('Field', () => {
describe('constructor', () => {
it('it is an instance of BaseParamType', () => {
- const aggParam = new FieldParamType({
- name: 'field',
- type: 'field',
- });
+ const aggParam = new FieldParamType(
+ {
+ name: 'field',
+ type: 'field',
+ },
+ fieldParamTypeDependencies
+ );
expect(aggParam instanceof BaseParamType).toBeTruthy();
});
@@ -63,10 +75,13 @@ describe('Field', () => {
describe('getAvailableFields', () => {
it('should return only aggregatable fields by default', () => {
- const aggParam = new FieldParamType({
- name: 'field',
- type: 'field',
- });
+ const aggParam = new FieldParamType(
+ {
+ name: 'field',
+ type: 'field',
+ },
+ fieldParamTypeDependencies
+ );
const fields = aggParam.getAvailableFields(agg);
@@ -78,10 +93,13 @@ describe('Field', () => {
});
it('should return all fields if onlyAggregatable is false', () => {
- const aggParam = new FieldParamType({
- name: 'field',
- type: 'field',
- });
+ const aggParam = new FieldParamType(
+ {
+ name: 'field',
+ type: 'field',
+ },
+ fieldParamTypeDependencies
+ );
aggParam.onlyAggregatable = false;
@@ -91,10 +109,13 @@ describe('Field', () => {
});
it('should return all fields if filterFieldTypes was not specified', () => {
- const aggParam = new FieldParamType({
- name: 'field',
- type: 'field',
- });
+ const aggParam = new FieldParamType(
+ {
+ name: 'field',
+ type: 'field',
+ },
+ fieldParamTypeDependencies
+ );
indexPattern.fields[1].aggregatable = true;
diff --git a/src/plugins/data/public/search/aggs/param_types/field.ts b/src/plugins/data/public/search/aggs/param_types/field.ts
index 34b77e14a3a71..4d67f41905c5a 100644
--- a/src/plugins/data/public/search/aggs/param_types/field.ts
+++ b/src/plugins/data/public/search/aggs/param_types/field.ts
@@ -24,7 +24,7 @@ import { BaseParamType } from './base';
import { propFilter } from '../filter';
import { isNestedField, KBN_FIELD_TYPES } from '../../../../common';
import { Field as IndexPatternField } from '../../../index_patterns';
-import { getNotifications } from '../../../../public/services';
+import { GetInternalStartServicesFn } from '../../../types';
const filterByType = propFilter('type');
@@ -32,13 +32,20 @@ export type FieldTypes = KBN_FIELD_TYPES | KBN_FIELD_TYPES[] | '*';
// TODO need to make a more explicit interface for this
export type IFieldParamType = FieldParamType;
+export interface FieldParamTypeDependencies {
+ getInternalStartServices: GetInternalStartServicesFn;
+}
+
export class FieldParamType extends BaseParamType {
required = true;
scriptable = true;
filterFieldTypes: FieldTypes;
onlyAggregatable: boolean;
- constructor(config: Record) {
+ constructor(
+ config: Record,
+ { getInternalStartServices }: FieldParamTypeDependencies
+ ) {
super(config);
this.filterFieldTypes = config.filterFieldTypes || '*';
@@ -87,7 +94,7 @@ export class FieldParamType extends BaseParamType {
// @ts-ignore
const validField = this.getAvailableFields(aggConfig).find((f: any) => f.name === fieldName);
if (!validField) {
- getNotifications().toasts.addDanger(
+ getInternalStartServices().notifications.toasts.addDanger(
i18n.translate(
'data.search.aggs.paramTypes.field.invalidSavedFieldParameterErrorMessage',
{
diff --git a/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts b/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts
index 57d27b7da6313..2383affa2a8c5 100644
--- a/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts
+++ b/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts
@@ -18,12 +18,13 @@
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { coreMock } from '../../../../../../../src/core/public/mocks';
+import { coreMock, notificationServiceMock } from '../../../../../../../src/core/public/mocks';
import { AggTypesRegistry, AggTypesRegistryStart } from '../agg_types_registry';
import { getAggTypes } from '../agg_types';
-import { BucketAggType } from '../buckets/_bucket_agg_type';
+import { BucketAggType } from '../buckets/bucket_agg_type';
import { MetricAggType } from '../metrics/metric_agg_type';
import { queryServiceMock } from '../../../query/mocks';
+import { fieldFormatsServiceMock } from '../../../field_formats/mocks';
/**
* Testing utility which creates a new instance of AggTypesRegistry,
@@ -55,8 +56,11 @@ export function mockAggTypesRegistry | MetricAggTyp
const core = coreMock.createSetup();
const aggTypes = getAggTypes({
uiSettings: core.uiSettings,
- notifications: core.notifications,
query: queryServiceMock.createSetupContract(),
+ getInternalStartServices: () => ({
+ fieldFormats: fieldFormatsServiceMock.createStartContract(),
+ notifications: notificationServiceMock.createStartContract(),
+ }),
});
aggTypes.buckets.forEach(type => registrySetup.registerBucket(type));
diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts
index dc1c99f76d59a..42f31ef450d28 100644
--- a/src/plugins/data/public/search/search_service.ts
+++ b/src/plugins/data/public/search/search_service.ts
@@ -26,6 +26,7 @@ import { getEsClient, LegacyApiCaller } from './es_client';
import { ES_SEARCH_STRATEGY, DEFAULT_SEARCH_STRATEGY } from '../../common/search';
import { esSearchStrategyProvider } from './es_search/es_search_strategy';
import { QuerySetup } from '../query/query_service';
+import { GetInternalStartServicesFn } from '../types';
import { SearchInterceptor } from './search_interceptor';
import {
getAggTypes,
@@ -44,6 +45,7 @@ import {
interface SearchServiceSetupDependencies {
packageInfo: PackageInfo;
query: QuerySetup;
+ getInternalStartServices: GetInternalStartServicesFn;
}
/**
@@ -81,7 +83,7 @@ export class SearchService implements Plugin {
public setup(
core: CoreSetup,
- { packageInfo, query }: SearchServiceSetupDependencies
+ { packageInfo, query, getInternalStartServices }: SearchServiceSetupDependencies
): ISearchSetup {
this.esClient = getEsClient(core.injectedMetadata, core.http, packageInfo);
this.registerSearchStrategyProvider(SYNC_SEARCH_STRATEGY, syncSearchStrategyProvider);
@@ -91,7 +93,7 @@ export class SearchService implements Plugin {
const aggTypes = getAggTypes({
query,
uiSettings: core.uiSettings,
- notifications: core.notifications,
+ getInternalStartServices,
});
aggTypes.buckets.forEach(b => aggTypesSetup.registerBucket(b));
diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts
index 45160cbf30179..e24e01d241278 100644
--- a/src/plugins/data/public/types.ts
+++ b/src/plugins/data/public/types.ts
@@ -71,3 +71,12 @@ export interface IDataPluginServices extends Partial {
storage: IStorageWrapper;
data: DataPublicPluginStart;
}
+
+/** @internal **/
+export interface InternalStartServices {
+ fieldFormats: FieldFormatsStart;
+ notifications: CoreStart['notifications'];
+}
+
+/** @internal **/
+export type GetInternalStartServicesFn = () => InternalStartServices;
diff --git a/src/plugins/data/server/index_patterns/routes.ts b/src/plugins/data/server/index_patterns/routes.ts
index 8f017a73083ec..8b9fa28c77165 100644
--- a/src/plugins/data/server/index_patterns/routes.ts
+++ b/src/plugins/data/server/index_patterns/routes.ts
@@ -70,7 +70,22 @@ export function registerRoutes(http: HttpServiceSetup) {
},
});
} catch (error) {
- return response.notFound();
+ if (
+ typeof error === 'object' &&
+ !!error?.isBoom &&
+ !!error?.output?.payload &&
+ typeof error?.output?.payload === 'object'
+ ) {
+ const payload = error?.output?.payload;
+ return response.notFound({
+ body: {
+ message: payload.message,
+ attributes: payload,
+ },
+ });
+ } else {
+ return response.notFound();
+ }
}
}
);
diff --git a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx
index 9e47da5cea032..2a0ffd723850b 100644
--- a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx
+++ b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx
@@ -29,7 +29,7 @@ import {
ContactCardEmbeddable,
} from '../test_samples/embeddables/contact_card/contact_card_embeddable';
// eslint-disable-next-line
-import { inspectorPluginMock } from 'src/plugins/inspector/public/mocks';
+import { inspectorPluginMock } from '../../../../inspector/public/mocks';
import { mount } from 'enzyme';
import { embeddablePluginMock } from '../../mocks';
diff --git a/src/plugins/embeddable/public/lib/embeddables/with_subscription.tsx b/src/plugins/embeddable/public/lib/embeddables/with_subscription.tsx
index 47b8001961cf5..9bc5889715c76 100644
--- a/src/plugins/embeddable/public/lib/embeddables/with_subscription.tsx
+++ b/src/plugins/embeddable/public/lib/embeddables/with_subscription.tsx
@@ -23,18 +23,19 @@ import { IEmbeddable, EmbeddableInput, EmbeddableOutput } from './i_embeddable';
export const withEmbeddableSubscription = <
I extends EmbeddableInput,
O extends EmbeddableOutput,
- E extends IEmbeddable = IEmbeddable
+ E extends IEmbeddable = IEmbeddable,
+ ExtraProps = {}
>(
- WrappedComponent: React.ComponentType<{ input: I; output: O; embeddable: E }>
-): React.ComponentType<{ embeddable: E }> =>
+ WrappedComponent: React.ComponentType<{ input: I; output: O; embeddable: E } & ExtraProps>
+): React.ComponentType<{ embeddable: E } & ExtraProps> =>
class WithEmbeddableSubscription extends React.Component<
- { embeddable: E },
+ { embeddable: E } & ExtraProps,
{ input: I; output: O }
> {
private subscription?: Rx.Subscription;
private mounted: boolean = false;
- constructor(props: { embeddable: E }) {
+ constructor(props: { embeddable: E } & ExtraProps) {
super(props);
this.state = {
input: this.props.embeddable.getInput(),
@@ -71,6 +72,7 @@ export const withEmbeddableSubscription = <
input={this.state.input}
output={this.state.output}
embeddable={this.props.embeddable}
+ {...this.props}
/>
);
}
diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx
index 649677dc67c7d..1e7cbb2f3dafc 100644
--- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx
+++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx
@@ -25,7 +25,7 @@ import { nextTick } from 'test_utils/enzyme_helpers';
import { findTestSubject } from '@elastic/eui/lib/test';
import { I18nProvider } from '@kbn/i18n/react';
import { CONTEXT_MENU_TRIGGER } from '../triggers';
-import { Action, UiActionsStart, ActionType } from 'src/plugins/ui_actions/public';
+import { Action, UiActionsStart, ActionType } from '../../../../ui_actions/public';
import { Trigger, ViewMode } from '../types';
import { isErrorEmbeddable } from '../embeddables';
import { EmbeddablePanel } from './embeddable_panel';
@@ -41,7 +41,7 @@ import {
ContactCardEmbeddableOutput,
} from '../test_samples/embeddables/contact_card/contact_card_embeddable';
// eslint-disable-next-line
-import { inspectorPluginMock } from 'src/plugins/inspector/public/mocks';
+import { inspectorPluginMock } from '../../../../inspector/public/mocks';
import { EuiBadge } from '@elastic/eui';
import { embeddablePluginMock } from '../../mocks';
diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx
index ee31127cb5a40..491eaad9faefa 100644
--- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx
+++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx
@@ -27,7 +27,7 @@ import {
ContactCardEmbeddable,
} from '../../../test_samples';
// eslint-disable-next-line
-import { inspectorPluginMock } from 'src/plugins/inspector/public/mocks';
+import { inspectorPluginMock } from '../../../../../../../plugins/inspector/public/mocks';
import { EmbeddableOutput, isErrorEmbeddable, ErrorEmbeddable } from '../../../embeddables';
import { of } from '../../../../tests/helpers';
import { esFilters } from '../../../../../../../plugins/data/public';
diff --git a/src/plugins/embeddable/public/mocks.ts b/src/plugins/embeddable/public/mocks.ts
index 2ee05d8316ace..65b15f3a7614f 100644
--- a/src/plugins/embeddable/public/mocks.ts
+++ b/src/plugins/embeddable/public/mocks.ts
@@ -16,11 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-
import { EmbeddableStart, EmbeddableSetup } from '.';
import { EmbeddablePublicPlugin } from './plugin';
import { coreMock } from '../../../core/public/mocks';
+// eslint-disable-next-line
+import { inspectorPluginMock } from '../../inspector/public/mocks';
// eslint-disable-next-line
import { uiActionsPluginMock } from '../../ui_actions/public/mocks';
@@ -39,6 +40,7 @@ const createStartContract = (): Start => {
const startContract: Start = {
getEmbeddableFactories: jest.fn(),
getEmbeddableFactory: jest.fn(),
+ EmbeddablePanel: jest.fn(),
};
return startContract;
};
@@ -48,7 +50,11 @@ const createInstance = () => {
const setup = plugin.setup(coreMock.createSetup(), {
uiActions: uiActionsPluginMock.createSetupContract(),
});
- const doStart = () => plugin.start(coreMock.createStart());
+ const doStart = () =>
+ plugin.start(coreMock.createStart(), {
+ uiActions: uiActionsPluginMock.createStartContract(),
+ inspector: inspectorPluginMock.createStartContract(),
+ });
return {
plugin,
setup,
diff --git a/src/plugins/embeddable/public/plugin.ts b/src/plugins/embeddable/public/plugin.tsx
similarity index 76%
rename from src/plugins/embeddable/public/plugin.ts
rename to src/plugins/embeddable/public/plugin.tsx
index a483f90f76dde..01fbf52c80182 100644
--- a/src/plugins/embeddable/public/plugin.ts
+++ b/src/plugins/embeddable/public/plugin.tsx
@@ -16,7 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { UiActionsSetup } from 'src/plugins/ui_actions/public';
+import React from 'react';
+import { getSavedObjectFinder } from '../../saved_objects/public';
+import { UiActionsSetup, UiActionsStart } from '../../ui_actions/public';
+import { Start as InspectorStart } from '../../inspector/public';
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public';
import { EmbeddableFactoryRegistry, EmbeddableFactoryProvider } from './types';
import { bootstrap } from './bootstrap';
@@ -26,6 +29,7 @@ import {
EmbeddableOutput,
defaultEmbeddableFactoryProvider,
IEmbeddable,
+ EmbeddablePanel,
} from './lib';
import { EmbeddableFactoryDefinition } from './lib/embeddables/embeddable_factory_definition';
@@ -33,6 +37,11 @@ export interface EmbeddableSetupDependencies {
uiActions: UiActionsSetup;
}
+export interface EmbeddableStartDependencies {
+ uiActions: UiActionsStart;
+ inspector: InspectorStart;
+}
+
export interface EmbeddableSetup {
registerEmbeddableFactory: (
id: string,
@@ -50,6 +59,7 @@ export interface EmbeddableStart {
embeddableFactoryId: string
) => EmbeddableFactory | undefined;
getEmbeddableFactories: () => IterableIterator;
+ EmbeddablePanel: React.FC<{ embeddable: IEmbeddable; hideHeader?: boolean }>;
}
export class EmbeddablePublicPlugin implements Plugin {
@@ -78,7 +88,10 @@ export class EmbeddablePublicPlugin implements Plugin {
this.embeddableFactories.set(
def.type,
@@ -89,15 +102,36 @@ export class EmbeddablePublicPlugin implements Plugin {
- this.ensureFactoriesExist();
- return this.embeddableFactories.values();
- },
+ getEmbeddableFactories: this.getEmbeddableFactories,
+ EmbeddablePanel: ({
+ embeddable,
+ hideHeader,
+ }: {
+ embeddable: IEmbeddable;
+ hideHeader?: boolean;
+ }) => (
+
+ ),
};
}
public stop() {}
+ private getEmbeddableFactories = () => {
+ this.ensureFactoriesExist();
+ return this.embeddableFactories.values();
+ };
+
private registerEmbeddableFactory = (
embeddableFactoryId: string,
factory: EmbeddableFactoryDefinition
@@ -130,11 +164,11 @@ export class EmbeddablePublicPlugin implements Plugin {
this.embeddableFactoryDefinitions.forEach(def => this.ensureFactoryExists(def.type));
- }
+ };
- private ensureFactoryExists(type: string) {
+ private ensureFactoryExists = (type: string) => {
if (!this.embeddableFactories.get(type)) {
const def = this.embeddableFactoryDefinitions.get(type);
if (!def) return;
@@ -145,5 +179,5 @@ export class EmbeddablePublicPlugin implements Plugin {
diff --git a/src/plugins/embeddable/public/tests/test_plugin.ts b/src/plugins/embeddable/public/tests/test_plugin.ts
index e199ef193aa1c..e13a906e30338 100644
--- a/src/plugins/embeddable/public/tests/test_plugin.ts
+++ b/src/plugins/embeddable/public/tests/test_plugin.ts
@@ -18,9 +18,11 @@
*/
import { CoreSetup, CoreStart } from 'src/core/public';
+import { UiActionsStart } from '../../../ui_actions/public';
// eslint-disable-next-line
-import { uiActionsPluginMock } from 'src/plugins/ui_actions/public/mocks';
-import { UiActionsStart } from 'src/plugins/ui_actions/public';
+import { uiActionsPluginMock } from '../../../ui_actions/public/mocks';
+// eslint-disable-next-line
+import { inspectorPluginMock } from '../../../inspector/public/mocks';
import { coreMock } from '../../../../core/public/mocks';
import { EmbeddablePublicPlugin, EmbeddableSetup, EmbeddableStart } from '../plugin';
@@ -48,7 +50,10 @@ export const testPlugin = (
coreStart,
setup,
doStart: (anotherCoreStart: CoreStart = coreStart) => {
- const start = plugin.start(anotherCoreStart);
+ const start = plugin.start(anotherCoreStart, {
+ uiActions: uiActionsPluginMock.createStartContract(),
+ inspector: inspectorPluginMock.createStartContract(),
+ });
return start;
},
uiActions: uiActions.doStart(coreStart),
diff --git a/test/examples/embeddables/list_container.ts b/test/examples/embeddables/list_container.ts
index b1b91ad2c37f1..9e93d479471e8 100644
--- a/test/examples/embeddables/list_container.ts
+++ b/test/examples/embeddables/list_container.ts
@@ -57,13 +57,12 @@ export default function({ getService }: PluginFunctionalProviderContext) {
expect(text).to.eql(['HELLO WORLD!']);
});
- it('searchable container filters multi-task children', async () => {
+ it('searchable container finds matches in multi-task children', async () => {
await testSubjects.setValue('filterTodos', 'earth');
+ await testSubjects.click('checkMatchingTodos');
+ await testSubjects.click('deleteCheckedTodos');
- await retry.try(async () => {
- const tasks = await testSubjects.getVisibleTextAll('multiTaskTodoTask');
- expect(tasks).to.eql(['Watch planet earth']);
- });
+ await testSubjects.missingOrFail('multiTaskTodoTask');
});
});
}
diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/app.tsx b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/app.tsx
index 54d13efe4d790..2ecde823dc4df 100644
--- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/app.tsx
+++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/app.tsx
@@ -18,21 +18,11 @@
*/
import { EuiTab } from '@elastic/eui';
import React, { Component } from 'react';
-import { CoreStart } from 'src/core/public';
import { EmbeddableStart } from 'src/plugins/embeddable/public';
-import { UiActionsService } from '../../../../../../../../src/plugins/ui_actions/public';
import { DashboardContainerExample } from './dashboard_container_example';
-import { Start as InspectorStartContract } from '../../../../../../../../src/plugins/inspector/public';
export interface AppProps {
- getActions: UiActionsService['getTriggerCompatibleActions'];
- getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'];
- getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories'];
- overlays: CoreStart['overlays'];
- notifications: CoreStart['notifications'];
- inspector: InspectorStartContract;
- SavedObjectFinder: React.ComponentType;
- I18nContext: CoreStart['i18n']['Context'];
+ embeddableServices: EmbeddableStart;
}
export class App extends Component {
@@ -72,29 +62,17 @@ export class App extends Component {
public render() {
return (
-
-
-
{this.renderTabs()}
- {this.getContentsForTab()}
-
-
+
+
{this.renderTabs()}
+ {this.getContentsForTab()}
+
);
}
private getContentsForTab() {
switch (this.state.selectedTabId) {
case 'dashboardContainer': {
- return (
-
- );
+ return ;
}
}
}
diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_container_example.tsx b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_container_example.tsx
index fd07416cadbc5..16c2840d6a32e 100644
--- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_container_example.tsx
+++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_container_example.tsx
@@ -19,32 +19,17 @@
import React from 'react';
import { EuiButton, EuiLoadingChart } from '@elastic/eui';
import { ContainerOutput } from 'src/plugins/embeddable/public';
-import {
- ErrorEmbeddable,
- ViewMode,
- isErrorEmbeddable,
- EmbeddablePanel,
- EmbeddableStart,
-} from '../embeddable_api';
+import { ErrorEmbeddable, ViewMode, isErrorEmbeddable, EmbeddableStart } from '../embeddable_api';
import {
DASHBOARD_CONTAINER_TYPE,
DashboardContainer,
DashboardContainerInput,
} from '../../../../../../../../src/plugins/dashboard/public';
-import { CoreStart } from '../../../../../../../../src/core/public';
import { dashboardInput } from './dashboard_input';
-import { Start as InspectorStartContract } from '../../../../../../../../src/plugins/inspector/public';
-import { UiActionsService } from '../../../../../../../../src/plugins/ui_actions/public';
interface Props {
- getActions: UiActionsService['getTriggerCompatibleActions'];
- getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'];
- getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories'];
- overlays: CoreStart['overlays'];
- notifications: CoreStart['notifications'];
- inspector: InspectorStartContract;
- SavedObjectFinder: React.ComponentType;
+ embeddableServices: EmbeddableStart;
}
interface State {
@@ -67,7 +52,7 @@ export class DashboardContainerExample extends React.Component {
public async componentDidMount() {
this.mounted = true;
- const dashboardFactory = this.props.getEmbeddableFactory<
+ const dashboardFactory = this.props.embeddableServices.getEmbeddableFactory<
DashboardContainerInput,
ContainerOutput,
DashboardContainer
@@ -99,6 +84,7 @@ export class DashboardContainerExample extends React.Component {
};
public render() {
+ const { embeddableServices } = this.props;
return (
Dashboard Container
@@ -108,16 +94,7 @@ export class DashboardContainerExample extends React.Component
{
{!this.state.loaded || !this.container ? (
) : (
-
+
)}
);
diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx
index 18ceec652392d..e5f5faa6ac361 100644
--- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx
+++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx
@@ -33,7 +33,6 @@ const REACT_ROOT_ID = 'embeddableExplorerRoot';
import { SayHelloAction, createSendMessageAction } from './embeddable_api';
import { App } from './app';
-import { getSavedObjectFinder } from '../../../../../../../src/plugins/saved_objects/public';
import {
EmbeddableStart,
EmbeddableSetup,
@@ -78,19 +77,7 @@ export class EmbeddableExplorerPublicPlugin
plugins.__LEGACY.onRenderComplete(() => {
const root = document.getElementById(REACT_ROOT_ID);
- ReactDOM.render(
- ,
- root
- );
+ ReactDOM.render(, root);
});
}
diff --git a/test/scripts/jenkins_visual_regression.sh b/test/scripts/jenkins_visual_regression.sh
index 4fdd197147eac..c6fefd45b005d 100755
--- a/test/scripts/jenkins_visual_regression.sh
+++ b/test/scripts/jenkins_visual_regression.sh
@@ -12,7 +12,7 @@ tar -xzf "$linuxBuild" -C "$installDir" --strip=1
echo " -> running visual regression tests from kibana directory"
checks-reporter-with-killswitch "X-Pack visual regression tests" \
- yarn percy exec -t 500 \
+ yarn percy exec -t 500 -- -- \
node scripts/functional_tests \
--debug --bail \
--kibana-install-dir "$installDir" \
diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh
index 777d98080e407..962d2794f712f 100755
--- a/test/scripts/jenkins_xpack_build_kibana.sh
+++ b/test/scripts/jenkins_xpack_build_kibana.sh
@@ -7,6 +7,7 @@ echo " -> building kibana platform plugins"
node scripts/build_kibana_platform_plugins \
--scan-dir "$XPACK_DIR/test/plugin_functional/plugins" \
--scan-dir "$XPACK_DIR/test/functional_with_es_ssl/fixtures/plugins" \
+ --scan-dir "$XPACK_DIR/test/plugin_api_integration/plugins" \
--verbose;
# doesn't persist, also set in kibanaPipeline.groovy
diff --git a/test/scripts/jenkins_xpack_visual_regression.sh b/test/scripts/jenkins_xpack_visual_regression.sh
index 73e92da3bad63..96521ccc8f787 100755
--- a/test/scripts/jenkins_xpack_visual_regression.sh
+++ b/test/scripts/jenkins_xpack_visual_regression.sh
@@ -14,7 +14,7 @@ tar -xzf "$linuxBuild" -C "$installDir" --strip=1
echo " -> running visual regression tests from x-pack directory"
cd "$XPACK_DIR"
checks-reporter-with-killswitch "X-Pack visual regression tests" \
- yarn percy exec -t 500 \
+ yarn percy exec -t 500 -- -- \
node scripts/functional_tests \
--debug --bail \
--kibana-install-dir "$installDir" \
diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx
index 17ec42b3e2016..07af7b0c0e7db 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx
@@ -28,7 +28,7 @@ export const Title = () => (
'xpack.apm.settings.customizeUI.customLink.info',
{
defaultMessage:
- "These links will be shown in the 'Actions' context menu for the transaction detail."
+ 'These links will be shown in the Actions context menu for transactions.'
}
)}
/>
diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/index.tsx
index 1cd1298fdd549..350f2185fb3c8 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/index.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/index.tsx
@@ -14,8 +14,8 @@ export const CustomizeUI = () => {
<>
- {i18n.translate('xpack.apm.settings.customizeUI', {
- defaultMessage: 'Customize UI'
+ {i18n.translate('xpack.apm.settings.customizeApp', {
+ defaultMessage: 'Customize app'
})}
diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/index.tsx
index f33bb17decd4e..2bb85876686bf 100644
--- a/x-pack/legacy/plugins/apm/public/components/app/Settings/index.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/index.tsx
@@ -57,8 +57,8 @@ export const Settings: React.FC = props => {
isSelected: pathname === '/settings/apm-indices'
},
{
- name: i18n.translate('xpack.apm.settings.customizeUI', {
- defaultMessage: 'Customize UI'
+ name: i18n.translate('xpack.apm.settings.customizeApp', {
+ defaultMessage: 'Customize app'
}),
id: '3',
href: getAPMHref('/settings/customize-ui', search),
diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx
index 2dab8d63f99b2..9d1eeb9a3136d 100644
--- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx
@@ -28,7 +28,7 @@ describe('Custom links', () => {
);
expectTextsInDocument(component, [
- 'No custom links found. Set up your own custom links i.e. a link to a specific Dashboard or external link.'
+ 'No custom links found. Set up your own custom links, e.g., a link to a specific Dashboard or external link.'
]);
expectTextsNotInDocument(component, ['Create']);
});
diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx
index b32d8f0d9582c..38b672a181fce 100644
--- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx
@@ -55,7 +55,7 @@ export const CustomLink = ({
{i18n.translate('xpack.apm.customLink.empty', {
defaultMessage:
- 'No custom links found. Set up your own custom links i.e. a link to a specific Dashboard or external link.'
+ 'No custom links found. Set up your own custom links, e.g., a link to a specific Dashboard or external link.'
})}
diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx
index 048ed662ec502..e3fbcf8485d54 100644
--- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx
+++ b/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx
@@ -85,7 +85,13 @@ export const TransactionActionMenu: FunctionComponent = ({
urlParams
});
+ const closePopover = () => {
+ setIsActionPopoverOpen(false);
+ setIsCustomLinksPopoverOpen(false);
+ };
+
const toggleCustomLinkFlyout = () => {
+ closePopover();
setIsCustomLinkFlyoutOpen(isOpen => !isOpen);
};
@@ -111,10 +117,7 @@ export const TransactionActionMenu: FunctionComponent = ({
)}