diff --git a/.eslintrc.js b/.eslintrc.js
index 2a4fbe7db3723..b12dc63066370 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -304,8 +304,8 @@ module.exports = {
*/
{
files: [
- 'packages/elastic-datemath/**/*.{js,mjs,ts,tsx}',
'packages/elastic-eslint-config-kibana/**/*.{js,mjs,ts,tsx}',
+ 'packages/kbn-datemath/**/*.{js,mjs,ts,tsx}',
],
rules: {
'@kbn/eslint/require-license-header': [
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 11488ea7613b3..3c991e6a61d53 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -5,11 +5,6 @@
# The #CC# prefix delineates Code Coverage,
# used for the 'team' designator within Kibana Stats
-# Tech leads
-/dev_docs @elastic/kibana-tech-leads
-/src/dev/license_checker/config.ts @elastic/kibana-tech-leads
-/packages/kbn-docs-utils/ @elastic/kibana-tech-leads @elastic/kibana-operations
-
# Virtual teams
/x-pack/plugins/rule_registry/ @elastic/rac @elastic/response-ops
@@ -60,7 +55,7 @@
/examples/field_formats_example/ @elastic/kibana-app-services
/examples/partial_results_example/ @elastic/kibana-app-services
/examples/search_examples/ @elastic/kibana-app-services
-/packages/elastic-datemath/ @elastic/kibana-app-services
+/packages/kbn-datemath/ @elastic/kibana-app-services
/packages/kbn-interpreter/ @elastic/kibana-app-services
/packages/kbn-react-field/ @elastic/kibana-app-services
/packages/kbn-es-query/ @elastic/kibana-app-services
@@ -216,25 +211,29 @@
/packages/kbn-mapbox-gl @elastic/kibana-gis
# Operations
+/src/dev/license_checker/config.ts @elastic/kibana-operations
+/packages/kbn-docs-utils/ @elastic/kibana-operations
/src/dev/ @elastic/kibana-operations
/src/setup_node_env/ @elastic/kibana-operations
/packages/*eslint*/ @elastic/kibana-operations
/packages/*babel*/ @elastic/kibana-operations
+/packages/kbn-ambient-ui-types/ @elastic/kibana-operations
+/packages/kbn-ambient-storybook-types/ @elastic/kibana-operations
+/packages/kbn-bazel-packages/ @elastic/kibana-operations
+/packages/kbn-cli-dev-mode/ @elastic/kibana-operations
/packages/kbn-dev-utils*/ @elastic/kibana-operations
+/packages/kbn-es-archiver/ @elastic/kibana-operations
/packages/kbn-es/ @elastic/kibana-operations
/packages/kbn-eslint-plugin-imports/ @elastic/kibana-operations
+/packages/kbn-generate/ @elastic/kibana-operations
/packages/kbn-optimizer/ @elastic/kibana-operations
+/packages/kbn-plugin-discovery/ @elastic/kibana-operations
/packages/kbn-pm/ @elastic/kibana-operations
/packages/kbn-test/ @elastic/kibana-operations
/packages/kbn-type-summarizer/ @elastic/kibana-operations
/packages/kbn-ui-shared-deps-npm/ @elastic/kibana-operations
/packages/kbn-ui-shared-deps-src/ @elastic/kibana-operations
-/packages/kbn-bazel-packages/ @elastic/kibana-operations
-/packages/kbn-es-archiver/ @elastic/kibana-operations
/packages/kbn-utils/ @elastic/kibana-operations
-/packages/kbn-cli-dev-mode/ @elastic/kibana-operations
-/packages/kbn-generate/ @elastic/kibana-operations
-/packages/kbn-plugin-discovery/ @elastic/kibana-operations
/src/cli/keystore/ @elastic/kibana-operations
/.ci/es-snapshots/ @elastic/kibana-operations
/.github/workflows/ @elastic/kibana-operations
@@ -325,6 +324,7 @@
/src/plugins/interactive_setup/ @elastic/kibana-security
/test/interactive_setup_api_integration/ @elastic/kibana-security
/test/interactive_setup_functional/ @elastic/kibana-security
+/test/plugin_functional/test_suites/core_plugins/rendering.ts @elastic/kibana-security
/x-pack/plugins/spaces/ @elastic/kibana-security
/x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security
/x-pack/plugins/security/ @elastic/kibana-security
diff --git a/.i18nrc.json b/.i18nrc.json
index d6256e753df6f..573462d497438 100644
--- a/.i18nrc.json
+++ b/.i18nrc.json
@@ -66,6 +66,7 @@
"share": "src/plugins/share",
"sharedUX": "src/plugins/shared_ux",
"sharedUXComponents": "packages/kbn-shared-ux-components/src",
+ "coloring": "packages/kbn-coloring/src",
"statusPage": "src/legacy/core_plugins/status_page",
"telemetry": [
"src/plugins/telemetry",
@@ -94,4 +95,4 @@
"unifiedSearch": "src/plugins/unified_search"
},
"translations": []
-}
\ No newline at end of file
+}
diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel
index 4a2e6ddf76b17..ff9014214d4c0 100644
--- a/WORKSPACE.bazel
+++ b/WORKSPACE.bazel
@@ -10,15 +10,16 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch Node.js rules
http_archive(
name = "build_bazel_rules_nodejs",
- sha256 = "8a7c981217239085f78acc9898a1f7ba99af887c1996ceb3b4504655383a2c3c",
- urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/4.0.0/rules_nodejs-4.0.0.tar.gz"],
+ sha256 = "523da2d6b50bc00eaf14b00ed28b1a366b3ab456e14131e9812558b26599125c",
+ urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.3.1/rules_nodejs-5.3.1.tar.gz"],
)
-# Now that we have the rules let's import from them to complete the work
-load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install")
+# Build Node.js rules dependencies
+load("@build_bazel_rules_nodejs//:repositories.bzl", "build_bazel_rules_nodejs_dependencies")
+build_bazel_rules_nodejs_dependencies()
-# Assure we have at least a given rules_nodejs version
-check_rules_nodejs_version(minimum_version_string = "4.0.0")
+# Now that we have the rules let's import from them to complete the work
+load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories", "yarn_install")
# Setup the Node.js toolchain for the architectures we want to support
#
@@ -38,14 +39,13 @@ node_repositories(
node_urls = [
"https://nodejs.org/dist/v{version}/{filename}",
],
- yarn_repositories = {
+ yarn_releases = {
"1.21.1": ("yarn-v1.21.1.tar.gz", "yarn-v1.21.1", "d1d9f4a0f16f5ed484e814afeb98f39b82d4728c6c8beaafb5abc99c02db6674"),
},
yarn_version = "1.21.1",
yarn_urls = [
"https://github.com/yarnpkg/yarn/releases/download/v{version}/{filename}",
],
- package_json = ["//:package.json"],
)
# Run yarn_install rule to take care of dependencies
diff --git a/dev_docs/assets/kibana_template_no_data_config.png b/dev_docs/assets/kibana_template_no_data_config.png
index a3d12fc018503..197ba6b0bfaa3 100644
Binary files a/dev_docs/assets/kibana_template_no_data_config.png and b/dev_docs/assets/kibana_template_no_data_config.png differ
diff --git a/docs/developer/getting-started/monorepo-packages.asciidoc b/docs/developer/getting-started/monorepo-packages.asciidoc
index e8e792f13c0dd..0216d26023a78 100644
--- a/docs/developer/getting-started/monorepo-packages.asciidoc
+++ b/docs/developer/getting-started/monorepo-packages.asciidoc
@@ -51,7 +51,6 @@ yarn kbn watch
[discrete]
=== List of Already Migrated Packages to Bazel
-- @elastic/datemath
- @elastic/eslint-config-kibana
- @elastic/safer-lodash-set
- @kbn/ace
@@ -64,6 +63,7 @@ yarn kbn watch
- @kbn/config
- @kbn/config-schema
- @kbn/crypto
+- @kbn/datemath
- @kbn/dev-utils
- @kbn/docs-utils
- @kbn/es
diff --git a/docs/development/core/public/kibana-plugin-core-public.app.id.md b/docs/development/core/public/kibana-plugin-core-public.app.id.md
index 9899cfc0cf572..39f6e62dae04c 100644
--- a/docs/development/core/public/kibana-plugin-core-public.app.id.md
+++ b/docs/development/core/public/kibana-plugin-core-public.app.id.md
@@ -4,7 +4,9 @@
## App.id property
-The unique identifier of the application
+The unique identifier of the application.
+
+Can only be composed of alphanumeric characters, `-`, `:` and `_`
Signature:
diff --git a/docs/development/core/public/kibana-plugin-core-public.app.md b/docs/development/core/public/kibana-plugin-core-public.app.md
index 7af32efcb9c12..71bf216f30250 100644
--- a/docs/development/core/public/kibana-plugin-core-public.app.md
+++ b/docs/development/core/public/kibana-plugin-core-public.app.md
@@ -23,7 +23,7 @@ export interface App extends AppNavOptions
| [deepLinks?](./kibana-plugin-core-public.app.deeplinks.md) | AppDeepLink\[\] | (Optional) Input type for registering secondary in-app locations for an application.Deep links must include at least one of path
or deepLinks
. A deep link that does not have a path
represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. |
| [defaultPath?](./kibana-plugin-core-public.app.defaultpath.md) | string | (Optional) Allow to define the default path a user should be directed to when navigating to the app. When defined, this value will be used as a default for the path
option when calling [navigateToApp](./kibana-plugin-core-public.applicationstart.navigatetoapp.md)\`, and will also be appended to the [application navLink](./kibana-plugin-core-public.chromenavlink.md) in the navigation bar. |
| [exactRoute?](./kibana-plugin-core-public.app.exactroute.md) | boolean | (Optional) If set to true, the application's route will only be checked against an exact match. Defaults to false
. |
-| [id](./kibana-plugin-core-public.app.id.md) | string | The unique identifier of the application |
+| [id](./kibana-plugin-core-public.app.id.md) | string | The unique identifier of the application.Can only be composed of alphanumeric characters, -
, :
and _
|
| [keywords?](./kibana-plugin-core-public.app.keywords.md) | string\[\] | (Optional) Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. |
| [mount](./kibana-plugin-core-public.app.mount.md) | AppMount<HistoryLocationState> | A mount function called when the user navigates to this app's route. |
| [navLinkStatus?](./kibana-plugin-core-public.app.navlinkstatus.md) | AppNavLinkStatus | (Optional) The initial status of the application's navLink. Defaulting to visible
if status
is accessible
and hidden
if status is inaccessible
See [AppNavLinkStatus](./kibana-plugin-core-public.appnavlinkstatus.md) |
diff --git a/docs/development/core/public/kibana-plugin-core-public.applicationstart.navigatetourl.md b/docs/development/core/public/kibana-plugin-core-public.applicationstart.navigatetourl.md
index 601018c0cce45..b6093340cfbf3 100644
--- a/docs/development/core/public/kibana-plugin-core-public.applicationstart.navigatetourl.md
+++ b/docs/development/core/public/kibana-plugin-core-public.applicationstart.navigatetourl.md
@@ -23,7 +23,7 @@ navigateToUrl(url: string, options?: NavigateToUrlOptions): Promise;
| Parameter | Type | Description |
| --- | --- | --- |
| url | string | an absolute URL, an absolute path or a relative path, to navigate to. |
-| options | NavigateToUrlOptions | |
+| options | NavigateToUrlOptions | navigation options |
Returns:
diff --git a/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.enabledonanonymouspages.md b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.enabledonanonymouspages.md
new file mode 100644
index 0000000000000..472bac3dde7d8
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.enabledonanonymouspages.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [DiscoveredPlugin](./kibana-plugin-core-server.discoveredplugin.md) > [enabledOnAnonymousPages](./kibana-plugin-core-server.discoveredplugin.enabledonanonymouspages.md)
+
+## DiscoveredPlugin.enabledOnAnonymousPages property
+
+Specifies whether this plugin - and its required dependencies - will be enabled for anonymous pages (login page, status page when configured, etc.) Default is false.
+
+Signature:
+
+```typescript
+readonly enabledOnAnonymousPages?: boolean;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md
index cf98a0cd68dbd..258acfa9ddc36 100644
--- a/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md
+++ b/docs/development/core/server/kibana-plugin-core-server.discoveredplugin.md
@@ -17,6 +17,7 @@ export interface DiscoveredPlugin
| Property | Type | Description |
| --- | --- | --- |
| [configPath](./kibana-plugin-core-server.discoveredplugin.configpath.md) | ConfigPath | Root configuration path used by the plugin, defaults to "id" in snake\_case format. |
+| [enabledOnAnonymousPages?](./kibana-plugin-core-server.discoveredplugin.enabledonanonymouspages.md) | boolean | (Optional) Specifies whether this plugin - and its required dependencies - will be enabled for anonymous pages (login page, status page when configured, etc.) Default is false. |
| [id](./kibana-plugin-core-server.discoveredplugin.id.md) | PluginName | Identifier of the plugin. |
| [optionalPlugins](./kibana-plugin-core-server.discoveredplugin.optionalplugins.md) | readonly PluginName\[\] | An optional list of the other plugins that if installed and enabled \*\*may be\*\* leveraged by this plugin for some additional functionality but otherwise are not required for this plugin to work properly. |
| [requiredBundles](./kibana-plugin-core-server.discoveredplugin.requiredbundles.md) | readonly PluginName\[\] | List of plugin ids that this plugin's UI code imports modules from that are not in requiredPlugins
. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.irenderoptions.includeusersettings.md b/docs/development/core/server/kibana-plugin-core-server.irenderoptions.includeusersettings.md
deleted file mode 100644
index 2fa61c816bd78..0000000000000
--- a/docs/development/core/server/kibana-plugin-core-server.irenderoptions.includeusersettings.md
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IRenderOptions](./kibana-plugin-core-server.irenderoptions.md) > [includeUserSettings](./kibana-plugin-core-server.irenderoptions.includeusersettings.md)
-
-## IRenderOptions.includeUserSettings property
-
-Set whether to output user settings in the page metadata. `true` by default.
-
-Signature:
-
-```typescript
-includeUserSettings?: boolean;
-```
diff --git a/docs/development/core/server/kibana-plugin-core-server.irenderoptions.isanonymouspage.md b/docs/development/core/server/kibana-plugin-core-server.irenderoptions.isanonymouspage.md
new file mode 100644
index 0000000000000..dc2af11f9f9d3
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.irenderoptions.isanonymouspage.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IRenderOptions](./kibana-plugin-core-server.irenderoptions.md) > [isAnonymousPage](./kibana-plugin-core-server.irenderoptions.isanonymouspage.md)
+
+## IRenderOptions.isAnonymousPage property
+
+Set whether the page is anonymous, which determines what plugins are enabled and whether to output user settings in the page metadata. `false` by default.
+
+Signature:
+
+```typescript
+isAnonymousPage?: boolean;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.irenderoptions.md b/docs/development/core/server/kibana-plugin-core-server.irenderoptions.md
index b7c43bc77867d..84539a6aa73ca 100644
--- a/docs/development/core/server/kibana-plugin-core-server.irenderoptions.md
+++ b/docs/development/core/server/kibana-plugin-core-server.irenderoptions.md
@@ -15,5 +15,5 @@ export interface IRenderOptions
| Property | Type | Description |
| --- | --- | --- |
-| [includeUserSettings?](./kibana-plugin-core-server.irenderoptions.includeusersettings.md) | boolean | (Optional) Set whether to output user settings in the page metadata. true
by default. |
+| [isAnonymousPage?](./kibana-plugin-core-server.irenderoptions.isanonymouspage.md) | boolean | (Optional) Set whether the page is anonymous, which determines what plugins are enabled and whether to output user settings in the page metadata. false
by default. |
diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.enabledonanonymouspages.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.enabledonanonymouspages.md
new file mode 100644
index 0000000000000..359e84c67cac2
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.enabledonanonymouspages.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [PluginManifest](./kibana-plugin-core-server.pluginmanifest.md) > [enabledOnAnonymousPages](./kibana-plugin-core-server.pluginmanifest.enabledonanonymouspages.md)
+
+## PluginManifest.enabledOnAnonymousPages property
+
+Specifies whether this plugin - and its required dependencies - will be enabled for anonymous pages (login page, status page when configured, etc.) Default is false.
+
+Signature:
+
+```typescript
+readonly enabledOnAnonymousPages?: boolean;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md
index 4c7c63b791a79..eb3ba06c311c9 100644
--- a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md
+++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md
@@ -22,6 +22,7 @@ Should never be used in code outside of Core but is exported for documentation p
| --- | --- | --- |
| [configPath](./kibana-plugin-core-server.pluginmanifest.configpath.md) | ConfigPath | Root used by the plugin, defaults to "id" in snake\_case format. |
| [description?](./kibana-plugin-core-server.pluginmanifest.description.md) | string | (Optional) TODO: make required once all plugins specify this. A brief description of what this plugin does and any capabilities it provides. |
+| [enabledOnAnonymousPages?](./kibana-plugin-core-server.pluginmanifest.enabledonanonymouspages.md) | boolean | (Optional) Specifies whether this plugin - and its required dependencies - will be enabled for anonymous pages (login page, status page when configured, etc.) Default is false. |
| [extraPublicDirs?](./kibana-plugin-core-server.pluginmanifest.extrapublicdirs.md) | string\[\] | (Optional) Specifies directory names that can be imported by other ui-plugins built using the same instance of the @kbn/optimizer. A temporary measure we plan to replace with better mechanisms for sharing static code between plugins |
| [id](./kibana-plugin-core-server.pluginmanifest.id.md) | PluginName | Identifier of the plugin. Must be a string in camelCase. Part of a plugin public contract. Other plugins leverage it to access plugin API, navigate to the plugin, etc. |
| [kibanaVersion](./kibana-plugin-core-server.pluginmanifest.kibanaversion.md) | string | The version of Kibana the plugin is compatible with, defaults to "version". |
diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc
index 5906f2dd5008f..a702c7d607e55 100644
--- a/docs/management/advanced-options.asciidoc
+++ b/docs/management/advanced-options.asciidoc
@@ -478,13 +478,6 @@ The default index when using the `.es()` query.
[[timelion-estimefield]]`timelion:es.timefield`::
The default field containing a timestamp when using the `.es()` query.
-[[timelion-graphite-url]]`timelion:graphite.url`::
-experimental:[]
-Used with graphite queries, this is the URL of your graphite host
-in the form https://www.hostedgraphite.com/UID/ACCESS_KEY/graphite. This URL can
-be selected from an allow-list configured in the `kibana.yml` under
-`timelion.graphiteUrls`.
-
[[timelion-maxbuckets]]`timelion:max_buckets`::
The maximum number of buckets a single data source can return. This value is
used for calculating automatic intervals in visualizations.
@@ -492,11 +485,6 @@ used for calculating automatic intervals in visualizations.
[[timelion-mininterval]]`timelion:min_interval`::
The smallest interval to calculate when using "auto".
-[[timelion-quandlkey]]`timelion:quandl.key`::
-experimental:[]
-Used with quandl queries, this is your API key from
-https://www.quandl.com/[www.quandl.com].
-
[[timelion-targetbuckets]]`timelion:target_buckets`::
Used for calculating automatic intervals in visualizations, this is the number
of buckets to try to represent.
diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc
index b0f238124a008..c0b37ba9ec6f3 100644
--- a/docs/setup/settings.asciidoc
+++ b/docs/setup/settings.asciidoc
@@ -682,6 +682,8 @@ sources and images. When false, Vega can only get data from {es}. *Default: `fal
`exploreDataInContextMenu.enabled`
| Enables the *Explore underlying data* option that allows you to open *Discover* from a dashboard panel and view the panel data. *Default: `false`*
+ When you create visualizations using the *Lens* drag-and-drop editor, you can use the toolbar to open and explore your data in *Discover*. For more information, check out <>.
+
|[[settings-explore-data-in-chart]] `xpack.discoverEnhanced.actions.`
`exploreDataInChart.enabled`
| Enables you to view the underlying documents in a data series from a dashboard panel. *Default: `false`*
diff --git a/docs/user/dashboard/images/lens_annotations_8.2.0.png b/docs/user/dashboard/images/lens_annotations_8.2.0.png
new file mode 100644
index 0000000000000..bd60c1b60be6e
Binary files /dev/null and b/docs/user/dashboard/images/lens_annotations_8.2.0.png differ
diff --git a/docs/user/dashboard/lens-advanced.asciidoc b/docs/user/dashboard/lens-advanced.asciidoc
index a115dfbc30474..d98fd6c45c49f 100644
--- a/docs/user/dashboard/lens-advanced.asciidoc
+++ b/docs/user/dashboard/lens-advanced.asciidoc
@@ -67,7 +67,7 @@ image::images/lens_clickAndDragZoom_7.16.gif[Cursor clicking and dragging across
To identify the 75th percentile of orders, add a reference line:
-. In the layer pane, click *Add layer > Add reference layer*.
+. In the layer pane, click *Add layer > Reference lines*.
. Click *Static value*.
@@ -154,7 +154,7 @@ To analyze multiple visualization types, create an area chart that displays the
Add a layer to display the customer traffic:
-. In the layer pane, click *Add layer > Add visualization layer*.
+. In the layer pane, click *Add layer > Visualization*.
. From the *Available fields* list, drag *customer_id* to the *Vertical Axis* field in the second layer.
diff --git a/docs/user/dashboard/lens.asciidoc b/docs/user/dashboard/lens.asciidoc
index 1fcc3eb797b59..513671dd51238 100644
--- a/docs/user/dashboard/lens.asciidoc
+++ b/docs/user/dashboard/lens.asciidoc
@@ -10,9 +10,11 @@ With *Lens*, you can:
* Create area, line, and bar charts with layers to display multiple indices and chart types.
* Change the aggregation function to change the data in the visualization.
+* Create custom tables.
* Perform math on aggregations using *Formula*.
* Use time shifts to compare the data in two time intervals, such as month over month.
-* Create custom tables.
+* Add annotations and reference lines.
+
++++