Merge remote-tracking branch 'kibana/master' into save-object-modal

# Conflicts:
#	src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js
This commit is contained in:
maryia-lapata 2020-01-30 09:19:34 +03:00
commit 3b498003b1
430 changed files with 6353 additions and 4097 deletions

View file

@ -40,16 +40,11 @@ stage("Kibana Pipeline") { // This stage is just here to help the BlueOcean UI a
'oss-ciGroup11': kibanaPipeline.getOssCiGroupWorker(11),
'oss-ciGroup12': kibanaPipeline.getOssCiGroupWorker(12),
]),
'kibana-xpack-agent-1': kibanaPipeline.withWorkers('kibana-xpack-tests-1', { kibanaPipeline.buildXpack() }, [
'kibana-xpack-agent': kibanaPipeline.withWorkers('kibana-xpack-tests', { kibanaPipeline.buildXpack() }, [
'xpack-ciGroup1': kibanaPipeline.getXpackCiGroupWorker(1),
'xpack-ciGroup2': kibanaPipeline.getXpackCiGroupWorker(2),
]),
'kibana-xpack-agent-2': kibanaPipeline.withWorkers('kibana-xpack-tests-2', { kibanaPipeline.buildXpack() }, [
'xpack-ciGroup3': kibanaPipeline.getXpackCiGroupWorker(3),
'xpack-ciGroup4': kibanaPipeline.getXpackCiGroupWorker(4),
]),
'kibana-xpack-agent-3': kibanaPipeline.withWorkers('kibana-xpack-tests-3', { kibanaPipeline.buildXpack() }, [
'xpack-ciGroup5': kibanaPipeline.getXpackCiGroupWorker(5),
'xpack-ciGroup6': kibanaPipeline.getXpackCiGroupWorker(6),
'xpack-ciGroup7': kibanaPipeline.getXpackCiGroupWorker(7),
@ -75,9 +70,7 @@ stage("Kibana Pipeline") { // This stage is just here to help the BlueOcean UI a
echo extracting kibana-oss-tests
tar -xzf /tmp/downloaded_coverage/coverage/kibana-oss-tests/kibana-coverage.tar.gz -C /tmp/extracted_coverage
echo extracting kibana-xpack-tests
for i in {1..3}; do
tar -xzf /tmp/downloaded_coverage/coverage/kibana-xpack-tests-${i}/kibana-coverage.tar.gz -C /tmp/extracted_coverage
done
tar -xzf /tmp/downloaded_coverage/coverage/kibana-xpack-tests/kibana-coverage.tar.gz -C /tmp/extracted_coverage
# replace path in json files to have valid html report
pwd=$(pwd)
du -sh /tmp/extracted_coverage/target/kibana-coverage/

View file

@ -88,6 +88,14 @@ module.exports = {
'react-hooks/exhaustive-deps': 'off',
},
},
{
files: [
'src/legacy/core_plugins/vis_default_editor/public/components/controls/**/*.{ts,tsx}',
],
rules: {
'react-hooks/exhaustive-deps': 'off',
},
},
{
files: ['src/legacy/ui/public/vis/**/*.{js,ts,tsx}'],
rules: {

View file

@ -35,6 +35,7 @@
"tileMap": "src/legacy/core_plugins/tile_map",
"timelion": ["src/legacy/core_plugins/timelion", "src/legacy/core_plugins/vis_type_timelion", "src/plugins/timelion"],
"uiActions": "src/plugins/ui_actions",
"visDefaultEditor": "src/legacy/core_plugins/vis_default_editor",
"visTypeMarkdown": "src/legacy/core_plugins/vis_type_markdown",
"visTypeMetric": "src/legacy/core_plugins/vis_type_metric",
"visTypeTable": "src/legacy/core_plugins/vis_type_table",

View file

@ -174,6 +174,16 @@ yarn kbn bootstrap
(You can also run `yarn kbn` to see the other available commands. For more info about this tool, see https://github.com/elastic/kibana/tree/master/packages/kbn-pm.)
When switching branches which use different versions of npm packages you may need to run;
```bash
yarn kbn clean
```
If you have failures during `yarn kbn bootstrap` you may have some corrupted packages in your yarn cache which you can clean with;
```bash
yarn cache clean
```
#### Increase node.js heap size
Kibana is a big project and for some commands it can happen that the process hits the default heap limit and crashes with an out-of-memory error. If you run into this problem, you can increase maximum heap size by setting the `--max_old_space_size` option on the command line. To set the limit for all commands, simply add the following line to your shell config: `export NODE_OPTIONS="--max_old_space_size=2048"`.
@ -193,7 +203,7 @@ yarn es snapshot
##### Keeping data between snapshots
If you want to keep the data inside your Elasticsearch between usages of this command,
you should use the following command, to keep your data folder outside the downloaded snapshot
you should use the following command, to keep your data folder outside the downloaded snapshot
folder:
```bash
@ -290,6 +300,7 @@ Follow the [cross-cluster search](https://www.elastic.co/guide/en/kibana/current
### Running Kibana
Change to your local Kibana directory.
Start the development server.
```bash

View file

@ -42,9 +42,10 @@ when `csp.strict` is enabled.
to Elasticsearch. Any custom headers cannot be overwritten by client-side
headers, regardless of the `elasticsearch.requestHeadersWhitelist` configuration.
`elasticsearch.hosts:`:: *Default: "http://localhost:9200"* The URLs of the
Elasticsearch instances to use for all your queries. All nodes listed here must
be on the same cluster.
`elasticsearch.hosts:`:: *Default: `[ "http://localhost:9200" ]`* The URLs of the {es} instances to use for all your queries. All nodes
listed here must be on the same cluster.
+
To enable SSL/TLS for outbound connections to {es}, use the `https` protocol in this setting.
`elasticsearch.logQueries:`:: *Default: `false`* Logs queries sent to
Elasticsearch. Requires `logging.verbose` set to `true`. This is useful for
@ -82,52 +83,59 @@ Elasticsearch nodes on startup.
`elasticsearch.sniffOnConnectionFault:`:: *Default: false* Update the list of
Elasticsearch nodes immediately following a connection fault.
`elasticsearch.ssl.alwaysPresentCertificate:`:: *Default: false* Controls whether to always present the certificate specified by
`elasticsearch.ssl.certificate` or `elasticsearch.ssl.keystore.path` when requested. This setting applies to all requests to Elasticsearch,
including requests that are proxied for end users. Setting this to `true` when Elasticsearch is using certificates to authenticate users can
lead to proxied requests for end users being executed as the identity tied to the configured certificate.
`elasticsearch.ssl.certificate:` and `elasticsearch.ssl.key:`:: Paths to a PEM-encoded X.509 certificate and its private key, respectively.
When `xpack.security.http.ssl.client_authentication` in Elasticsearch is set to `required` or `optional`, the certificate and key are used
to prove Kibana's identity when it makes an outbound request to your Elasticsearch cluster.
`elasticsearch.ssl.alwaysPresentCertificate:`:: *Default: false* Controls {kib}'s behavior in regard to presenting a client certificate when
requested by {es}. This setting applies to all outbound SSL/TLS connections to {es}, including requests that are proxied for end users.
+
WARNING: If {es} uses certificates to authenticate end users with a PKI realm and `elasticsearch.ssl.alwaysPresentCertificate` is `true`,
proxied requests may be executed as the identity that is tied to the {kib} server.
`elasticsearch.ssl.certificate:` and `elasticsearch.ssl.key:`:: Paths to a PEM-encoded X.509 client certificate and its corresponding
private key. These are used by {kib} to authenticate itself when making outbound SSL/TLS connections to {es}. For this setting to take
effect, the `xpack.security.http.ssl.client_authentication` setting in {es} must be also be set to `"required"` or `"optional"` to request a
client certificate from {kib}.
+
--
NOTE: These settings cannot be used in conjunction with `elasticsearch.ssl.keystore.path`.
--
`elasticsearch.ssl.certificateAuthorities:`:: Paths to one or more PEM-encoded X.509 certificates. These certificates may consist of a root
certificate authority (CA), and one or more intermediate CAs, which make up a trusted certificate chain for Kibana. This chain is used to
establish trust when Kibana creates an SSL connection with your Elasticsearch cluster. In addition to this setting, trusted certificates may
be specified via `elasticsearch.ssl.keystore.path` and/or `elasticsearch.ssl.truststore.path`.
`elasticsearch.ssl.certificateAuthorities:`:: Paths to one or more PEM-encoded X.509 certificate authority (CA) certificates which make up a
trusted certificate chain for {es}. This chain is used by {kib} to establish trust when making outbound SSL/TLS connections to {es}.
+
In addition to this setting, trusted certificates may be specified via `elasticsearch.ssl.keystore.path` and/or
`elasticsearch.ssl.truststore.path`.
`elasticsearch.ssl.keyPassphrase:`:: The passphrase that will be used to decrypt the private key that is specified via
`elasticsearch.ssl.keyPassphrase:`:: The password that will be used to decrypt the private key that is specified via
`elasticsearch.ssl.key`. This value is optional, as the key may not be encrypted.
`elasticsearch.ssl.keystore.path:`:: Path to a PKCS #12 file that contains an X.509 certificate with its private key. When
`xpack.security.http.ssl.client_authentication` in Elasticsearch is set to `required` or `optional`, the certificate and key are used to
prove Kibana's identity when it makes an outbound request to your Elasticsearch cluster. If the file contains any additional certificates,
those will be used as a trusted certificate chain for your Elasticsearch cluster. This chain is used to establish trust when Kibana creates
an SSL connection with your Elasticsearch cluster. In addition to this setting, trusted certificates may be specified via
`elasticsearch.ssl.certificateAuthorities` and/or `elasticsearch.ssl.truststore.path`.
`elasticsearch.ssl.keystore.path:`:: Path to a PKCS#12 keystore that contains an X.509 client certificate and its corresponding private key.
These are used by {kib} to authenticate itself when making outbound SSL/TLS connections to {es}. For this setting to take effect, the
`xpack.security.http.ssl.client_authentication` setting in {es} must also be set to `"required"` or `"optional"` to request a client
certificate from {kib}.
+
--
If the keystore contains any additional certificates, those will be used as a trusted certificate chain for {es}. This chain is used by
{kib} to establish trust when making outbound SSL/TLS connections to {es}. In addition to this setting, trusted certificates may be
specified via `elasticsearch.ssl.certificateAuthorities` and/or `elasticsearch.ssl.truststore.path`.
NOTE: This setting cannot be used in conjunction with `elasticsearch.ssl.certificate` or `elasticsearch.ssl.key`.
--
`elasticsearch.ssl.keystore.password:`:: The password that will be used to decrypt the key store and its private key. If your key store has
no password, leave this unset. If your key store has an empty password, set this to `""`.
`elasticsearch.ssl.keystore.password:`:: The password that will be used to decrypt the keystore that is specified via
`elasticsearch.ssl.keystore.path`. If the keystore has no password, leave this unset. If the keystore has an empty password, set this to
`""`.
`elasticsearch.ssl.truststore.path:`:: Path to a PKCS #12 trust store that contains one or more X.509 certificates. This may consist of a
root certificate authority (CA) and one or more intermediate CAs, which make up a trusted certificate chain for your Elasticsearch cluster.
This chain is used to establish trust when Kibana creates an SSL connection with your Elasticsearch cluster. In addition to this setting,
trusted certificates may be specified via `elasticsearch.ssl.certificateAuthorities` and/or `elasticsearch.ssl.keystore.path`.
`elasticsearch.ssl.truststore.path:`:: Path to a PKCS#12 trust store that contains one or more X.509 certificate authority (CA) certificates
which make up a trusted certificate chain for {es}. This chain is used by {kib} to establish trust when making outbound SSL/TLS connections
to {es}.
+
In addition to this setting, trusted certificates may be specified via `elasticsearch.ssl.certificateAuthorities` and/or
`elasticsearch.ssl.keystore.path`.
`elasticsearch.ssl.truststore.password:`:: The password that will be used to decrypt the trust store. If your trust store has no password,
leave this unset. If your trust store has an empty password, set this to `""`.
`elasticsearch.ssl.truststore.password:`:: The password that will be used to decrypt the trust store specified via
`elasticsearch.ssl.truststore.path`. If the trust store has no password, leave this unset. If the trust store has an empty password, set
this to `""`.
`elasticsearch.ssl.verificationMode:`:: *Default: full* Controls the verification of certificates presented by Elasticsearch. Valid values
are `none`, `certificate`, and `full`. `full` performs hostname verification and `certificate` does not. This setting is used only when
traffic to Elasticsearch is encrypted, which is specified by using the HTTPS protocol in `elasticsearch.hosts`.
`elasticsearch.ssl.verificationMode:`:: *Default: `"full"`* Controls the verification of the server certificate that {kib} receives when
making an outbound SSL/TLS connection to {es}. Valid values are `"full"`, `"certificate"`, and `"none"`. Using `"full"` will perform
hostname verification, using `"certificate"` will skip hostname verification, and using `"none"` will skip verification entirely.
`elasticsearch.startupTimeout:`:: *Default: 5000* Time in milliseconds to wait
for Elasticsearch at Kibana startup before retrying.
@ -348,58 +356,57 @@ default is `true`.
`server.socketTimeout:`:: *Default: "120000"* The number of milliseconds to wait before closing an
inactive socket.
`server.ssl.certificate:` and `server.ssl.key:`:: Paths to a PEM-encoded X.509 certificate and its private key, respectively. These are used
when enabling SSL for inbound requests from web browsers to the Kibana server.
`server.ssl.certificate:` and `server.ssl.key:`:: Paths to a PEM-encoded X.509 server certificate and its corresponding private key. These
are used by {kib} to establish trust when receiving inbound SSL/TLS connections from end users.
+
--
NOTE: These settings cannot be used in conjunction with `server.ssl.keystore.path`.
--
`server.ssl.certificateAuthorities:`:: Paths to one or more PEM-encoded X.509 certificates. These certificates may consist of a root
certificate authority (CA) and one or more intermediate CAs, which make up a trusted certificate chain for Kibana. This chain is used when a
web browser creates an SSL connection with the Kibana server; the certificate chain is sent to the browser along with the end-entity
certificate to establish trust. This chain is also used to determine whether client certificates should be trusted when PKI authentication
is enabled. In addition to this setting, trusted certificates may be specified via `server.ssl.keystore.path` and/or
`server.ssl.truststore.path`.
`server.ssl.certificateAuthorities:`:: Paths to one or more PEM-encoded X.509 certificate authority (CA) certificates which make up a
trusted certificate chain for {kib}. This chain is used by {kib} to establish trust when receiving inbound SSL/TLS connections from end
users. If PKI authentication is enabled, this chain is also used by {kib} to verify client certificates from end users.
+
In addition to this setting, trusted certificates may be specified via `server.ssl.keystore.path` and/or `server.ssl.truststore.path`.
`server.ssl.cipherSuites:`:: *Default: ECDHE-RSA-AES128-GCM-SHA256, ECDHE-ECDSA-AES128-GCM-SHA256, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-GCM-SHA384, DHE-RSA-AES128-GCM-SHA256, ECDHE-RSA-AES128-SHA256, DHE-RSA-AES128-SHA256, ECDHE-RSA-AES256-SHA384, DHE-RSA-AES256-SHA384, ECDHE-RSA-AES256-SHA256, DHE-RSA-AES256-SHA256, HIGH,!aNULL, !eNULL, !EXPORT, !DES, !RC4, !MD5, !PSK, !SRP, !CAMELLIA*.
Details on the format, and the valid options, are available via the
https://www.openssl.org/docs/man1.0.2/apps/ciphers.html#CIPHER-LIST-FORMAT[OpenSSL cipher list format documentation].
`server.ssl.clientAuthentication:`:: *Default: none* Controls the servers behavior in regard to requesting a certificate from client
connections. Valid values are `required`, `optional`, and `none`. `required` forces a client to present a certificate, while `optional`
requests a client certificate but the client is not required to present one.
`server.ssl.clientAuthentication:`:: *Default: `"none"`* Controls {kib}s behavior in regard to requesting a certificate from client
connections. Valid values are `"required"`, `"optional"`, and `"none"`. Using `"required"` will refuse to establish the connection unless a
client presents a certificate, using `"optional"` will allow a client to present a certificate if it has one, and using `"none"` will
prevent a client from presenting a certificate.
`server.ssl.enabled:`:: *Default: "false"* Enables SSL for inbound requests from the browser to the Kibana server. When set to `true`, a
certificate and private key must be provided. These can be specified via `server.ssl.keystore.path` or the combination of
`server.ssl.enabled:`:: *Default: `false`* Enables SSL/TLS for inbound connections to {kib}. When set to `true`, a certificate and its
corresponding private key must be provided. These can be specified via `server.ssl.keystore.path` or the combination of
`server.ssl.certificate` and `server.ssl.key`.
`server.ssl.keyPassphrase:`:: The passphrase that will be used to decrypt the private key that is specified via `server.ssl.key`. This value
`server.ssl.keyPassphrase:`:: The password that will be used to decrypt the private key that is specified via `server.ssl.key`. This value
is optional, as the key may not be encrypted.
`server.ssl.keystore.path:`:: Path to a PKCS #12 file that contains an X.509 certificate with its private key. These are used when enabling
SSL for inbound requests from web browsers to the Kibana server. If the file contains any additional certificates, those will be used as a
trusted certificate chain for Kibana. This chain is used when a web browser creates an SSL connection with the Kibana server; the
certificate chain is sent to the browser along with the end-entity certificate to establish trust. This chain is also used to determine
whether client certificates should be trusted when PKI authentication is enabled. In addition to this setting, trusted certificates may be
specified via `server.ssl.certificateAuthorities` and/or `server.ssl.truststore.path`.
`server.ssl.keystore.path:`:: Path to a PKCS#12 keystore that contains an X.509 server certificate and its corresponding private key. If the
keystore contains any additional certificates, those will be used as a trusted certificate chain for {kib}. All of these are used by {kib}
to establish trust when receiving inbound SSL/TLS connections from end users. The certificate chain is also used by {kib} to verify client
certificates from end users when PKI authentication is enabled.
+
--
In addition to this setting, trusted certificates may be specified via `server.ssl.certificateAuthorities` and/or
`server.ssl.truststore.path`.
NOTE: This setting cannot be used in conjunction with `server.ssl.certificate` or `server.ssl.key`.
--
`server.ssl.keystore.password:`:: The password that will be used to decrypt the key store and its private key. If your key store has no
password, leave this unset. If your key store has an empty password, set this to `""`.
`server.ssl.keystore.password:`:: The password that will be used to decrypt the keystore specified via `server.ssl.keystore.path`. If the
keystore has no password, leave this unset. If the keystore has an empty password, set this to `""`.
`server.ssl.truststore.path:`:: Path to a PKCS #12 trust store that contains one or more X.509 certificates. These certificates may consist
of a root certificate authority (CA) and one or more intermediate CAs, which make up a trusted certificate chain for Kibana. This chain is
used when a web browser creates an SSL connection with the Kibana server; the certificate chain is sent to the browser along with the
end-entity certificate to establish trust. This chain is also used to determine whether client certificates should be trusted when PKI
authentication is enabled. In addition to this setting, trusted certificates may be specified via `server.ssl.certificateAuthorities` and/or
`server.ssl.truststore.path:`:: Path to a PKCS#12 trust store that contains one or more X.509 certificate authority (CA) certificates which
make up a trusted certificate chain for {kib}. This chain is used by {kib} to establish trust when receiving inbound SSL/TLS connections
from end users. If PKI authentication is enabled, this chain is also used by {kib} to verify client certificates from end users.
+
In addition to this setting, trusted certificates may be specified via `server.ssl.certificateAuthorities` and/or
`server.ssl.keystore.path`.
`server.ssl.truststore.password:`:: The password that will be used to decrypt the trust store. If your trust store has no password, leave
this unset. If your trust store has an empty password, set this to `""`.
`server.ssl.truststore.password:`:: The password that will be used to decrypt the trust store specified via `server.ssl.truststore.path`. If
the trust store has no password, leave this unset. If the trust store has an empty password, set this to `""`.
`server.ssl.redirectHttpFromPort:`:: Kibana will bind to this port and redirect
all http requests to https over the port configured as `server.port`.

View file

@ -93,34 +93,7 @@ valid user ID and password in the `elasticsearch.username` and
`elasticsearch.password` settings in the `kibana.yml` file. These values are
used when {kib} sends monitoring data to the production cluster.
.. Configure {kib} to encrypt communications between the {kib} server and the
production cluster. This set up involves generating a server certificate and
setting `server.ssl.*` and `elasticsearch.ssl.certificateAuthorities` settings
in the `kibana.yml` file on the {kib} server. For example, using a PEM-formatted
certificate and private key:
+
--
[source,yaml]
--------------------------------------------------------------------------------
server.ssl.key: /path/to/your/server.key
server.ssl.certificate: /path/to/your/server.crt
--------------------------------------------------------------------------------
If you are using your own certificate authority (CA) to sign certificates,
specify the location of the PEM file in the `kibana.yml` file:
[source,yaml]
--------------------------------------------------------------------------------
elasticsearch.ssl.certificateAuthorities: /path/to/your/cacert.pem
--------------------------------------------------------------------------------
NOTE: Alternatively, the PKCS #12 format can be used for the Kibana certificate
and key, along with any included CA certificates, by setting
`server.ssl.keystore.path`. If your CA certificate chain is in a separate trust
store, you can also use `server.ssl.truststore.path`.
For more information, see <<using-kibana-with-security>>.
--
.. <<configuring-tls-kib-es,Configure encryption for traffic between {kib} and {es}>>.
. <<start-stop,Start {kib}>>.

View file

@ -1,6 +1,6 @@
[role="xpack"]
[[kibana-authentication]]
=== Authentication in Kibana
=== Authentication in {kib}
++++
<titleabbrev>Authentication</titleabbrev>
++++
@ -16,9 +16,9 @@
[[basic-authentication]]
==== Basic authentication
Basic authentication requires a username and password to successfully log in to {kib}. It is enabled by default and based on the Native security realm provided by {es}. The basic authentication provider uses a Kibana provided login form, and supports authentication using the `Authorization` request header's `Basic` scheme.
To successfully log in to {kib}, basic authentication requires a username and password. Basic authentication is enabled by default, and is based on the Native security realm or LDAP security realm that is provided by {es}. The basic authentication provider uses a {kib} provided login form, and supports authentication using the `Authorization` request header `Basic` scheme.
The session cookies that are issued by the basic authentication provider are stateless. Therefore, logging out of Kibana when using the basic authentication provider clears the session cookies from the browser but does not invalidate the session cookie for reuse.
The session cookies that are issued by the basic authentication provider are stateless. Therefore, logging out of {kib} when using the basic authentication provider clears the session cookies from the browser, but does not invalidate the session cookie for reuse.
For more information about basic authentication and built-in users, see
{ref}/setting-up-authentication.html[User authentication].
@ -26,13 +26,13 @@ For more information about basic authentication and built-in users, see
[[token-authentication]]
==== Token authentication
Token authentication allows users to login using the same Kibana provided login form as basic authentication. The token authentication provider is built on {es}'s token APIs. The bearer tokens returned by {es}'s {ref}/security-api-get-token.html[get token API] can be used directly with Kibana using the `Authorization` request header with the `Bearer` scheme.
Token authentication allows users to login using the same {kib} provided login form as basic authentication, and is based on the Native security realm or LDAP security realm that is provided by {es}. The token authentication provider is built on {es} token APIs. The bearer tokens returned by {es}'s {ref}/security-api-get-token.html[get token API] can be used directly with {kib} using the `Authorization` request header with the `Bearer` scheme.
The session cookies that are issued by the token authentication provider are stateful, and logging out of Kibana invalidates the session cookies for reuse.
The session cookies that are issued by the token authentication provider are stateful, and logging out of {kib} invalidates the session cookies for reuse.
Prior to configuring Kibana, ensure token support is enabled in Elasticsearch. See the {ref}/security-api-get-token.html[Elasticsearch token API] documentation for more information.
Prior to configuring {kib}, ensure token support is enabled in {es}. See the {ref}/security-api-get-token.html[{es} token API] documentation for more information.
To enable the token authentication provider in Kibana, set the following value in your `kibana.yml`:
To enable the token authentication provider in {kib}, set the following value in your `kibana.yml`:
[source,yaml]
--------------------------------------------------------------------------------
@ -67,7 +67,7 @@ server.ssl.clientAuthentication: required
xpack.security.authc.providers: [pki]
--------------------------------------------------------------------------------
NOTE: Trusted CAs can also be specified in a PKCS #12 keystore bundled with your Kibana server certificate/key using
NOTE: Trusted CAs can also be specified in a PKCS #12 keystore bundled with your {kib} server certificate/key using
`server.ssl.keystore.path` or in a separate trust store using `server.ssl.truststore.path`.
PKI support in {kib} is designed to be the primary (or sole) authentication method for users of that {kib} instance. However, you can configure both PKI and Basic authentication for the same {kib} instance:
@ -128,7 +128,7 @@ Basic authentication is supported _only_ if `basic` authentication provider is e
At the beginning of the SAML handshake, {kib} stores the initial URL in the session cookie, so it can redirect the user back to that URL after successful SAML authentication.
If the URL is long, the session cookie might exceed the maximum size supported by the browser--typically 4KB for all cookies per domain. When this happens, the session cookie is truncated,
or dropped completely, and you might experience sporadic failures during SAML authentication.
or dropped completely, and you might experience sporadic failures during SAML authentication.
To remedy this issue, you can decrease the maximum
size of the URL that {kib} is allowed to store during the SAML handshake. The default value is 2KB.
@ -185,7 +185,7 @@ Users will be able to access the login page and use Basic authentication by navi
[float]
==== Single sign-on provider details
The following sections apply both to <<saml>> and <<oidc>>
The following sections apply both to <<saml>> and <<oidc>>
[float]
===== Access and refresh tokens

View file

@ -5,70 +5,90 @@
<titleabbrev>Mutual TLS with {es}</titleabbrev>
++++
In a standard Transport Layer Security (TLS/SSL) configuration, the server presents a signed certificate to authenticate itself to the
client. In a mutual TLS configuration, the client also presents a signed certificate to authenticate itself to the server.
Secure Sockets Layer (SSL) and Transport Layer Security (TLS) provide encryption for data-in-transit. While these terms are often used
interchangeably, {kib} supports only TLS, which supersedes the old SSL protocols.
When {security} is enabled on your cluster, each request that {kib} makes to {es} must be authenticated. Most requests made through {kib} to
{es} are authenticated by using the credentials of the logged-in user. There are, however, a few internal requests that the {kib} server
needs to make to the {es} cluster. For this reason, you must configure credentials for the {kib} server to use for those requests.
TLS requires X.509 certificates to authenticate the communicating parties and perform encryption of data-in-transit. Each certificate
contains a public key and has and an associated -- but separate -- private key; these keys are used for cryptographic operations. {kib}
supports certificates and private keys in PEM or PKCS#12 format.
In a standard TLS configuration, the server presents a signed certificate to authenticate itself to the client. In a mutual TLS
configuration, the client also presents a signed certificate to authenticate itself to the server.
When {es} {security-features} is enabled on your cluster, each request that {kib} (the client) makes to {es} (the server) must be
authenticated. Most requests made by end users through {kib} to {es} are authenticated by using the credentials of the logged-in user. There
are, however, a few internal requests that {kib} needs to make to {es}. For this reason, you must configure credentials for {kib} to use for
those requests.
If {kib} has `elasticsearch.username` and `elasticsearch.password` configured, it will attempt to use these to authenticate to {es} via the
{ref}/native-realm.html[Native realm]. However, {kib} also supports mutual TLS authentication with {es} via a {ref}/pki-realm.html[Public
{ref}/native-realm.html[native realm]. However, {kib} also supports mutual TLS authentication with {es} via a {ref}/pki-realm.html[Public
Key Infrastructure (PKI) realm]. To do so, {es} needs to verify the signature on the {kib} client certificate, and it also needs to map the
certificate's distinguished name (DN) to the appropriate `kibana_system` role.
client certificate's distinguished name (DN) to the appropriate `kibana_system` role.
NOTE: Using a PKI realm is a gold feature. For a comparison of the Elastic license levels, see https://www.elastic.co/subscriptions[the
subscription page].
To configure {kib} and {es} to use mutual TLS authentication:
. <<using-kibana-with-security,Set up {kib} to work with {security}>> with a username and password.
. <<using-kibana-with-security,Set up {kib} to work with {stack} {security-features} with a username and password>>.
. <<configuring-tls-kib-es,Set up TLS encryption between {kib} and {es}>>. At a minimum, this requires a server certificate for {es}.
. <<configuring-tls-kib-es,Set up TLS encryption between {kib} and {es}>>.
+
This entails generating a "server certificate" for {es} to use on the HTTP layer.
. Create a client certificate and private key for {kib} to use when connecting to {es}.
+
--
NOTE: This is not the same as the <<configuring-tls-browser-kib,server certificate>> that {kib} will present to web browsers.
You may choose to generate a certificate and private key using {ref}/certutil.html[the {es} certutil tool]. At this point, you will have
already set up a certificate authority (CA) to sign the {es} server certificate. You may choose to use the same CA to sign the {kib} client
certificate. You would do this like so:
[source,sh]
--------------------------------------------------------------------------------
bin/elasticsearch-certutil cert -ca elastic-stack-ca.p12 -name kibana-client
--------------------------------------------------------------------------------
This will generate a certificate and private key in a PKCS #12 keystore named `kibana-client.p12`. The certificate has a Common Name (CN) of
"kibana-client".
You will also need to use the CA certificate when setting up the PKI realm in {es}. While you could use the CA keystore in the above example
for this purpose, it is bad practice to expose the CA's private key in such a manner. Instead, you can extract the CA certificate (without
its private key) like so:
[source,sh]
--------------------------------------------------------------------------------
openssl pkcs12 -in kibana-client.p12 -cacerts -nokeys -out ca.crt
--------------------------------------------------------------------------------
--
. Configure a PKI realm and a Native realm in your {es} cluster:
. Obtain a client certificate and private key for {kib}.
+
--
By default, {es} provides a Native realm. However, to support both a PKI realm (for {kib}) and a Native realm (for end users), you must
configure each realm in `elasticsearch.yml`:
{kib} must this "client certificate" and corresponding private key when connecting to {es}.
NOTE: This is not the same as the <<configuring-tls-browser-kib,server certificate>> that {kib} will present to web browsers.
You may choose to generate a client certificate and private key using the {ref}/certutil.html[`elasticsearch-certutil`] tool. If you
followed the {es} documentation for {ref}/configuring-tls.html#node-certificates[generating node certificates], then you likely have already
set up a certificate authority (CA) to sign the {es} server certificate. You may choose to use the same CA to sign the {kib} client
certificate. For example:
[source,sh]
--------------------------------------------------------------------------------
bin/elasticsearch-certutil cert -ca elastic-stack-ca.p12 -name kibana-client -dns <your_kibana_hostname>
--------------------------------------------------------------------------------
This will generate a client certificate and private key in a PKCS#12 file named `kibana-client.p12`. In this example, the client certificate
has a Common Name (CN) of `"kibana-client"` and a subject alternative name (SAN) of `"<your_kibana_hostname>"`. The SAN may be required if
you have hostname verification enabled on {es}.
--
. Obtain the certificate authority (CA) certificate chain for {kib}.
+
--
{es} needs the appropriate CA certificate chain to properly establish trust when receiving connections from {kib}.
If you followed the instructions above to generate a client certificate, then you will have a PKCS#12 file for {kib}. You can extract the CA
certificate chain from this file. For example:
[source,sh]
--------------------------------------------------------------------------------
openssl pkcs12 -in kibana-client.p12 -cacerts -nokeys -out kibana-ca.crt
--------------------------------------------------------------------------------
This will produce a PEM-formatted file named `kibana-ca.crt` that contains the CA certificate from the PKCS#12 file.
--
. Configure {es} with a PKI realm and a native realm.
+
--
By default, {es} provides a native realm for authenticating with a username and password. However, to support both a PKI realm (for {kib})
and a native realm (for end users), you must configure each realm in `elasticsearch.yml`:
[source,yaml]
--------------------------------------------------------------------------------
xpack.security.authc.realms.pki.realm1.order: 1
xpack.security.authc.realms.pki.realm1.certificate_authorities: "/path/to/ca.crt"
xpack.security.authc.realms.pki.realm1.certificate_authorities: "/path/to/kibana-ca.crt"
xpack.security.authc.realms.native.realm2.order: 2
--------------------------------------------------------------------------------
--
. Configure your {es} cluster to request client certificates:
. Configure {es} to request client certificates.
+
--
By default, {es} will not request a client certificate when establishing a TLS connection. To change this, you must set up optional client
@ -80,9 +100,9 @@ xpack.security.http.ssl.client_authentication: "optional"
--------------------------------------------------------------------------------
--
. Restart your {es} cluster.
. Restart {es}.
. Use {kib} to create a <<role-mappings,role mapping>> for your new client certificate:
. Use {kib} to create a role mapping in {es} for the client certificate.
+
--
This role mapping will assign the `kibana_system` role to any user that matches the included mapping rule, which is set to equal the client
@ -90,31 +110,61 @@ certificate's DN attribute:
[role="screenshot"]
image:user/security/images/mutual-tls-role-mapping.png["Role mapping for the {kib} client certificate"]
For more information, see <<role-mappings,role mappings>>.
--
. Configure {kib} to use the client certificate:
. Configure {kib} to use the client certificate and private key.
+
You need to specify the information required to access your client certificate and corresponding private key.
.. If your certificate and private key are contained in a PKCS#12 file:
+
--
Assuming you used the {es} certutil tool to generate a certificate and private key in a PKCS #12 keystore, add the following values to
`kibana.yml`:
Specify your PKCS#12 file in `kibana.yml`:
[source,yaml]
--------------------------------------------------------------------------------
elasticsearch.ssl.keystore.path: "/path/to/kibana-client.p12"
elasticsearch.ssl.keystore.password: "decryption password"
--------------------------------------------------------------------------------
The decryption password should match what you entered when prompted by the {es} certutil tool.
If your PKCS#12 file is encrypted, add the decryption password to your <<secure-settings,{kib} keystore>>:
You must also remove the `elasticsearch.username` and `elasticsearch.password` values from the configuration file. Otherwise, {kib} will
attempt to use those to authenticate via the Native realm.
[source,yaml]
--------------------------------------------------------------------------------
bin/kibana-keystore add elasticsearch.ssl.keystore.password
--------------------------------------------------------------------------------
TIP: Alternatively, {kib} also supports using a client certificate and private key in PEM format with the `elasticsearch.ssl.certificate`
and `elasticsearch.ssl.key` settings. For more information, see <<settings,{kib} configuration settings>>.
TIP: If your PKCS#12 file isn't protected with a password, depending on how it was generated, you may need to set
`elasticsearch.ssl.keystore.password` to an empty string.
--
.. Otherwise, if your certificate and private key are in PEM format:
+
--
Specify your certificate and private key in `kibana.yml`:
[source,yaml]
--------------------------------------------------------------------------------
elasticsearch.ssl.certificate: "/path/to/kibana-client.crt"
elasticsearch.ssl.key: "/path/to/kibana-client.key"
--------------------------------------------------------------------------------
If your private key is encrypted, add the decryption password to your <<secure-settings,{kib} keystore>>:
[source,yaml]
--------------------------------------------------------------------------------
bin/kibana-keystore add elasticsearch.ssl.keyPassphrase
--------------------------------------------------------------------------------
--
. Configure {kib} _not_ to use a username and password for {es}.
+
You must remove the `elasticsearch.username` and `elasticsearch.password` settings from `kibana.yml`. If these are present, {kib} will
attempt to use them to authenticate to {es} via the native realm.
. Restart {kib}.
NOTE: The steps above enable {kib} to authenticate to {es} using a certificate. However, end users will only be able to authenticate to
{kib} with a username and password. To allow end users to authenticate to {kib} using certificates, see <<pki-authentication,{kib} PKI
authentication>>.
{kib} with a username and password. To allow end users to authenticate to {kib} using a client certificate, see <<pki-authentication,{kib}
PKI authentication>>.

View file

@ -4,127 +4,189 @@
<titleabbrev>Encrypting communications</titleabbrev>
++++
{kib} supports Transport Layer Security (TLS/SSL) encryption for all forms of
data-in-transit. Browsers send traffic to {kib} and {kib} sends traffic to {es}.
These communications are configured separately.
Secure Sockets Layer (SSL) and Transport Layer Security (TLS) provide encryption for data-in-transit. While these terms are often used
interchangeably, {kib} supports only TLS, which supersedes the old SSL protocols.
Browsers send traffic to {kib} and {kib} sends traffic to {es}. These communication channels are configured separately to use TLS.
TLS requires X.509 certificates to authenticate the communicating parties and perform encryption of data-in-transit. Each certificate
contains a public key and has an associated -- but separate -- private key; these keys are used for cryptographic operations. {kib}
supports certificates and private keys in PEM or PKCS#12 format.
[[configuring-tls-browser-kib]]
==== Encrypting traffic between the browser and {kib}
NOTE: You do not need to enable {security-features} for this type of encryption.
NOTE: You do not need to enable the {es} {security-features} for this type of encryption.
. Obtain a server certificate and private key for {kib}.
+
--
{kib} supports certificates/keys in both PKCS #12 key stores and PEM format.
{kib} will need to use this "server certificate" and corresponding private key when receiving connections from web browsers.
When you obtain a certificate, you must do at least one of the following:
When you obtain a server certificate, you must set its subject alternative name (SAN) correctly to ensure that modern web browsers with
hostname verification will trust it. You can set one or more SANs to the {kib} server's fully-qualified domain name (FQDN), hostname, or IP
address. When choosing the SAN, you should pick whichever attribute you will be using to connect to {kib} in your browser, which is likely
the FQDN.
.. Set the certificate's `subjectAltName` to the hostname, fully-qualified domain name (FQDN), or IP address of the {kib} server.
.. Set the certificate's Common Name (CN) to the {kib} server's hostname or FQDN. Using the server's IP address as the CN does not work.
You may choose to generate a certificate and private key using {ref}/certutil.html[the {es} certutil tool]. If you already used certutil to
generate a certificate authority (CA), you would generate a certificate/key for Kibana like so (using the `--dns` param to set the
`subjectAltName`):
You may choose to generate a certificate signing request (CSR) and private key using the {ref}/certutil.html[`elasticsearch-certutil`] tool.
For example:
[source,sh]
--------------------------------------------------------------------------------
bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12 --name kibana --dns localhost
bin/elasticsearch-certutil csr -name kibana-server -dns some-website.com,www.some-website.com
--------------------------------------------------------------------------------
This will generate a certificate and private key in a PKCS #12 keystore named `kibana.p12`.
This will produce a ZIP archive named `kibana-server.zip`. Extract that archive to obtain the PEM-formatted CSR (`kibana-server.csr`) and
unencrypted private key (`kibana-server.key`). In this example, the CSR has a common name (CN) of `kibana-server`, a SAN of
`some-website.com`, and another SAN of `www.some-website.com`.
NOTE: You will need to use a certificate authority (CA) to sign your CSR to obtain your server certificate. This certificate's signature
will be verified by web browsers that are configured to trust the CA.
--
. Enable TLS/SSL in `kibana.yml`:
. Configure {kib} to access the server certificate and private key.
.. If your server certificate and private key are in PEM format:
+
--
Specify your server certificate and private key in `kibana.yml`:
[source,yaml]
--------------------------------------------------------------------------------
server.ssl.certificate: "/path/to/kibana-server.crt"
server.ssl.key: "/path/to/kibana-server.key"
--------------------------------------------------------------------------------
If your private key is encrypted, add the decryption password to your <<secure-settings,{kib} keystore>>:
[source,yaml]
--------------------------------------------------------------------------------
bin/kibana-keystore add server.ssl.keyPassphrase
--------------------------------------------------------------------------------
--
.. Otherwise, if your server certificate and private key are contained in a PKCS#12 file:
+
--
Specify your PKCS#12 file in `kibana.yml`:
[source,yaml]
--------------------------------------------------------------------------------
server.ssl.keystore.path: "/path/to/kibana-server.p12"
--------------------------------------------------------------------------------
If your PKCS#12 file is encrypted, add the decryption password to your <<secure-settings,{kib} keystore>>:
[source,yaml]
--------------------------------------------------------------------------------
bin/kibana-keystore add server.ssl.keystore.password
--------------------------------------------------------------------------------
TIP: If your PKCS#12 file isn't protected with a password, depending on how it was generated, you may need to set
`server.ssl.keystore.password` to an empty string.
--
+
For more information about settings for certificates and keys, see <<settings,{kib} configuration settings>>.
. Configure {kib} to enable TLS for inbound connections.
+
--
Specify that TLS is used in `kibana.yml`:
[source,yaml]
--------------------------------------------------------------------------------
server.ssl.enabled: true
--------------------------------------------------------------------------------
--
. Specify your server certificate and private key in `kibana.yml`:
+
--
If your certificate and private key are in a PKCS #12 keystore, specify it like so:
. Restart {kib}.
[source,yaml]
--------------------------------------------------------------------------------
server.ssl.keystore.path: "/path/to/your/keystore.p12"
server.ssl.keystore.password: "optional decryption password"
--------------------------------------------------------------------------------
Otherwise, if your certificate/key are in PEM format, specify them like so:
[source,yaml]
--------------------------------------------------------------------------------
server.ssl.certificate: "/path/to/your/server.crt"
server.ssl.key: "/path/to/your/server.key"
server.ssl.keyPassphrase: "optional decryption password"
--------------------------------------------------------------------------------
After making these changes, you must always access {kib} via HTTPS. For example,
https://localhost:5601.
For more information, see <<settings,{kib} configuration settings>>.
--
After making these changes, you must always access {kib} via HTTPS. For example, https://<your_kibana_host>.com.
[[configuring-tls-kib-es]]
==== Encrypting traffic between {kib} and {es}
NOTE: To perform this step, you must
{ref}/configuring-security.html[enable the {es} {security-features}] or you
must have a proxy that provides an HTTPS endpoint for {es}.
NOTE: To perform this step, you must {ref}/configuring-security.html[enable the {es} {security-features}] or you must have a proxy that
provides an HTTPS endpoint for {es}.
. Specify the HTTPS URL in the `elasticsearch.hosts` setting in the {kib}
configuration file, `kibana.yml`:
. {ref}/configuring-tls.html#tls-http[Enable TLS on the HTTP layer in {es}].
. Obtain the certificate authority (CA) certificate chain for {es}.
+
{kib} needs the appropriate CA certificate chain to properly establish trust when connecting to {es}.
.. If you followed the {es} documentation for {ref}/configuring-tls.html#node-certificates[generating node certificates] and used the
`elasticsearch-certutil http` command, check the `kibana` directory in its output. Depending on what options you chose, the output may
include the CA certificate chain in PEM format.
.. Otherwise, you likely have a PKCS#12 file for each your {es} nodes. You can extract the CA certificate chain from one of these files. For
example:
+
--
[source,sh]
--------------------------------------------------------------------------------
openssl pkcs12 -in elastic-certificates.p12 -cacerts -nokeys -out elasticsearch-ca.pem
--------------------------------------------------------------------------------
This will produce a PEM-formatted file named `elasticsearch-ca.pem` that contains all CA certificates from the PKCS#12 file.
--
. Configure {kib} to trust the {es} CA certificate chain for the HTTP layer.
.. If your CA certificate chain is in PEM format:
+
--
Specify one or more CA certificates in `kibana.yml`:
[source,yaml]
--------------------------------------------------------------------------------
elasticsearch.ssl.certificateAuthorities: ["/path/to/elasticsearch-ca.pem"]
--------------------------------------------------------------------------------
--
.. Otherwise, if your CA certificate chain is contained in a PKCS#12 file:
+
--
WARNING: You should not use a PKCS#12 file that contains a private key. This is an unnecessary security risk. If you only have a PKCS#12
file that contains a private key, a safer approach is to extract the CA certificate chain in PEM format as described above.
Specify your PKCS#12 file in `kibana.yml`:
[source,yaml]
--------------------------------------------------------------------------------
elasticsearch.ssl.truststore.path: "/path/to/elasticsearch-ca.p12"
--------------------------------------------------------------------------------
If your PKCS#12 file is encrypted, add the decryption password to your <<secure-settings,{kib} keystore>>:
[source,yaml]
--------------------------------------------------------------------------------
bin/kibana-keystore add elasticsearch.ssl.truststore.password
--------------------------------------------------------------------------------
TIP: If your PKCS#12 file isn't protected with a password, depending on how it was generated, you may need to set
`elasticsearch.ssl.truststore.password` to an empty string.
--
+
For more information about settings for certificates and keys, see <<settings,{kib} configuration settings>>.
. Configure {kib} to enable TLS for outbound connections to {es}.
+
--
Specify the HTTPS URL for {es} in `kibana.yml`:
[source,yaml]
--------------------------------------------------------------------------------
elasticsearch.hosts: ["https://<your_elasticsearch_host>.com:9200"]
--------------------------------------------------------------------------------
Using the HTTPS protocol results in a default
`elasticsearch.ssl.verificationMode` option of `full`, which utilizes hostname
verification.
For more information, see <<settings,{kib} configuration settings>>.
NOTE: Using the HTTPS protocol results in a default `elasticsearch.ssl.verificationMode` option of `full`, which utilizes hostname
verification. For more information about this setting, see <<settings,{kib} configuration settings>>.
--
. Specify the {es} cluster's CA certificate chain in `kibana.yml`:
+
--
If you are using your own CA to sign certificates for {es}, then you need to
specify the CA certificate chain in {kib} to properly establish trust in TLS
connections. If your CA certificate chain is contained in a PKCS #12 trust store,
specify it like so:
[source,yaml]
--------------------------------------------------------------------------------
elasticsearch.ssl.truststore.path: "/path/to/your/truststore.p12"
elasticsearch.ssl.truststore.password: "optional decryption password"
--------------------------------------------------------------------------------
Otherwise, if your CA certificate chain is in PEM format, specify each
certificate like so:
[source,yaml]
--------------------------------------------------------------------------------
elasticsearch.ssl.certificateAuthorities: ["/path/to/your/cacert1.pem", "/path/to/your/cacert2.pem"]
--------------------------------------------------------------------------------
TIP: You can use the {ref}/certutil.html[`elasticsearch-certutil http` command]
to generate a PEM format x.509 certificate for the {es} CA. It also provides
detailed configuration details in readme files.
--
. (Optional) If the Elastic {monitor-features} are enabled, configure {kib} to
connect to the {es} monitoring cluster via HTTPS. The steps are the same as
above, but each setting is prefixed by `xpack.monitoring.`. For example, `xpack.monitoring.elasticsearch.hosts`,
`xpack.monitoring.elasticsearch.ssl.truststore.path`, etc.
If the Elastic {monitor-features} are enabled and you have set up a separate {es} monitoring cluster, you can also configure {kib} to
connect to the monitoring cluster via HTTPS. The steps are the same as above, but each setting is prefixed by `xpack.monitoring.`. For
example, `xpack.monitoring.elasticsearch.hosts`, `xpack.monitoring.elasticsearch.ssl.truststore.path`, etc.

View file

@ -25,7 +25,7 @@
'Team:Operations',
'renovate',
'v8.0.0',
'v7.6.0',
'v7.7.0',
],
major: {
labels: [
@ -33,7 +33,7 @@
'Team:Operations',
'renovate',
'v8.0.0',
'v7.6.0',
'v7.7.0',
'renovate:major',
],
},
@ -238,7 +238,7 @@
'Team:Operations',
'renovate',
'v8.0.0',
'v7.6.0',
'v7.7.0',
':ml',
],
},

View file

@ -21,7 +21,7 @@ import { RENOVATE_PACKAGE_GROUPS } from './package_groups';
import { PACKAGE_GLOBS } from './package_globs';
import { wordRegExp, maybeFlatMap, maybeMap, getTypePackageName } from './utils';
const DEFAULT_LABELS = ['release_note:skip', 'Team:Operations', 'renovate', 'v8.0.0', 'v7.6.0'];
const DEFAULT_LABELS = ['release_note:skip', 'Team:Operations', 'renovate', 'v8.0.0', 'v7.7.0'];
export const RENOVATE_CONFIG = {
extends: ['config:base'],

View file

@ -30,6 +30,8 @@ import {
EuiSelect,
} from '@elastic/eui';
import { VisOptionsProps } from 'src/legacy/core_plugins/vis_default_editor/public';
import { IIndexPattern } from 'src/plugins/data/public';
import { ControlEditor } from './control_editor';
import {
addControl,
@ -42,8 +44,6 @@ import {
ControlParamsOptions,
} from '../../editor_utils';
import { getLineageMap, getParentCandidates } from '../../lineage';
import { IIndexPattern } from '../../../../../../plugins/data/public';
import { VisOptionsProps } from '../../legacy_imports';
import { InputControlVisDependencies } from '../../plugin';
interface ControlsTabUiState {

View file

@ -21,8 +21,8 @@ import React from 'react';
import { shallow } from 'enzyme';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { Vis } from 'src/legacy/core_plugins/visualizations/public';
import { OptionsTab, OptionsTabProps } from './options_tab';
import { Vis } from '../../legacy_imports';
describe('OptionsTab', () => {
let props: OptionsTabProps;

View file

@ -23,7 +23,7 @@ import { EuiForm, EuiFormRow, EuiSwitch } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiSwitchEvent } from '@elastic/eui';
import { VisOptionsProps } from '../../legacy_imports';
import { VisOptionsProps } from 'src/legacy/core_plugins/vis_default_editor/public';
interface OptionsTabParams {
updateFiltersOnChange: boolean;

View file

@ -22,8 +22,6 @@ import { SearchSource as SearchSourceClass, ISearchSource } from '../../../../pl
export { SearchSourceFields } from '../../../../plugins/data/public';
export { Vis, VisParams } from 'ui/vis';
export { VisOptionsProps } from 'ui/vis/editors/default';
export { ValidatedDualRange } from 'ui/validated_range';
export type SearchSource = Class<ISearchSource>;

View file

@ -21,7 +21,7 @@ import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { I18nStart } from 'kibana/public';
import { Vis, VisParams, SearchSource } from './legacy_imports';
import { SearchSource } from './legacy_imports';
import { InputControlVis } from './components/vis/input_control_vis';
import { getControlFactory } from './control/control_factory';
@ -31,6 +31,7 @@ import { RangeControl } from './control/range_control_factory';
import { ListControl } from './control/list_control_factory';
import { InputControlVisDependencies } from './plugin';
import { FilterManager, esFilters } from '../../../../plugins/data/public';
import { VisParams, Vis } from '../../visualizations/public';
export const createInputControlVisController = (deps: InputControlVisDependencies) => {
return class InputControlVisController {

View file

@ -74,7 +74,6 @@ export { unhashUrl } from '../../../../../plugins/kibana_utils/public';
export { formatMsg, formatStack } from 'ui/notify/lib/index';
// EXPORT types
export { Vis } from 'ui/vis';
export {
IndexPatternsContract,
IIndexPattern,

View file

@ -52,11 +52,11 @@ import {
stateMonitorFactory,
subscribeWithScope,
tabifyAggResponse,
Vis,
getAngularModule,
ensureDefaultIndexPattern,
registerTimefilterWithGlobalStateFactory,
} from '../../kibana_services';
import { Vis } from '../../../../../visualizations/public';
const {
core,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 546 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

View file

@ -424,7 +424,7 @@ exports[`should render a Welcome screen with the telemetry disclaimer when optIn
/>
</EuiLink>
<FormattedMessage
defaultMessage="To stop collection, "
defaultMessage=" To stop collection, "
id="kbn.home.dataManagementDisableCollection"
values={Object {}}
/>

View file

@ -42,7 +42,7 @@ interface Props {
export function SampleDataCard({ urlBasePath, onDecline, onConfirm }: Props) {
return (
<EuiCard
image={`${urlBasePath}/plugins/kibana/home/assets/illo_dashboard.png`}
image={`${urlBasePath}/plugins/kibana/home/assets/illustration_elastic_heart.png`}
textAlign="left"
title={<FormattedMessage id="kbn.home.letsStartTitle" defaultMessage="Let's get started" />}
description={

View file

@ -90,7 +90,7 @@ export class Welcome extends React.Component<Props> {
<Fragment>
<FormattedMessage
id="kbn.home.dataManagementDisableCollection"
defaultMessage="To stop collection, "
defaultMessage=" To stop collection, "
/>
<EuiLink href="#/management/kibana/settings">
<FormattedMessage

View file

@ -62,9 +62,9 @@ export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
export { VisType } from 'ui/vis';
export { wrapInI18nContext } from 'ui/i18n';
export { DashboardConstants } from '../dashboard/np_ready/dashboard_constants';
export { VisSavedObject } from '../../../visualizations/public/embeddable/visualize_embeddable';
export { VISUALIZE_EMBEDDABLE_TYPE } from '../../../visualizations/public/embeddable';
export { VisType } from '../../../visualizations/public';

View file

@ -56,7 +56,7 @@ export function initEditorDirective(app, deps) {
};
});
initVisEditorDirective(app);
initVisEditorDirective(app, deps);
initVisualizationDirective(app, deps);
}

View file

@ -17,7 +17,7 @@
* under the License.
*/
export function initVisEditorDirective(app) {
export function initVisEditorDirective(app, deps) {
app.directive('visualizationEditor', function($timeout, getAppState) {
return {
restrict: 'E',
@ -34,6 +34,9 @@ export function initVisEditorDirective(app) {
$scope.renderFunction = () => {
editor.render({
core: deps.core,
data: deps.data,
embeddables: deps.embeddables,
uiState: $scope.uiState,
timeRange: $scope.timeRange,
filters: $scope.filters,

View file

@ -17,11 +17,16 @@
* under the License.
*/
import { TimeRange, Query, esFilters } from 'src/plugins/data/public';
import { TimeRange, Query, esFilters, DataPublicPluginStart } from 'src/plugins/data/public';
import { IEmbeddableStart } from 'src/plugins/embeddable/public';
import { LegacyCoreStart } from 'kibana/public';
import { VisSavedObject, AppState, PersistedState } from '../legacy_imports';
export interface EditorRenderProps {
appState: AppState;
core: LegacyCoreStart;
data: DataPublicPluginStart;
embeddables: IEmbeddableStart;
filters: esFilters.Filter[];
uiState: PersistedState;
timeRange: TimeRange;

File diff suppressed because one or more lines are too long

View file

@ -22,7 +22,6 @@ import ngMock from 'ng_mock';
import _ from 'lodash';
import ChoroplethLayer from '../choropleth_layer';
import LogstashIndexPatternStubProvider from 'fixtures/stubbed_logstash_index_pattern';
import { Vis } from 'ui/vis';
import { ImageComparator } from 'test_utils/image_comparator';
import worldJson from './world.json';
import EMS_CATALOGUE from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_manifest.json';
@ -40,6 +39,7 @@ import afterdatachangeandresizePng from './afterdatachangeandresize.png';
import aftercolorchangePng from './aftercolorchange.png';
import changestartupPng from './changestartup.png';
import { setup as visualizationsSetup } from '../../../visualizations/public/np_ready/public/legacy';
import { Vis } from '../../../visualizations/public/np_ready/public/vis';
import { createRegionMapVisualization } from '../region_map_visualization';
import { createRegionMapTypeDefinition } from '../region_map_type';

View file

@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { FileLayerField, VectorLayer, ServiceSettings } from 'ui/vis/map/service_settings';
import { VisOptionsProps } from 'ui/vis/editors/default';
import { VisOptionsProps } from 'src/legacy/core_plugins/vis_default_editor/public';
import { NumberInputOption, SelectOption, SwitchOption } from '../../../vis_type_vislib/public';
import { WmsOptions } from '../../../tile_map/public/components/wms_options';
import { RegionMapVisParams } from '../types';

View file

@ -18,7 +18,7 @@
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { Schemas } from 'ui/vis/editors/default/schemas';
import { Schemas } from 'ui/agg_types';
import { mapToLayerWithId } from './util';
import { createRegionMapVisualization } from './region_map_visualization';
import { Status } from '../../visualizations/public';

View file

@ -20,7 +20,6 @@
import expect from '@kbn/expect';
import ngMock from 'ng_mock';
import LogstashIndexPatternStubProvider from 'fixtures/stubbed_logstash_index_pattern';
import { Vis } from 'ui/vis';
import { ImageComparator } from 'test_utils/image_comparator';
import dummyESResponse from './dummy_es_response.json';
import initial from './initial.png';
@ -34,6 +33,7 @@ import EMS_STYLE_ROAD_MAP_BRIGHT from '../../../../ui/public/vis/__tests__/map/e
import EMS_STYLE_ROAD_MAP_DESATURATED from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_desaturated';
import EMS_STYLE_DARK_MAP from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_dark';
import { setup as visualizationsSetup } from '../../../visualizations/public/np_ready/public/legacy';
import { Vis } from '../../../visualizations/public/np_ready/public/vis';
import { createTileMapVisualization } from '../tile_map_visualization';
import { createTileMapTypeDefinition } from '../tile_map_type';

View file

@ -21,7 +21,7 @@ import React, { useEffect } from 'react';
import { EuiPanel, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { VisOptionsProps } from 'ui/vis/editors/default';
import { VisOptionsProps } from 'src/legacy/core_plugins/vis_default_editor/public';
import {
BasicOptions,
RangeOption,

View file

@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { TmsLayer } from 'ui/vis/map/service_settings';
import { Vis } from 'ui/vis';
import { Vis } from '../../../visualizations/public';
import { RegionMapVisParams } from '../../../region_map/public/types';
import { SelectOption, SwitchOption } from '../../../vis_type_vislib/public';
import { WmsInternalOptions } from './wms_internal_options';

View file

@ -20,11 +20,11 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { Schemas } from 'ui/vis/editors/default/schemas';
import { convertToGeoJson } from 'ui/vis/map/convert_to_geojson';
import { Schemas } from 'ui/agg_types';
import { createTileMapVisualization } from './tile_map_visualization';
import { Status } from '../../visualizations/public';
import { createTileMapVisualization } from './tile_map_visualization';
import { TileMapOptions } from './components/tile_map_options';
import { MapTypes } from './map_types';
import { supportsCssFilters } from './css_filters';

View file

@ -38,7 +38,7 @@ import 'ui/directives/input_focus';
import './directives/saved_object_finder';
import 'ui/directives/listen';
import 'ui/kbn_top_nav';
import 'ui/saved_objects/ui/saved_object_save_as_checkbox';
import './directives/saved_object_save_as_checkbox';
import '../../data/public/legacy';
import './services/saved_sheet_register';

View file

@ -2,7 +2,7 @@
<div
ng-hide="!savedObject.isTitleChanged() || savedObject.copyOnSave"
class="kuiLocalDropdownWarning kuiVerticalRhythmSmall"
i18n-id="common.ui.savedObjects.howToSaveAsNewDescription"
i18n-id="timelion.savedObjects.howToSaveAsNewDescription"
i18n-default-message="In previous versions of Kibana, changing the name of a {savedObjectName} would make a copy with the new name. Use the 'Save as a new {savedObjectName}' checkbox to do this now."
i18n-values="{ savedObjectName: savedObject.getDisplayName() }"
i18n-description="'Save as a new {savedObjectName}' refers to common.ui.savedObjects.saveAsNewLabel and should be the same text."
@ -19,7 +19,7 @@
<span
class="kuiCheckBoxLabel__text"
i18n-id="common.ui.savedObjects.saveAsNewLabel"
i18n-id="timelion.savedObjects.saveAsNewLabel"
i18n-default-message="Save as a new {savedObjectName}"
i18n-values="{ savedObjectName: savedObject.getDisplayName() }"
></span>

View file

@ -17,7 +17,7 @@
* under the License.
*/
import { uiModules } from '../../modules';
import { uiModules } from 'ui/modules';
import saveObjectSaveAsCheckboxTemplate from './saved_object_save_as_checkbox.html';
uiModules.get('kibana').directive('savedObjectSaveAsCheckBox', function() {

View file

@ -17,7 +17,26 @@
* under the License.
*/
import { BaseVisType } from '../../../../core_plugins/visualizations/public/np_ready/public/types/base_vis_type';
import { ReactVisType } from '../../../../core_plugins/visualizations/public/np_ready/public/types/react_vis_type';
import { resolve } from 'path';
import { Legacy } from 'kibana';
export { BaseVisType, ReactVisType };
import { LegacyPluginApi, LegacyPluginInitializer } from '../../../../src/legacy/types';
const vidDefaultEditorPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPluginApi) =>
new Plugin({
id: 'vis_default_editor',
require: [],
publicDir: resolve(__dirname, 'public'),
uiExports: {
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
},
init: (server: Legacy.Server) => ({}),
config(Joi: any) {
return Joi.object({
enabled: Joi.boolean().default(true),
}).default();
},
} as Legacy.PluginSpecOptions);
// eslint-disable-next-line import/no-default-export
export default vidDefaultEditorPluginInitializer;

View file

@ -0,0 +1,4 @@
{
"name": "vis_default_editor",
"version": "kibana"
}

View file

@ -71,6 +71,7 @@
.visEditor__visualization {
display: flex;
flex-basis: 100%;
flex: 1;
@include euiBreakpoint('xs', 's', 'm') {
// If we are on a small screen we force the visualization to take 100% width.

View file

@ -59,15 +59,6 @@
+ .visEditorSidebar__section {
margin-top: $euiSizeS;
}
label:not([class^='eui']) {
@include __legacyLabelStyles__bad;
display: block;
}
.form-group label {
margin-bottom: $euiSizeS;
}
}
// Collapsible section

View file

@ -19,15 +19,18 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { VisState } from '../../..';
import { AggGroupNames } from '../agg_groups';
import { DefaultEditorAgg, DefaultEditorAggProps } from './agg';
import { act } from 'react-dom/test-utils';
import { IndexPattern } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { AggType, AggGroupNames } from '../legacy_imports';
import { DefaultEditorAgg, DefaultEditorAggProps } from './agg';
import { DefaultEditorAggParams } from './agg_params';
import { AggType } from 'ui/agg_types';
import { IndexPattern } from '../../../../../../../plugins/data/public';
import { AGGS_ACTION_KEYS } from './agg_group_state';
jest.mock('ui/new_platform');
jest.mock('./agg_params', () => ({
DefaultEditorAggParams: () => null,
}));
@ -173,11 +176,11 @@ describe('DefaultEditorAgg component', () => {
it('should add schema component', () => {
defaultProps.agg.schema = {
editorComponent: () => <div className="schemaComponent" />,
name: 'split',
} as any;
const comp = mount(<DefaultEditorAgg {...defaultProps} />);
expect(comp.find('.schemaComponent').exists()).toBeTruthy();
expect(comp.find('RowsOrColumnsControl').exists()).toBeTruthy();
});
describe('agg actions', () => {

View file

@ -28,10 +28,12 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../..';
import { AggConfig } from '../legacy_imports';
import { DefaultEditorAggParams } from './agg_params';
import { DefaultEditorAggCommonProps } from './agg_common_props';
import { AGGS_ACTION_KEYS, AggsAction } from './agg_group_state';
import { RowsOrColumnsControl } from './controls/rows_or_columns';
import { RadiusRatioOptionControl } from './controls/radius_ratio_option';
export interface DefaultEditorAggProps extends DefaultEditorAggCommonProps {
agg: AggConfig;
@ -70,18 +72,27 @@ function DefaultEditorAgg({
const [validState, setValidState] = useState(true);
const showDescription = !isEditorOpen && validState;
const showError = !isEditorOpen && !validState;
const aggName = agg.type?.name;
let disabledParams;
let aggError;
// When a Parent Pipeline agg is selected and this agg is the last bucket.
const isLastBucketAgg = isLastBucket && lastParentPipelineAggTitle && agg.type;
const SchemaComponent = agg.schema.editorComponent;
let SchemaComponent;
if (agg.schema.name === 'split') {
SchemaComponent = RowsOrColumnsControl;
}
if (agg.schema.name === 'radius') {
SchemaComponent = RadiusRatioOptionControl;
}
if (isLastBucketAgg) {
if (['date_histogram', 'histogram'].includes(agg.type.name)) {
if (['date_histogram', 'histogram'].includes(aggName)) {
disabledParams = ['min_doc_count'];
} else {
aggError = i18n.translate('common.ui.aggTypes.metrics.wrongLastBucketTypeErrorMessage', {
aggError = i18n.translate('visDefaultEditor.metrics.wrongLastBucketTypeErrorMessage', {
defaultMessage:
'Last bucket aggregation must be "Date Histogram" or "Histogram" when using "{type}" metric aggregation.',
values: { type: lastParentPipelineAggTitle },
@ -104,16 +115,16 @@ function DefaultEditorAgg({
}
useEffect(() => {
if (isLastBucketAgg && ['date_histogram', 'histogram'].includes(agg.type.name)) {
if (isLastBucketAgg && ['date_histogram', 'histogram'].includes(aggName)) {
setAggParamValue(
agg.id,
'min_doc_count',
// "histogram" agg has an editor for "min_doc_count" param, which accepts boolean
// "date_histogram" agg doesn't have an editor for "min_doc_count" param, it should be set as a numeric value
agg.type.name === 'histogram' ? true : 0
aggName === 'histogram' ? true : 0
);
}
}, [lastParentPipelineAggTitle, isLastBucket, agg.type]);
}, [aggName, isLastBucketAgg, agg.id, setAggParamValue]);
const setTouched = useCallback(
(touched: boolean) => {
@ -123,7 +134,7 @@ function DefaultEditorAgg({
aggId: agg.id,
});
},
[setAggsState]
[agg.id, setAggsState]
);
const setValidity = useCallback(
@ -135,7 +146,7 @@ function DefaultEditorAgg({
});
setValidState(isValid);
},
[setAggsState]
[agg.id, setAggsState]
);
const onToggle = useCallback(
@ -156,7 +167,7 @@ function DefaultEditorAgg({
id: 'hasErrors',
color: 'danger',
type: 'alert',
tooltip: i18n.translate('common.ui.vis.editors.agg.errorsAriaLabel', {
tooltip: i18n.translate('visDefaultEditor.agg.errorsAriaLabel', {
defaultMessage: 'Aggregation has errors',
}),
dataTestSubj: 'hasErrorsAggregationIcon',
@ -170,7 +181,7 @@ function DefaultEditorAgg({
disabled: isDisabled,
type: 'eye',
onClick: () => onToggleEnableAgg(agg.id, false),
tooltip: i18n.translate('common.ui.vis.editors.agg.disableAggButtonTooltip', {
tooltip: i18n.translate('visDefaultEditor.agg.disableAggButtonTooltip', {
defaultMessage: 'Disable aggregation',
}),
dataTestSubj: 'toggleDisableAggregationBtn disable',
@ -182,7 +193,7 @@ function DefaultEditorAgg({
color: 'text',
type: 'eyeClosed',
onClick: () => onToggleEnableAgg(agg.id, true),
tooltip: i18n.translate('common.ui.vis.editors.agg.enableAggButtonTooltip', {
tooltip: i18n.translate('visDefaultEditor.agg.enableAggButtonTooltip', {
defaultMessage: 'Enable aggregation',
}),
dataTestSubj: 'toggleDisableAggregationBtn enable',
@ -192,7 +203,7 @@ function DefaultEditorAgg({
actionIcons.push({
id: 'dragHandle',
type: 'grab',
tooltip: i18n.translate('common.ui.vis.editors.agg.modifyPriorityButtonTooltip', {
tooltip: i18n.translate('visDefaultEditor.agg.modifyPriorityButtonTooltip', {
defaultMessage: 'Modify priority by dragging',
}),
dataTestSubj: 'dragHandleBtn',
@ -204,7 +215,7 @@ function DefaultEditorAgg({
color: 'danger',
type: 'cross',
onClick: () => removeAgg(agg.id),
tooltip: i18n.translate('common.ui.vis.editors.agg.removeDimensionButtonTooltip', {
tooltip: i18n.translate('visDefaultEditor.agg.removeDimensionButtonTooltip', {
defaultMessage: 'Remove dimension',
}),
dataTestSubj: 'removeDimensionBtn',
@ -259,7 +270,7 @@ function DefaultEditorAgg({
buttonClassName="eui-textTruncate"
buttonContentClassName="visEditorSidebar__aggGroupAccordionButtonContent eui-textTruncate"
className="visEditorSidebar__section visEditorSidebar__collapsible visEditorSidebar__collapsible--marginBottom"
aria-label={i18n.translate('common.ui.vis.editors.agg.toggleEditorButtonAriaLabel', {
aria-label={i18n.translate('visDefaultEditor.agg.toggleEditorButtonAriaLabel', {
defaultMessage: 'Toggle {schema} editor',
values: { schema: agg.schema.title },
})}

View file

@ -29,9 +29,7 @@ import {
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../..';
import { Schema } from '../schemas';
import { AggGroupNames } from '../agg_groups';
import { AggConfig, AggGroupNames, Schema } from '../legacy_imports';
interface DefaultEditorAggAddProps {
group?: AggConfig[];
@ -64,14 +62,14 @@ function DefaultEditorAggAdd({
data-test-subj={`visEditorAdd_${groupName}`}
onClick={() => setIsPopoverOpen(!isPopoverOpen)}
>
<FormattedMessage id="common.ui.vis.editors.aggAdd.addButtonLabel" defaultMessage="Add" />
<FormattedMessage id="visDefaultEditor.aggAdd.addButtonLabel" defaultMessage="Add" />
</EuiButtonEmpty>
);
const groupNameLabel =
groupName === AggGroupNames.Buckets
? i18n.translate('common.ui.vis.editors.aggAdd.bucketLabel', { defaultMessage: 'bucket' })
: i18n.translate('common.ui.vis.editors.aggAdd.metricLabel', { defaultMessage: 'metric' });
? i18n.translate('visDefaultEditor.aggAdd.bucketLabel', { defaultMessage: 'bucket' })
: i18n.translate('visDefaultEditor.aggAdd.metricLabel', { defaultMessage: 'metric' });
const isSchemaDisabled = (schema: Schema): boolean => {
const count = group.filter(agg => agg.schema.name === schema.name).length;
@ -92,14 +90,14 @@ function DefaultEditorAggAdd({
<EuiPopoverTitle>
{(groupName !== AggGroupNames.Buckets || !stats.count) && (
<FormattedMessage
id="common.ui.vis.editors.aggAdd.addGroupButtonLabel"
id="visDefaultEditor.aggAdd.addGroupButtonLabel"
defaultMessage="Add {groupNameLabel}"
values={{ groupNameLabel }}
/>
)}
{groupName === AggGroupNames.Buckets && stats.count > 0 && (
<FormattedMessage
id="common.ui.vis.editors.aggAdd.addSubGroupButtonLabel"
id="visDefaultEditor.aggAdd.addSubGroupButtonLabel"
defaultMessage="Add sub-{groupNameLabel}"
values={{ groupNameLabel }}
/>

View file

@ -17,10 +17,8 @@
* under the License.
*/
import { AggType } from 'ui/agg_types';
import { AggConfig, VisState, VisParams } from 'ui/vis';
import { AggGroupNames } from '../agg_groups';
import { Schema } from '../schemas';
import { VisState, VisParams } from 'src/legacy/core_plugins/visualizations/public';
import { AggType, AggConfig, AggGroupNames, Schema } from '../legacy_imports';
type AggId = AggConfig['id'];
type AggParams = AggConfig['params'];

View file

@ -20,10 +20,8 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { act } from 'react-dom/test-utils';
import { VisState, AggConfig } from '../../../';
import { Schema } from '../schemas';
import { AggGroupNames } from '../agg_groups';
import { AggConfigs } from '../../../../agg_types/agg_configs';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { AggConfigs, AggConfig, Schema } from '../legacy_imports';
import { DefaultEditorAggGroup, DefaultEditorAggGroupProps } from './agg_group';
import { DefaultEditorAgg } from './agg';
import { DefaultEditorAggAdd } from './agg_add';
@ -37,6 +35,17 @@ jest.mock('@elastic/eui', () => ({
EuiPanel: 'eui-panel',
}));
jest.mock('../legacy_imports', () => ({
aggGroupNamesMap: () => ({
metrics: 'Metrics',
buckets: 'Buckets',
}),
AggGroupNames: {
Metrics: 'metrics',
Buckets: 'buckets',
},
}));
jest.mock('./agg', () => ({
DefaultEditorAgg: () => <div />,
}));
@ -92,7 +101,7 @@ describe('DefaultEditorAgg component', () => {
defaultProps = {
formIsTouched: false,
metricAggs: [],
groupName: AggGroupNames.Metrics,
groupName: 'metrics',
state: {
aggs,
} as VisState,
@ -129,7 +138,7 @@ describe('DefaultEditorAgg component', () => {
});
it('should last bucket has truthy isLastBucket prop', () => {
defaultProps.groupName = AggGroupNames.Buckets;
defaultProps.groupName = 'buckets';
const comp = mount(<DefaultEditorAggGroup {...defaultProps} />);
const lastAgg = comp.find(DefaultEditorAgg).last();
@ -150,7 +159,7 @@ describe('DefaultEditorAgg component', () => {
});
it('should show add button when schemas count is less than max', () => {
defaultProps.groupName = AggGroupNames.Buckets;
defaultProps.groupName = 'buckets';
const comp = shallow(<DefaultEditorAggGroup {...defaultProps} />);
expect(comp.find(DefaultEditorAggAdd).exists()).toBeTruthy();

View file

@ -30,8 +30,7 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../../../agg_types/agg_config';
import { aggGroupNamesMap, AggGroupNames } from '../agg_groups';
import { AggConfig, aggGroupNamesMap, AggGroupNames, Schema } from '../legacy_imports';
import { DefaultEditorAgg } from './agg';
import { DefaultEditorAggAdd } from './agg_add';
import { AddSchema, ReorderAggs, DefaultEditorAggCommonProps } from './agg_common_props';
@ -42,7 +41,6 @@ import {
getEnabledMetricAggsCount,
} from './agg_group_helper';
import { aggGroupReducer, initAggsState, AGGS_ACTION_KEYS } from './agg_group_state';
import { Schema } from '../schemas';
export interface DefaultEditorAggGroupProps extends DefaultEditorAggCommonProps {
schemas: Schema[];
@ -73,7 +71,7 @@ function DefaultEditorAggGroup({
// e.g. buckets can have no aggs
const group: AggConfig[] = useMemo(
() => state.aggs.aggs.filter((agg: AggConfig) => agg.schema.group === groupName) || [],
[state.aggs.aggs]
[groupName, state.aggs.aggs]
);
const stats = {
@ -89,7 +87,7 @@ function DefaultEditorAggGroup({
const bucketsError =
lastParentPipelineAggTitle && groupName === AggGroupNames.Buckets && !group.length
? i18n.translate('common.ui.aggTypes.buckets.mustHaveBucketErrorMessage', {
? i18n.translate('visDefaultEditor.buckets.mustHaveBucketErrorMessage', {
defaultMessage: 'Add a bucket with "Date Histogram" or "Histogram" aggregation.',
description: 'Date Histogram and Histogram should not be translated',
})
@ -120,6 +118,9 @@ function DefaultEditorAggGroup({
});
});
}
// adding all of the values to the deps array cause a circular re-render
// the logic should be rewised
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [formIsTouched]);
useEffect(() => {

View file

@ -17,7 +17,7 @@
* under the License.
*/
import { AggConfig } from '../../../../agg_types/agg_config';
import { AggConfig } from '../legacy_imports';
import {
isAggRemovable,
calcAggIsTooLow,

View file

@ -18,7 +18,7 @@
*/
import { findIndex, isEmpty } from 'lodash';
import { AggConfig } from '../../../../agg_types/agg_config';
import { AggConfig } from '../legacy_imports';
import { AggsState } from './agg_group_state';
const isAggRemovable = (agg: AggConfig, group: AggConfig[]) => {

View file

@ -17,7 +17,7 @@
* under the License.
*/
import { AggConfig } from '../../../../agg_types/agg_config';
import { AggConfig } from '../legacy_imports';
export enum AGGS_ACTION_KEYS {
TOUCHED = 'aggsTouched',

View file

@ -75,7 +75,7 @@ function DefaultEditorAggParam<T>(props: DefaultEditorAggParamProps<T>) {
if (aggParam.shouldShow && !aggParam.shouldShow(agg)) {
setValidity(true);
}
}, [agg, agg.params.field]);
}, [agg, agg.params.field, aggParam, setValidity]);
if (aggParam.shouldShow && !aggParam.shouldShow(agg)) {
return null;

View file

@ -17,12 +17,10 @@
* under the License.
*/
import { AggParam } from 'ui/agg_types';
import { AggConfig } from '../../../../agg_types/agg_config';
import { Field } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { AggConfig, AggParam, EditorConfig } from '../legacy_imports';
import { ComboBoxGroupedOptions } from '../utils';
import { EditorConfig } from '../../config/types';
import { VisState } from '../../..';
import { Field } from '../../../../../../../plugins/data/public';
// NOTE: we cannot export the interface with export { InterfaceName }
// as there is currently a bug on babel typescript transform plugin for it

View file

@ -19,10 +19,11 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { AggConfig, VisState } from '../../..';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { IndexPattern } from 'src/plugins/data/public';
import { DefaultEditorAggParams, DefaultEditorAggParamsProps } from './agg_params';
import { AggGroupNames } from '../agg_groups';
import { IndexPattern } from '../../../../../../../plugins/data/public';
import { AggConfig, AggGroupNames } from '../legacy_imports';
const mockEditorConfig = {
useNormalizedEsInterval: { hidden: false, fixedValue: false },
@ -34,15 +35,8 @@ const mockEditorConfig = {
},
};
jest.mock('ui/agg_types', () => ({
aggTypes: {
byType: {
metrics: [],
buckets: [],
},
},
}));
jest.mock('../../config/editor_config_providers', () => ({
jest.mock('ui/new_platform');
jest.mock('ui/vis/config', () => ({
editorConfigProviders: {
getConfigForAgg: jest.fn(() => mockEditorConfig),
},

View file

@ -22,8 +22,15 @@ import { EuiForm, EuiAccordion, EuiSpacer, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import useUnmount from 'react-use/lib/useUnmount';
import { AggConfig } from 'ui/agg_types/';
import { IndexPattern } from '../../../../../../../plugins/data/public';
import { IndexPattern } from 'src/plugins/data/public';
import {
AggConfig,
AggGroupNames,
editorConfigProviders,
FixedParam,
TimeIntervalParam,
EditorParamConfig,
} from '../legacy_imports';
import { DefaultEditorAggSelect } from './agg_select';
import { DefaultEditorAggParam } from './agg_param';
@ -38,9 +45,6 @@ import {
AGG_PARAMS_ACTION_KEYS,
initAggParamsState,
} from './agg_params_state';
import { editorConfigProviders } from '../../config/editor_config_providers';
import { FixedParam, TimeIntervalParam, EditorParamConfig } from '../../config/types';
import { AggGroupNames } from '../agg_groups';
import { DefaultEditorCommonProps } from './agg_common_props';
const FIXED_VALUE_PROP = 'fixedValue';
@ -84,7 +88,7 @@ function DefaultEditorAggParams({
groupName,
]);
const error = aggIsTooLow
? i18n.translate('common.ui.vis.editors.aggParams.errors.aggWrongRunOrderErrorMessage', {
? i18n.translate('visDefaultEditor.aggParams.errors.aggWrongRunOrderErrorMessage', {
defaultMessage: '"{schema}" aggs must run before all other buckets!',
values: { schema: agg.schema.title },
})
@ -160,20 +164,21 @@ function DefaultEditorAggParams({
}
}
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [editorConfig]);
useEffect(() => {
setTouched(false);
}, [agg.type]);
}, [agg.type, setTouched]);
useEffect(() => {
setValidity(isFormValid);
}, [isFormValid, agg.type]);
}, [isFormValid, agg.type, setValidity]);
useEffect(() => {
// when all invalid controls were touched or they are untouched
setTouched(isAllInvalidParamsTouched);
}, [isAllInvalidParamsTouched]);
}, [isAllInvalidParamsTouched, setTouched]);
return (
<EuiForm
@ -218,12 +223,9 @@ function DefaultEditorAggParams({
<EuiAccordion
id="advancedAccordion"
data-test-subj={`advancedParams-${agg.id}`}
buttonContent={i18n.translate(
'common.ui.vis.editors.advancedToggle.advancedLinkLabel',
{
defaultMessage: 'Advanced',
}
)}
buttonContent={i18n.translate('visDefaultEditor.advancedToggle.advancedLinkLabel', {
defaultMessage: 'Advanced',
})}
>
<EuiSpacer size="s" />
{params.advanced.map(param => {

View file

@ -17,27 +17,29 @@
* under the License.
*/
import { AggConfig, VisState } from '../../..';
import { AggType } from 'ui/agg_types';
import { IndexedArray } from 'ui/indexed_array';
import { IndexPattern, Field } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import {
AggConfig,
AggType,
AggGroupNames,
BUCKET_TYPES,
IndexedArray,
EditorConfig,
} from '../legacy_imports';
import {
getAggParamsToRender,
getAggTypeOptions,
isInvalidParamsTouched,
} from './agg_params_helper';
import { EditorConfig } from '../../config/types';
import { IndexPattern, Field } from '../../../../../../../plugins/data/public';
import { FieldParamEditor, OrderByParamEditor } from './controls';
jest.mock('ui/agg_types', () => ({
aggTypes: {
metrics: [],
buckets: [],
},
}));
jest.mock('../utils', () => ({
groupAndSortBy: jest.fn(() => ['indexedFields']),
}));
jest.mock('ui/new_platform');
describe('DefaultEditorAggParams helpers', () => {
describe('getAggParamsToRender', () => {
let agg: AggConfig;
@ -102,6 +104,8 @@ describe('DefaultEditorAggParams helpers', () => {
const filterFieldTypes = ['number', 'boolean', 'date'];
agg = ({
type: {
type: AggGroupNames.Buckets,
name: BUCKET_TYPES.TERMS,
params: [
{
name: 'field',
@ -110,11 +114,9 @@ describe('DefaultEditorAggParams helpers', () => {
getAvailableFields: jest.fn((fields: IndexedArray<Field>) =>
fields.filter(({ type }) => filterFieldTypes.includes(type))
),
editorComponent: jest.fn(),
},
{
name: 'orderBy',
editorComponent: jest.fn(),
},
],
},
@ -139,7 +141,7 @@ describe('DefaultEditorAggParams helpers', () => {
aggParam: agg.type.params[0],
editorConfig,
indexedFields: ['indexedFields'],
paramEditor: agg.type.params[0].editorComponent,
paramEditor: FieldParamEditor,
metricAggs,
state,
value: agg.params.field,
@ -149,7 +151,7 @@ describe('DefaultEditorAggParams helpers', () => {
aggParam: agg.type.params[1],
editorConfig,
indexedFields: [],
paramEditor: agg.type.params[1].editorComponent,
paramEditor: OrderByParamEditor,
metricAggs,
state,
value: agg.params.orderBy,

View file

@ -18,15 +18,23 @@
*/
import { get, isEmpty } from 'lodash';
import { aggTypeFilters } from 'ui/agg_types/filter';
import { aggTypes, AggParam, FieldParamType, AggType } from 'ui/agg_types';
import { aggTypeFieldFilters } from 'ui/agg_types/param_types/filter';
import { AggConfig, VisState } from '../../..';
import { IndexPattern, Field } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { groupAndSortBy, ComboBoxGroupedOptions } from '../utils';
import { EditorConfig } from '../../config/types';
import { AggTypeState, AggParamsState } from './agg_params_state';
import { AggParamEditorProps } from './agg_param_props';
import { IndexPattern, Field } from '../../../../../../../plugins/data/public';
import { aggParamsMap } from './agg_params_map';
import {
aggTypeFilters,
aggTypeFieldFilters,
aggTypes,
AggConfig,
AggParam,
FieldParamType,
AggType,
EditorConfig,
} from '../legacy_imports';
interface ParamInstanceBase {
agg: AggConfig;
@ -79,14 +87,25 @@ function getAggParamsToRender({ agg, editorConfig, metricAggs, state }: ParamIns
const type = param.advanced ? 'advanced' : 'basic';
let paramEditor: ParamInstance['paramEditor'];
if (agg.type.subtype && aggParamsMap[agg.type.subtype]) {
paramEditor = get(aggParamsMap, [agg.type.subtype, param.name]);
} else {
const aggType = agg.type.type;
const aggName = agg.type.name;
const aggParams = get(aggParamsMap, [aggType, aggName], {});
paramEditor = get(aggParams, param.name) || get(aggParamsMap, ['common', param.type]);
}
// show params with an editor component
if (param.editorComponent) {
if (paramEditor) {
params[type].push({
agg,
aggParam: param,
editorConfig,
indexedFields,
paramEditor: param.editorComponent,
paramEditor,
metricAggs,
state,
value: agg.params[param.name],

View file

@ -0,0 +1,106 @@
/*
* 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 * as controls from './controls';
import {
AggGroupNames,
BUCKET_TYPES,
METRIC_TYPES,
siblingPipelineType,
parentPipelineType,
} from '../legacy_imports';
import { wrapWithInlineComp } from './controls/utils';
const buckets = {
[BUCKET_TYPES.DATE_HISTOGRAM]: {
scaleMetricValues: controls.ScaleMetricsParamEditor,
interval: controls.TimeIntervalParamEditor,
drop_partials: controls.DropPartialsParamEditor,
},
[BUCKET_TYPES.DATE_RANGE]: {
ranges: controls.DateRangesParamEditor,
},
[BUCKET_TYPES.FILTERS]: {
filters: controls.FiltersParamEditor,
},
[BUCKET_TYPES.GEOHASH_GRID]: {
autoPrecision: controls.AutoPrecisionParamEditor,
precision: controls.PrecisionParamEditor,
useGeocentroid: controls.UseGeocentroidParamEditor,
isFilteredByCollar: controls.IsFilteredByCollarParamEditor,
},
[BUCKET_TYPES.HISTOGRAM]: {
interval: controls.NumberIntervalParamEditor,
min_doc_count: controls.MinDocCountParamEditor,
has_extended_bounds: controls.HasExtendedBoundsParamEditor,
extended_bounds: controls.ExtendedBoundsParamEditor,
},
[BUCKET_TYPES.IP_RANGE]: {
ipRangeType: controls.IpRangeTypeParamEditor,
ranges: controls.IpRangesParamEditor,
},
[BUCKET_TYPES.RANGE]: {
ranges: controls.RangesControl,
},
[BUCKET_TYPES.SIGNIFICANT_TERMS]: {
size: controls.SizeParamEditor,
},
[BUCKET_TYPES.TERMS]: {
orderBy: controls.OrderByParamEditor,
orderAgg: controls.OrderAggParamEditor,
order: wrapWithInlineComp(controls.OrderParamEditor),
size: wrapWithInlineComp(controls.SizeParamEditor),
otherBucket: controls.OtherBucketParamEditor,
missingBucket: controls.MissingBucketParamEditor,
},
};
const metrics = {
[METRIC_TYPES.TOP_HITS]: {
field: controls.TopFieldParamEditor,
aggregate: wrapWithInlineComp(controls.TopAggregateParamEditor),
size: wrapWithInlineComp(controls.TopSizeParamEditor),
sortField: controls.TopSortFieldParamEditor,
sortOrder: controls.OrderParamEditor,
},
[METRIC_TYPES.PERCENTILES]: {
percents: controls.PercentilesEditor,
},
[METRIC_TYPES.PERCENTILE_RANKS]: {
values: controls.PercentileRanksEditor,
},
};
export const aggParamsMap = {
common: {
string: controls.StringParamEditor,
json: controls.RawJsonParamEditor,
field: controls.FieldParamEditor,
},
[siblingPipelineType]: {
customBucket: controls.SubMetricParamEditor,
customMetric: controls.SubMetricParamEditor,
},
[parentPipelineType]: {
metricAgg: controls.MetricAggParamEditor,
customMetric: controls.SubAggParamEditor,
},
[AggGroupNames.Buckets]: buckets,
[AggGroupNames.Metrics]: metrics,
};

View file

@ -22,10 +22,10 @@ import React, { useEffect, useCallback } from 'react';
import { EuiComboBox, EuiComboBoxOptionProps, EuiFormRow, EuiLink, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { AggType } from 'ui/agg_types';
import { documentationLinks } from '../../../../documentation_links/documentation_links';
import { IndexPattern } from 'src/plugins/data/public';
import { AggType, documentationLinks } from '../legacy_imports';
import { ComboBoxGroupedOptions } from '../utils';
import { IndexPattern } from '../../../../../../../plugins/data/public';
import { AGG_TYPE_ACTION_KEYS, AggTypeAction } from './agg_params_state';
interface DefaultEditorAggSelectProps {
@ -57,12 +57,12 @@ function DefaultEditorAggSelect({
const label = isSubAggregation ? (
<FormattedMessage
id="common.ui.vis.defaultEditor.aggSelect.subAggregationLabel"
id="visDefaultEditor.aggSelect.subAggregationLabel"
defaultMessage="Sub aggregation"
/>
) : (
<FormattedMessage
id="common.ui.vis.defaultEditor.aggSelect.aggregationLabel"
id="visDefaultEditor.aggSelect.aggregationLabel"
defaultMessage="Aggregation"
/>
);
@ -76,7 +76,7 @@ function DefaultEditorAggSelect({
<EuiLink href={aggHelpLink} target="_blank" rel="noopener">
<EuiText size="xs">
<FormattedMessage
id="common.ui.vis.defaultEditor.aggSelect.helpLinkLabel"
id="visDefaultEditor.aggSelect.helpLinkLabel"
defaultMessage="{aggTitle} help"
values={{ aggTitle: value ? value.title : '' }}
/>
@ -88,7 +88,7 @@ function DefaultEditorAggSelect({
if (!aggTypeOptions.length) {
errors.push(
i18n.translate('common.ui.vis.defaultEditor.aggSelect.noCompatibleAggsDescription', {
i18n.translate('visDefaultEditor.aggSelect.noCompatibleAggsDescription', {
defaultMessage:
'The index pattern {indexPatternTitle} does not have any aggregatable fields.',
values: {
@ -121,13 +121,13 @@ function DefaultEditorAggSelect({
useEffect(() => {
setValidity(isValid);
}, [isValid]);
}, [isValid, setValidity]);
useEffect(() => {
if (errors.length) {
setTouched();
}
}, [errors.length]);
}, [errors.length, setTouched]);
return (
<EuiFormRow
@ -139,7 +139,7 @@ function DefaultEditorAggSelect({
compressed
>
<EuiComboBox
placeholder={i18n.translate('common.ui.vis.defaultEditor.aggSelect.selectAggPlaceholder', {
placeholder={i18n.translate('visDefaultEditor.aggSelect.selectAggPlaceholder', {
defaultMessage: 'Select an aggregation',
})}
id={`visDefaultEditorAggSelect${id}`}

View file

@ -13,7 +13,7 @@ exports[`SizeParamEditor should init with the default set of props 1`] = `
<React.Fragment>
<FormattedMessage
defaultMessage="Size"
id="common.ui.aggTypes.sizeLabel"
id="visDefaultEditor.controls.sizeLabel"
values={Object {}}
/>
</React.Fragment>

View file

@ -13,7 +13,7 @@ exports[`TopAggregateParamEditor should init with the default set of props 1`] =
<React.Fragment>
<FormattedMessage
defaultMessage="Aggregate with"
id="common.ui.aggTypes.aggregateWithLabel"
id="visDefaultEditor.controls.aggregateWithLabel"
values={Object {}}
/>

View file

@ -17,8 +17,9 @@
* under the License.
*/
import { AggConfig, VisParams } from 'ui/vis';
import { DefaultEditorAggCommonProps } from '../components/agg_common_props';
import { VisParams } from 'src/legacy/core_plugins/visualizations/public';
import { AggConfig } from '../../legacy_imports';
import { DefaultEditorAggCommonProps } from '../agg_common_props';
export interface AggControlProps {
agg: AggConfig;

View file

@ -20,14 +20,14 @@
import React, { FunctionComponent } from 'react';
import { mount, ReactWrapper } from 'enzyme';
import { AggConfig } from 'ui/agg_types';
import { AggConfig } from '../../legacy_imports';
import {
safeMakeLabel,
useAvailableOptions,
useFallbackMetric,
useValidation,
CUSTOM_METRIC,
} from './agg_utils';
} from './utils';
type Callback = () => void;

View file

@ -21,10 +21,10 @@ import React from 'react';
import { EuiSwitch, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
function AutoPrecisionParamEditor({ value = false, setValue }: AggParamEditorProps<boolean>) {
const label = i18n.translate('common.ui.aggTypes.changePrecisionLabel', {
const label = i18n.translate('visDefaultEditor.controls.changePrecisionLabel', {
defaultMessage: 'Change precision on map zoom',
});

View file

@ -20,7 +20,8 @@
import React from 'react';
import { EuiFieldText, EuiFlexItem, EuiIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { Ipv4Address } from '../../../../../../../../plugins/kibana_utils/public';
import { Ipv4Address } from '../../../../../../../plugins/kibana_utils/public';
import { InputList, InputListConfig, InputModel, InputObject, InputItem } from './input_list';
const EMPTY_STRING = '';
@ -59,7 +60,7 @@ function FromToList({ showValidation, onBlur, ...rest }: FromToListProps) {
to: { value: item.to || EMPTY_STRING, model: item.to || EMPTY_STRING, isInvalid: false },
}),
getRemoveBtnAriaLabel: (item: FromToModel) =>
i18n.translate('common.ui.aggTypes.ipRanges.removeRangeAriaLabel', {
i18n.translate('visDefaultEditor.controls.ipRanges.removeRangeAriaLabel', {
defaultMessage: 'Remove the range of {from} to {to}',
values: { from: item.from.value || '*', to: item.to.value || '*' },
}),
@ -78,7 +79,7 @@ function FromToList({ showValidation, onBlur, ...rest }: FromToListProps) {
<>
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.ipRanges.ipRangeFromAriaLabel', {
aria-label={i18n.translate('visDefaultEditor.controls.ipRanges.ipRangeFromAriaLabel', {
defaultMessage: 'IP range from: {value}',
values: { value: item.from.value || '*' },
})}
@ -97,7 +98,7 @@ function FromToList({ showValidation, onBlur, ...rest }: FromToListProps) {
</EuiFlexItem>
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.ipRanges.ipRangeToAriaLabel', {
aria-label={i18n.translate('visDefaultEditor.controls.ipRanges.ipRangeToAriaLabel', {
defaultMessage: 'IP range to: {value}',
values: { value: item.to.value || '*' },
})}

View file

@ -197,7 +197,7 @@ function InputList({ config, list, onChange, setValidity }: InputListProps) {
<EuiFlexItem>
<EuiButtonEmpty iconType="plusInCircleFilled" onClick={onAdd} size="xs">
<FormattedMessage
id="common.ui.aggTypes.ipRanges.addRangeButtonLabel"
id="visDefaultEditor.controls.ipRanges.addRangeButtonLabel"
defaultMessage="Add range"
/>
</EuiButtonEmpty>

View file

@ -20,8 +20,9 @@
import React from 'react';
import { EuiFieldText, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { CidrMask } from '../../../../../agg_types/buckets/lib/cidr_mask';
import { InputList, InputListConfig, InputObject, InputModel, InputItem } from './input_list';
import { CidrMask } from '../../../legacy_imports';
const EMPTY_STRING = '';
@ -56,11 +57,11 @@ function MaskList({ showValidation, onBlur, ...rest }: MaskListProps) {
}),
getRemoveBtnAriaLabel: (item: MaskModel) =>
item.mask.value
? i18n.translate('common.ui.aggTypes.ipRanges.removeCidrMaskButtonAriaLabel', {
? i18n.translate('visDefaultEditor.controls.ipRanges.removeCidrMaskButtonAriaLabel', {
defaultMessage: 'Remove the CIDR mask value of {mask}',
values: { mask: item.mask.value },
})
: i18n.translate('common.ui.aggTypes.ipRanges.removeEmptyCidrMaskButtonAriaLabel', {
: i18n.translate('visDefaultEditor.controls.ipRanges.removeEmptyCidrMaskButtonAriaLabel', {
defaultMessage: 'Remove the CIDR mask default value',
}),
onChangeFn: ({ mask }: MaskModel) => {
@ -73,7 +74,7 @@ function MaskList({ showValidation, onBlur, ...rest }: MaskListProps) {
renderInputRow: ({ mask }: MaskModel, index, onChangeValue) => (
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.ipRanges.cidrMaskAriaLabel', {
aria-label={i18n.translate('visDefaultEditor.controls.ipRanges.cidrMaskAriaLabel', {
defaultMessage: 'CIDR mask: {mask}',
values: { mask: mask.value || '*' },
})}

View file

@ -64,7 +64,7 @@ exports[`NumberList should be rendered with default set of props 1`] = `
>
<FormattedMessage
defaultMessage="Add {unitName}"
id="common.ui.aggTypes.numberList.addUnitButtonLabel"
id="visDefaultEditor.controls.numberList.addUnitButtonLabel"
values={
Object {
"unitName": "value",

View file

@ -34,7 +34,7 @@ import {
getUpdatedModels,
hasInvalidValues,
} from './utils';
import { useValidation } from '../../agg_utils';
import { useValidation } from '../../utils';
export interface NumberListProps {
labelledbyId: string;
@ -72,7 +72,7 @@ function NumberList({
setAscendingError(
isValidOrder
? EMPTY_STRING
: i18n.translate('common.ui.aggTypes.numberList.invalidAscOrderErrorMessage', {
: i18n.translate('visDefaultEditor.controls.numberList.invalidAscOrderErrorMessage', {
defaultMessage: 'The values should be in ascending order.',
})
);
@ -160,7 +160,7 @@ function NumberList({
<EuiFlexItem>
<EuiButtonEmpty iconType="plusInCircleFilled" onClick={onAdd} size="xs">
<FormattedMessage
id="common.ui.aggTypes.numberList.addUnitButtonLabel"
id="visDefaultEditor.controls.numberList.addUnitButtonLabel"
defaultMessage="Add {unitName}"
values={{ unitName }}
/>

View file

@ -54,7 +54,7 @@ function NumberRow({
onChange,
}: NumberRowProps) {
const deleteBtnAriaLabel = i18n.translate(
'common.ui.aggTypes.numberList.removeUnitButtonAriaLabel',
'visDefaultEditor.controls.numberList.removeUnitButtonAriaLabel',
{
defaultMessage: 'Remove the rank value of {value}',
values: { value: model.value },
@ -80,9 +80,12 @@ function NumberRow({
autoFocus={autoFocus}
compressed={true}
isInvalid={isInvalid}
placeholder={i18n.translate('common.ui.aggTypes.numberList.enterValuePlaceholder', {
defaultMessage: 'Enter a value',
})}
placeholder={i18n.translate(
'visDefaultEditor.controls.numberList.enterValuePlaceholder',
{
defaultMessage: 'Enter a value',
}
)}
onChange={onValueChanged}
value={model.value}
fullWidth={true}

View file

@ -51,7 +51,7 @@ function validateValue(value: number | '', numberRange: NumberListRange) {
result.isInvalid = true;
} else if (!numberRange.within(value)) {
result.isInvalid = true;
result.error = i18n.translate('common.ui.aggTypes.numberList.invalidRangeErrorMessage', {
result.error = i18n.translate('visDefaultEditor.controls.numberList.invalidRangeErrorMessage', {
defaultMessage: 'The value should be in the range of {min} to {max}.',
values: { min: numberRange.min, max: numberRange.max },
});

View file

@ -21,7 +21,7 @@ import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { DateRangesParamEditor } from './date_ranges';
jest.mock('../../../../documentation_links', () => ({
jest.mock('../../legacy_imports', () => ({
getDocLink: jest.fn(),
}));

View file

@ -36,8 +36,9 @@ import dateMath from '@elastic/datemath';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { isEqual, omit } from 'lodash';
import { getDocLink } from '../../../../documentation_links';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
import { getDocLink } from '../../legacy_imports';
const FROM_PLACEHOLDER = '\u2212\u221E';
const TO_PLACEHOLDER = '+\u221E';
@ -116,7 +117,7 @@ function DateRangesParamEditor({
<EuiText size="xs">
<EuiLink href={getDocLink('date.dateMath')} target="_blank">
<FormattedMessage
id="common.ui.aggTypes.dateRanges.acceptedDateFormatsLinkText"
id="visDefaultEditor.controls.dateRanges.acceptedDateFormatsLinkText"
defaultMessage="Acceptable date formats"
/>
</EuiLink>
@ -125,7 +126,7 @@ function DateRangesParamEditor({
{ranges.map(({ from, to, id }) => {
const deleteBtnTitle = i18n.translate(
'common.ui.aggTypes.dateRanges.removeRangeButtonAriaLabel',
'visDefaultEditor.controls.dateRanges.removeRangeButtonAriaLabel',
{
defaultMessage: 'Remove the range of {from} to {to}',
values: { from: from || FROM_PLACEHOLDER, to: to || TO_PLACEHOLDER },
@ -138,11 +139,14 @@ function DateRangesParamEditor({
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.dateRanges.fromColumnLabel', {
defaultMessage: 'From',
description:
'Beginning of a date range, e.g. *From* 2018-02-26 To 2018-02-28',
})}
aria-label={i18n.translate(
'visDefaultEditor.controls.dateRanges.fromColumnLabel',
{
defaultMessage: 'From',
description:
'Beginning of a date range, e.g. *From* 2018-02-26 To 2018-02-28',
}
)}
compressed
fullWidth={true}
isInvalid={areBothEmpty || !validateDateMath(from)}
@ -156,10 +160,13 @@ function DateRangesParamEditor({
</EuiFlexItem>
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.dateRanges.toColumnLabel', {
defaultMessage: 'To',
description: 'End of a date range, e.g. From 2018-02-26 *To* 2018-02-28',
})}
aria-label={i18n.translate(
'visDefaultEditor.controls.dateRanges.toColumnLabel',
{
defaultMessage: 'To',
description: 'End of a date range, e.g. From 2018-02-26 *To* 2018-02-28',
}
)}
compressed
fullWidth={true}
isInvalid={areBothEmpty || !validateDateMath(to)}
@ -187,7 +194,7 @@ function DateRangesParamEditor({
{hasInvalidRange && (
<EuiFormErrorText>
<FormattedMessage
id="common.ui.aggTypes.dateRanges.errorMessage"
id="visDefaultEditor.controls.dateRanges.errorMessage"
defaultMessage="Each range should have at least one valid date."
/>
</EuiFormErrorText>
@ -197,7 +204,7 @@ function DateRangesParamEditor({
<EuiFlexItem>
<EuiButtonEmpty iconType="plusInCircleFilled" onClick={onAddRange} size="xs">
<FormattedMessage
id="common.ui.aggTypes.dateRanges.addRangeButtonLabel"
id="visDefaultEditor.controls.dateRanges.addRangeButtonLabel"
defaultMessage="Add range"
/>
</EuiButtonEmpty>

View file

@ -20,16 +20,16 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { SwitchParamEditor } from './switch';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
function DropPartialsParamEditor(props: AggParamEditorProps<boolean>) {
return (
<SwitchParamEditor
dataTestSubj="dropPartialBucketsCheckbox"
displayLabel={i18n.translate('common.ui.aggTypes.dropPartialBucketsLabel', {
displayLabel={i18n.translate('visDefaultEditor.controls.dropPartialBucketsLabel', {
defaultMessage: 'Drop partial buckets',
})}
displayToolTip={i18n.translate('common.ui.aggTypes.dropPartialBucketsTooltip', {
displayToolTip={i18n.translate('visDefaultEditor.controls.dropPartialBucketsTooltip', {
defaultMessage:
"Remove buckets that span time outside the time range so the histogram doesn't start and end with incomplete buckets.",
})}

View file

@ -21,7 +21,7 @@ import React from 'react';
import { mount, shallow } from 'enzyme';
import { ExtendedBoundsParamEditor, Bounds } from './extended_bounds';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
describe('ExtendedBoundsParamEditor', () => {
let defaultProps: Partial<AggParamEditorProps<Bounds>>;

View file

@ -22,8 +22,9 @@ import React, { ChangeEvent } from 'react';
import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { isUndefined } from 'lodash';
import { useValidation } from './agg_utils';
import { AggParamEditorProps } from '..';
import { useValidation } from './utils';
import { AggParamEditorProps } from '../agg_param_props';
export interface Bounds {
min: number | '';
@ -45,11 +46,11 @@ function ExtendedBoundsParamEditor({
showValidation,
setTouched,
}: AggParamEditorProps<Bounds>) {
const minLabel = i18n.translate('common.ui.aggTypes.extendedBounds.minLabel', {
const minLabel = i18n.translate('visDefaultEditor.controls.extendedBounds.minLabel', {
defaultMessage: 'Min',
});
const maxLabel = i18n.translate('common.ui.aggTypes.extendedBounds.maxLabel', {
const maxLabel = i18n.translate('visDefaultEditor.controls.extendedBounds.maxLabel', {
defaultMessage: 'Max',
});
@ -57,7 +58,7 @@ function ExtendedBoundsParamEditor({
let error;
if (!isValid) {
error = i18n.translate('common.ui.aggTypes.extendedBounds.errorMessage', {
error = i18n.translate('visDefaultEditor.controls.extendedBounds.errorMessage', {
defaultMessage: 'Min should be less than or equal to Max.',
});
}

View file

@ -21,10 +21,12 @@ import React from 'react';
import { act } from 'react-dom/test-utils';
import { mount, shallow, ReactWrapper } from 'enzyme';
import { EuiComboBoxProps, EuiComboBox } from '@elastic/eui';
import { Field } from '../../../../../../../plugins/data/public';
import { ComboBoxGroupedOptions } from '..';
import { Field } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { ComboBoxGroupedOptions } from '../../utils';
import { FieldParamEditor, FieldParamEditorProps } from './field';
import { AggConfig, VisState } from '../../..';
import { AggConfig } from '../../legacy_imports';
function callComboBoxOnChange(comp: ReactWrapper, value: any = []) {
const comboBoxProps: EuiComboBoxProps<string> = comp.find(EuiComboBox).props();

View file

@ -22,14 +22,16 @@ import React, { useEffect } from 'react';
import { EuiComboBox, EuiComboBoxOptionProps, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../..';
import { Field } from '../../../../../../../plugins/data/public';
import { formatListAsProse, parseCommaSeparatedList } from '../../../../../../utils';
import { AggParam, FieldParamType } from '../../../../agg_types';
import { useValidation } from './agg_utils';
import { AggParamEditorProps, ComboBoxGroupedOptions } from '..';
const label = i18n.translate('common.ui.aggTypes.field.fieldLabel', { defaultMessage: 'Field' });
import { Field } from 'src/plugins/data/public';
import { AggConfig, AggParam, FieldParamType } from '../../legacy_imports';
import { formatListAsProse, parseCommaSeparatedList, useValidation } from './utils';
import { AggParamEditorProps } from '../agg_param_props';
import { ComboBoxGroupedOptions } from '../../utils';
const label = i18n.translate('visDefaultEditor.controls.field.fieldLabel', {
defaultMessage: 'Field',
});
export interface FieldParamEditorProps extends AggParamEditorProps<Field> {
customError?: string;
@ -66,7 +68,7 @@ function FieldParamEditor({
if (!indexedFields.length) {
errors.push(
i18n.translate('common.ui.aggTypes.field.noCompatibleFieldsDescription', {
i18n.translate('visDefaultEditor.controls.field.noCompatibleFieldsDescription', {
defaultMessage:
'The index pattern {indexPatternTitle} does not contain any of the following compatible field types: {fieldTypes}',
values: {
@ -106,7 +108,7 @@ function FieldParamEditor({
>
<EuiComboBox
compressed
placeholder={i18n.translate('common.ui.aggTypes.field.selectFieldPlaceholder', {
placeholder={i18n.translate('visDefaultEditor.controls.field.selectFieldPlaceholder', {
defaultMessage: 'Select a field',
})}
options={indexedFields}

View file

@ -20,12 +20,9 @@
import React, { useState } from 'react';
import { EuiForm, EuiButtonIcon, EuiFieldText, EuiFormRow, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../..';
import { npStart } from '../../../../new_platform';
import { Query, QueryStringInput } from '../../../../../../../plugins/data/public';
import { Storage } from '../../../../../../../plugins/kibana_utils/public';
import { KibanaContextProvider } from '../../../../../../../plugins/kibana_react/public';
const localStorage = new Storage(window.localStorage);
import { Query, QueryStringInput } from '../../../../../../plugins/data/public';
import { AggConfig } from '../../legacy_imports';
interface FilterRowProps {
id: string;
@ -53,7 +50,7 @@ function FilterRow({
onRemoveFilter,
}: FilterRowProps) {
const [showCustomLabel, setShowCustomLabel] = useState(false);
const filterLabel = i18n.translate('common.ui.aggTypes.filters.filterLabel', {
const filterLabel = i18n.translate('visDefaultEditor.controls.filters.filterLabel', {
defaultMessage: 'Filter {index}',
values: {
index: arrayIndex + 1,
@ -64,9 +61,12 @@ function FilterRow({
<div>
<EuiButtonIcon
iconType="tag"
aria-label={i18n.translate('common.ui.aggTypes.filters.toggleFilterButtonAriaLabel', {
defaultMessage: 'Toggle filter label',
})}
aria-label={i18n.translate(
'visDefaultEditor.controls.filters.toggleFilterButtonAriaLabel',
{
defaultMessage: 'Toggle filter label',
}
)}
aria-expanded={showCustomLabel}
aria-controls={`visEditorFilterLabel${arrayIndex}`}
onClick={() => setShowCustomLabel(!showCustomLabel)}
@ -75,15 +75,17 @@ function FilterRow({
iconType="trash"
color="danger"
disabled={disableRemove}
aria-label={i18n.translate('common.ui.aggTypes.filters.removeFilterButtonAriaLabel', {
defaultMessage: 'Remove this filter',
})}
aria-label={i18n.translate(
'visDefaultEditor.controls.filters.removeFilterButtonAriaLabel',
{
defaultMessage: 'Remove this filter',
}
)}
onClick={() => onRemoveFilter(id)}
/>
</div>
);
// TODO: KibanaContextProvider should be raised to the top of the vis plugin
return (
<EuiForm>
<EuiFormRow
@ -91,29 +93,20 @@ function FilterRow({
labelAppend={FilterControl}
fullWidth={true}
>
<KibanaContextProvider
services={{
appName: 'filtersAgg',
storage: localStorage,
data: npStart.plugins.data,
...npStart.core,
}}
>
<QueryStringInput
query={value}
indexPatterns={[agg.getIndexPattern()]}
onChange={(query: Query) => onChangeValue(id, query, customLabel)}
disableAutoFocus={!autoFocus}
dataTestSubj={dataTestSubj}
bubbleSubmitEvent={true}
languageSwitcherPopoverAnchorPosition="leftDown"
/>
</KibanaContextProvider>
<QueryStringInput
query={value}
indexPatterns={[agg.getIndexPattern()]}
onChange={(query: Query) => onChangeValue(id, query, customLabel)}
disableAutoFocus={!autoFocus}
dataTestSubj={dataTestSubj}
bubbleSubmitEvent={true}
languageSwitcherPopoverAnchorPosition="leftDown"
/>
</EuiFormRow>
{showCustomLabel ? (
<EuiFormRow
id={`visEditorFilterLabel${arrayIndex}`}
label={i18n.translate('common.ui.aggTypes.filters.definiteFilterLabel', {
label={i18n.translate('visDefaultEditor.controls.filters.definiteFilterLabel', {
defaultMessage: 'Filter {index} label',
description:
"'Filter {index}' represents the name of the filter as a noun, similar to 'label for filter 1'.",
@ -126,7 +119,7 @@ function FilterRow({
>
<EuiFieldText
value={customLabel}
placeholder={i18n.translate('common.ui.aggTypes.filters.labelPlaceholder', {
placeholder={i18n.translate('visDefaultEditor.controls.filters.labelPlaceholder', {
defaultMessage: 'Label',
})}
onChange={ev => onChangeValue(id, value, ev.target.value)}

View file

@ -21,15 +21,15 @@ import React, { useState, useEffect } from 'react';
import { omit, isEqual } from 'lodash';
import { htmlIdGenerator, EuiButton, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { Query } from 'src/plugins/data/public';
import chrome from '../../../../chrome';
import { useKibana } from '../../../../../../plugins/kibana_react/public';
import { FilterRow } from './filter';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
const generateId = htmlIdGenerator();
const config = chrome.getUiSettingsClient();
export interface FilterValue {
interface FilterValue {
input: Query;
label: string;
id: string;
@ -61,11 +61,13 @@ function FiltersParamEditor({ agg, value = [], setValue }: AggParamEditorProps<F
setFilters(updatedFilters);
};
const { services } = useKibana();
const onAddFilter = () =>
updateFilters([
...filters,
{
input: { query: '', language: config.get('search:queryLanguage') },
input: { query: '', language: services.uiSettings.get('search:queryLanguage') },
label: '',
id: generateId(),
},
@ -111,7 +113,7 @@ function FiltersParamEditor({ agg, value = [], setValue }: AggParamEditorProps<F
data-test-subj="visEditorAddFilterButton"
>
<FormattedMessage
id="common.ui.aggTypes.filters.addFilterButtonLabel"
id="visDefaultEditor.controls.filters.addFilterButtonLabel"
defaultMessage="Add filter"
/>
</EuiButton>

View file

@ -19,9 +19,10 @@
import React, { useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { SwitchParamEditor } from './switch';
import { isType } from '../../../../agg_types/buckets/migrate_include_exclude_format';
import { AggParamEditorProps } from '..';
import { isType } from '../../legacy_imports';
import { AggParamEditorProps } from '../agg_param_props';
function HasExtendedBoundsParamEditor(props: AggParamEditorProps<boolean>) {
useEffect(() => {
@ -30,10 +31,10 @@ function HasExtendedBoundsParamEditor(props: AggParamEditorProps<boolean>) {
return (
<SwitchParamEditor
displayLabel={i18n.translate('common.ui.aggTypes.extendedBoundsLabel', {
displayLabel={i18n.translate('visDefaultEditor.controls.extendedBoundsLabel', {
defaultMessage: 'Extend bounds',
})}
displayToolTip={i18n.translate('common.ui.aggTypes.extendedBoundsTooltip', {
displayToolTip={i18n.translate('visDefaultEditor.controls.extendedBoundsTooltip', {
defaultMessage:
'Min and Max do not filter the results, but rather extend the bounds of the result set.',
})}

View file

@ -0,0 +1,53 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export { AutoPrecisionParamEditor } from './auto_precision';
export { DateRangesParamEditor } from './date_ranges';
export { DropPartialsParamEditor } from './drop_partials';
export { ExtendedBoundsParamEditor } from './extended_bounds';
export { FieldParamEditor } from './field';
export { FiltersParamEditor } from './filters';
export { HasExtendedBoundsParamEditor } from './has_extended_bounds';
export { IpRangesParamEditor } from './ip_ranges';
export { IpRangeTypeParamEditor } from './ip_range_type';
export { IsFilteredByCollarParamEditor } from './is_filtered_by_collar';
export { MetricAggParamEditor } from './metric_agg';
export { MinDocCountParamEditor } from './min_doc_count';
export { MissingBucketParamEditor } from './missing_bucket';
export { NumberIntervalParamEditor } from './number_interval';
export { OrderByParamEditor } from './order_by';
export { OtherBucketParamEditor } from './other_bucket';
export { OrderAggParamEditor } from './order_agg';
export { PercentilesEditor } from './percentiles';
export { PercentileRanksEditor } from './percentile_ranks';
export { PrecisionParamEditor } from './precision';
export { RangesControl } from './range_control';
export { RawJsonParamEditor } from './raw_json';
export { ScaleMetricsParamEditor } from './scale_metrics';
export { SizeParamEditor } from './size';
export { StringParamEditor } from './string';
export { SubAggParamEditor } from './sub_agg';
export { SubMetricParamEditor } from './sub_metric';
export { TimeIntervalParamEditor } from './time_interval';
export { TopAggregateParamEditor } from './top_aggregate';
export { TopFieldParamEditor } from './top_field';
export { TopSizeParamEditor } from './top_size';
export { TopSortFieldParamEditor } from './top_sort_field';
export { OrderParamEditor } from './order';
export { UseGeocentroidParamEditor } from './use_geocentroid';

View file

@ -21,7 +21,8 @@ import React from 'react';
import { EuiButtonGroup, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
enum IpRangeTypes {
MASK = 'mask',
@ -32,13 +33,13 @@ function IpRangeTypeParamEditor({ agg, value, setValue }: AggParamEditorProps<Ip
const options = [
{
id: `visEditorIpRangeFromToLabel${agg.id}`,
label: i18n.translate('common.ui.aggTypes.ipRanges.fromToButtonLabel', {
label: i18n.translate('visDefaultEditor.controls.ipRanges.fromToButtonLabel', {
defaultMessage: 'From/to',
}),
},
{
id: `visEditorIpRangeCidrLabel${agg.id}`,
label: i18n.translate('common.ui.aggTypes.ipRanges.cidrMasksButtonLabel', {
label: i18n.translate('visDefaultEditor.controls.ipRanges.cidrMasksButtonLabel', {
defaultMessage: 'CIDR masks',
}),
},
@ -56,7 +57,7 @@ function IpRangeTypeParamEditor({ agg, value, setValue }: AggParamEditorProps<Ip
onChange={onClick}
idSelected={value === IpRangeTypes.FROM_TO ? options[0].id : options[1].id}
options={options}
legend={i18n.translate('common.ui.aggTypes.ipRangesAriaLabel', {
legend={i18n.translate('visDefaultEditor.controls.ipRangesAriaLabel', {
defaultMessage: 'IP ranges',
})}
/>

View file

@ -23,7 +23,8 @@ import { EuiFormRow } from '@elastic/eui';
import { FromToList, FromToObject } from './components/from_to_list';
import { MaskList, MaskObject } from './components/mask_list';
import { IpRangeTypes } from './ip_range_type';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
interface IpRange {
fromTo: FromToObject[];
mask: MaskObject[];

Some files were not shown because too many files have changed in this diff Show more