mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
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:
commit
3b498003b1
430 changed files with 6353 additions and 4097 deletions
|
@ -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/
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 server’s 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`.
|
||||
|
|
|
@ -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}>>.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>>.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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',
|
||||
],
|
||||
},
|
||||
|
|
|
@ -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'],
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 |
|
@ -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 {}}
|
||||
/>
|
||||
|
|
|
@ -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={
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -56,7 +56,7 @@ export function initEditorDirective(app, deps) {
|
|||
};
|
||||
});
|
||||
|
||||
initVisEditorDirective(app);
|
||||
initVisEditorDirective(app, deps);
|
||||
initVisualizationDirective(app, deps);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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() {
|
|
@ -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;
|
4
src/legacy/core_plugins/vis_default_editor/package.json
Normal file
4
src/legacy/core_plugins/vis_default_editor/package.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "vis_default_editor",
|
||||
"version": "kibana"
|
||||
}
|
|
@ -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.
|
|
@ -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
|
|
@ -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', () => {
|
|
@ -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 },
|
||||
})}
|
|
@ -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 }}
|
||||
/>
|
|
@ -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'];
|
|
@ -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();
|
|
@ -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(() => {
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { AggConfig } from '../../../../agg_types/agg_config';
|
||||
import { AggConfig } from '../legacy_imports';
|
||||
import {
|
||||
isAggRemovable,
|
||||
calcAggIsTooLow,
|
|
@ -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[]) => {
|
|
@ -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',
|
|
@ -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;
|
|
@ -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
|
|
@ -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),
|
||||
},
|
|
@ -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 => {
|
|
@ -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,
|
|
@ -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],
|
|
@ -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,
|
||||
};
|
|
@ -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}`}
|
|
@ -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>
|
|
@ -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 {}}
|
||||
/>
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
@ -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',
|
||||
});
|
||||
|
|
@ -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 || '*' },
|
||||
})}
|
|
@ -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>
|
|
@ -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 || '*' },
|
||||
})}
|
|
@ -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",
|
|
@ -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 }}
|
||||
/>
|
|
@ -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}
|
|
@ -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 },
|
||||
});
|
|
@ -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(),
|
||||
}));
|
||||
|
|
@ -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>
|
|
@ -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.",
|
||||
})}
|
|
@ -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>>;
|
|
@ -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.',
|
||||
});
|
||||
}
|
|
@ -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();
|
|
@ -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}
|
|
@ -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)}
|
|
@ -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>
|
|
@ -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.',
|
||||
})}
|
|
@ -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';
|
|
@ -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',
|
||||
})}
|
||||
/>
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue